Skip to content

Commit 55ca8f1

Browse files
peter50216robertfoss
authored andcommitted
drm/bridge: anx7625: refactor power control to use runtime PM framework
The driver originally use an atomic_t for keep track of the power status, which makes the driver more complicated than needed, and has some race condition as it's possible to have the power on and power off sequence going at the same time. This patch remove the usage of the atomic_t power_status, and use the kernel runtime power management framework instead. Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org> Reviewed-by: Tzung-Bi Shih <tzungbi@google.com> Signed-off-by: Robert Foss <robert.foss@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20210517063553.554955-1-pihsun@chromium.org
1 parent 1a343a9 commit 55ca8f1

File tree

2 files changed

+64
-86
lines changed

2 files changed

+64
-86
lines changed

drivers/gpu/drm/bridge/analogix/anx7625.c

Lines changed: 64 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/kernel.h>
1212
#include <linux/module.h>
1313
#include <linux/mutex.h>
14+
#include <linux/pm_runtime.h>
1415
#include <linux/regulator/consumer.h>
1516
#include <linux/slab.h>
1617
#include <linux/types.h>
@@ -1005,33 +1006,6 @@ static void anx7625_power_on_init(struct anx7625_data *ctx)
10051006
}
10061007
}
10071008

1008-
static void anx7625_chip_control(struct anx7625_data *ctx, int state)
1009-
{
1010-
struct device *dev = &ctx->client->dev;
1011-
1012-
DRM_DEV_DEBUG_DRIVER(dev, "before set, power_state(%d).\n",
1013-
atomic_read(&ctx->power_status));
1014-
1015-
if (!ctx->pdata.low_power_mode)
1016-
return;
1017-
1018-
if (state) {
1019-
atomic_inc(&ctx->power_status);
1020-
if (atomic_read(&ctx->power_status) == 1)
1021-
anx7625_power_on_init(ctx);
1022-
} else {
1023-
if (atomic_read(&ctx->power_status)) {
1024-
atomic_dec(&ctx->power_status);
1025-
1026-
if (atomic_read(&ctx->power_status) == 0)
1027-
anx7625_power_standby(ctx);
1028-
}
1029-
}
1030-
1031-
DRM_DEV_DEBUG_DRIVER(dev, "after set, power_state(%d).\n",
1032-
atomic_read(&ctx->power_status));
1033-
}
1034-
10351009
static void anx7625_init_gpio(struct anx7625_data *platform)
10361010
{
10371011
struct device *dev = &platform->client->dev;
@@ -1061,9 +1035,6 @@ static void anx7625_stop_dp_work(struct anx7625_data *ctx)
10611035
ctx->hpd_status = 0;
10621036
ctx->hpd_high_cnt = 0;
10631037
ctx->display_timing_valid = 0;
1064-
1065-
if (ctx->pdata.low_power_mode == 0)
1066-
anx7625_disable_pd_protocol(ctx);
10671038
}
10681039

10691040
static void anx7625_start_dp_work(struct anx7625_data *ctx)
@@ -1105,49 +1076,26 @@ static void anx7625_hpd_polling(struct anx7625_data *ctx)
11051076
int ret, val;
11061077
struct device *dev = &ctx->client->dev;
11071078

1108-
if (atomic_read(&ctx->power_status) != 1) {
1109-
DRM_DEV_DEBUG_DRIVER(dev, "No need to poling HPD status.\n");
1110-
return;
1111-
}
1112-
11131079
ret = readx_poll_timeout(anx7625_read_hpd_status_p0,
11141080
ctx, val,
11151081
((val & HPD_STATUS) || (val < 0)),
11161082
5000,
11171083
5000 * 100);
11181084
if (ret) {
1119-
DRM_DEV_ERROR(dev, "HPD polling timeout!\n");
1120-
} else {
1121-
DRM_DEV_DEBUG_DRIVER(dev, "HPD raise up.\n");
1122-
anx7625_reg_write(ctx, ctx->i2c.tcpc_client,
1123-
INTR_ALERT_1, 0xFF);
1124-
anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
1125-
INTERFACE_CHANGE_INT, 0);
1085+
DRM_DEV_ERROR(dev, "no hpd.\n");
1086+
return;
11261087
}
11271088

