Commit 801ab9e9 authored by Simon Glass's avatar Simon Glass

dm: video: Add support for video bridges

A video bridge typically converts video from one format to another, e.g.
DisplayPort to LVDS. Add driver model support for these with a simple
interface to control activation and backlight. The uclass supports GPIO
control of power and reset lines.
Signed-off-by: default avatarSimon Glass <sjg@chromium.org>
parent 224d1ddc
......@@ -240,3 +240,5 @@ config VIDEO_TEGRA124
HDMI. At present only eDP is supported by U-Boot. This option
enables this support which can be used on devices which
have an eDP display connected.
source "drivers/video/bridge/Kconfig"
......@@ -54,3 +54,5 @@ obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
obj-$(CONFIG_VIDEO_PARADE) += parade.o
obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
obj-y += bridge/
config VIDEO_BRIDGE
bool "Support video bridges"
depends on DM
help
Some platforms use video bridges to convert from one output to
another. For example, where the SoC only supports eDP and the LCD
requires LVDS, an eDP->LVDS bridge chip can be used to provide the
necessary conversion. This option enables support for these devices.
#
# Copyright (C) 2015 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_VIDEO_BRIDGE) += video-bridge-uclass.o
/*
* Copyright (C) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <video_bridge.h>
int video_bridge_set_backlight(struct udevice *dev, int percent)
{
struct video_bridge_ops *ops = video_bridge_get_ops(dev);
if (!ops->set_backlight)
return -ENOSYS;
return ops->set_backlight(dev, percent);
}
int video_bridge_attach(struct udevice *dev)
{
struct video_bridge_ops *ops = video_bridge_get_ops(dev);
if (!ops->attach)
return -ENOSYS;
return ops->attach(dev);
}
int video_bridge_check_attached(struct udevice *dev)
{
struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
struct video_bridge_ops *ops = video_bridge_get_ops(dev);
int ret;
if (!ops->check_attached) {
ret = dm_gpio_get_value(&uc_priv->hotplug);
return ret > 0 ? 0 : ret == 0 ? -ENOTCONN : ret;
}
return ops->check_attached(dev);
}
static int video_bridge_pre_probe(struct udevice *dev)
{
struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
int ret;
debug("%s\n", __func__);
ret = gpio_request_by_name(dev, "sleep-gpios", 0,
&uc_priv->sleep, GPIOD_IS_OUT);
if (ret) {
debug("%s: Could not decode sleep-gpios (%d)\n", __func__, ret);
return ret;
}
ret = dm_gpio_set_pull(&uc_priv->sleep, GPIO_PULL_NONE);
if (ret) {
debug("%s: Could not set sleep pull value\n", __func__);
return ret;
}
ret = gpio_request_by_name(dev, "reset-gpios", 0, &uc_priv->reset,
GPIOD_IS_OUT);
if (ret) {
debug("%s: Could not decode reset-gpios (%d)\n", __func__, ret);
return ret;
}
ret = dm_gpio_set_pull(&uc_priv->reset, GPIO_PULL_NONE);
if (ret) {
debug("%s: Could not set reset pull value\n", __func__);
return ret;
}
ret = gpio_request_by_name(dev, "hotplug-gpios", 0, &uc_priv->hotplug,
GPIOD_IS_IN);
if (ret && ret != -ENOENT) {
debug("%s: Could not decode hotplug (%d)\n", __func__, ret);
return ret;
}
return 0;
}
int video_bridge_set_active(struct udevice *dev, bool active)
{
struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
int ret;
debug("%s: %d\n", __func__, active);
ret = dm_gpio_set_value(&uc_priv->sleep, !active);
if (ret)
return ret;
if (active) {
ret = dm_gpio_set_value(&uc_priv->reset, true);
if (ret)
return ret;
udelay(10);
ret = dm_gpio_set_value(&uc_priv->reset, false);
}
return ret;
}
UCLASS_DRIVER(video_bridge) = {
.id = UCLASS_VIDEO_BRIDGE,
.name = "video_bridge",
.per_device_auto_alloc_size = sizeof(struct video_bridge_priv),
.pre_probe = video_bridge_pre_probe,
};
......@@ -57,6 +57,7 @@ enum uclass_id {
UCLASS_USB, /* USB bus */
UCLASS_USB_DEV_GENERIC, /* USB generic device */
UCLASS_USB_HUB, /* USB hub */
UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */
UCLASS_COUNT,
UCLASS_INVALID = -1,
......
/*
* Copyright (C) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __VIDEO_BRIDGE
#define __VIDEO_BRIDGE
#include <asm/gpio.h>
/**
* struct video_bridge_priv - uclass information for video bridges
*
* @sleep: GPIO to assert to power down the bridge
* @reset: GPIO to assert to reset the bridge
* @hotplug: Optional GPIO to check if bridge is connected
*/
struct video_bridge_priv {
struct gpio_desc sleep;
struct gpio_desc reset;
struct gpio_desc hotplug;
};
/**
* Operations for video bridges
*/
struct video_bridge_ops {
/**
* attach() - attach a video bridge
*
* @return 0 if OK, -ve on error
*/
int (*attach)(struct udevice *dev);
/**
* check_attached() - check if a bridge is correctly attached
*
* This method is optional - if not provided then the hotplug GPIO
* will be checked instead.
*
* @dev: Device to check
* @return 0 if attached, -EENOTCONN if not, or other -ve error
*/
int (*check_attached)(struct udevice *dev);
/**
* set_backlight() - Set the backlight brightness
*
* @dev: device to adjust
* @percent: brightness percentage (0=off, 100=full brightness)
* @return 0 if OK, -ve on error
*/
int (*set_backlight)(struct udevice *dev, int percent);
};
#define video_bridge_get_ops(dev) \
((struct video_bridge_ops *)(dev)->driver->ops)
/**
* video_bridge_attach() - attach a video bridge
*
* @return 0 if OK, -ve on error
*/
int video_bridge_attach(struct udevice *dev);
/**
* video_bridge_set_backlight() - Set the backlight brightness
*
* @percent: brightness percentage (0=off, 100=full brightness)
* @return 0 if OK, -ve on error
*/
int video_bridge_set_backlight(struct udevice *dev, int percent);
/**
* video_bridge_set_active() - take the bridge in/out of reset/powerdown
*
* @dev: Device to adjust
* @active: true to power up and reset, false to power down
*/
int video_bridge_set_active(struct udevice *dev, bool active);
/**
* check_attached() - check if a bridge is correctly attached
*
* @dev: Device to check
* @return 0 if attached, -EENOTCONN if not, or other -ve error
*/
int video_bridge_check_attached(struct udevice *dev);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment