Files

324 lines
8.2 KiB
C

#include <linux/module.h>
#include <linux/cpufreq.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include "drv_dev_defines.h"
#include "version.h"
#include "pmoc_comm.h"
#include "temperature.h"
#include "drv_svb.h"
#include "drv_pmc.h"
#include "drv_pm_ddr.h"
#include "xmedia_errcode.h"
#define DEFAULT_THREAD_TIME 100
#define XMEDIA_PM_INIT _IO('n', CMD_PM_INIT)
#define XMEDIA_PM_DEINIT _IO('n', CMD_PM_DEINIT)
#define XMEDIA_PM_GET_WAKEUP_SOURCE _IOWR('n', CMD_PM_GET_WK_SOURCE, lotus_pmc_wakeup_type)
#define XMEDIA_PM_GET_ATTR _IOWR('n', CMD_PM_GET_ALL_ATTR, lotus_pmc_all_attr)
#define XMEDIA_PM_SET_ATTR _IOWR('n', CMD_PM_SET_ALL_ATTR, lotus_pmc_all_attr)
#define XMEDIA_PM_GET_RTC_ATTR _IOWR('n', CMD_PM_GET_RTC_ATTR, lotus_pmc_rtc_attr)
#define XMEDIA_PM_SET_RTC_ATTR _IOWR('n', CMD_PM_SET_RTC_ATTR, lotus_pmc_rtc_attr)
#define XMEDIA_PM_GET_WK_ATTR _IOWR('n', CMD_PM_GET_WK_ATTR, lotus_pmc_wakeup_attr)
#define XMEDIA_PM_SET_WK_ATTR _IOWR('n', CMD_PM_SET_WK_ATTR, lotus_pmc_wakeup_attr)
#define XMEDIA_PM_GET_RTC_TIMER _IO('n', CMD_PM_GET_RTC_TIMER)
#define XMEDIA_PM_SET_AUX _IOWR('n', CMD_PM_SET_AUX, struct aux_mem)
#define XMEDIA_PM_GET_DDR_PARAM _IOR('n', CMD_PM_GET_DDR_PARAM, struct lpds_param)
#ifdef PM_WAKEUP1_SUPPORT
#define XMEDIA_PM_GET_WK_INFO _IOWR('n', CMD_PM_GET_WK_INFO, lotus_pm_wakeup_info)
#endif
#define XMEDIA_PM_GET_RTC_INFO _IOR('n', CMD_PM_GET_RTC_INFO, lotus_pm_rtc_info)
static osal_dev_t *g_pm_dev = XMEDIA_NULL;
static osal_task_t *g_ctrl_thread = XMEDIA_NULL;
xmedia_bool g_pm_resume = false;
xmedia_s32 pm_ctrl_thread(xmedia_void *data)
{
xmedia_s32 ret;
bool was_frozen;
set_freezable();
ret = drv_svb_init();
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "svb init fail\n");
return XMEDIA_FAILURE;
}
if (!is_svb_enabled())
return XMEDIA_SUCCESS;
temp_init();
while (!kthread_freezable_should_stop(&was_frozen)) {
if (was_frozen || g_pm_resume) {
pr_info("T Ctrl Thread resumed after freeze\n");
temp_init();
g_pm_resume = false;
}
freezable_schedule_timeout_interruptible(msecs_to_jiffies(DEFAULT_THREAD_TIME));
temp_control_thread();
}
return XMEDIA_SUCCESS;
}
static int drv_pm_proc_show(struct osal_proc_dir_entry *s)
{
xmedia_char version_info[128] = {0};
VERSION_FORMAT(version_info, "Pm", "V1.0", "");
osal_seq_printf(s, "\n%s\n", version_info);
osal_seq_printf(s, "Temperature : %d\n", get_chip_temperature());
osal_seq_printf(s, "CpuFreq(khz) : %d\n", get_cpu_freq() / 1000);
osal_seq_printf(s, "HPM : %u\n", get_chip_hpm());
osal_seq_printf(s, "CoreVolt(mv) : %u\n", get_core_volt());
return 0;
}
xmedia_s32 drv_pm_open(xmedia_void *private_data)
{
return XMEDIA_SUCCESS;
}
xmedia_s32 drv_pm_close(xmedia_void *private_data)
{
return XMEDIA_SUCCESS;
}
static long drv_pm_ioctl(unsigned int cmd, unsigned long arg, xmedia_void *private_data)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
lotus_pmc_wakeup_type *type;
lotus_pmc_all_attr *param;
lotus_pmc_rtc_attr *rtc_attr;
lotus_pmc_wakeup_attr *wk_attr;
struct aux_mem *aux;
#ifdef PM_WAKEUP1_SUPPORT
lotus_pm_wakeup_info *wakeup_info;
#endif
lotus_pm_rtc_info *rtc_info;
switch (cmd) {
case XMEDIA_PM_INIT:
ret = lotus_pmc_init();
break;
case XMEDIA_PM_DEINIT:
lotus_pmc_deinit();
break;
case XMEDIA_PM_SET_ATTR:
param = (lotus_pmc_all_attr *)arg;
ret = lotus_set_all_attr(param);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "lotus_set_wakeup_source failed: %d\n", ret);
return ret;
}
break;
case XMEDIA_PM_GET_ATTR:
param = (lotus_pmc_all_attr *)arg;
ret = lotus_get_all_attr(param);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "lotus_get_wakeup_source failed: %d\n", ret);
return ret;
}
break;
case XMEDIA_PM_GET_RTC_ATTR:
rtc_attr = (lotus_pmc_rtc_attr *)arg;
ret = lotus_get_rtc_attr(rtc_attr);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "lotus_get_rtc_attr failed: %d\n", ret);
return ret;
}
break;
case XMEDIA_PM_SET_RTC_ATTR:
rtc_attr = (lotus_pmc_rtc_attr *)arg;
ret = lotus_set_rtc_attr(rtc_attr);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "lotus_set_rtc_attr failed: %d\n", ret);
return ret;
}
break;
case XMEDIA_PM_GET_WK_ATTR:
wk_attr = (lotus_pmc_wakeup_attr *)arg;
ret = lotus_get_wakeup_attr(wk_attr);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "lotus_set_wakeup_attr failed: %d\n", ret);
return ret;
}
break;
case XMEDIA_PM_SET_WK_ATTR:
wk_attr = (lotus_pmc_wakeup_attr *)arg;
ret = lotus_set_wakeup_attr(wk_attr);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "lotus_set_wakeup_attr failed: %d\n", ret);
return ret;
}
break;
case XMEDIA_PM_GET_WAKEUP_SOURCE:
type = (lotus_pmc_wakeup_type *)arg;
ret = lotus_get_wakeup_type(type);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "lotus_get_wakeup_type failed:%d\n", ret);
return ret;
}
break;
case XMEDIA_PM_GET_RTC_TIMER:
lotus_get_rtc_timer();
return XMEDIA_SUCCESS;
case XMEDIA_PM_SET_AUX:
aux = (struct aux_mem *)arg;
ret = lotus_pmc_set_aux(aux);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "lotus_set_aux failed:%d\n", ret);
return ret;
}
break;
case XMEDIA_PM_GET_DDR_PARAM:
#ifdef CONFIG_PM
struct lpds_param *plpds_param;
plpds_param = (struct lpds_param *)arg;
ret = pm_ddr_param_get(plpds_param);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "get ddr param failed:%d\n", ret);
return ret;
}
break;
#else
return XMEDIA_ERRCODE_NOT_SUPPORT;
#endif
#ifdef PM_WAKEUP1_SUPPORT
case XMEDIA_PM_GET_WK_INFO:
wakeup_info = (lotus_pm_wakeup_info *)arg;
ret = lotus_pm_get_wakeup_info(wakeup_info);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "get wakeup info failed:%d\n", ret);
return ret;
}
break;
#endif
case XMEDIA_PM_GET_RTC_INFO:
rtc_info = (lotus_pm_rtc_info *)arg;
ret = lotus_pm_get_rtc_info(rtc_info);
if (ret != XMEDIA_SUCCESS) {
PM_TRACE(MODULE_DBG_ERR, "get rtc info failed:%d\n", ret);
return ret;
}
break;
default:
break;
}
return ret;
}
xmedia_s32 drv_pm_suspend(osal_dev_t *pdev)
{
osal_printk("pm suspend OK!\n");
return XMEDIA_SUCCESS;
}
xmedia_s32 drv_pm_resume(osal_dev_t *pdev)
{
g_pm_resume = true;
osal_printk("pm resume OK!\n");
return XMEDIA_SUCCESS;
}
static struct osal_fileops g_pm_fops = {
.open = drv_pm_open,
.unlocked_ioctl = drv_pm_ioctl,
.release = drv_pm_close,
};
struct osal_pmops g_pm_drv_ops = {
.pm_suspend = drv_pm_suspend,
.pm_resume = drv_pm_resume,
};
xmedia_s32 pmoc_drv_modinit(xmedia_void)
{
osal_proc_entry_t *proc = XMEDIA_NULL;
g_pm_dev = osal_createdev(UMAP_DEVNAME_PM_BASE);
if (g_pm_dev == XMEDIA_NULL) {
PM_TRACE(MODULE_DBG_ERR, "pm create dev err!\n");
goto out0;
}
g_pm_dev->fops = &g_pm_fops;
g_pm_dev->minor = UMAP_PM_MINOR_BASE;
g_pm_dev->osal_pmops = &g_pm_drv_ops;
if (osal_registerdevice(g_pm_dev) < 0) {
PM_TRACE(MODULE_DBG_ERR, "regist pm device err!\n");
goto out1;
}
g_ctrl_thread = osal_kthread_create(pm_ctrl_thread, XMEDIA_NULL, "lotus_pm_control");
if (g_ctrl_thread == XMEDIA_NULL) {
PM_TRACE(MODULE_DBG_ERR, "create pm control failed.\n");
goto out2;
}
/* create proc */
proc = osal_create_proc_entry(MPP_MOD_PM, XMEDIA_NULL);
if (proc == XMEDIA_NULL) {
PM_TRACE(MODULE_DBG_ERR, "MODULE_DBG_ERR, Create pm proc err!\n");
goto out3;
}
proc->read = drv_pm_proc_show;
proc->write = XMEDIA_NULL;
osal_printk("load xm_pm.ko OK!\n");
return XMEDIA_SUCCESS;
out3:
osal_kthread_destroy(g_ctrl_thread, 1);
g_ctrl_thread = XMEDIA_NULL;
out2:
osal_deregisterdevice(g_pm_dev);
out1:
osal_destroydev(g_pm_dev);
g_pm_dev = XMEDIA_NULL;
out0:
osal_printk("load xm_pm.ko err!\n");
return XMEDIA_FAILURE;
}
xmedia_void pmoc_drv_modexit(xmedia_void)
{
osal_remove_proc_entry(MPP_MOD_PM, XMEDIA_NULL);
if (g_ctrl_thread && is_svb_enabled()) {
osal_kthread_destroy(g_ctrl_thread, 1);
g_ctrl_thread = XMEDIA_NULL;
}
drv_svb_deinit();
osal_deregisterdevice(g_pm_dev);
osal_destroydev(g_pm_dev);
g_pm_dev = XMEDIA_NULL;
osal_printk("unload xm_pm.ko OK!\n");
return;
}
#ifdef MODULE
module_init(pmoc_drv_modinit);
module_exit(pmoc_drv_modexit);
MODULE_LICENSE("GPL");
#else
int __init pmoc_driver_init(void)
{
return pmoc_drv_modinit();
}
#endif