Loading drivers/hwmon/qti_amoled_ecm.c +142 −18 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ #include <linux/regmap.h> #include <linux/workqueue.h> #include <drm/drm_panel.h> /* AMOLED AB register definitions */ #define AB_REVISION2 0x01 Loading Loading @@ -150,11 +152,14 @@ struct amoled_ecm_data { * @sdam: Pointer for array of ECM sdams * @sdam_lock: Locking for mutual exclusion * @average_work: Delayed work to calculate ECM average * @drm_notifier: The notifier block for receiving DRM notifications * @active_panel: Active DRM panel which sends DRM notifications * @num_sdams: Number of SDAMs used for AMOLED ECM * @base: Base address of the AMOLED ECM module * @ab_revision: Revision of the AMOLED AB module * @enable: Flag to enable/disable AMOLED ECM * @abort: Flag to indicated AMOLED ECM has aborted * @reenable: Flag to reenable ECM when display goes unblank */ struct amoled_ecm { struct regmap *regmap; Loading @@ -163,11 +168,14 @@ struct amoled_ecm { struct amoled_ecm_sdam *sdam; struct mutex sdam_lock; struct delayed_work average_work; struct notifier_block drm_notifier; struct drm_panel *active_panel; u32 num_sdams; u32 base; u8 ab_revision; bool enable; bool abort; bool reenable; }; static struct amoled_ecm_sdam_config ecm_reset_config[] = { Loading Loading @@ -309,8 +317,6 @@ static int amoled_ecm_disable(struct amoled_ecm *ecm) cancel_delayed_work(&ecm->average_work); ecm->data.frames = 0; ecm->data.time_period_ms = 0; ecm->data.avg_current = 0; ecm->data.m_cumulative = 0; ecm->data.num_m_samples = 0; Loading @@ -327,25 +333,17 @@ static void ecm_average_work(struct work_struct *work) struct amoled_ecm *ecm = container_of(work, struct amoled_ecm, average_work.work); struct amoled_ecm_data *data = &ecm->data; int rc; mutex_lock(&ecm->sdam_lock); if (!data->num_m_samples || !data->m_cumulative) { pr_err("num_m_samples=%u m_cumulative:%u disabling ECM\n", pr_warn("Invalid data, num_m_samples=%u m_cumulative:%u\n", data->num_m_samples, data->m_cumulative); data->avg_current = -EINVAL; rc = amoled_ecm_disable(ecm); if (rc < 0) pr_err("Failed to disable AMOLED ECM, rc=%d\n", rc); return; } mutex_lock(&ecm->sdam_lock); } else { data->avg_current = data->m_cumulative / data->num_m_samples; pr_debug("avg_current=%u mA\n", data->avg_current); } data->m_cumulative = 0; data->num_m_samples = 0; Loading Loading @@ -399,6 +397,9 @@ static ssize_t enable_store(struct device *dev, pr_err("Failed to disable AMOLED ECM, rc=%d\n", rc); return rc; } ecm->data.frames = 0; ecm->data.time_period_ms = 0; } return count; Loading Loading @@ -672,6 +673,37 @@ static irqreturn_t sdam_full_irq_handler(int irq, void *_ecm) return IRQ_HANDLED; } #ifdef CONFIG_DRM static int amoled_ecm_parse_panel_dt(struct amoled_ecm *ecm) { struct device_node *np = ecm->dev->of_node; struct device_node *pnode; struct drm_panel *panel; int i, count; count = of_count_phandle_with_args(np, "display-panels", NULL); if (count <= 0) return 0; for (i = 0; i < count; i++) { pnode = of_parse_phandle(np, "display-panels", i); panel = of_drm_find_panel(pnode); of_node_put(pnode); if (!IS_ERR(panel)) { ecm->active_panel = panel; return 0; } } return PTR_ERR(panel); } #else static inline int amoled_ecm_parse_panel_dt(struct amoled_ecm *ecm) { return 0; } #endif static int amoled_ecm_parse_dt(struct amoled_ecm *ecm) { int rc = 0, i; Loading Loading @@ -726,9 +758,93 @@ static int amoled_ecm_parse_dt(struct amoled_ecm *ecm) } } rc = amoled_ecm_parse_panel_dt(ecm); if (rc < 0) pr_err("failed to get active panel, rc=%d\n", rc); return rc; } #ifdef CONFIG_DRM static int drm_notifier_callback(struct notifier_block *nb, unsigned long event, void *data) { struct amoled_ecm *ecm = container_of(nb, struct amoled_ecm, drm_notifier); struct drm_panel_notifier *evdata = data; int blank, rc; pr_debug("DRM event received: %d\n", event); if (event != DRM_PANEL_EVENT_BLANK) return NOTIFY_DONE; blank = *(int *)evdata->data; if (blank == DRM_PANEL_BLANK_POWERDOWN && ecm->enable) { rc = amoled_ecm_disable(ecm); if (rc < 0) { pr_err("Failed to disable ECM for display BLANK, rc=%d\n", rc); return rc; } ecm->reenable = true; pr_debug("Disabled ECM for display BLANK\n"); } else if (blank == DRM_PANEL_BLANK_UNBLANK && ecm->reenable) { rc = amoled_ecm_enable(ecm); if (rc < 0) { pr_err("Failed to reenable ECM for display UNBLANK, rc=%d\n", rc); return rc; } ecm->reenable = false; pr_debug("Enabled ECM for display UNBLANK\n"); } return NOTIFY_DONE; } static int qti_amoled_register_drm_notifier(struct amoled_ecm *ecm) { int rc = 0; if (ecm->active_panel) { ecm->drm_notifier.notifier_call = drm_notifier_callback; rc = drm_panel_notifier_register(ecm->active_panel, &ecm->drm_notifier); if (rc < 0) pr_err("failed to register DRM notifier, rc=%d\n", rc); } return rc; } static int qti_amoled_unregister_drm_notifier(struct amoled_ecm *ecm) { if (ecm->active_panel) return drm_panel_notifier_unregister(ecm->active_panel, &ecm->drm_notifier); return 0; } #else static inline int drm_notifier_callback(struct notifier_block *nb, unsigned long event, void *data) { return NOTIFY_DONE; } static inline int qti_amoled_register_drm_notifier(struct amoled_ecm *ecm) { return 0; } static inline int qti_amoled_unregister_drm_notifier(struct amoled_ecm *ecm) { return 0; } #endif static int qti_amoled_ecm_probe(struct platform_device *pdev) { struct device *hwmon_dev; Loading Loading @@ -793,13 +909,21 @@ static int qti_amoled_ecm_probe(struct platform_device *pdev) hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, "amoled_ecm", ecm, amoled_ecm_groups); if (IS_ERR_OR_NULL(hwmon_dev)) { rc = PTR_ERR(hwmon_dev); pr_err("failed to register hwmon device for amoled-ecm, rc=%d\n", rc); return rc; } return PTR_ERR_OR_ZERO(hwmon_dev); return qti_amoled_register_drm_notifier(ecm); } static int qti_amoled_ecm_remove(struct platform_device *pdev) { return 0; struct amoled_ecm *ecm = dev_get_drvdata(&pdev->dev); return qti_amoled_unregister_drm_notifier(ecm); } static const struct of_device_id amoled_ecm_match_table[] = { Loading Loading
drivers/hwmon/qti_amoled_ecm.c +142 −18 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ #include <linux/regmap.h> #include <linux/workqueue.h> #include <drm/drm_panel.h> /* AMOLED AB register definitions */ #define AB_REVISION2 0x01 Loading Loading @@ -150,11 +152,14 @@ struct amoled_ecm_data { * @sdam: Pointer for array of ECM sdams * @sdam_lock: Locking for mutual exclusion * @average_work: Delayed work to calculate ECM average * @drm_notifier: The notifier block for receiving DRM notifications * @active_panel: Active DRM panel which sends DRM notifications * @num_sdams: Number of SDAMs used for AMOLED ECM * @base: Base address of the AMOLED ECM module * @ab_revision: Revision of the AMOLED AB module * @enable: Flag to enable/disable AMOLED ECM * @abort: Flag to indicated AMOLED ECM has aborted * @reenable: Flag to reenable ECM when display goes unblank */ struct amoled_ecm { struct regmap *regmap; Loading @@ -163,11 +168,14 @@ struct amoled_ecm { struct amoled_ecm_sdam *sdam; struct mutex sdam_lock; struct delayed_work average_work; struct notifier_block drm_notifier; struct drm_panel *active_panel; u32 num_sdams; u32 base; u8 ab_revision; bool enable; bool abort; bool reenable; }; static struct amoled_ecm_sdam_config ecm_reset_config[] = { Loading Loading @@ -309,8 +317,6 @@ static int amoled_ecm_disable(struct amoled_ecm *ecm) cancel_delayed_work(&ecm->average_work); ecm->data.frames = 0; ecm->data.time_period_ms = 0; ecm->data.avg_current = 0; ecm->data.m_cumulative = 0; ecm->data.num_m_samples = 0; Loading @@ -327,25 +333,17 @@ static void ecm_average_work(struct work_struct *work) struct amoled_ecm *ecm = container_of(work, struct amoled_ecm, average_work.work); struct amoled_ecm_data *data = &ecm->data; int rc; mutex_lock(&ecm->sdam_lock); if (!data->num_m_samples || !data->m_cumulative) { pr_err("num_m_samples=%u m_cumulative:%u disabling ECM\n", pr_warn("Invalid data, num_m_samples=%u m_cumulative:%u\n", data->num_m_samples, data->m_cumulative); data->avg_current = -EINVAL; rc = amoled_ecm_disable(ecm); if (rc < 0) pr_err("Failed to disable AMOLED ECM, rc=%d\n", rc); return; } mutex_lock(&ecm->sdam_lock); } else { data->avg_current = data->m_cumulative / data->num_m_samples; pr_debug("avg_current=%u mA\n", data->avg_current); } data->m_cumulative = 0; data->num_m_samples = 0; Loading Loading @@ -399,6 +397,9 @@ static ssize_t enable_store(struct device *dev, pr_err("Failed to disable AMOLED ECM, rc=%d\n", rc); return rc; } ecm->data.frames = 0; ecm->data.time_period_ms = 0; } return count; Loading Loading @@ -672,6 +673,37 @@ static irqreturn_t sdam_full_irq_handler(int irq, void *_ecm) return IRQ_HANDLED; } #ifdef CONFIG_DRM static int amoled_ecm_parse_panel_dt(struct amoled_ecm *ecm) { struct device_node *np = ecm->dev->of_node; struct device_node *pnode; struct drm_panel *panel; int i, count; count = of_count_phandle_with_args(np, "display-panels", NULL); if (count <= 0) return 0; for (i = 0; i < count; i++) { pnode = of_parse_phandle(np, "display-panels", i); panel = of_drm_find_panel(pnode); of_node_put(pnode); if (!IS_ERR(panel)) { ecm->active_panel = panel; return 0; } } return PTR_ERR(panel); } #else static inline int amoled_ecm_parse_panel_dt(struct amoled_ecm *ecm) { return 0; } #endif static int amoled_ecm_parse_dt(struct amoled_ecm *ecm) { int rc = 0, i; Loading Loading @@ -726,9 +758,93 @@ static int amoled_ecm_parse_dt(struct amoled_ecm *ecm) } } rc = amoled_ecm_parse_panel_dt(ecm); if (rc < 0) pr_err("failed to get active panel, rc=%d\n", rc); return rc; } #ifdef CONFIG_DRM static int drm_notifier_callback(struct notifier_block *nb, unsigned long event, void *data) { struct amoled_ecm *ecm = container_of(nb, struct amoled_ecm, drm_notifier); struct drm_panel_notifier *evdata = data; int blank, rc; pr_debug("DRM event received: %d\n", event); if (event != DRM_PANEL_EVENT_BLANK) return NOTIFY_DONE; blank = *(int *)evdata->data; if (blank == DRM_PANEL_BLANK_POWERDOWN && ecm->enable) { rc = amoled_ecm_disable(ecm); if (rc < 0) { pr_err("Failed to disable ECM for display BLANK, rc=%d\n", rc); return rc; } ecm->reenable = true; pr_debug("Disabled ECM for display BLANK\n"); } else if (blank == DRM_PANEL_BLANK_UNBLANK && ecm->reenable) { rc = amoled_ecm_enable(ecm); if (rc < 0) { pr_err("Failed to reenable ECM for display UNBLANK, rc=%d\n", rc); return rc; } ecm->reenable = false; pr_debug("Enabled ECM for display UNBLANK\n"); } return NOTIFY_DONE; } static int qti_amoled_register_drm_notifier(struct amoled_ecm *ecm) { int rc = 0; if (ecm->active_panel) { ecm->drm_notifier.notifier_call = drm_notifier_callback; rc = drm_panel_notifier_register(ecm->active_panel, &ecm->drm_notifier); if (rc < 0) pr_err("failed to register DRM notifier, rc=%d\n", rc); } return rc; } static int qti_amoled_unregister_drm_notifier(struct amoled_ecm *ecm) { if (ecm->active_panel) return drm_panel_notifier_unregister(ecm->active_panel, &ecm->drm_notifier); return 0; } #else static inline int drm_notifier_callback(struct notifier_block *nb, unsigned long event, void *data) { return NOTIFY_DONE; } static inline int qti_amoled_register_drm_notifier(struct amoled_ecm *ecm) { return 0; } static inline int qti_amoled_unregister_drm_notifier(struct amoled_ecm *ecm) { return 0; } #endif static int qti_amoled_ecm_probe(struct platform_device *pdev) { struct device *hwmon_dev; Loading Loading @@ -793,13 +909,21 @@ static int qti_amoled_ecm_probe(struct platform_device *pdev) hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, "amoled_ecm", ecm, amoled_ecm_groups); if (IS_ERR_OR_NULL(hwmon_dev)) { rc = PTR_ERR(hwmon_dev); pr_err("failed to register hwmon device for amoled-ecm, rc=%d\n", rc); return rc; } return PTR_ERR_OR_ZERO(hwmon_dev); return qti_amoled_register_drm_notifier(ecm); } static int qti_amoled_ecm_remove(struct platform_device *pdev) { return 0; struct amoled_ecm *ecm = dev_get_drvdata(&pdev->dev); return qti_amoled_unregister_drm_notifier(ecm); } static const struct of_device_id amoled_ecm_match_table[] = { Loading