Loading drivers/video/msm/mdss/dsi_status_6g.c +18 −20 Original line number Diff line number Diff line /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -14,6 +14,7 @@ #include <linux/delay.h> #include <linux/kobject.h> #include <linux/sysfs.h> #include <linux/interrupt.h> #include "mdss_dsi.h" #include "mdss_mdp.h" Loading @@ -22,7 +23,7 @@ * mdss_check_te_status() - Check the status of panel for TE based ESD. * @ctrl_pdata : dsi controller data * @pstatus_data : dsi status data * @interval : duration in milliseconds to schedule work queue * @interval : duration in milliseconds for panel TE wait * * This function is called when the TE signal from the panel doesn't arrive * after 'interval' milliseconds. If the TE IRQ is not ready, the workqueue Loading @@ -33,21 +34,14 @@ static bool mdss_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, { bool ret; /* * During resume, the panel status will be ON but due to race condition * between ESD thread and display UNBLANK (or rather can be put as * asynchronuous nature between these two threads), the ESD thread might * reach this point before the TE IRQ line is enabled or before the * first TE interrupt arrives after the TE IRQ line is enabled. For such * cases, re-schedule the ESD thread. */ ret = !atomic_read(&ctrl_pdata->te_irq_ready); if (ret) { schedule_delayed_work(&pstatus_data->check_status, atomic_set(&ctrl_pdata->te_irq_ready, 0); reinit_completion(&ctrl_pdata->te_irq_comp); enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); /* Define TE interrupt timeout value as 3x(1/fps) */ ret = wait_for_completion_timeout(&ctrl_pdata->te_irq_comp, msecs_to_jiffies(interval)); pr_debug("%s: TE IRQ line not enabled yet\n", __func__); } disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); pr_debug("%s: Panel TE check done with ret = %d\n", __func__, ret); return ret; } Loading Loading @@ -110,13 +104,17 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) } if (ctrl_pdata->status_mode == ESD_TE) { if (mdss_check_te_status(ctrl_pdata, pstatus_data, interval)) return; uint32_t fps = mdss_panel_get_framerate(&pdata->panel_info, FPS_RESOLUTION_HZ); uint32_t timeout = ((1000 / fps) + 1) * MDSS_STATUS_TE_WAIT_MAX; if (mdss_check_te_status(ctrl_pdata, pstatus_data, timeout)) goto sim; else goto status_dead; } /* * TODO: Because mdss_dsi_cmd_mdp_busy has made sure DMA to * be idle in mdss_dsi_cmdlist_commit, it is not necessary Loading Loading @@ -173,7 +171,7 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) else goto status_dead; } sim: if (pdata->panel_info.panel_force_dead) { pr_debug("force_dead=%d\n", pdata->panel_info.panel_force_dead); pdata->panel_info.panel_force_dead--; Loading drivers/video/msm/mdss/dsi_status_v2.c +73 −13 Original line number Diff line number Diff line /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -9,16 +9,48 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/workqueue.h> #include <linux/delay.h> #include <linux/kobject.h> #include <linux/string.h> #include <linux/sysfs.h> #include <linux/interrupt.h> #include "mdss_dsi.h" #include "mdp3_ctrl.h" /* * mdp3_check_te_status() - Check the status of panel for TE based ESD. * @ctrl_pdata : dsi controller data * @pstatus_data : dsi status data * @interval : duration in milliseconds for panel TE wait * * This function waits for TE signal from the panel for a maximum * duration of 3 vsyncs. If timeout occurs, report the panel to be * dead due to ESD attack. * NOTE: The TE IRQ handling is linked to the ESD thread scheduling, * i.e. rate of TE IRQs firing is bound by the ESD interval. */ static int mdp3_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, struct dsi_status_data *pstatus_data, uint32_t interval) { int ret; pr_debug("%s: Checking panel TE status\n", __func__); atomic_set(&ctrl_pdata->te_irq_ready, 0); reinit_completion(&ctrl_pdata->te_irq_comp); enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); ret = wait_for_completion_timeout(&ctrl_pdata->te_irq_comp, msecs_to_jiffies(interval)); disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); pr_debug("%s: Panel TE check done with ret = %d\n", __func__, ret); return ret; } /* * mdp3_check_dsi_ctrl_status() - Check MDP3 DSI controller status periodically. * @work : dsi controller status data Loading @@ -33,6 +65,7 @@ void mdp3_check_dsi_ctrl_status(struct work_struct *work, { struct dsi_status_data *pdsi_status = NULL; struct mdss_panel_data *pdata = NULL; struct mipi_panel_info *mipi = NULL; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdp3_session_data *mdp3_session = NULL; int ret = 0; Loading @@ -51,15 +84,25 @@ void mdp3_check_dsi_ctrl_status(struct work_struct *work, return; } mipi = &pdata->panel_info.mipi; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata || !ctrl_pdata->check_status) { if (!ctrl_pdata || (!ctrl_pdata->check_status && (ctrl_pdata->status_mode != ESD_TE))) { pr_err("%s: DSI ctrl or status_check callback not available\n", __func__); return; } if (!pdata->panel_info.esd_rdy) { pr_err("%s: unblank not complete, reschedule check status\n", __func__); schedule_delayed_work(&pdsi_status->check_status, msecs_to_jiffies(interval)); return; } mdp3_session = pdsi_status->mfd->mdp.private1; if (!mdp3_session) { pr_err("%s: Display is off\n", __func__); Loading @@ -73,6 +116,19 @@ void mdp3_check_dsi_ctrl_status(struct work_struct *work, return; } if (mipi->mode == DSI_CMD_MODE && mipi->hw_vsync_mode && mdss_dsi_is_te_based_esd(ctrl_pdata)) { uint32_t fps = mdss_panel_get_framerate(&pdata->panel_info, FPS_RESOLUTION_HZ); uint32_t timeout = ((1000 / fps) + 1) * MDSS_STATUS_TE_WAIT_MAX; if (mdp3_check_te_status(ctrl_pdata, pdsi_status, timeout) > 0) return; goto status_dead; } mutex_lock(&mdp3_session->lock); if (!mdp3_session->status) { pr_debug("%s: display off already\n", __func__); Loading @@ -90,18 +146,22 @@ void mdp3_check_dsi_ctrl_status(struct work_struct *work, mutex_unlock(&mdp3_session->lock); if (mdss_fb_is_power_on_interactive(pdsi_status->mfd)) { if (ret > 0) { if (ret > 0) schedule_delayed_work(&pdsi_status->check_status, msecs_to_jiffies(interval)); } else { char *envp[2] = {"PANEL_ALIVE=0", NULL}; pdata->panel_info.panel_dead = true; ret = kobject_uevent_env( &pdsi_status->mfd->fbi->dev->kobj, KOBJ_CHANGE, envp); pr_err("%s: Panel has gone bad, sending uevent - %s\n", __func__, envp[0]); else goto status_dead; } if (pdata->panel_info.panel_force_dead) { pr_debug("force_dead=%d\n", pdata->panel_info.panel_force_dead); pdata->panel_info.panel_force_dead--; if (!pdata->panel_info.panel_force_dead) goto status_dead; } return; status_dead: mdss_fb_report_panel_dead(pdsi_status->mfd); } drivers/video/msm/mdss/mdss_dsi.c +1 −7 Original line number Diff line number Diff line Loading @@ -1623,8 +1623,6 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) if ((pdata->panel_info.type == MIPI_CMD_PANEL) && mipi->vsync_enable && mipi->hw_vsync_mode) { mdss_dsi_set_tear_on(ctrl_pdata); if (mdss_dsi_is_te_based_esd(ctrl_pdata)) enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); } ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT; Loading Loading @@ -1694,11 +1692,6 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata, int power_state) if ((pdata->panel_info.type == MIPI_CMD_PANEL) && mipi->vsync_enable && mipi->hw_vsync_mode) { if (mdss_dsi_is_te_based_esd(ctrl_pdata)) { disable_irq(gpio_to_irq( ctrl_pdata->disp_te_gpio)); atomic_dec(&ctrl_pdata->te_irq_ready); } mdss_dsi_set_tear_off(ctrl_pdata); } Loading Loading @@ -3252,6 +3245,7 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) } if (mdss_dsi_is_te_based_esd(ctrl_pdata)) { init_completion(&ctrl_pdata->te_irq_comp); rc = devm_request_irq(&pdev->dev, gpio_to_irq(ctrl_pdata->disp_te_gpio), hw_vsync_handler, IRQF_TRIGGER_FALLING, Loading drivers/video/msm/mdss/mdss_dsi.h +2 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ #define MDSS_DSI_HW_REV_STEP_1 0x1 #define MDSS_DSI_HW_REV_STEP_2 0x2 #define MDSS_STATUS_TE_WAIT_MAX 3 #define NONE_PANEL "none" enum { /* mipi dsi panel */ Loading Loading @@ -488,6 +489,7 @@ struct mdss_dsi_ctrl_pdata { struct completion video_comp; struct completion dynamic_comp; struct completion bta_comp; struct completion te_irq_comp; spinlock_t irq_lock; spinlock_t mdp_lock; int mdp_busy; Loading drivers/video/msm/mdss/mdss_dsi_status.c +9 −4 Original line number Diff line number Diff line /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -24,6 +24,7 @@ #include <linux/kobject.h> #include <linux/string.h> #include <linux/sysfs.h> #include <linux/interrupt.h> #include "mdss_fb.h" #include "mdss_dsi.h" Loading Loading @@ -94,8 +95,10 @@ irqreturn_t hw_vsync_handler(int irq, void *data) else pr_err("Pstatus data is NULL\n"); if (!atomic_read(&ctrl_pdata->te_irq_ready)) if (!atomic_read(&ctrl_pdata->te_irq_ready)) { complete_all(&ctrl_pdata->te_irq_comp); atomic_inc(&ctrl_pdata->te_irq_ready); } return IRQ_HANDLED; } Loading Loading @@ -160,10 +163,12 @@ static int fb_event_callback(struct notifier_block *self, schedule_delayed_work(&pdata->check_status, msecs_to_jiffies(interval)); break; case FB_BLANK_POWERDOWN: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_NORMAL: pr_debug("%s : ESD thread running\n", __func__); break; case FB_BLANK_POWERDOWN: case FB_BLANK_HSYNC_SUSPEND: cancel_delayed_work(&pdata->check_status); break; default: Loading Loading
drivers/video/msm/mdss/dsi_status_6g.c +18 −20 Original line number Diff line number Diff line /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -14,6 +14,7 @@ #include <linux/delay.h> #include <linux/kobject.h> #include <linux/sysfs.h> #include <linux/interrupt.h> #include "mdss_dsi.h" #include "mdss_mdp.h" Loading @@ -22,7 +23,7 @@ * mdss_check_te_status() - Check the status of panel for TE based ESD. * @ctrl_pdata : dsi controller data * @pstatus_data : dsi status data * @interval : duration in milliseconds to schedule work queue * @interval : duration in milliseconds for panel TE wait * * This function is called when the TE signal from the panel doesn't arrive * after 'interval' milliseconds. If the TE IRQ is not ready, the workqueue Loading @@ -33,21 +34,14 @@ static bool mdss_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, { bool ret; /* * During resume, the panel status will be ON but due to race condition * between ESD thread and display UNBLANK (or rather can be put as * asynchronuous nature between these two threads), the ESD thread might * reach this point before the TE IRQ line is enabled or before the * first TE interrupt arrives after the TE IRQ line is enabled. For such * cases, re-schedule the ESD thread. */ ret = !atomic_read(&ctrl_pdata->te_irq_ready); if (ret) { schedule_delayed_work(&pstatus_data->check_status, atomic_set(&ctrl_pdata->te_irq_ready, 0); reinit_completion(&ctrl_pdata->te_irq_comp); enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); /* Define TE interrupt timeout value as 3x(1/fps) */ ret = wait_for_completion_timeout(&ctrl_pdata->te_irq_comp, msecs_to_jiffies(interval)); pr_debug("%s: TE IRQ line not enabled yet\n", __func__); } disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); pr_debug("%s: Panel TE check done with ret = %d\n", __func__, ret); return ret; } Loading Loading @@ -110,13 +104,17 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) } if (ctrl_pdata->status_mode == ESD_TE) { if (mdss_check_te_status(ctrl_pdata, pstatus_data, interval)) return; uint32_t fps = mdss_panel_get_framerate(&pdata->panel_info, FPS_RESOLUTION_HZ); uint32_t timeout = ((1000 / fps) + 1) * MDSS_STATUS_TE_WAIT_MAX; if (mdss_check_te_status(ctrl_pdata, pstatus_data, timeout)) goto sim; else goto status_dead; } /* * TODO: Because mdss_dsi_cmd_mdp_busy has made sure DMA to * be idle in mdss_dsi_cmdlist_commit, it is not necessary Loading Loading @@ -173,7 +171,7 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) else goto status_dead; } sim: if (pdata->panel_info.panel_force_dead) { pr_debug("force_dead=%d\n", pdata->panel_info.panel_force_dead); pdata->panel_info.panel_force_dead--; Loading
drivers/video/msm/mdss/dsi_status_v2.c +73 −13 Original line number Diff line number Diff line /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -9,16 +9,48 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/workqueue.h> #include <linux/delay.h> #include <linux/kobject.h> #include <linux/string.h> #include <linux/sysfs.h> #include <linux/interrupt.h> #include "mdss_dsi.h" #include "mdp3_ctrl.h" /* * mdp3_check_te_status() - Check the status of panel for TE based ESD. * @ctrl_pdata : dsi controller data * @pstatus_data : dsi status data * @interval : duration in milliseconds for panel TE wait * * This function waits for TE signal from the panel for a maximum * duration of 3 vsyncs. If timeout occurs, report the panel to be * dead due to ESD attack. * NOTE: The TE IRQ handling is linked to the ESD thread scheduling, * i.e. rate of TE IRQs firing is bound by the ESD interval. */ static int mdp3_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, struct dsi_status_data *pstatus_data, uint32_t interval) { int ret; pr_debug("%s: Checking panel TE status\n", __func__); atomic_set(&ctrl_pdata->te_irq_ready, 0); reinit_completion(&ctrl_pdata->te_irq_comp); enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); ret = wait_for_completion_timeout(&ctrl_pdata->te_irq_comp, msecs_to_jiffies(interval)); disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); pr_debug("%s: Panel TE check done with ret = %d\n", __func__, ret); return ret; } /* * mdp3_check_dsi_ctrl_status() - Check MDP3 DSI controller status periodically. * @work : dsi controller status data Loading @@ -33,6 +65,7 @@ void mdp3_check_dsi_ctrl_status(struct work_struct *work, { struct dsi_status_data *pdsi_status = NULL; struct mdss_panel_data *pdata = NULL; struct mipi_panel_info *mipi = NULL; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdp3_session_data *mdp3_session = NULL; int ret = 0; Loading @@ -51,15 +84,25 @@ void mdp3_check_dsi_ctrl_status(struct work_struct *work, return; } mipi = &pdata->panel_info.mipi; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata || !ctrl_pdata->check_status) { if (!ctrl_pdata || (!ctrl_pdata->check_status && (ctrl_pdata->status_mode != ESD_TE))) { pr_err("%s: DSI ctrl or status_check callback not available\n", __func__); return; } if (!pdata->panel_info.esd_rdy) { pr_err("%s: unblank not complete, reschedule check status\n", __func__); schedule_delayed_work(&pdsi_status->check_status, msecs_to_jiffies(interval)); return; } mdp3_session = pdsi_status->mfd->mdp.private1; if (!mdp3_session) { pr_err("%s: Display is off\n", __func__); Loading @@ -73,6 +116,19 @@ void mdp3_check_dsi_ctrl_status(struct work_struct *work, return; } if (mipi->mode == DSI_CMD_MODE && mipi->hw_vsync_mode && mdss_dsi_is_te_based_esd(ctrl_pdata)) { uint32_t fps = mdss_panel_get_framerate(&pdata->panel_info, FPS_RESOLUTION_HZ); uint32_t timeout = ((1000 / fps) + 1) * MDSS_STATUS_TE_WAIT_MAX; if (mdp3_check_te_status(ctrl_pdata, pdsi_status, timeout) > 0) return; goto status_dead; } mutex_lock(&mdp3_session->lock); if (!mdp3_session->status) { pr_debug("%s: display off already\n", __func__); Loading @@ -90,18 +146,22 @@ void mdp3_check_dsi_ctrl_status(struct work_struct *work, mutex_unlock(&mdp3_session->lock); if (mdss_fb_is_power_on_interactive(pdsi_status->mfd)) { if (ret > 0) { if (ret > 0) schedule_delayed_work(&pdsi_status->check_status, msecs_to_jiffies(interval)); } else { char *envp[2] = {"PANEL_ALIVE=0", NULL}; pdata->panel_info.panel_dead = true; ret = kobject_uevent_env( &pdsi_status->mfd->fbi->dev->kobj, KOBJ_CHANGE, envp); pr_err("%s: Panel has gone bad, sending uevent - %s\n", __func__, envp[0]); else goto status_dead; } if (pdata->panel_info.panel_force_dead) { pr_debug("force_dead=%d\n", pdata->panel_info.panel_force_dead); pdata->panel_info.panel_force_dead--; if (!pdata->panel_info.panel_force_dead) goto status_dead; } return; status_dead: mdss_fb_report_panel_dead(pdsi_status->mfd); }
drivers/video/msm/mdss/mdss_dsi.c +1 −7 Original line number Diff line number Diff line Loading @@ -1623,8 +1623,6 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) if ((pdata->panel_info.type == MIPI_CMD_PANEL) && mipi->vsync_enable && mipi->hw_vsync_mode) { mdss_dsi_set_tear_on(ctrl_pdata); if (mdss_dsi_is_te_based_esd(ctrl_pdata)) enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); } ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT; Loading Loading @@ -1694,11 +1692,6 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata, int power_state) if ((pdata->panel_info.type == MIPI_CMD_PANEL) && mipi->vsync_enable && mipi->hw_vsync_mode) { if (mdss_dsi_is_te_based_esd(ctrl_pdata)) { disable_irq(gpio_to_irq( ctrl_pdata->disp_te_gpio)); atomic_dec(&ctrl_pdata->te_irq_ready); } mdss_dsi_set_tear_off(ctrl_pdata); } Loading Loading @@ -3252,6 +3245,7 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) } if (mdss_dsi_is_te_based_esd(ctrl_pdata)) { init_completion(&ctrl_pdata->te_irq_comp); rc = devm_request_irq(&pdev->dev, gpio_to_irq(ctrl_pdata->disp_te_gpio), hw_vsync_handler, IRQF_TRIGGER_FALLING, Loading
drivers/video/msm/mdss/mdss_dsi.h +2 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ #define MDSS_DSI_HW_REV_STEP_1 0x1 #define MDSS_DSI_HW_REV_STEP_2 0x2 #define MDSS_STATUS_TE_WAIT_MAX 3 #define NONE_PANEL "none" enum { /* mipi dsi panel */ Loading Loading @@ -488,6 +489,7 @@ struct mdss_dsi_ctrl_pdata { struct completion video_comp; struct completion dynamic_comp; struct completion bta_comp; struct completion te_irq_comp; spinlock_t irq_lock; spinlock_t mdp_lock; int mdp_busy; Loading
drivers/video/msm/mdss/mdss_dsi_status.c +9 −4 Original line number Diff line number Diff line /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -24,6 +24,7 @@ #include <linux/kobject.h> #include <linux/string.h> #include <linux/sysfs.h> #include <linux/interrupt.h> #include "mdss_fb.h" #include "mdss_dsi.h" Loading Loading @@ -94,8 +95,10 @@ irqreturn_t hw_vsync_handler(int irq, void *data) else pr_err("Pstatus data is NULL\n"); if (!atomic_read(&ctrl_pdata->te_irq_ready)) if (!atomic_read(&ctrl_pdata->te_irq_ready)) { complete_all(&ctrl_pdata->te_irq_comp); atomic_inc(&ctrl_pdata->te_irq_ready); } return IRQ_HANDLED; } Loading Loading @@ -160,10 +163,12 @@ static int fb_event_callback(struct notifier_block *self, schedule_delayed_work(&pdata->check_status, msecs_to_jiffies(interval)); break; case FB_BLANK_POWERDOWN: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_NORMAL: pr_debug("%s : ESD thread running\n", __func__); break; case FB_BLANK_POWERDOWN: case FB_BLANK_HSYNC_SUSPEND: cancel_delayed_work(&pdata->check_status); break; default: Loading