Re: [PATCH v9 2/2] drm: bridge: Add thc63lvd1024 LVDS decoder driver

2018-04-20 Thread Vladimir Zapolskiy
Hi Jacopo,

On 04/18/2018 05:40 PM, Jacopo Mondi wrote:
> Add DRM bridge driver for Thine THC63LVD1024 LVDS to digital parallel
> output converter.
> 
> Signed-off-by: Jacopo Mondi 
> Reviewed-by: Andrzej Hajda 
> Reviewed-by: Niklas Söderlund 
> Reviewed-by: Laurent Pinchart 
> ---
>  drivers/gpu/drm/bridge/Kconfig|   6 +
>  drivers/gpu/drm/bridge/Makefile   |   1 +
>  drivers/gpu/drm/bridge/thc63lvd1024.c | 206 
> ++
>  3 files changed, 213 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/thc63lvd1024.c

Reviewed-by: Vladimir Zapolskiy 

--
With best wishes,
Vladimir


[PATCH v9 2/2] drm: bridge: Add thc63lvd1024 LVDS decoder driver

2018-04-18 Thread Jacopo Mondi
Add DRM bridge driver for Thine THC63LVD1024 LVDS to digital parallel
output converter.

Signed-off-by: Jacopo Mondi 
Reviewed-by: Andrzej Hajda 
Reviewed-by: Niklas Söderlund 
Reviewed-by: Laurent Pinchart 
---
 drivers/gpu/drm/bridge/Kconfig|   6 +
 drivers/gpu/drm/bridge/Makefile   |   1 +
 drivers/gpu/drm/bridge/thc63lvd1024.c | 206 ++
 3 files changed, 213 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/thc63lvd1024.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 3aa65bd..42c9c2d 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -93,6 +93,12 @@ config DRM_SII9234
  It is an I2C driver, that detects connection of MHL bridge
  and starts encapsulation of HDMI signal.
 
+config DRM_THINE_THC63LVD1024
+   tristate "Thine THC63LVD1024 LVDS decoder bridge"
+   depends on OF
+   ---help---
+ Thine THC63LVD1024 LVDS/parallel converter driver.
+
 config DRM_TOSHIBA_TC358767
tristate "Toshiba TC358767 eDP bridge"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 373eb28..fd90b16 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
 obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
 obj-$(CONFIG_DRM_SII902X) += sii902x.o
 obj-$(CONFIG_DRM_SII9234) += sii9234.o
+obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
 obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
 obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
 obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
diff --git a/drivers/gpu/drm/bridge/thc63lvd1024.c 
b/drivers/gpu/drm/bridge/thc63lvd1024.c
new file mode 100644
index 000..c8b9edd
--- /dev/null
+++ b/drivers/gpu/drm/bridge/thc63lvd1024.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * THC63LVD1024 LVDS to parallel data DRM bridge driver.
+ *
+ * Copyright (C) 2018 Jacopo Mondi 
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+enum thc63_ports {
+   THC63_LVDS_IN0,
+   THC63_LVDS_IN1,
+   THC63_RGB_OUT0,
+   THC63_RGB_OUT1,
+};
+
+struct thc63_dev {
+   struct device *dev;
+
+   struct regulator *vcc;
+
+   struct gpio_desc *pdwn;
+   struct gpio_desc *oe;
+
+   struct drm_bridge bridge;
+   struct drm_bridge *next;
+};
+
+static inline struct thc63_dev *to_thc63(struct drm_bridge *bridge)
+{
+   return container_of(bridge, struct thc63_dev, bridge);
+}
+
+static int thc63_attach(struct drm_bridge *bridge)
+{
+   struct thc63_dev *thc63 = to_thc63(bridge);
+
+   return drm_bridge_attach(bridge->encoder, thc63->next, bridge);
+}
+
+static void thc63_enable(struct drm_bridge *bridge)
+{
+   struct thc63_dev *thc63 = to_thc63(bridge);
+   int ret;
+
+   ret = regulator_enable(thc63->vcc);
+   if (ret) {
+   dev_err(thc63->dev,
+   "Failed to enable regulator \"vcc\": %d\n", ret);
+   return;
+   }
+
+   gpiod_set_value(thc63->pdwn, 0);
+   gpiod_set_value(thc63->oe, 1);
+}
+
+static void thc63_disable(struct drm_bridge *bridge)
+{
+   struct thc63_dev *thc63 = to_thc63(bridge);
+   int ret;
+
+   gpiod_set_value(thc63->oe, 0);
+   gpiod_set_value(thc63->pdwn, 1);
+
+   ret = regulator_disable(thc63->vcc);
+   if (ret)
+   dev_err(thc63->dev,
+   "Failed to disable regulator \"vcc\": %d\n", ret);
+}
+
+static const struct drm_bridge_funcs thc63_bridge_func = {
+   .attach = thc63_attach,
+   .enable = thc63_enable,
+   .disable = thc63_disable,
+};
+
+static int thc63_parse_dt(struct thc63_dev *thc63)
+{
+   struct device_node *thc63_out;
+   struct device_node *remote;
+
+   thc63_out = of_graph_get_endpoint_by_regs(thc63->dev->of_node,
+ THC63_RGB_OUT0, -1);
+   if (!thc63_out) {
+   dev_err(thc63->dev, "Missing endpoint in port@%u\n",
+   THC63_RGB_OUT0);
+   return -ENODEV;
+   }
+
+   remote = of_graph_get_remote_port_parent(thc63_out);
+   of_node_put(thc63_out);
+   if (!remote) {
+   dev_err(thc63->dev, "Endpoint in port@%u unconnected\n",
+   THC63_RGB_OUT0);
+   return -ENODEV;
+   }
+
+   if (!of_device_is_available(remote)) {
+   dev_err(thc63->dev, "port@%u remote endpoint is disabled\n",
+   THC63_RGB_OUT0);
+   of_node_put(remote);
+   return -ENODEV;
+   }
+
+   thc63->next = of_drm_find_bridge(remote);
+   of_node_put(remote);
+   if (!thc63->next)
+