324 lines
8.2 KiB
C
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
|