From d36627f141f5cfd75a687a6d63671a2c3402bb96 Mon Sep 17 00:00:00 2001 From: Yong Qin Date: Sat, 28 Sep 2019 10:54:01 +0800 Subject: [PATCH] cec: Add Feature for freeze mode power on [1/2] PD#TV-10483 Problem: Add feature for freeze mode power on by cec. Solution: Add feature for freeze mode power on by cec. Verify: tl1 Change-Id: I3e0271cb000d64c4b30cfc75c59e8ca374993d7f Signed-off-by: Yong Qin --- drivers/amlogic/cec/hdmi_ao_cec.c | 170 ++++++++++++++---- drivers/amlogic/cec/hdmi_ao_cec.h | 3 +- .../media/vout/hdmi_tx/hdmi_tx_cec_20.h | 2 + 3 files changed, 143 insertions(+), 32 deletions(-) diff --git a/drivers/amlogic/cec/hdmi_ao_cec.c b/drivers/amlogic/cec/hdmi_ao_cec.c index 41c18d63610a..f1c7eaa95628 100644 --- a/drivers/amlogic/cec/hdmi_ao_cec.c +++ b/drivers/amlogic/cec/hdmi_ao_cec.c @@ -48,7 +48,9 @@ #include #include #include - +#include +#include +#include #include #include #include @@ -580,6 +582,8 @@ void cecb_irq_handle(void) complete(&cec_dev->rx_ok); new_msg = 1; dwork = &cec_dev->cec_work; + if (is_pm_freeze_mode()) + cec_freeze_mode_process(); mod_delayed_work(cec_dev->cec_thread, dwork, 0); } @@ -1864,6 +1868,10 @@ static int cec_late_check_rx_buffer(void) void cec_key_report(int suspend) { + if (is_pm_freeze_mode()) { + pm_wakeup_event(cec_dev->dbg_dev, 2000); + CEC_INFO("freeze mode:pm_wakeup_event\n"); + } input_event(cec_dev->cec_info.remote_cec_dev, EV_KEY, KEY_POWER, 1); input_sync(cec_dev->cec_info.remote_cec_dev); input_event(cec_dev->cec_info.remote_cec_dev, EV_KEY, KEY_POWER, 0); @@ -2159,6 +2167,63 @@ static bool cec_service_suspended(void) return false; } +static void cec_save_pre_setting(void) +{ + unsigned int config_data; + + /*if (is_pm_freeze_mode())*/ + /* cec_config(CEC_FUNC_CFG_ALL, 1);*/ + /* AO_DEBUG_REG1 + * 0-15 : phy addr + * 16-20: logical address + * 21-23: device type + */ + config_data = cec_dev->cec_info.log_addr; + cec_set_reg_bits(AO_DEBUG_REG1, config_data, 16, 4); + config_data = cec_dev->dev_type; + cec_set_reg_bits(AO_DEBUG_REG1, config_data, 20, 4); + CEC_ERR("%s: logaddr:0x%x, devtype:0x%x\n", __func__, + cec_dev->cec_info.log_addr, + config_data = cec_dev->dev_type); +} + +static void cec_restore_pre_setting(void) +{ + unsigned int logaddr; + unsigned int devtype; + unsigned int config_data; + char *token; + + config_data = cec_config(0, 0); + /*get device type*/ + logaddr = (config_data >> 16) & 0xf; + devtype = (config_data >> 20) & 0xf; + /*get logical address*/ + if (cec_dev->cec_num > ENABLE_ONE_CEC) + cec_logicaddr_add(CEC_B, logaddr); + else + cec_logicaddr_add(ee_cec, logaddr); + cec_dev->cec_info.addr_enable |= (1 << logaddr); + + /* add by hal, to init some data structure */ + cec_dev->dev_type = devtype; + cec_dev->cec_info.log_addr = logaddr; + cec_dev->cec_info.vendor_id = cec_dev->v_data.vendor_id; + CEC_ERR("%s: logaddr:0x%x, devtype:0x%x\n", __func__, + cec_dev->cec_info.log_addr, + config_data = cec_dev->dev_type); + + /*suspend freeze mode, driver handle cec msg*/ + cec_dev->hal_flag &= ~(1 << HDMI_OPTION_SERVICE_FLAG); + if (cec_msg_dbg_en) { + cec_status(); + token = kmalloc(2048, GFP_KERNEL); + dump_cecrx_reg(token); + CEC_ERR("%s\n", token); + kfree(token); + } +} + static void cec_task(struct work_struct *work) { struct delayed_work *dwork = &cec_dev->cec_work; @@ -2185,6 +2250,16 @@ static void cec_task(struct work_struct *work) queue_delayed_work(cec_dev->cec_thread, dwork, CEC_FRAME_DELAY); } +void cec_freeze_mode_process(void) +{ + unsigned int cec_cfg; + + CEC_ERR("%s\n", __func__); + cec_cfg = cec_config(0, 0); + if (cec_cfg & CEC_FUNC_CFG_CEC_ON) + cec_rx_process(); +} + static void ceca_tasklet_pro(unsigned long arg) { unsigned int intr_stat = 0; @@ -2717,6 +2792,9 @@ static ssize_t dbg_store(struct class *cla, struct class_attribute *attr, return count; cec_ip_share_io(true, val); pr_info("share_io %d (0:a to b, 1:b to a)\n", val); + } else if (token && strncmp(token, "setfreeze", 9) == 0) { + cec_save_pre_setting(); + CEC_ERR("Set enter freeze mode\n"); } else { if (token) CEC_ERR("no cmd:%s, supported list:\n", token); @@ -2751,7 +2829,6 @@ static ssize_t dbg_show(struct class *cla, return 0; } - static struct class_attribute aocec_class_attr[] = { __ATTR_WO(cmd), __ATTR_WO(cmda), @@ -3206,7 +3283,13 @@ static long hdmitx_cec_ioctl(struct file *f, return -EINVAL; } break; - + case CEC_IOC_SET_FREEZE_MODE: + /* system enter power down freeze mode + * need save current device type and logical addr + */ + cec_save_pre_setting(); + CEC_ERR("need enter freeze mode\n"); + break; default: CEC_ERR("error ioctrl\n"); break; @@ -3259,13 +3342,13 @@ static const struct file_operations hdmitx_cec_fops = { static void aocec_early_suspend(struct early_suspend *h) { cec_dev->cec_suspend = CEC_PW_STANDBY; - CEC_INFO("%s, suspend:%d\n", __func__, cec_dev->cec_suspend); + CEC_ERR("%s, suspend sts:%d\n", __func__, cec_dev->cec_suspend); } static void aocec_late_resume(struct early_suspend *h) { cec_dev->cec_suspend = CEC_PW_POWER_ON; - CEC_INFO("%s, suspend:%d\n", __func__, cec_dev->cec_suspend); + CEC_ERR("%s, suspend sts:%d\n", __func__, cec_dev->cec_suspend); } #endif @@ -3705,25 +3788,29 @@ static int aml_cec_probe(struct platform_device *pdev) /* request two int source */ CEC_ERR("request_irq two irq src\n"); r = request_irq(cec_dev->irq_ceca, &ceca_isr, - IRQF_SHARED, irq_name_a, (void *)cec_dev); + IRQF_SHARED | IRQF_NO_SUSPEND, irq_name_a, + (void *)cec_dev); if (r < 0) CEC_INFO("aocec irq request fail\n"); r = request_irq(cec_dev->irq_cecb, &cecb_isr, - IRQF_SHARED, irq_name_b, (void *)cec_dev); + IRQF_SHARED | IRQF_NO_SUSPEND, irq_name_b, + (void *)cec_dev); if (r < 0) CEC_INFO("cecb irq request fail\n"); } else { if (!r && (ee_cec == CEC_A)) { r = request_irq(cec_dev->irq_ceca, &ceca_isr, - IRQF_SHARED, irq_name_a, (void *)cec_dev); + IRQF_SHARED | IRQF_NO_SUSPEND, irq_name_a, + (void *)cec_dev); if (r < 0) CEC_INFO("aocec irq request fail\n"); } if (!r && (ee_cec == CEC_B)) { r = request_irq(cec_dev->irq_cecb, &cecb_isr, - IRQF_SHARED, irq_name_b, (void *)cec_dev); + IRQF_SHARED | IRQF_NO_SUSPEND, irq_name_b, + (void *)cec_dev); if (r < 0) CEC_INFO("cecb irq request fail\n"); } @@ -3754,6 +3841,19 @@ static int aml_cec_probe(struct platform_device *pdev) ret = -EFAULT; goto tag_cec_threat_err; } + /*freeze wakeup init*/ + device_init_wakeup(&pdev->dev, 1); + CEC_INFO("dev init wakeup\n"); + if (cec_dev->cec_num > ENABLE_ONE_CEC) { + dev_pm_set_wake_irq(&pdev->dev, cec_dev->irq_ceca); + dev_pm_set_wake_irq(&pdev->dev, cec_dev->irq_cecb); + } else { + if (ee_cec == CEC_A) + dev_pm_set_wake_irq(&pdev->dev, cec_dev->irq_ceca); + else + dev_pm_set_wake_irq(&pdev->dev, cec_dev->irq_cecb); + } + INIT_DELAYED_WORK(&cec_dev->cec_work, cec_task); queue_delayed_work(cec_dev->cec_thread, &cec_dev->cec_work, 0); tasklet_init(&ceca_tasklet, ceca_tasklet_pro, @@ -3827,7 +3927,7 @@ static int aml_cec_remove(struct platform_device *pdev) static int aml_cec_pm_prepare(struct device *dev) { //cec_dev->cec_suspend = CEC_DEEP_SUSPEND; - CEC_INFO("%s\n", __func__); + CEC_ERR("%s\n", __func__); return 0; } @@ -3840,7 +3940,7 @@ static void aml_cec_pm_complete(struct device *dev) CEC_ERR("clr wakeup reason fail\n"); } - CEC_INFO("%s\n", __func__); + CEC_ERR("%s\n", __func__); } static int aml_cec_suspend_noirq(struct device *dev) @@ -3850,17 +3950,20 @@ static int aml_cec_suspend_noirq(struct device *dev) cec_dev->cec_info.power_status = CEC_PW_TRANS_ON_TO_STANDBY; cec_dev->cec_suspend = CEC_PW_TRANS_ON_TO_STANDBY; - CEC_INFO("cec suspend noirq\n"); - if (cec_dev->cec_num > ENABLE_ONE_CEC) - cec_clear_all_logical_addr(CEC_B); - else - cec_clear_all_logical_addr(ee_cec); - - if (!IS_ERR(cec_dev->dbg_dev->pins->sleep_state)) - ret = pinctrl_pm_select_sleep_state(cec_dev->dbg_dev); - else - CEC_ERR("pinctrl sleep_state error\n"); + if (is_pm_freeze_mode()) { + CEC_ERR("%s:freeze mode\n", __func__); + cec_restore_pre_setting(); + } else { + if (cec_dev->cec_num > ENABLE_ONE_CEC) + cec_clear_all_logical_addr(CEC_B); + else + cec_clear_all_logical_addr(ee_cec); + if (!IS_ERR(cec_dev->dbg_dev->pins->sleep_state)) + ret = pinctrl_pm_select_sleep_state(cec_dev->dbg_dev); + else + CEC_ERR("pinctrl sleep_state error\n"); + } cec_dev->cec_info.power_status = CEC_PW_STANDBY; cec_dev->cec_suspend = CEC_PW_STANDBY; return 0; @@ -3871,20 +3974,25 @@ static int aml_cec_resume_noirq(struct device *dev) int ret = 0; unsigned int temp; - CEC_INFO("cec resume noirq!\n"); + CEC_ERR("cec resume noirq!\n"); cec_dev->cec_info.power_status = CEC_PW_TRANS_STANDBY_TO_ON; cec_dev->cec_suspend = CEC_PW_TRANS_STANDBY_TO_ON; + if (!is_pm_freeze_mode()) { + scpi_get_wakeup_reason(&cec_dev->wakeup_reason); + CEC_ERR("wakeup_reason:0x%x\n", cec_dev->wakeup_reason); - scpi_get_wakeup_reason(&cec_dev->wakeup_reason); - CEC_ERR("wakeup_reason:0x%x\n", cec_dev->wakeup_reason); - - scpi_get_cec_val(SCPI_CMD_GET_CEC1, - (unsigned int *)&cec_dev->wakup_data); - scpi_get_cec_val(SCPI_CMD_GET_CEC2, &temp); - CEC_ERR("cev val1: %#x;val2: %#x\n", - *((unsigned int *)&cec_dev->wakup_data), - temp); + scpi_get_cec_val(SCPI_CMD_GET_CEC1, + (unsigned int *)&cec_dev->wakup_data); + CEC_ERR("cev val1:0x%x,0x%x,0x%x\n", + cec_dev->wakup_data.wk_logic_addr, + cec_dev->wakup_data.wk_phy_addr, + cec_dev->wakup_data.wk_port_id); + scpi_get_cec_val(SCPI_CMD_GET_CEC2, &temp); + CEC_ERR("cev val2: 0x%#x\n", temp); + } else { + CEC_ERR("freeze mode\n"); + } cec_pre_init(); if (!IS_ERR(cec_dev->dbg_dev->pins->default_state)) ret = pinctrl_pm_select_default_state(cec_dev->dbg_dev); diff --git a/drivers/amlogic/cec/hdmi_ao_cec.h b/drivers/amlogic/cec/hdmi_ao_cec.h index f017978c63c1..295772036135 100644 --- a/drivers/amlogic/cec/hdmi_ao_cec.h +++ b/drivers/amlogic/cec/hdmi_ao_cec.h @@ -18,7 +18,7 @@ #ifndef __AO_CEC_H__ #define __AO_CEC_H__ -#define CEC_DRIVER_VERSION "2019/10/11: Fix coverity error\n" +#define CEC_DRIVER_VERSION "2019/10/11:add freeze mode wake up func-1\n" #define CEC_FRAME_DELAY msecs_to_jiffies(400) #define CEC_DEV_NAME "cec" @@ -580,5 +580,6 @@ extern void cec_logicaddr_add(unsigned int cec_sel, unsigned int l_add); extern void cec_clear_all_logical_addr(unsigned int cec_sel); extern int dump_cecrx_reg(char *b); extern void cec_ip_share_io(u32 share, u32 cec_ip); +void cec_freeze_mode_process(void); #endif /* __AO_CEC_H__ */ diff --git a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h index 0c218f6021c8..f09515a36866 100644 --- a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h +++ b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h @@ -100,6 +100,8 @@ enum _cec_log_dev_addr_e { #define CEC_IOC_SET_AUTO_DEVICE_OFF _IOW(CEC_IOC_MAGIC, 0x0F, uint32_t) #define CEC_IOC_GET_BOOT_ADDR _IOW(CEC_IOC_MAGIC, 0x10, uint32_t) #define CEC_IOC_GET_BOOT_REASON _IOW(CEC_IOC_MAGIC, 0x11, uint32_t) +#define CEC_IOC_SET_FREEZE_MODE _IOW(CEC_IOC_MAGIC, 0x12, uint32_t) + #define CEC_FAIL_NONE 0 #define CEC_FAIL_NACK 1