mirror of
https://github.com/torvalds/linux.git
synced 2026-07-30 19:21:28 +02:00
hwmon: amoled-ecm: add support to re-enable ECM dynamically
When ECM is enabled, disable ECM if display goes blank, and re-enable ECM once display restores to unblank. This helps in keeping ECM HW enabled only when display is active. Meanwhile, update the logic a little bit on calculating the average current. When any of the accumulated values is invalid, just ignore the calculation instead of disabling the ECM. Change-Id: Ibfe973df4dabd1b1cd48927ce567a094da6382a3 Signed-off-by: Fenglin Wu <fenglinw@codeaurora.org>
This commit is contained in:
parent
ad61c83861
commit
48c3279d8d
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "AMOLED_ECM: %s: " fmt, __func__
|
||||
|
|
@ -19,6 +19,8 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/soc/qcom/panel_event_notifier.h>
|
||||
|
||||
/* AMOLED AB register definitions */
|
||||
#define AB_REVISION2 0x01
|
||||
|
||||
|
|
@ -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
|
||||
* @active_panel: Active DRM panel which sends panel notifications
|
||||
* @notifier_cookie: The cookie from panel notifier
|
||||
* @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;
|
||||
|
|
@ -163,11 +168,14 @@ struct amoled_ecm {
|
|||
struct amoled_ecm_sdam *sdam;
|
||||
struct mutex sdam_lock;
|
||||
struct delayed_work average_work;
|
||||
struct drm_panel *active_panel;
|
||||
void *notifier_cookie;
|
||||
u32 num_sdams;
|
||||
u32 base;
|
||||
u8 ab_revision;
|
||||
bool enable;
|
||||
bool abort;
|
||||
bool reenable;
|
||||
};
|
||||
|
||||
static struct amoled_ecm_sdam_config ecm_reset_config[] = {
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
||||
if (!data->num_m_samples || !data->m_cumulative) {
|
||||
pr_err("num_m_samples=%u m_cumulative:%u disabling ECM\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);
|
||||
|
||||
data->avg_current = data->m_cumulative / data->num_m_samples;
|
||||
|
||||
pr_debug("avg_current=%u mA\n", data->avg_current);
|
||||
if (!data->num_m_samples || !data->m_cumulative) {
|
||||
pr_warn("Invalid data, num_m_samples=%u m_cumulative:%u\n",
|
||||
data->num_m_samples, data->m_cumulative);
|
||||
data->avg_current = -EINVAL;
|
||||
} 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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -726,9 +727,124 @@ static int amoled_ecm_parse_dt(struct amoled_ecm *ecm)
|
|||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_QCOM_PANEL_EVENT_NOTIFIER)
|
||||
static void panel_event_notifier_callback(enum panel_event_notifier_tag tag,
|
||||
struct panel_event_notification *notification, void *data)
|
||||
{
|
||||
struct amoled_ecm *ecm = data;
|
||||
int rc;
|
||||
|
||||
if (!notification) {
|
||||
pr_err("Invalid panel notification\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("panel event received, type: %d\n", notification->notif_type);
|
||||
switch (notification->notif_type) {
|
||||
case DRM_PANEL_EVENT_BLANK:
|
||||
if (ecm->enable) {
|
||||
rc = amoled_ecm_disable(ecm);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to disable ECM for display BLANK, rc=%d\n",
|
||||
rc);
|
||||
return;
|
||||
}
|
||||
|
||||
ecm->reenable = true;
|
||||
pr_debug("Disabled ECM for display BLANK\n");
|
||||
}
|
||||
break;
|
||||
case DRM_PANEL_EVENT_UNBLANK:
|
||||
if (ecm->reenable) {
|
||||
rc = amoled_ecm_enable(ecm);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to re-enable ECM for display UNBLANK, rc=%d\n",
|
||||
rc);
|
||||
return;
|
||||
}
|
||||
|
||||
ecm->reenable = false;
|
||||
pr_debug("Enabled ECM for display UNBLANK\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_debug("Ignore panel event: %d\n", notification->notif_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int qti_amoled_register_panel_notifier(struct amoled_ecm *ecm)
|
||||
{
|
||||
struct device_node *np = ecm->dev->of_node;
|
||||
struct device_node *pnode;
|
||||
struct drm_panel *panel;
|
||||
void *cookie = NULL;
|
||||
int i, count, rc;
|
||||
|
||||
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);
|
||||
if (!pnode)
|
||||
return -ENODEV;
|
||||
|
||||
panel = of_drm_find_panel(pnode);
|
||||
of_node_put(pnode);
|
||||
if (!IS_ERR(panel)) {
|
||||
ecm->active_panel = panel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ecm->active_panel) {
|
||||
rc = PTR_ERR(panel);
|
||||
if (rc != -EPROBE_DEFER)
|
||||
pr_err("failed to find active panel, rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
cookie = panel_event_notifier_register(
|
||||
PANEL_EVENT_NOTIFICATION_PRIMARY,
|
||||
PANEL_EVENT_NOTIFIER_CLIENT_ECM,
|
||||
ecm->active_panel,
|
||||
panel_event_notifier_callback,
|
||||
(void *)ecm);
|
||||
if (IS_ERR(cookie)) {
|
||||
rc = PTR_ERR(cookie);
|
||||
pr_err("failed to register panel event notifier, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_debug("register panel notifier successfully\n");
|
||||
ecm->notifier_cookie = cookie;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qti_amoled_unregister_panel_notifier(struct amoled_ecm *ecm)
|
||||
{
|
||||
if (ecm->notifier_cookie)
|
||||
panel_event_notifier_unregister(ecm->notifier_cookie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int qti_amoled_register_panel_notifier(struct amoled_ecm *ecm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int qti_amoled_unregister_panel_notifier(struct amoled_ecm *ecm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int qti_amoled_ecm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *hwmon_dev;
|
||||
|
|
@ -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_panel_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_panel_notifier(ecm);
|
||||
}
|
||||
|
||||
static const struct of_device_id amoled_ecm_match_table[] = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user