Commit 2eb22214 authored by Pin-yen Lin's avatar Pin-yen Lin Committed by Douglas Anderson
Browse files

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: default avatarPin-yen Lin <treapking@chromium.org>
Reviewed-by: default avatarDouglas Anderson <dianders@chromium.org>
Signed-off-by: default avatarDouglas Anderson <dianders@chromium.org>
Link: https://lore.kernel.org/r/20250818115015.2909525-1-treapking@chromium.org
parent efe927b9
Loading
Loading
Loading
Loading
+62 −11
Original line number Diff line number Diff line
@@ -134,6 +134,9 @@ void drm_panel_prepare(struct drm_panel *panel)
	panel->prepared = true;

	list_for_each_entry(follower, &panel->followers, list) {
		if (!follower->funcs->panel_prepared)
			continue;

		ret = follower->funcs->panel_prepared(follower);
		if (ret < 0)
			dev_info(panel->dev, "%ps failed: %d\n",
@@ -179,6 +182,9 @@ void drm_panel_unprepare(struct drm_panel *panel)
	mutex_lock(&panel->follower_lock);

	list_for_each_entry(follower, &panel->followers, list) {
		if (!follower->funcs->panel_unpreparing)
			continue;

		ret = follower->funcs->panel_unpreparing(follower);
		if (ret < 0)
			dev_info(panel->dev, "%ps failed: %d\n",
@@ -209,6 +215,7 @@ EXPORT_SYMBOL(drm_panel_unprepare);
 */
void drm_panel_enable(struct drm_panel *panel)
{
	struct drm_panel_follower *follower;
	int ret;

	if (!panel)
@@ -219,10 +226,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;

@@ -230,6 +239,19 @@ 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->funcs->panel_enabled)
			continue;

		ret = follower->funcs->panel_enabled(follower);
		if (ret < 0)
			dev_info(panel->dev, "%ps failed: %d\n",
				 follower->funcs->panel_enabled, ret);
	}

exit:
	mutex_unlock(&panel->follower_lock);
}
EXPORT_SYMBOL(drm_panel_enable);

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

	if (!panel)
@@ -262,6 +285,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->funcs->panel_disabling)
			continue;

		ret = follower->funcs->panel_disabling(follower);
		if (ret < 0)
			dev_info(panel->dev, "%ps failed: %d\n",
				 follower->funcs->panel_disabling, ret);
	}

	ret = backlight_disable(panel->backlight);
	if (ret < 0)
		DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n",
@@ -270,9 +305,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);

@@ -539,13 +577,13 @@ EXPORT_SYMBOL(drm_is_panel_follower);
 * @follower_dev: The 'struct device' for the follower.
 * @follower:     The panel follower descriptor for the follower.
 *
 * A panel follower is called right after preparing the panel and right before
 * unpreparing the panel. It's primary intention is to power on an associated
 * touchscreen, though it could be used for any similar devices. Multiple
 * devices are allowed the follow the same panel.
 * A panel follower is called right after preparing/enabling the panel and right
 * before unpreparing/disabling the panel. It's primary intention is to power on
 * an associated touchscreen, though it could be used for any similar devices.
 * Multiple devices are allowed the follow the same panel.
 *
 * If a follower is added to a panel that's already been turned on, the
 * follower's prepare callback is called right away.
 * If a follower is added to a panel that's already been prepared/enabled, the
 * follower's prepared/enabled callback is called right away.
 *
 * The "panel" property of the follower points to the panel to be followed.
 *
@@ -569,12 +607,18 @@ 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->funcs->panel_prepared) {
		ret = follower->funcs->panel_prepared(follower);
		if (ret < 0)
			dev_info(panel->dev, "%ps failed: %d\n",
				 follower->funcs->panel_prepared, ret);
	}
	if (panel->enabled && follower->funcs->panel_enabled) {
		ret = follower->funcs->panel_enabled(follower);
		if (ret < 0)
			dev_info(panel->dev, "%ps failed: %d\n",
				 follower->funcs->panel_enabled, ret);
	}

	mutex_unlock(&panel->follower_lock);

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

	mutex_lock(&panel->follower_lock);

	if (panel->prepared) {
	if (panel->enabled && follower->funcs->panel_disabling) {
		ret = follower->funcs->panel_disabling(follower);
		if (ret < 0)
			dev_info(panel->dev, "%ps failed: %d\n",
				 follower->funcs->panel_disabling, ret);
	}
	if (panel->prepared && follower->funcs->panel_unpreparing) {
		ret = follower->funcs->panel_unpreparing(follower);
		if (ret < 0)
			dev_info(panel->dev, "%ps failed: %d\n",
+14 −0
Original line number Diff line number Diff line
@@ -160,6 +160,20 @@ struct drm_panel_follower_funcs {
	 * Called before the panel is powered off.
	 */
	int (*panel_unpreparing)(struct drm_panel_follower *follower);

	/**
	 * @panel_enabled:
	 *
	 * Called after the panel and the backlight have been enabled.
	 */
	int (*panel_enabled)(struct drm_panel_follower *follower);

	/**
	 * @panel_disabling:
	 *
	 * Called before the panel and the backlight are disabled.
	 */
	int (*panel_disabling)(struct drm_panel_follower *follower);
};

struct drm_panel_follower {