1128-
anx7625_start_dp_work(ctx);
1129-
}
1130-
1131-
static void anx7625_disconnect_check(struct anx7625_data *ctx)
1132-
{
1133-
if (atomic_read(&ctx->power_status) == 0)
1134-
anx7625_stop_dp_work(ctx);
1135-
}
1136-
1137-
static void anx7625_low_power_mode_check(struct anx7625_data *ctx,
1138-
int state)
1139-
{
1140-
struct device *dev = &ctx->client->dev;
1089+
DRM_DEV_DEBUG_DRIVER(dev, "system status: 0x%x. HPD raise up.\n", val);
1090+
anx7625_reg_write(ctx, ctx->i2c.tcpc_client,
1091+
INTR_ALERT_1, 0xFF);
1092+
anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
1093+
INTERFACE_CHANGE_INT, 0);
11411094

1142-
DRM_DEV_DEBUG_DRIVER(dev, "low power mode check, state(%d).\n", state);
1095+
anx7625_start_dp_work(ctx);
11431096

1144-
if (ctx->pdata.low_power_mode) {
1145-
anx7625_chip_control(ctx, state);
1146-
if (state)
1147-
anx7625_hpd_polling(ctx);
1148-
else
1149-
anx7625_disconnect_check(ctx);
1150-
}
1097+
if (!ctx->pdata.panel_bridge && ctx->bridge_attached)
1098+
drm_helper_hpd_irq_event(ctx->bridge.dev);
11511099
}
11521100

11531101
static void anx7625_remove_edid(struct anx7625_data *ctx)
@@ -1180,9 +1128,6 @@ static int anx7625_hpd_change_detect(struct anx7625_data *ctx)
11801128
int intr_vector, status;
11811129
struct device *dev = &ctx->client->dev;
11821130

1183-
DRM_DEV_DEBUG_DRIVER(dev, "power_status=%d\n",
1184-
(u32)atomic_read(&ctx->power_status));
1185-
11861131
status = anx7625_reg_write(ctx, ctx->i2c.tcpc_client,
11871132
INTR_ALERT_1, 0xFF);
11881133
if (status < 0) {
@@ -1228,22 +1173,25 @@ static void anx7625_work_func(struct work_struct *work)
12281173
struct anx7625_data, work);
12291174

12301175
mutex_lock(&ctx->lock);
1176+
1177+
if (pm_runtime_suspended(&ctx->client->dev))
1178+
goto unlock;
1179+
12311180
event = anx7625_hpd_change_detect(ctx);
1232-
mutex_unlock(&ctx->lock);
12331181
if (event < 0)
1234-
return;
1182+
goto unlock;
12351183

12361184
if (ctx->bridge_attached)
12371185
drm_helper_hpd_irq_event(ctx->bridge.dev);
1186+
1187+
unlock:
1188+
mutex_unlock(&ctx->lock);
12381189
}
12391190

12401191
static irqreturn_t anx7625_intr_hpd_isr(int irq, void *data)
12411192
{
12421193
struct anx7625_data *ctx = (struct anx7625_data *)data;
12431194

1244-
if (atomic_read(&ctx->power_status) != 1)
1245-
return IRQ_NONE;
1246-
12471195
queue_work(ctx->workqueue, &ctx->work);
12481196

12491197
return IRQ_HANDLED;
@@ -1305,9 +1253,9 @@ static struct edid *anx7625_get_edid(struct anx7625_data *ctx)
13051253
return (struct edid *)edid;
13061254
}
13071255

1308-
anx7625_low_power_mode_check(ctx, 1);
1256+
pm_runtime_get_sync(dev);
13091257
edid_num = sp_tx_edid_read(ctx, p_edid->edid_raw_data);
1310-
anx7625_low_power_mode_check(ctx, 0);
1258+
pm_runtime_put(dev);
13111259

13121260
if (edid_num < 1) {
13131261
DRM_DEV_ERROR(dev, "Fail to read EDID: %d\n", edid_num);
@@ -1611,10 +1559,7 @@ static void anx7625_bridge_enable(struct drm_bridge *bridge)
16111559

16121560
DRM_DEV_DEBUG_DRIVER(dev, "drm enable\n");
16131561

1614-
anx7625_low_power_mode_check(ctx, 1);
1615-
1616-
if (WARN_ON(!atomic_read(&ctx->power_status)))
1617-
return;
1562+
pm_runtime_get_sync(dev);
16181563

16191564
anx7625_dp_start(ctx);
16201565
}
@@ -1624,14 +1569,11 @@ static void anx7625_bridge_disable(struct drm_bridge *bridge)
16241569
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
16251570
struct device *dev = &ctx->client->dev;
16261571

1627-
if (WARN_ON(!atomic_read(&ctx->power_status)))
1628-
return;
1629-
16301572
DRM_DEV_DEBUG_DRIVER(dev, "drm disable\n");
16311573

16321574
anx7625_dp_stop(ctx);
16331575

1634-
anx7625_low_power_mode_check(ctx, 0);
1576+
pm_runtime_put(dev);
16351577
}
16361578

16371579
static enum drm_connector_status
@@ -1735,6 +1677,39 @@ static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx)
17351677
i2c_unregister_device(ctx->i2c.tcpc_client);
17361678
}
17371679

1680+
static int __maybe_unused anx7625_runtime_pm_suspend(struct device *dev)
1681+
{
1682+
struct anx7625_data *ctx = dev_get_drvdata(dev);
1683+
1684+
mutex_lock(&ctx->lock);
1685+
1686+
anx7625_stop_dp_work(ctx);
1687+
anx7625_power_standby(ctx);
1688+
1689+
mutex_unlock(&ctx->lock);
1690+
1691+
return 0;
1692+
}
1693+
1694+
static int __maybe_unused anx7625_runtime_pm_resume(struct device *dev)
1695+
{
1696+
struct anx7625_data *ctx = dev_get_drvdata(dev);
1697+
1698+
mutex_lock(&ctx->lock);
1699+
1700+
anx7625_power_on_init(ctx);
1701+
anx7625_hpd_polling(ctx);
1702+
1703+
mutex_unlock(&ctx->lock);
1704+
1705+
return 0;
1706+
}
1707+
1708+
static const struct dev_pm_ops anx7625_pm_ops = {
1709+
SET_RUNTIME_PM_OPS(anx7625_runtime_pm_suspend,
1710+
anx7625_runtime_pm_resume, NULL)
1711+
};
1712+
17381713
static int anx7625_i2c_probe(struct i2c_client *client,
17391714
const struct i2c_device_id *id)
17401715
{
@@ -1778,8 +1753,6 @@ static int anx7625_i2c_probe(struct i2c_client *client,
17781753
}
17791754
anx7625_init_gpio(platform);
17801755

1781-
atomic_set(&platform->power_status, 0);
1782-
17831756
mutex_init(&platform->lock);
17841757

17851758
platform->pdata.intp_irq = client->irq;
@@ -1809,9 +1782,11 @@ static int anx7625_i2c_probe(struct i2c_client *client,
18091782
goto free_wq;
18101783
}
18111784

1812-
if (platform->pdata.low_power_mode == 0) {
1785+
pm_runtime_enable(dev);
1786+
1787+
if (!platform->pdata.low_power_mode) {
18131788
anx7625_disable_pd_protocol(platform);
1814-
atomic_set(&platform->power_status, 1);
1789+
pm_runtime_get_sync(dev);
18151790
}
18161791

18171792
/* Add work function */
@@ -1847,6 +1822,9 @@ static int anx7625_i2c_remove(struct i2c_client *client)
18471822
if (platform->pdata.intp_irq)
18481823
destroy_workqueue(platform->workqueue);
18491824

1825+
if (!platform->pdata.low_power_mode)
1826+
pm_runtime_put_sync_suspend(&client->dev);
1827+
18501828
anx7625_unregister_i2c_dummy_clients(platform);
18511829

18521830
kfree(platform);
@@ -1869,6 +1847,7 @@ static struct i2c_driver anx7625_driver = {
18691847
.driver = {
18701848
.name = "anx7625",
18711849
.of_match_table = anx_match_table,
1850+
.pm = &anx7625_pm_ops,
18721851
},
18731852
.probe = anx7625_i2c_probe,
18741853
.remove = anx7625_i2c_remove,

drivers/gpu/drm/bridge/analogix/anx7625.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,6 @@ struct anx7625_i2c_client {
369369

370370
struct anx7625_data {
371371
struct anx7625_platform_data pdata;
372-
atomic_t power_status;
373372
int hpd_status;
374373
int hpd_high_cnt;
375374
/* Lock for work queue */

0 commit comments

Comments
 (0)