From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0B357C433ED for ; Mon, 17 May 2021 06:36:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E079E6121F for ; Mon, 17 May 2021 06:36:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231417AbhEQGhW (ORCPT ); Mon, 17 May 2021 02:37:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45902 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230260AbhEQGhQ (ORCPT ); Mon, 17 May 2021 02:37:16 -0400 Received: from mail-pl1-x62e.google.com (mail-pl1-x62e.google.com [IPv6:2607:f8b0:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C5244C061573 for ; Sun, 16 May 2021 23:36:00 -0700 (PDT) Received: by mail-pl1-x62e.google.com with SMTP id v12so2551822plo.10 for ; Sun, 16 May 2021 23:36:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Xk0ntXUor2j99C3NO8/vo2p+c0gfsVi1yMkjAZ3Fvxo=; b=RCF08xjDj32HNzU+b+i45uFVfnBYxa1OU9pSqA9fZVtv7NrTCAt+/hyahDAKhszYkK p2nEoWPMGmlZl3AEs0Xog0sYx95BT1A4EYKOWH8+FbV4AMmJY8DvH8YjEHVMdqYWCKyY Icb554NrEjvkSVE8sYqniBGWvs4cc2g/WBFSw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Xk0ntXUor2j99C3NO8/vo2p+c0gfsVi1yMkjAZ3Fvxo=; b=AsvXklAt0D6tBN5mlnVElhCdRKiS3B6bD6VCxrbkuzuL4PyVxWKkLCW+XrhTLkPkDi xbNdFuv6j8AkqFVzQ3Bu4DST6wZUeztX0NWgvIW9ETNEVzkQnA56fQM4aj4MDgB11P2p 8KS6hlT7SGCQm/or7qWHz0X634drHW2N+JWdtwsWHR8GwKxvR6Wkos7s+dQwSg0lWaYl kpLugQcuq9vvodOr39JSYfdo/pgUMIQRwLJThSgeZlW2c6EFn3R4sgMbGCi7GWc+d1dt t21xHa+FXiIiDAbyceIBFLQY8vime0kQilk3y5XWbFEcAjDDBLcavy5nJ3966mRr34ni 3YPw== X-Gm-Message-State: AOAM532mZzOhQc+pElr9/18pFnlcdSjDXVIN+RtO4/89gAdeysGcvo63 CmbMgaaX1hHor+xww0i9+XJ/GQ== X-Google-Smtp-Source: ABdhPJzCxwFjTg8K8TDG3atxsHG1clpfMK5dGppkmJiYh3C01TIqrBk0gWWk7lMdOVRpg6H6ZeQg2Q== X-Received: by 2002:a17:90a:7e09:: with SMTP id i9mr25687960pjl.166.1621233360134; Sun, 16 May 2021 23:36:00 -0700 (PDT) Received: from kafuu-chino.c.googlers.com.com (105.219.229.35.bc.googleusercontent.com. [35.229.219.105]) by smtp.googlemail.com with ESMTPSA id js6sm13287612pjb.0.2021.05.16.23.35.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 23:35:59 -0700 (PDT) From: Pi-Hsun Shih Cc: Pi-Hsun Shih , Tzung-Bi Shih , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , David Airlie , Daniel Vetter , Xin Ji , Hsin-Yi Wang , Sam Ravnborg , dri-devel@lists.freedesktop.org (open list:DRM DRIVERS), linux-kernel@vger.kernel.org (open list) Subject: [PATCH v5 1/2] drm/bridge: anx7625: refactor power control to use runtime PM framework Date: Mon, 17 May 2021 14:35:28 +0800 Message-Id: <20210517063553.554955-1-pihsun@chromium.org> X-Mailer: git-send-email 2.31.1.751.gd2f1c929bd-goog MIME-Version: 1.0 Content-Transfer-Encoding: 8bit To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- Changes in v5: * Revert changes from v4, and move fix to the suspend / resume hook (2/2 in series). Changes in v4: * Maintain separate powered state, since the power state is not sync with runtime PM suspended state on suspend / resume, and the irq callback shouldn't be run while suspending. Changes in v3: * Add missing .pm field to anx7625_driver. --- drivers/gpu/drm/bridge/analogix/anx7625.c | 149 ++++++++++------------ drivers/gpu/drm/bridge/analogix/anx7625.h | 1 - 2 files changed, 64 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 23283ba0c4f9..e1bf31eafe22 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1005,33 +1006,6 @@ static void anx7625_power_on_init(struct anx7625_data *ctx) } } -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; @@ -1061,9 +1035,6 @@ static void anx7625_stop_dp_work(struct anx7625_data *ctx) 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) @@ -1105,49 +1076,26 @@ static void anx7625_hpd_polling(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) @@ -1180,9 +1128,6 @@ static int anx7625_hpd_change_detect(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) { @@ -1228,22 +1173,25 @@ static void anx7625_work_func(struct work_struct *work) 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; @@ -1305,9 +1253,9 @@ static struct edid *anx7625_get_edid(struct anx7625_data *ctx) 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); @@ -1611,10 +1559,7 @@ static void anx7625_bridge_enable(struct drm_bridge *bridge) 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); } @@ -1624,14 +1569,11 @@ static void anx7625_bridge_disable(struct drm_bridge *bridge) 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 @@ -1735,6 +1677,39 @@ static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx) 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) { @@ -1778,8 +1753,6 @@ static int anx7625_i2c_probe(struct i2c_client *client, } anx7625_init_gpio(platform); - atomic_set(&platform->power_status, 0); - mutex_init(&platform->lock); platform->pdata.intp_irq = client->irq; @@ -1809,9 +1782,11 @@ static int anx7625_i2c_probe(struct i2c_client *client, 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 */ @@ -1847,6 +1822,9 @@ static int anx7625_i2c_remove(struct i2c_client *client) 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); @@ -1869,6 +1847,7 @@ static struct i2c_driver anx7625_driver = { .driver = { .name = "anx7625", .of_match_table = anx_match_table, + .pm = &anx7625_pm_ops, }, .probe = anx7625_i2c_probe, .remove = anx7625_i2c_remove, diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index e4a086b3a3d7..034c3840028f 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -369,7 +369,6 @@ struct anx7625_i2c_client { struct anx7625_data { struct anx7625_platform_data pdata; - atomic_t power_status; int hpd_status; int hpd_high_cnt; /* Lock for work queue */ base-commit: e48661230cc35b3d0f4367eddfc19f86463ab917 -- 2.31.1.751.gd2f1c929bd-goog From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5195BC43460 for ; Mon, 17 May 2021 07:32:32 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 19D5E611B0 for ; Mon, 17 May 2021 07:32:32 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 19D5E611B0 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=chromium.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 050E66E8E3; Mon, 17 May 2021 07:32:22 +0000 (UTC) Received: from mail-pl1-x635.google.com (mail-pl1-x635.google.com [IPv6:2607:f8b0:4864:20::635]) by gabe.freedesktop.org (Postfix) with ESMTPS id A26A56E8CA for ; Mon, 17 May 2021 06:36:00 +0000 (UTC) Received: by mail-pl1-x635.google.com with SMTP id p6so2550694plr.11 for ; Sun, 16 May 2021 23:36:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Xk0ntXUor2j99C3NO8/vo2p+c0gfsVi1yMkjAZ3Fvxo=; b=RCF08xjDj32HNzU+b+i45uFVfnBYxa1OU9pSqA9fZVtv7NrTCAt+/hyahDAKhszYkK p2nEoWPMGmlZl3AEs0Xog0sYx95BT1A4EYKOWH8+FbV4AMmJY8DvH8YjEHVMdqYWCKyY Icb554NrEjvkSVE8sYqniBGWvs4cc2g/WBFSw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Xk0ntXUor2j99C3NO8/vo2p+c0gfsVi1yMkjAZ3Fvxo=; b=KB9a2Pv+ia/iuwpkvsl7JI0M3MmrV3w+dpYutg526p3/jkmLVSkZ2xO20kRidcp9LV nXs212zhyMnAC/XXK93prSBKub8Mh8TCHj8C84ck1Wcl7omWvDlFiavQYeffgGh6U9HY unt7fhy+5oYDnde6N7F9HJBW1AjTywOgVHzWyugR3oVOkSnXS69DEo6sjoED6l6GClvK tdd9wJlKGyEf7TjDDP5Ro2WQ8ZPvPD2y9CpEULeose7LMFVEVm37s2+El28MUwgQG18u gxGzgo8GAUmT+b/vETJBa0as+q0AxXxq+fjwAoXdak13E/va+JQig4rqyvckq/yJwUP6 DC+w== X-Gm-Message-State: AOAM533CeFX7i8qjjaHRcUH4ZOzA7Q4mZ1ZPiEBD9R5ZgM2YVzc3U0R0 dJsts0YJb4OszaxkM6TdMpLFjQ== X-Google-Smtp-Source: ABdhPJzCxwFjTg8K8TDG3atxsHG1clpfMK5dGppkmJiYh3C01TIqrBk0gWWk7lMdOVRpg6H6ZeQg2Q== X-Received: by 2002:a17:90a:7e09:: with SMTP id i9mr25687960pjl.166.1621233360134; Sun, 16 May 2021 23:36:00 -0700 (PDT) Received: from kafuu-chino.c.googlers.com.com (105.219.229.35.bc.googleusercontent.com. [35.229.219.105]) by smtp.googlemail.com with ESMTPSA id js6sm13287612pjb.0.2021.05.16.23.35.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 May 2021 23:35:59 -0700 (PDT) From: Pi-Hsun Shih To: Subject: [PATCH v5 1/2] drm/bridge: anx7625: refactor power control to use runtime PM framework Date: Mon, 17 May 2021 14:35:28 +0800 Message-Id: <20210517063553.554955-1-pihsun@chromium.org> X-Mailer: git-send-email 2.31.1.751.gd2f1c929bd-goog MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailman-Approved-At: Mon, 17 May 2021 07:32:15 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jernej Skrabec , Neil Armstrong , David Airlie , "open list:DRM DRIVERS" , Jonas Karlman , open list , Robert Foss , Andrzej Hajda , Tzung-Bi Shih , Laurent Pinchart , Pi-Hsun Shih , Hsin-Yi Wang , Sam Ravnborg , Xin Ji Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" 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 --- Changes in v5: * Revert changes from v4, and move fix to the suspend / resume hook (2/2 in series). Changes in v4: * Maintain separate powered state, since the power state is not sync with runtime PM suspended state on suspend / resume, and the irq callback shouldn't be run while suspending. Changes in v3: * Add missing .pm field to anx7625_driver. --- drivers/gpu/drm/bridge/analogix/anx7625.c | 149 ++++++++++------------ drivers/gpu/drm/bridge/analogix/anx7625.h | 1 - 2 files changed, 64 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 23283ba0c4f9..e1bf31eafe22 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1005,33 +1006,6 @@ static void anx7625_power_on_init(struct anx7625_data *ctx) } } -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; @@ -1061,9 +1035,6 @@ static void anx7625_stop_dp_work(struct anx7625_data *ctx) 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) @@ -1105,49 +1076,26 @@ static void anx7625_hpd_polling(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) @@ -1180,9 +1128,6 @@ static int anx7625_hpd_change_detect(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) { @@ -1228,22 +1173,25 @@ static void anx7625_work_func(struct work_struct *work) 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; @@ -1305,9 +1253,9 @@ static struct edid *anx7625_get_edid(struct anx7625_data *ctx) 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); @@ -1611,10 +1559,7 @@ static void anx7625_bridge_enable(struct drm_bridge *bridge) 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); } @@ -1624,14 +1569,11 @@ static void anx7625_bridge_disable(struct drm_bridge *bridge) 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 @@ -1735,6 +1677,39 @@ static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx) 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) { @@ -1778,8 +1753,6 @@ static int anx7625_i2c_probe(struct i2c_client *client, } anx7625_init_gpio(platform); - atomic_set(&platform->power_status, 0); - mutex_init(&platform->lock); platform->pdata.intp_irq = client->irq; @@ -1809,9 +1782,11 @@ static int anx7625_i2c_probe(struct i2c_client *client, 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 */ @@ -1847,6 +1822,9 @@ static int anx7625_i2c_remove(struct i2c_client *client) 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); @@ -1869,6 +1847,7 @@ static struct i2c_driver anx7625_driver = { .driver = { .name = "anx7625", .of_match_table = anx_match_table, + .pm = &anx7625_pm_ops, }, .probe = anx7625_i2c_probe, .remove = anx7625_i2c_remove, diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index e4a086b3a3d7..034c3840028f 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -369,7 +369,6 @@ struct anx7625_i2c_client { struct anx7625_data { struct anx7625_platform_data pdata; - atomic_t power_status; int hpd_status; int hpd_high_cnt; /* Lock for work queue */ base-commit: e48661230cc35b3d0f4367eddfc19f86463ab917 -- 2.31.1.751.gd2f1c929bd-goog