mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-11 23:24:22 -04:00
hwmon: amoled-ecm: add support to re-enable ECM dynamically
When ECM is enabled, disable ECM if display goes blank, and reenable 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
31f07c0ce9
commit
cd3230bf33
1 changed files with 142 additions and 18 deletions
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
@ -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[] = {
|
||||
|
|
@ -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;
|
||||
|
|
@ -672,6 +673,37 @@ irq_exit:
|
|||
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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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…
Reference in a new issue