On Thu, 31 Jul 2025, Pin-Yen Lin <treapk...@chromium.org> wrote: > Some touch controllers have to be powered on after the panel's backlight > is enabled. To support these controllers, introduce after_panel_enabled > flag to the panel follower and power on the device after the panel and > its backlight are enabled.
I think it's *very* confusing and error prone to call follower hooks at different places depending on a flag. The hook names and documentation say *when* they get called, and that should not change. I think the right approach would be to add .panel_enabled and .panel_disabling hooks to struct drm_panel_follower_funcs, and have them called after panel (and backlight) have been enabled and before panel (and backlight) are disabled, respectively. In i2c-hid-core.c, you'd then have two copies of struct drm_panel_follower_funcs, and use one or the other depending on the quirk. You can even reuse the functions. I think overall it'll be be more consistent, more flexible, and probably fewer lines of code too. BR, Jani. > Signed-off-by: Pin-Yen Lin <treapk...@google.com> PS. Your Signed-off-by doesn't match the patch author. > --- > > drivers/gpu/drm/drm_panel.c | 47 +++++++++++++++++++++++++++++++++---- > include/drm/drm_panel.h | 8 +++++++ > 2 files changed, 51 insertions(+), 4 deletions(-) > > diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c > index 650de4da08537..58125f8418f37 100644 > --- a/drivers/gpu/drm/drm_panel.c > +++ b/drivers/gpu/drm/drm_panel.c > @@ -133,6 +133,9 @@ void drm_panel_prepare(struct drm_panel *panel) > panel->prepared = true; > > list_for_each_entry(follower, &panel->followers, list) { > + if (follower->after_panel_enabled) > + continue; > + > ret = follower->funcs->panel_prepared(follower); > if (ret < 0) > dev_info(panel->dev, "%ps failed: %d\n", > @@ -178,6 +181,9 @@ void drm_panel_unprepare(struct drm_panel *panel) > mutex_lock(&panel->follower_lock); > > list_for_each_entry(follower, &panel->followers, list) { > + if (follower->after_panel_enabled) > + continue; > + > ret = follower->funcs->panel_unpreparing(follower); > if (ret < 0) > dev_info(panel->dev, "%ps failed: %d\n", > @@ -208,6 +214,7 @@ EXPORT_SYMBOL(drm_panel_unprepare); > */ > void drm_panel_enable(struct drm_panel *panel) > { > + struct drm_panel_follower *follower; > int ret; > > if (!panel) > @@ -218,10 +225,12 @@ void drm_panel_enable(struct drm_panel *panel) > return; > } > > + mutex_lock(&panel->follower_lock); > + > if (panel->funcs && panel->funcs->enable) { > ret = panel->funcs->enable(panel); > if (ret < 0) > - return; > + goto exit; > } > panel->enabled = true; > > @@ -229,6 +238,18 @@ void drm_panel_enable(struct drm_panel *panel) > if (ret < 0) > DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n", > ret); > + > + list_for_each_entry(follower, &panel->followers, list) { > + if (!follower->after_panel_enabled) > + continue; > + > + ret = follower->funcs->panel_prepared(follower); > + if (ret < 0) > + dev_info(panel->dev, "%ps failed: %d\n", > + follower->funcs->panel_prepared, ret); > + } > +exit: > + mutex_unlock(&panel->follower_lock); > } > EXPORT_SYMBOL(drm_panel_enable); > > @@ -242,6 +263,7 @@ EXPORT_SYMBOL(drm_panel_enable); > */ > void drm_panel_disable(struct drm_panel *panel) > { > + struct drm_panel_follower *follower; > int ret; > > if (!panel) > @@ -261,6 +283,18 @@ void drm_panel_disable(struct drm_panel *panel) > return; > } > > + mutex_lock(&panel->follower_lock); > + > + list_for_each_entry(follower, &panel->followers, list) { > + if (!follower->after_panel_enabled) > + continue; > + > + ret = follower->funcs->panel_unpreparing(follower); > + if (ret < 0) > + dev_info(panel->dev, "%ps failed: %d\n", > + follower->funcs->panel_unpreparing, ret); > + } > + > ret = backlight_disable(panel->backlight); > if (ret < 0) > DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n", > @@ -269,9 +303,12 @@ void drm_panel_disable(struct drm_panel *panel) > if (panel->funcs && panel->funcs->disable) { > ret = panel->funcs->disable(panel); > if (ret < 0) > - return; > + goto exit; > } > panel->enabled = false; > + > +exit: > + mutex_unlock(&panel->follower_lock); > } > EXPORT_SYMBOL(drm_panel_disable); > > @@ -537,7 +574,8 @@ int drm_panel_add_follower(struct device *follower_dev, > mutex_lock(&panel->follower_lock); > > list_add_tail(&follower->list, &panel->followers); > - if (panel->prepared) { > + if ((panel->prepared && !follower->after_panel_enabled) || > + (panel->enabled && follower->after_panel_enabled)) { > ret = follower->funcs->panel_prepared(follower); > if (ret < 0) > dev_info(panel->dev, "%ps failed: %d\n", > @@ -566,7 +604,8 @@ void drm_panel_remove_follower(struct drm_panel_follower > *follower) > > mutex_lock(&panel->follower_lock); > > - if (panel->prepared) { > + if ((panel->prepared && !follower->after_panel_enabled) || > + (panel->enabled && follower->after_panel_enabled)) { > ret = follower->funcs->panel_unpreparing(follower); > if (ret < 0) > dev_info(panel->dev, "%ps failed: %d\n", > diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h > index 843fb756a2950..aa9b6218702fd 100644 > --- a/include/drm/drm_panel.h > +++ b/include/drm/drm_panel.h > @@ -183,6 +183,14 @@ struct drm_panel_follower { > * The panel we're dependent on; set by drm_panel_add_follower(). > */ > struct drm_panel *panel; > + > + /** > + * @after_panel_enabled > + * > + * If true then this panel follower should be powered after the panel > + * and the backlight are enabled, instead of after panel is prepared. > + */ > + bool after_panel_enabled; > }; > > /** -- Jani Nikula, Intel