#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/types.h>
}
}
-static void anx7625_chip_control(struct anx7625_data *ctx, int state)
-{
- struct device *dev = &ctx->client->dev;
-
- DRM_DEV_DEBUG_DRIVER(dev, "before set, power_state(%d).\n",
- atomic_read(&ctx->power_status));
-
- if (!ctx->pdata.low_power_mode)
- return;
-
- if (state) {
- atomic_inc(&ctx->power_status);
- if (atomic_read(&ctx->power_status) == 1)
- anx7625_power_on_init(ctx);
- } else {
- if (atomic_read(&ctx->power_status)) {
- atomic_dec(&ctx->power_status);
-
- if (atomic_read(&ctx->power_status) == 0)
- anx7625_power_standby(ctx);
- }
- }
-
- DRM_DEV_DEBUG_DRIVER(dev, "after set, power_state(%d).\n",
- atomic_read(&ctx->power_status));
-}
-
static void anx7625_init_gpio(struct anx7625_data *platform)
{
struct device *dev = &platform->client->dev;
ctx->hpd_status = 0;
ctx->hpd_high_cnt = 0;
ctx->display_timing_valid = 0;
-
- if (ctx->pdata.low_power_mode == 0)
- anx7625_disable_pd_protocol(ctx);
}
static void anx7625_start_dp_work(struct anx7625_data *ctx)
int ret, val;
struct device *dev = &ctx->client->dev;
- if (atomic_read(&ctx->power_status) != 1) {
- DRM_DEV_DEBUG_DRIVER(dev, "No need to poling HPD status.\n");
- return;
- }
-
ret = readx_poll_timeout(anx7625_read_hpd_status_p0,
ctx, val,
((val & HPD_STATUS) || (val < 0)),
5000,
5000 * 100);
if (ret) {
- DRM_DEV_ERROR(dev, "HPD polling timeout!\n");
- } else {
- DRM_DEV_DEBUG_DRIVER(dev, "HPD raise up.\n");
- anx7625_reg_write(ctx, ctx->i2c.tcpc_client,
- INTR_ALERT_1, 0xFF);
- anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
- INTERFACE_CHANGE_INT, 0);
+ DRM_DEV_ERROR(dev, "no hpd.\n");
+ return;
}
- anx7625_start_dp_work(ctx);
-}
-
-static void anx7625_disconnect_check(struct anx7625_data *ctx)
-{
- if (atomic_read(&ctx->power_status) == 0)
- anx7625_stop_dp_work(ctx);
-}
-
-static void anx7625_low_power_mode_check(struct anx7625_data *ctx,
- int state)
-{
- struct device *dev = &ctx->client->dev;
+ DRM_DEV_DEBUG_DRIVER(dev, "system status: 0x%x. HPD raise up.\n", val);
+ anx7625_reg_write(ctx, ctx->i2c.tcpc_client,
+ INTR_ALERT_1, 0xFF);
+ anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+ INTERFACE_CHANGE_INT, 0);
- DRM_DEV_DEBUG_DRIVER(dev, "low power mode check, state(%d).\n", state);
+ anx7625_start_dp_work(ctx);
- if (ctx->pdata.low_power_mode) {
- anx7625_chip_control(ctx, state);
- if (state)
- anx7625_hpd_polling(ctx);
- else
- anx7625_disconnect_check(ctx);
- }
+ if (!ctx->pdata.panel_bridge && ctx->bridge_attached)
+ drm_helper_hpd_irq_event(ctx->bridge.dev);
}
static void anx7625_remove_edid(struct anx7625_data *ctx)
int intr_vector, status;
struct device *dev = &ctx->client->dev;
- DRM_DEV_DEBUG_DRIVER(dev, "power_status=%d\n",
- (u32)atomic_read(&ctx->power_status));
-
status = anx7625_reg_write(ctx, ctx->i2c.tcpc_client,
INTR_ALERT_1, 0xFF);
if (status < 0) {
struct anx7625_data, work);
mutex_lock(&ctx->lock);
+
+ if (pm_runtime_suspended(&ctx->client->dev))
+ goto unlock;
+
event = anx7625_hpd_change_detect(ctx);
- mutex_unlock(&ctx->lock);
if (event < 0)
- return;
+ goto unlock;
if (ctx->bridge_attached)
drm_helper_hpd_irq_event(ctx->bridge.dev);
+
+unlock:
+ mutex_unlock(&ctx->lock);
}
static irqreturn_t anx7625_intr_hpd_isr(int irq, void *data)
{
struct anx7625_data *ctx = (struct anx7625_data *)data;
- if (atomic_read(&ctx->power_status) != 1)
- return IRQ_NONE;
-
queue_work(ctx->workqueue, &ctx->work);
return IRQ_HANDLED;
return (struct edid *)edid;
}
- anx7625_low_power_mode_check(ctx, 1);
+ pm_runtime_get_sync(dev);
edid_num = sp_tx_edid_read(ctx, p_edid->edid_raw_data);
- anx7625_low_power_mode_check(ctx, 0);
+ pm_runtime_put(dev);
if (edid_num < 1) {
DRM_DEV_ERROR(dev, "Fail to read EDID: %d\n", edid_num);
DRM_DEV_DEBUG_DRIVER(dev, "drm enable\n");
- anx7625_low_power_mode_check(ctx, 1);
-
- if (WARN_ON(!atomic_read(&ctx->power_status)))
- return;
+ pm_runtime_get_sync(dev);
anx7625_dp_start(ctx);
}
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
struct device *dev = &ctx->client->dev;
- if (WARN_ON(!atomic_read(&ctx->power_status)))
- return;
-
DRM_DEV_DEBUG_DRIVER(dev, "drm disable\n");
anx7625_dp_stop(ctx);
- anx7625_low_power_mode_check(ctx, 0);
+ pm_runtime_put(dev);
}
static enum drm_connector_status
i2c_unregister_device(ctx->i2c.tcpc_client);
}
+static int __maybe_unused anx7625_runtime_pm_suspend(struct device *dev)
+{
+ struct anx7625_data *ctx = dev_get_drvdata(dev);
+
+ mutex_lock(&ctx->lock);
+
+ anx7625_stop_dp_work(ctx);
+ anx7625_power_standby(ctx);
+
+ mutex_unlock(&ctx->lock);
+
+ return 0;
+}
+
+static int __maybe_unused anx7625_runtime_pm_resume(struct device *dev)
+{
+ struct anx7625_data *ctx = dev_get_drvdata(dev);
+
+ mutex_lock(&ctx->lock);
+
+ anx7625_power_on_init(ctx);
+ anx7625_hpd_polling(ctx);
+
+ mutex_unlock(&ctx->lock);
+
+ return 0;
+}
+
+static const struct dev_pm_ops anx7625_pm_ops = {
+ SET_RUNTIME_PM_OPS(anx7625_runtime_pm_suspend,
+ anx7625_runtime_pm_resume, NULL)
+};
+
static int anx7625_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
}
anx7625_init_gpio(platform);
- atomic_set(&platform->power_status, 0);
-
mutex_init(&platform->lock);
platform->pdata.intp_irq = client->irq;
goto free_wq;
}
- if (platform->pdata.low_power_mode == 0) {
+ pm_runtime_enable(dev);
+
+ if (!platform->pdata.low_power_mode) {
anx7625_disable_pd_protocol(platform);
- atomic_set(&platform->power_status, 1);
+ pm_runtime_get_sync(dev);
}
/* Add work function */
if (platform->pdata.intp_irq)
destroy_workqueue(platform->workqueue);
+ if (!platform->pdata.low_power_mode)
+ pm_runtime_put_sync_suspend(&client->dev);
+
anx7625_unregister_i2c_dummy_clients(platform);
kfree(platform);
.driver = {
.name = "anx7625",
.of_match_table = anx_match_table,
+ .pm = &anx7625_pm_ops,
},
.probe = anx7625_i2c_probe,
.remove = anx7625_i2c_remove,