Skip to content

Commit 2eb2221

Browse files
ppetter1025dianders
authored andcommitted
drm/panel: Allow powering on panel follower after panel is enabled
Some touch controllers have to be powered on after the panel's backlight is enabled. To support these controllers, introduce .panel_enabled() and .panel_disabling() to panel_follower_funcs and use them to power on the device after the panel and its backlight are enabled. Signed-off-by: Pin-yen Lin <treapking@chromium.org> Reviewed-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Douglas Anderson <dianders@chromium.org> Link: https://lore.kernel.org/r/20250818115015.2909525-1-treapking@chromium.org
1 parent efe927b commit 2eb2221

2 files changed

Lines changed: 76 additions & 11 deletions

File tree

drivers/gpu/drm/drm_panel.c

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ void drm_panel_prepare(struct drm_panel *panel)
134134
panel->prepared = true;
135135

136136
list_for_each_entry(follower, &panel->followers, list) {
137+
if (!follower->funcs->panel_prepared)
138+
continue;
139+
137140
ret = follower->funcs->panel_prepared(follower);
138141
if (ret < 0)
139142
dev_info(panel->dev, "%ps failed: %d\n",
@@ -179,6 +182,9 @@ void drm_panel_unprepare(struct drm_panel *panel)
179182
mutex_lock(&panel->follower_lock);
180183

181184
list_for_each_entry(follower, &panel->followers, list) {
185+
if (!follower->funcs->panel_unpreparing)
186+
continue;
187+
182188
ret = follower->funcs->panel_unpreparing(follower);
183189
if (ret < 0)
184190
dev_info(panel->dev, "%ps failed: %d\n",
@@ -209,6 +215,7 @@ EXPORT_SYMBOL(drm_panel_unprepare);
209215
*/
210216
void drm_panel_enable(struct drm_panel *panel)
211217
{
218+
struct drm_panel_follower *follower;
212219
int ret;
213220

214221
if (!panel)
@@ -219,17 +226,32 @@ void drm_panel_enable(struct drm_panel *panel)
219226
return;
220227
}
221228

229+
mutex_lock(&panel->follower_lock);
230+
222231
if (panel->funcs && panel->funcs->enable) {
223232
ret = panel->funcs->enable(panel);
224233
if (ret < 0)
225-
return;
234+
goto exit;
226235
}
227236
panel->enabled = true;
228237

229238
ret = backlight_enable(panel->backlight);
230239
if (ret < 0)
231240
DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n",
232241
ret);
242+
243+
list_for_each_entry(follower, &panel->followers, list) {
244+
if (!follower->funcs->panel_enabled)
245+
continue;
246+
247+
ret = follower->funcs->panel_enabled(follower);
248+
if (ret < 0)
249+
dev_info(panel->dev, "%ps failed: %d\n",
250+
follower->funcs->panel_enabled, ret);
251+
}
252+
253+
exit:
254+
mutex_unlock(&panel->follower_lock);
233255
}
234256
EXPORT_SYMBOL(drm_panel_enable);
235257

@@ -243,6 +265,7 @@ EXPORT_SYMBOL(drm_panel_enable);
243265
*/
244266
void drm_panel_disable(struct drm_panel *panel)
245267
{
268+
struct drm_panel_follower *follower;
246269
int ret;
247270

248271
if (!panel)
@@ -262,6 +285,18 @@ void drm_panel_disable(struct drm_panel *panel)
262285
return;
263286
}
264287

288+
mutex_lock(&panel->follower_lock);
289+
290+
list_for_each_entry(follower, &panel->followers, list) {
291+
if (!follower->funcs->panel_disabling)
292+
continue;
293+
294+
ret = follower->funcs->panel_disabling(follower);
295+
if (ret < 0)
296+
dev_info(panel->dev, "%ps failed: %d\n",
297+
follower->funcs->panel_disabling, ret);
298+
}
299+
265300
ret = backlight_disable(panel->backlight);
266301
if (ret < 0)
267302
DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n",
@@ -270,9 +305,12 @@ void drm_panel_disable(struct drm_panel *panel)
270305
if (panel->funcs && panel->funcs->disable) {
271306
ret = panel->funcs->disable(panel);
272307
if (ret < 0)
273-
return;
308+
goto exit;
274309
}
275310
panel->enabled = false;
311+
312+
exit:
313+
mutex_unlock(&panel->follower_lock);
276314
}
277315
EXPORT_SYMBOL(drm_panel_disable);
278316

@@ -539,13 +577,13 @@ EXPORT_SYMBOL(drm_is_panel_follower);
539577
* @follower_dev: The 'struct device' for the follower.
540578
* @follower: The panel follower descriptor for the follower.
541579
*
542-
* A panel follower is called right after preparing the panel and right before
543-
* unpreparing the panel. It's primary intention is to power on an associated
544-
* touchscreen, though it could be used for any similar devices. Multiple
545-
* devices are allowed the follow the same panel.
580+
* A panel follower is called right after preparing/enabling the panel and right
581+
* before unpreparing/disabling the panel. It's primary intention is to power on
582+
* an associated touchscreen, though it could be used for any similar devices.
583+
* Multiple devices are allowed the follow the same panel.
546584
*
547-
* If a follower is added to a panel that's already been turned on, the
548-
* follower's prepare callback is called right away.
585+
* If a follower is added to a panel that's already been prepared/enabled, the
586+
* follower's prepared/enabled callback is called right away.
549587
*
550588
* The "panel" property of the follower points to the panel to be followed.
551589
*
@@ -569,12 +607,18 @@ int drm_panel_add_follower(struct device *follower_dev,
569607
mutex_lock(&panel->follower_lock);
570608

571609
list_add_tail(&follower->list, &panel->followers);
572-
if (panel->prepared) {
610+
if (panel->prepared && follower->funcs->panel_prepared) {
573611
ret = follower->funcs->panel_prepared(follower);
574612
if (ret < 0)
575613
dev_info(panel->dev, "%ps failed: %d\n",
576614
follower->funcs->panel_prepared, ret);
577615
}
616+
if (panel->enabled && follower->funcs->panel_enabled) {
617+
ret = follower->funcs->panel_enabled(follower);
618+
if (ret < 0)
619+
dev_info(panel->dev, "%ps failed: %d\n",
620+
follower->funcs->panel_enabled, ret);
621+
}
578622

579623
mutex_unlock(&panel->follower_lock);
580624

@@ -587,7 +631,8 @@ EXPORT_SYMBOL(drm_panel_add_follower);
587631
* @follower: The panel follower descriptor for the follower.
588632
*
589633
* Undo drm_panel_add_follower(). This includes calling the follower's
590-
* unprepare function if we're removed from a panel that's currently prepared.
634+
* unpreparing/disabling function if we're removed from a panel that's currently
635+
* prepared/enabled.
591636
*
592637
* Return: 0 or an error code.
593638
*/
@@ -598,7 +643,13 @@ void drm_panel_remove_follower(struct drm_panel_follower *follower)
598643

599644
mutex_lock(&panel->follower_lock);
600645

601-
if (panel->prepared) {
646+
if (panel->enabled && follower->funcs->panel_disabling) {
647+
ret = follower->funcs->panel_disabling(follower);
648+
if (ret < 0)
649+
dev_info(panel->dev, "%ps failed: %d\n",
650+
follower->funcs->panel_disabling, ret);
651+
}
652+
if (panel->prepared && follower->funcs->panel_unpreparing) {
602653
ret = follower->funcs->panel_unpreparing(follower);
603654
if (ret < 0)
604655
dev_info(panel->dev, "%ps failed: %d\n",

include/drm/drm_panel.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,20 @@ struct drm_panel_follower_funcs {
160160
* Called before the panel is powered off.
161161
*/
162162
int (*panel_unpreparing)(struct drm_panel_follower *follower);
163+
164+
/**
165+
* @panel_enabled:
166+
*
167+
* Called after the panel and the backlight have been enabled.
168+
*/
169+
int (*panel_enabled)(struct drm_panel_follower *follower);
170+
171+
/**
172+
* @panel_disabling:
173+
*
174+
* Called before the panel and the backlight are disabled.
175+
*/
176+
int (*panel_disabling)(struct drm_panel_follower *follower);
163177
};
164178

165179
struct drm_panel_follower {

0 commit comments

Comments
 (0)