devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/2] Sil9022 DPI to HDMI Encoder
@ 2014-03-18 10:07 Sathya Prakash M R
  2014-03-18 10:07 ` [PATCH 1/2] OMAPDSS: Add Sil9022 DPI-HDMI Encoder Driver Sathya Prakash M R
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Sathya Prakash M R @ 2014-03-18 10:07 UTC (permalink / raw)
  To: tony, tomi.valkeinen, devicetree, linux-omap, pawel.moll, paul
  Cc: Sathya Prakash M R

This patch series adds the Silicon Image Sil9022 driver.

Sil9022 is HDMI Transmitter compliant to HDMI 1.2a and DVI 1.0.
It supports 1080p and UXGA. It has single slave I2C from Host,
passing through to master I2C interface for DDC Connection.
It provides Transmitter Programming Interface (TPI) for simplified API programming.
Product brief:
http://www.semiconductorstore.com/pdf/newsite/siliconimage/SiI9022a_pb.pdf

Current driver is tested on AM43x SOC.

This series is on top of series posted to add DSS support on AM43x [2]
[2] https://patchwork.kernel.org/patch/3822691/

This is initial driver supporting limited features.

TODO ->
Audio Support
Detailed Hot Plug event handling and also routing the hot plug event to host processor

These features will be added in future.

Sathya Prakash M R (2):
  OMAPDSS: Add Sil9022 DPI-HDMI Encoder Driver
  ARM: DTS: AM43x: Add sii9022 dt information

 arch/arm/boot/dts/am437x-gp-evm.dts                |   58 +-
 arch/arm/boot/dts/am43x-epos-evm.dts               |   59 +-
 drivers/video/omap2/displays-new/Kconfig           |    8 +
 drivers/video/omap2/displays-new/Makefile          |    1 +
 drivers/video/omap2/displays-new/encoder-sil9022.c |  748 ++++++++++++++++++++
 drivers/video/omap2/displays-new/encoder-sil9022.h |  105 +++
 6 files changed, 973 insertions(+), 6 deletions(-)
 create mode 100644 drivers/video/omap2/displays-new/encoder-sil9022.c
 create mode 100644 drivers/video/omap2/displays-new/encoder-sil9022.h

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] OMAPDSS: Add Sil9022 DPI-HDMI Encoder Driver
  2014-03-18 10:07 [RFC PATCH 0/2] Sil9022 DPI to HDMI Encoder Sathya Prakash M R
@ 2014-03-18 10:07 ` Sathya Prakash M R
  2014-03-18 11:20   ` Tomi Valkeinen
  2014-03-18 10:07 ` [PATCH 2/2] ARM: DTS: AM43x: Add sii9022 dt information Sathya Prakash M R
  2014-03-18 10:56 ` [RFC PATCH 0/2] Sil9022 DPI to HDMI Encoder Mark Rutland
  2 siblings, 1 reply; 8+ messages in thread
From: Sathya Prakash M R @ 2014-03-18 10:07 UTC (permalink / raw)
  To: tony, tomi.valkeinen, devicetree, linux-omap, pawel.moll, paul
  Cc: Sathya Prakash M R

Sil9022 DPI to HDMI Encoder driver is part of
AM43xx SOC. Adding the basic Sil9022 driver
HPD and Audio support is not present yet.

Signed-off-by: Sathya Prakash M R <sathyap@ti.com>
---
 drivers/video/omap2/displays-new/Kconfig           |    8 +
 drivers/video/omap2/displays-new/Makefile          |    1 +
 drivers/video/omap2/displays-new/encoder-sil9022.c |  748 ++++++++++++++++++++
 drivers/video/omap2/displays-new/encoder-sil9022.h |  105 +++
 4 files changed, 862 insertions(+)
 create mode 100644 drivers/video/omap2/displays-new/encoder-sil9022.c
 create mode 100644 drivers/video/omap2/displays-new/encoder-sil9022.h

diff --git a/drivers/video/omap2/displays-new/Kconfig b/drivers/video/omap2/displays-new/Kconfig
index e6cfc38..9243dd7 100644
--- a/drivers/video/omap2/displays-new/Kconfig
+++ b/drivers/video/omap2/displays-new/Kconfig
@@ -12,6 +12,14 @@ config DISPLAY_ENCODER_TPD12S015
 	  Driver for TPD12S015, which offers HDMI ESD protection and level
 	  shifting.
 
+config DISPLAY_ENCODER_SIL9022
+        tristate "Sil9022 DPI to HDMI Encoder"
+	depends on I2C
+	help
+	  Driver for Silicon Image Sil9022 DPI to HDMI encoder and
+	  a brief about Sil9022 can be found here:
+	  http://www.semiconductorstore.com/pdf/newsite/siliconimage/SiI9022a_pb.pdf
+
 config DISPLAY_CONNECTOR_DVI
         tristate "DVI Connector"
 	depends on I2C
diff --git a/drivers/video/omap2/displays-new/Makefile b/drivers/video/omap2/displays-new/Makefile
index 0323a8a..f3c8997 100644
--- a/drivers/video/omap2/displays-new/Makefile
+++ b/drivers/video/omap2/displays-new/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
 obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
+obj-$(CONFIG_DISPLAY_ENCODER_SIL9022) += encoder-sil9022.o
 obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
 obj-$(CONFIG_DISPLAY_CONNECTOR_HDMI) += connector-hdmi.o
 obj-$(CONFIG_DISPLAY_CONNECTOR_ANALOG_TV) += connector-analog-tv.o
diff --git a/drivers/video/omap2/displays-new/encoder-sil9022.c b/drivers/video/omap2/displays-new/encoder-sil9022.c
new file mode 100644
index 0000000..411867b
--- /dev/null
+++ b/drivers/video/omap2/displays-new/encoder-sil9022.c
@@ -0,0 +1,748 @@
+/*
+ * Silicon image Sil9022 DPI-to-HDMI encoder driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Sathya Prakash M R <sathyap@ti.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+#include "encoder-sil9022.h"
+
+struct panel_drv_data {
+	struct omap_dss_device dssdev;
+	struct omap_dss_device *in;
+	struct i2c_client *i2c_client;
+	int reset_gpio;
+	int data_lines;
+	struct regmap *regmap;
+	struct omap_video_timings timings;
+};
+
+static struct regmap_config sil9022_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int sil9022_ddc_read(struct i2c_client *client,
+		unsigned char *buf, u16 count, u8 offset)
+{
+	int r, retries;
+
+	for (retries = 3; retries > 0; retries--) {
+		struct i2c_msg msgs[] = {
+			{
+				.addr   = 0x50,
+				.flags  = 0,
+				.len    = 1,
+				.buf    = &offset,
+			}, {
+				.addr   = 0x50,
+				.flags  = I2C_M_RD,
+				.len    = count,
+				.buf    = buf,
+			}
+		};
+
+		r = i2c_transfer(client->adapter, msgs, 2);
+		if (r == 2)
+			return 0;
+
+		if (r != -EAGAIN)
+			break;
+	}
+
+	return r < 0 ? r : -EIO;
+}
+
+static int sil9022_hw_enable(struct omap_dss_device *dssdev)
+{
+	int		r = 0;
+	u8		vals[8];
+	unsigned int val;
+	u16		xres;
+	u16		yres;
+	u16		pclk;
+
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct omap_video_timings *hdmi_timings = &ddata->timings;
+	struct i2c_client *sil9022_client = ddata->i2c_client;
+	struct regmap *map = ddata->regmap;
+
+	xres = hdmi_timings->x_res;
+	yres = hdmi_timings->y_res;
+	pclk = hdmi_timings->pixel_clock;
+
+	dev_info(dssdev->dev,
+			 "sii9022_ENABLE -> Timings\n"
+			 "pixel_clk			= %d\n"
+			 "horizontal res		= %d\n"
+			 "vertical res			= %d\n",
+			 pclk, xres, yres);
+
+	/*  Fill the TPI Video Mode Data structure */
+	vals[0] = (pclk & 0xFF);                  /* Pixel clock */
+	vals[1] = ((pclk & 0xFF00) >> 8);
+	vals[2] = VERTICAL_FREQ;                    /* Vertical freq */
+	/* register programming information on how vertical freq is to be
+	programmed to Sil9022 not clear. Hence setting to 60 for now */
+	vals[3] = 0x00;
+	vals[4] = (xres & 0xFF);         /* Horizontal pixels*/
+	vals[5] = ((xres & 0xFF00) >> 8);
+	vals[6] = (yres & 0xFF);           /* Vertical pixels */
+	vals[7] = ((yres & 0xFF00) >> 8);
+
+	/*  Write out the TPI Video Mode Data */
+	r = regmap_raw_write(map, HDMI_TPI_VIDEO_DATA_BASE_REG, vals, 8);
+
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR: writing TPI video mode data\n");
+		return r;
+	}
+
+	/* Write out the TPI Input bus and pixel repetition Data:
+	(24 bit wide bus, falling edge, no pixel replication, 1:1 CLK ratio) */
+	r = regmap_write(map,
+			HDMI_TPI_PIXEL_REPETITION_REG,
+			TPI_AVI_PIXEL_REP_BUS_24BIT |
+			TPI_AVI_PIXEL_REP_FALLING_EDGE |
+			TPI_AVI_PIXEL_REP_NONE |
+			TPI_CLK_RATIO_1X);
+
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR: writing TPI pixel repetition data\n");
+		return r;
+	}
+
+	 /*  Write out the TPI AVI Input Format */
+	r = regmap_write(map,
+			HDMI_TPI_AVI_IN_FORMAT_REG,
+			TPI_AVI_INPUT_BITMODE_8BIT |
+			TPI_AVI_INPUT_RANGE_AUTO |
+			TPI_AVI_INPUT_COLORSPACE_RGB);
+
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR: writing TPI AVI Input format\n");
+		return r;
+	}
+
+	/*  Write out the TPI AVI Output Format */
+	r = regmap_write(map,
+			HDMI_TPI_AVI_OUT_FORMAT_REG,
+			TPI_AVI_OUTPUT_CONV_BT709 |
+			TPI_AVI_OUTPUT_RANGE_AUTO |
+			TPI_AVI_OUTPUT_COLORSPACE_RGBHDMI);
+
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR: writing TPI AVI output format\n");
+		return r;
+	}
+
+	/* Write out the TPI System Control Data to power down */
+	r = regmap_write(map,
+			HDMI_SYS_CTRL_DATA_REG,
+			TPI_SYS_CTRL_POWER_DOWN);
+
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR: writing TPI power down control data\n");
+		return r;
+	}
+
+	/* Move from ENABLED -> FULLY ENABLED Power State  */
+	r = regmap_write(map,
+			HDMI_TPI_POWER_STATE_CTRL_REG,
+			TPI_AVI_POWER_STATE_D0);
+
+	if (r < 0) {
+		dev_err(&sil9022_client->dev,
+			"<%s> ERROR: Setting device power state to D0\n",
+			__func__);
+		return r;
+	}
+
+	/* Write out the TPI System Control Data to power up and
+	 * select output mode
+	 */
+
+	r = regmap_write(map,
+			HDMI_SYS_CTRL_DATA_REG,
+			TPI_SYS_CTRL_POWER_ACTIVE |
+			TPI_SYS_CTRL_OUTPUT_MODE_HDMI);
+
+	if (r < 0) {
+		dev_err(&sil9022_client->dev,
+			"<%s> ERROR: Writing system control data\n", __func__);
+		return r;
+	}
+
+	/*  Read back TPI System Control Data to latch settings */
+	r = regmap_read(map, HDMI_SYS_CTRL_DATA_REG, &val);
+
+	if (r < 0) {
+		dev_err(&sil9022_client->dev,
+			"<%s> ERROR: Reading back system control data\n",
+			__func__);
+		return r;
+	}
+
+	/* HDCP */
+	r = regmap_write(map,
+				HDMI_TPI_HDCP_CONTROLDATA_REG,
+				HDCP_DISABLE);
+
+	if (r < 0) {
+		dev_err(&sil9022_client->dev,
+			"<%s> ERROR: Writing HDCP information",
+			__func__);
+		return r;
+	}
+
+	dev_info(&sil9022_client->dev,
+		"<%s> hdmi over sil9022 is now enabled\n", __func__);
+	return 0;
+
+}
+
+static int sil9022_hw_disable(struct omap_dss_device *dssdev)
+{
+	unsigned int val = 0;
+	int r = 0;
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct regmap *map = ddata->regmap;
+
+	/*  Write out the TPI System Control Data to power down  */
+	r = regmap_write(map,
+			HDMI_SYS_CTRL_DATA_REG,
+			TPI_SYS_CTRL_POWER_DOWN);
+
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR: writing control data - power down\n");
+		return r;
+	}
+
+	/*  Move from FULLY ENABLED -> ENABLED Power state */
+	r = regmap_write(map,
+			HDMI_TPI_POWER_STATE_CTRL_REG,
+			TPI_AVI_POWER_STATE_D2);
+
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR: Setting device power state to D2\n");
+		return r;
+	}
+
+	/*  Read back TPI System Control Data to latch settings */
+	r = regmap_read(map, HDMI_SYS_CTRL_DATA_REG, &val);
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR:  Reading System control data "
+			"- latch settings\n");
+		return r;
+	}
+
+	dev_info(dssdev->dev, "hdmi disabled\n");
+	return 0;
+
+}
+
+static int sil9022_probe_chip_version(struct omap_dss_device *dssdev)
+{
+	int r = 0;
+	unsigned int ver;
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct regmap *map = ddata->regmap;
+
+	/* probe for sil9022 chip version*/
+	r = regmap_write(map, SIL9022_REG_TPI_RQB, 0x00);
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR: Writing HDMI configuration to "
+			"reg - SI9022_REG_TPI_RQB\n");
+		return r;
+	}
+
+	r = regmap_read(map, SIL9022_REG_CHIPID0, &ver);
+	if (r < 0) {
+		dev_err(dssdev->dev,
+			"ERROR: Reading HDMI version Id\n");
+	} else if (ver != SIL9022_CHIPID_902x) {
+		dev_err(dssdev->dev,
+			"Not a valid verId: 0x%x\n", ver);
+	} else {
+		dev_info(dssdev->dev,
+			 "sil9022 HDMI Chip version = %x\n", ver);
+	}
+	return r;
+}
+
+/* Hdmi ops */
+
+static int sil9022_connect(struct omap_dss_device *dssdev,
+		struct omap_dss_device *dst)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct omap_dss_device *in = ddata->in;
+	struct regmap *map = ddata->regmap;
+	int r = 0;
+
+	if (omapdss_device_is_connected(dssdev))
+		return -EBUSY;
+
+	r = in->ops.dpi->connect(in, dssdev);
+	if (r)
+		return r;
+
+	dst->src = dssdev;
+	dssdev->dst = dst;
+
+	/* Move from LOW -> ENABLED Power state */
+	r = regmap_write(map, HDMI_TPI_POWER_STATE_CTRL_REG,
+			TPI_AVI_POWER_STATE_D2);
+	if (r < 0) {
+		dev_err(dssdev->dev, "ERROR: Setting device power state to D2\n");
+		goto err_pwr;
+	}
+
+	return 0;
+err_pwr:
+		dst->src = NULL;
+		dssdev->dst = NULL;
+		in->ops.dpi->disconnect(in, dssdev);
+		return r;
+
+}
+
+static void sil9022_disconnect(struct omap_dss_device *dssdev,
+		struct omap_dss_device *dst)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct omap_dss_device *in = ddata->in;
+
+	WARN_ON(!omapdss_device_is_connected(dssdev));
+	if (!omapdss_device_is_connected(dssdev))
+		return;
+
+	WARN_ON(dst != dssdev->dst);
+	if (dst != dssdev->dst)
+		return;
+
+	/* we don't control the RESET pin, so we can't wake up from D3 */
+	/* Hence we dont move to D3 state when disconnect is done */
+
+	dst->src = NULL;
+	dssdev->dst = NULL;
+	in->ops.dpi->disconnect(in, &ddata->dssdev);
+}
+
+static int sil9022_enable(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct omap_dss_device *in = ddata->in;
+	int r;
+
+	if (!omapdss_device_is_connected(dssdev))
+		return -ENODEV;
+
+	if (omapdss_device_is_enabled(dssdev))
+		return 0;
+
+	in->ops.dpi->set_timings(in, &ddata->timings);
+	in->ops.dpi->set_data_lines(in, ddata->data_lines);
+
+	r = in->ops.dpi->enable(in);
+	if (r)
+		return r;
+
+	if (gpio_is_valid(ddata->reset_gpio))
+		gpio_set_value_cansleep(ddata->reset_gpio, 0);
+
+	r = sil9022_hw_enable(dssdev);
+	if (r)
+		goto err_hw_en;
+
+	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+	return 0;
+
+err_hw_en:
+		if (gpio_is_valid(ddata->reset_gpio))
+			gpio_set_value_cansleep(ddata->reset_gpio, 1);
+
+		in->ops.dpi->disable(in);
+		return r;
+}
+
+static void sil9022_disable(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct omap_dss_device *in = ddata->in;
+
+	if (!omapdss_device_is_enabled(dssdev))
+		return;
+
+	sil9022_hw_disable(dssdev);
+
+	if (gpio_is_valid(ddata->reset_gpio))
+		gpio_set_value_cansleep(ddata->reset_gpio, 1);
+
+	in->ops.dpi->disable(in);
+
+	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void sil9022_set_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct omap_dss_device *in = ddata->in;
+	struct omap_video_timings *sil9022_timings = timings;
+
+       /* update DPI specific timing info */
+	sil9022_timings->data_pclk_edge  = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+	sil9022_timings->de_level		  = OMAPDSS_SIG_ACTIVE_HIGH;
+	sil9022_timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
+	ddata->timings = *sil9022_timings;
+	dssdev->panel.timings = *sil9022_timings;
+
+	in->ops.dpi->set_timings(in, sil9022_timings);
+}
+
+static void sil9022_get_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	*timings = ddata->timings;
+}
+
+static int sil9022_check_timings(struct omap_dss_device *dssdev,
+		struct omap_video_timings *timings)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct omap_dss_device *in = ddata->in;
+	struct omap_video_timings *sil9022_timings = timings;
+
+	/* update DPI specific timing info */
+	sil9022_timings->data_pclk_edge  = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+	sil9022_timings->de_level		  = OMAPDSS_SIG_ACTIVE_HIGH;
+	sil9022_timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
+
+	return in->ops.dpi->check_timings(in, sil9022_timings);
+}
+
+static int sil9022_read_edid(struct omap_dss_device *dssdev,
+	       u8 *edid, int len)
+{
+
+	int r =  0;
+	unsigned int val = 0;
+	int retries = 0;
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+	struct i2c_client *client = ddata->i2c_client;
+	struct regmap *map = ddata->regmap;
+
+	len = (len < HDMI_EDID_MAX_LENGTH) ? len : HDMI_EDID_MAX_LENGTH;
+
+	/* Request DDC bus access to read EDID info */
+
+	/* Disable TMDS clock */
+
+	r = regmap_write(map, HDMI_SYS_CTRL_DATA_REG, 0x11);
+	if (r < 0) {
+		dev_err(&client->dev,
+			"ERROR: Failed to disable TMDS clock\n");
+		return r;
+	}
+
+	val = 0;
+
+	/* Read TPI system control register*/
+	r = regmap_read(map, HDMI_SYS_CTRL_DATA_REG, &val);
+	if (r < 0) {
+		dev_err(&client->dev,
+			"ERROR: Reading DDC BUS REQUEST\n");
+		return r;
+	}
+
+	/* The host writes 0x1A[2]=1 to request the
+	 * DDC(Display Data Channel) bus
+	 */
+	r = regmap_write(map, HDMI_SYS_CTRL_DATA_REG,
+				val | TPI_SYS_CTRL_DDC_BUS_REQUEST);
+	if (r < 0) {
+		dev_err(&client->dev,
+			"ERROR: Writing DDC BUS REQUEST\n");
+		return r;
+	}
+
+	/*  Poll for bus DDC Bus control to be granted */
+	val = 0;
+
+	/* Through trial and error, to get DDC BUS we need around 3 tries */
+	/* Hence keeping it rounded at 5 tries - a max of 4 retries allowed */
+	do {
+		r = regmap_read(map, HDMI_SYS_CTRL_DATA_REG, &val);
+		if (retries++ > 5) {
+			dev_err(&client->dev, "ERROR: Acquiring DDC Bus\n");
+			return r;
+		}
+	} while ((val & TPI_SYS_CTRL_DDC_BUS_GRANTED) == 0);
+
+	/*  Close the switch to the DDC */
+	r = regmap_write(map, HDMI_SYS_CTRL_DATA_REG,
+		val | TPI_SYS_CTRL_DDC_BUS_REQUEST |
+		TPI_SYS_CTRL_DDC_BUS_GRANTED);
+
+	if (r < 0) {
+		dev_err(&client->dev,
+			"<%s> ERROR: Close switch to DDC BUS REQUEST\n",
+			__func__);
+		return r;
+	}
+
+	r = sil9022_ddc_read(client, edid, len, 0);
+	if (r < 0) {
+		dev_err(&client->dev, "ERROR: Reading EDID\n");
+		return r;
+	}
+
+	/* Release DDC bus access */
+	val &= ~(TPI_SYS_CTRL_DDC_BUS_REQUEST | TPI_SYS_CTRL_DDC_BUS_GRANTED);
+
+	/*Through trial and error, seen that releasing BUS needed 3 tries */
+	/* Hence keeping it rounded at 5 tries - a max of 4 retries allowed */
+	retries = 0;
+	do {
+		r = regmap_write(map, HDMI_SYS_CTRL_DATA_REG, val);
+		if (r >= 0)
+			break;
+		retries++;
+	} while (retries < 5);
+	if (r < 0) {
+		dev_err(&client->dev, "ERROR: Releasing DDC Bus Access\n");
+		return r;
+		}
+	return 0;
+}
+
+static bool sil9022_detect(struct omap_dss_device *dssdev)
+{
+	/* Hot plug detection is not implemented */
+	/* Hence we assume monitor connected */
+	/* This will be fixed once HPD / polling is implemented */
+	return true;
+}
+
+static bool sil9022_audio_supported(struct omap_dss_device *dssdev)
+{
+	/* Audio configuration not present, hence returning false */
+	return false;
+}
+
+static const struct omapdss_hdmi_ops sil9022_hdmi_ops = {
+	.connect			= sil9022_connect,
+	.disconnect		= sil9022_disconnect,
+
+	.enable			= sil9022_enable,
+	.disable			= sil9022_disable,
+
+	.check_timings	= sil9022_check_timings,
+	.set_timings		= sil9022_set_timings,
+	.get_timings		= sil9022_get_timings,
+
+	.read_edid		= sil9022_read_edid,
+	.detect			= sil9022_detect,
+
+	.audio_supported	= sil9022_audio_supported,
+	/* Yet to implement audio ops */
+	/* For now audio_supported ops to return false */
+};
+
+
+static int sil9022_probe_of(struct i2c_client *client)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&client->dev);
+	struct device_node *node = client->dev.of_node;
+	struct device_node *src_node;
+	struct omap_dss_device *dssdev, *in;
+
+	int r, reset_gpio, datalines;
+
+	src_node = of_parse_phandle(node, "video-source", 0);
+	if (!src_node) {
+		dev_err(&client->dev, "failed to parse video source\n");
+		return -ENODEV;
+	}
+
+	in = omap_dss_find_output_by_node(src_node);
+	if (in == NULL) {
+		dev_err(&client->dev, "failed to find video source\n");
+		return -EPROBE_DEFER;
+	}
+	ddata->in = in;
+
+	reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
+
+	if (gpio_is_valid(reset_gpio) || reset_gpio == -ENOENT) {
+		ddata->reset_gpio = reset_gpio;
+	} else {
+		dev_err(&client->dev, "failed to parse lcdorhdmi gpio\n");
+		return reset_gpio;
+	}
+
+	r = of_property_read_u32(node, "data-lines", &datalines);
+	if (r) {
+		dev_err(&client->dev, "failed to parse datalines\n");
+		return r;
+	}
+
+	ddata->data_lines = datalines;
+	ddata->reset_gpio = reset_gpio;
+	dssdev = &ddata->dssdev;
+
+	return 0;
+
+}
+
+static int sil9022_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct panel_drv_data *ddata;
+	struct omap_dss_device *dssdev;
+	struct regmap *regmap;
+	int r = 0;
+
+	regmap = devm_regmap_init_i2c(client, &sil9022_regmap_config);
+	if (IS_ERR(regmap)) {
+		r = PTR_ERR(regmap);
+		dev_err(&client->dev, "Failed to init regmap: %d\n", r);
+		return r;
+	}
+
+	ddata = devm_kzalloc(&client->dev, sizeof(*ddata), GFP_KERNEL);
+	if (ddata == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(&client->dev, ddata);
+
+	if (client->dev.of_node) {
+		r = sil9022_probe_of(client);
+		if (r)
+			return r;
+	} else {
+		return -ENODEV;
+	}
+
+	if (gpio_is_valid(ddata->reset_gpio)) {
+		r = devm_gpio_request_one(&client->dev, ddata->reset_gpio,
+				GPIOF_OUT_INIT_HIGH, "Sil9022-Encoder");
+		if (r)
+			goto err_gpio;
+	}
+
+	ddata->regmap = regmap;
+	ddata->i2c_client = client;
+	dssdev = &ddata->dssdev;
+	dssdev->dev = &client->dev;
+	dssdev->ops.hdmi = &sil9022_hdmi_ops;
+	dssdev->type = OMAP_DISPLAY_TYPE_DPI;
+	dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
+	dssdev->owner = THIS_MODULE;
+	dssdev->phy.dpi.data_lines = ddata->data_lines;
+
+	/* Read sil9022 chip version */
+	r = sil9022_probe_chip_version(dssdev);
+	if (r) {
+		dev_err(&client->dev, "Failed to read CHIP VERSION\n");
+		goto err_i2c;
+	}
+
+	r = omapdss_register_output(dssdev);
+	if (r) {
+		dev_err(&client->dev, "Failed to register output\n");
+		goto err_reg;
+	}
+
+	return 0;
+
+err_reg:
+err_i2c:
+err_gpio:
+
+	omap_dss_put_device(ddata->in);
+	return r;
+}
+
+
+static int sil9022_remove(struct i2c_client *client)
+{
+	struct panel_drv_data *ddata = dev_get_drvdata(&client->dev);
+	struct omap_dss_device *dssdev = &ddata->dssdev;
+
+	omapdss_unregister_output(dssdev);
+
+	WARN_ON(omapdss_device_is_enabled(dssdev));
+	if (omapdss_device_is_enabled(dssdev))
+		sil9022_disable(dssdev);
+
+	WARN_ON(omapdss_device_is_connected(dssdev));
+	if (omapdss_device_is_connected(dssdev))
+		sil9022_disconnect(dssdev, dssdev->dst);
+
+	omap_dss_put_device(ddata->in);
+
+	return 0;
+}
+
+static const struct i2c_device_id sil9022_id[] = {
+	{ SIL9022_DRV_NAME, 0 },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, sil9022_id);
+
+static struct i2c_driver sil9022_driver = {
+	.driver = {
+		.name  = SIL9022_DRV_NAME,
+		.owner = THIS_MODULE,
+		},
+	.probe		= sil9022_probe,
+	.remove		= sil9022_remove,
+	.id_table	= sil9022_id,
+};
+
+module_i2c_driver(sil9022_driver);
+
+MODULE_AUTHOR("Sathya Prakash M R <sathyap@ti.com>");
+MODULE_DESCRIPTION("Sil9022 DPI to HDMI encoder Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays-new/encoder-sil9022.h b/drivers/video/omap2/displays-new/encoder-sil9022.h
new file mode 100644
index 0000000..2922662
--- /dev/null
+++ b/drivers/video/omap2/displays-new/encoder-sil9022.h
@@ -0,0 +1,105 @@
+/*
+ * drivers/video/omap2/displays-new/encoder-sil9022.c
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author : Sathya Prakash M R <sathyap@ti.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef _SI9022_H_
+#define _SI9022_H_
+
+#define SIL9022_DRV_NAME	"sii9022"
+
+#define SIL9022_REG_CHIPID0		0x1B
+#define SIL9022_CHIPID_902x		0xB0
+#define SIL9022_REG_TPI_RQB		0xC7
+
+
+#define HDMI_EDID_MAX_LENGTH	256
+
+#define VERTICAL_FREQ			0x3C /* 60 Hz */
+
+/* Sil9022 TPI mode Programming Register set  */
+#define HDMI_TPI_VIDEO_DATA_BASE_REG		0x00
+#define HDMI_TPI_PIXEL_REPETITION_REG		0x08
+#define HDMI_TPI_AVI_IN_FORMAT_REG			0x09
+#define HDMI_TPI_AVI_OUT_FORMAT_REG		0x0A
+#define HDMI_SYS_CTRL_DATA_REG			0x1A
+#define HDMI_TPI_POWER_STATE_CTRL_REG	0x1E
+#define HDMI_TPI_HDCP_QUERYDATA_REG		0x29
+#define HDMI_TPI_HDCP_CONTROLDATA_REG	0x2A
+
+
+/* Programming HDMI_SYS_CTRL_DATA_REG  power state and mode of operation*/
+#define TPI_SYS_CTRL_POWER_DOWN             (1 << 4)
+#define TPI_SYS_CTRL_POWER_ACTIVE           (0 << 4)
+
+#define TPI_SYS_CTRL_AV_MUTE                (1 << 3)
+
+#define TPI_SYS_CTRL_DDC_BUS_REQUEST        (1 << 2)
+#define TPI_SYS_CTRL_DDC_BUS_GRANTED        (1 << 1)
+
+#define TPI_SYS_CTRL_OUTPUT_MODE_HDMI       (1 << 0)
+#define TPI_SYS_CTRL_OUTPUT_MODE_DVI        (0 << 0)
+
+/* Programming HDMI_TPI_PIXEL_REPETITION_REG  - clock and pixel properties*/
+#define TPI_AVI_PIXEL_REP_BUS_24BIT         (1 << 5)
+#define TPI_AVI_PIXEL_REP_BUS_12BIT         (0 << 5)
+
+#define TPI_AVI_PIXEL_REP_RISING_EDGE       (1 << 4)
+#define TPI_AVI_PIXEL_REP_FALLING_EDGE      (0 << 4)
+
+#define TPI_AVI_PIXEL_REP_4X                (3 << 0)
+#define TPI_AVI_PIXEL_REP_2X                (1 << 0)
+#define TPI_AVI_PIXEL_REP_NONE              (0 << 0)
+
+#define TPI_CLK_RATIO_HALF		(0 << 6)
+#define TPI_CLK_RATIO_1X		(1 << 6)
+#define TPI_CLK_RATIO_2X		(2 << 6)
+#define TPI_CLK_RATIO_4X		(3 << 6)
+
+
+/* Programming HDMI_TPI_AVI_IN_FORMAT_REG - input properties*/
+#define TPI_AVI_INPUT_BITMODE_12BIT         (1 << 7)
+#define TPI_AVI_INPUT_BITMODE_8BIT          (0 << 7)
+
+#define TPI_AVI_INPUT_DITHER                (1 << 6)
+
+#define TPI_AVI_INPUT_RANGE_LIMITED         (2 << 2)
+#define TPI_AVI_INPUT_RANGE_FULL            (1 << 2)
+#define TPI_AVI_INPUT_RANGE_AUTO            (0 << 2)
+
+#define TPI_AVI_INPUT_COLORSPACE_BLACK      (3 << 0)
+#define TPI_AVI_INPUT_COLORSPACE_YUV422     (2 << 0)
+#define TPI_AVI_INPUT_COLORSPACE_YUV444     (1 << 0)
+#define TPI_AVI_INPUT_COLORSPACE_RGB        (0 << 0)
+
+
+/* Programming HDMI_TPI_AVI_OUT_FORMAT_REG  - output properties */
+#define TPI_AVI_OUTPUT_CONV_BT709           (1 << 4)
+#define TPI_AVI_OUTPUT_CONV_BT601           (0 << 4)
+
+#define TPI_AVI_OUTPUT_RANGE_LIMITED        (2 << 2)
+#define TPI_AVI_OUTPUT_RANGE_FULL           (1 << 2)
+#define TPI_AVI_OUTPUT_RANGE_AUTO           (0 << 2)
+
+#define TPI_AVI_OUTPUT_COLORSPACE_RGBDVI    (3 << 0)
+#define TPI_AVI_OUTPUT_COLORSPACE_YUV422    (2 << 0)
+#define TPI_AVI_OUTPUT_COLORSPACE_YUV444    (1 << 0)
+#define TPI_AVI_OUTPUT_COLORSPACE_RGBHDMI   (0 << 0)
+
+/* Programming HDMI_TPI_POWER_STATE_CTRL_REG  */
+#define TPI_AVI_POWER_STATE_D3			(3 << 0)
+#define TPI_AVI_POWER_STATE_D2			(2 << 0)
+#define TPI_AVI_POWER_STATE_D0			(0 << 0)
+
+/* Programming HDMI_TPI_HDCP_CONTROLDATA_REG */
+#define HDCP_DISABLE	0
+#define HDCP_ENABLE		1
+
+#endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] ARM: DTS: AM43x: Add sii9022 dt information
  2014-03-18 10:07 [RFC PATCH 0/2] Sil9022 DPI to HDMI Encoder Sathya Prakash M R
  2014-03-18 10:07 ` [PATCH 1/2] OMAPDSS: Add Sil9022 DPI-HDMI Encoder Driver Sathya Prakash M R
@ 2014-03-18 10:07 ` Sathya Prakash M R
  2014-03-18 10:31   ` Tomi Valkeinen
  2014-03-18 10:56 ` [RFC PATCH 0/2] Sil9022 DPI to HDMI Encoder Mark Rutland
  2 siblings, 1 reply; 8+ messages in thread
From: Sathya Prakash M R @ 2014-03-18 10:07 UTC (permalink / raw)
  To: tony, tomi.valkeinen, devicetree, linux-omap, pawel.moll, paul
  Cc: Sathya Prakash M R

AM43x-epos and AM437x-gp device use external sii9022
DPI to HDMI encoder.
Sii9022 use i2c for communication.
Sii9022 dt entries are added to corresponding dts.

Signed-off-by: Sathya prakash M R <sathyap@ti.com>
---
 arch/arm/boot/dts/am437x-gp-evm.dts  |   58 +++++++++++++++++++++++++++++++--
 arch/arm/boot/dts/am43x-epos-evm.dts |   59 ++++++++++++++++++++++++++++++++--
 2 files changed, 111 insertions(+), 6 deletions(-)

diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index a178e8d..c4225b1 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -51,6 +51,41 @@
 			remote-endpoint = <&dpi_out>;
 		};
 	};
+
+	sii9022: encoder@0 {
+		compatible = "sii,sii9022";
+		reset-gpio = <&gpio5 8 GPIO_ACTIVE_LOW>;/* 'SelLCDorHDMI' Gpio, LOW to select HDMI */
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+
+				sii9022_in: endpoint@0 {
+					remote-endpoint = <&dpi_out>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+
+				sii9022_out: endpoint@0 {
+					remote-endpoint = <&hdmi_connector_in>;
+				};
+			};
+		};
+	};
+
+	hdmi0: connector@0 {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+
+		hdmi_connector_in: endpoint {
+			remote-endpoint = <&sil9022_out>;
+		};
+	};
 };
 
 &am43xx_pinmux {
@@ -119,6 +154,9 @@
         status = "okay";
         pinctrl-names = "default";
         pinctrl-0 = <&i2c1_pins>;
+	&sii9022 {
+		reg = <0x3b>;
+	}
 };
 
 &epwmss0 {
@@ -141,8 +179,22 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&dss_pinctrl>;
 
-	dpi_out: endpoint@0 {
-		remote-endpoint = <&lcd_in>;
-		data-lines = <24>;
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+			dpi_out: endpoint@0 {
+				remote-endpoint = <&lcd_in>;
+				data-lines = <24>;
+			};
+
+			dpi_out:endpoint@1 {
+				remote-endpoint = <&sii9022_in>;
+				data-lines = <24>;
+
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 3f9643b..22bfa5e 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -29,6 +29,7 @@
 
 	aliases {
 		display0 = &lcd0;
+		display1 = &hdmi0;
 	};
 
 	lcd0: display {
@@ -54,6 +55,41 @@
 		};
 	};
 
+	sii9022: encoder@0 {
+		compatible = "sii,sii9022";
+		reset-gpio = <&gpio2 1 GPIO_ACTIVE_LOW>;/* 65'SelLCDorHDMI' Gpio, LOW to select HDMI */
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+
+				sii9022_in: endpoint@0 {
+					remote-endpoint = <&dpi_out>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+
+				sii9022_out: endpoint@0 {
+					remote-endpoint = <&hdmi_connector_in>;
+				};
+			};
+		};
+	};
+
+	hdmi0: connector@0 {
+		compatible = "hdmi-connector";
+		label = "hdmi";
+
+		hdmi_connector_in: endpoint {
+			remote-endpoint = <&sil9022_out>;
+		};
+	};
+
 	am43xx_pinmux: pinmux@44e10800 {
 		cpsw_default: cpsw_default {
 			pinctrl-single,pins = <
@@ -284,6 +320,9 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c2_pins>;
 	status = "okay";
+	&sii9022 {
+		reg = <0x3b>;
+	}
 };
 
 &gpio0 {
@@ -347,8 +386,22 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&dss_pinctrl>;
 
-	dpi_out: endpoint@0 {
-		remote-endpoint = <&lcd_in>;
-		data-lines = <24>;
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+			dpi_out: endpoint@0 {
+				remote-endpoint = <&lcd_in>;
+				data-lines = <24>;
+			};
+
+			dpi_out:endpoint@1 {
+				remote-endpoint = <&sii9022_in>;
+				data-lines = <24>;
+
+			};
+		};
 	};
 };
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] ARM: DTS: AM43x: Add sii9022 dt information
  2014-03-18 10:07 ` [PATCH 2/2] ARM: DTS: AM43x: Add sii9022 dt information Sathya Prakash M R
@ 2014-03-18 10:31   ` Tomi Valkeinen
  2014-03-18 10:57     ` Sathya Prakash
  0 siblings, 1 reply; 8+ messages in thread
From: Tomi Valkeinen @ 2014-03-18 10:31 UTC (permalink / raw)
  To: Sathya Prakash M R; +Cc: tony, devicetree, linux-omap, pawel.moll, paul

[-- Attachment #1: Type: text/plain, Size: 2580 bytes --]

On 18/03/14 12:07, Sathya Prakash M R wrote:
> AM43x-epos and AM437x-gp device use external sii9022
> DPI to HDMI encoder.
> Sii9022 use i2c for communication.
> Sii9022 dt entries are added to corresponding dts.
> 
> Signed-off-by: Sathya prakash M R <sathyap@ti.com>
> ---
>  arch/arm/boot/dts/am437x-gp-evm.dts  |   58 +++++++++++++++++++++++++++++++--
>  arch/arm/boot/dts/am43x-epos-evm.dts |   59 ++++++++++++++++++++++++++++++++--
>  2 files changed, 111 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
> index a178e8d..c4225b1 100644
> --- a/arch/arm/boot/dts/am437x-gp-evm.dts
> +++ b/arch/arm/boot/dts/am437x-gp-evm.dts
> @@ -51,6 +51,41 @@
>  			remote-endpoint = <&dpi_out>;
>  		};
>  	};
> +
> +	sii9022: encoder@0 {
> +		compatible = "sii,sii9022";

See Documentation/devicetree/bindings/vendor-prefixes.txt

The vendor prefix is "sil".

> +		reset-gpio = <&gpio5 8 GPIO_ACTIVE_LOW>;/* 'SelLCDorHDMI' Gpio, LOW to select HDMI */
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			port@0 {
> +				reg = <0>;
> +
> +				sii9022_in: endpoint@0 {
> +					remote-endpoint = <&dpi_out>;
> +				};
> +			};
> +
> +			port@1 {
> +				reg = <1>;
> +
> +				sii9022_out: endpoint@0 {
> +					remote-endpoint = <&hdmi_connector_in>;
> +				};
> +			};
> +		};
> +	};
> +
> +	hdmi0: connector@0 {
> +		compatible = "hdmi-connector";
> +		label = "hdmi";
> +
> +		hdmi_connector_in: endpoint {
> +			remote-endpoint = <&sil9022_out>;
> +		};
> +	};
>  };
>  
>  &am43xx_pinmux {
> @@ -119,6 +154,9 @@
>          status = "okay";
>          pinctrl-names = "default";
>          pinctrl-0 = <&i2c1_pins>;
> +	&sii9022 {
> +		reg = <0x3b>;
> +	}

This looks very very odd... The whole sii9022 node should be here.

>  };
>  
>  &epwmss0 {
> @@ -141,8 +179,22 @@
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&dss_pinctrl>;
>  
> -	dpi_out: endpoint@0 {
> -		remote-endpoint = <&lcd_in>;
> -		data-lines = <24>;
> +	ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		port@0 {
> +			reg = <0>;
> +			dpi_out: endpoint@0 {
> +				remote-endpoint = <&lcd_in>;
> +				data-lines = <24>;
> +			};
> +
> +			dpi_out:endpoint@1 {
> +				remote-endpoint = <&sii9022_in>;
> +				data-lines = <24>;
> +
> +			};

You add the same label, "dpi_out" to both endpoints. Does this even compile?

As there's just one port, you can leave out the 'ports' node.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH 0/2] Sil9022 DPI to HDMI Encoder
  2014-03-18 10:07 [RFC PATCH 0/2] Sil9022 DPI to HDMI Encoder Sathya Prakash M R
  2014-03-18 10:07 ` [PATCH 1/2] OMAPDSS: Add Sil9022 DPI-HDMI Encoder Driver Sathya Prakash M R
  2014-03-18 10:07 ` [PATCH 2/2] ARM: DTS: AM43x: Add sii9022 dt information Sathya Prakash M R
@ 2014-03-18 10:56 ` Mark Rutland
  2 siblings, 0 replies; 8+ messages in thread
From: Mark Rutland @ 2014-03-18 10:56 UTC (permalink / raw)
  To: Sathya Prakash M R
  Cc: tony@atomide.com, tomi.valkeinen@ti.com,
	devicetree@vger.kernel.org, linux-omap@vger.kernel.org,
	Pawel Moll, paul@pwsan.com

On Tue, Mar 18, 2014 at 10:07:55AM +0000, Sathya Prakash M R wrote:
> This patch series adds the Silicon Image Sil9022 driver.
> 
> Sil9022 is HDMI Transmitter compliant to HDMI 1.2a and DVI 1.0.
> It supports 1080p and UXGA. It has single slave I2C from Host,
> passing through to master I2C interface for DDC Connection.
> It provides Transmitter Programming Interface (TPI) for simplified API programming.
> Product brief:
> http://www.semiconductorstore.com/pdf/newsite/siliconimage/SiI9022a_pb.pdf
> 
> Current driver is tested on AM43x SOC.
> 
> This series is on top of series posted to add DSS support on AM43x [2]
> [2] https://patchwork.kernel.org/patch/3822691/
> 
> This is initial driver supporting limited features.
> 
> TODO ->
> Audio Support
> Detailed Hot Plug event handling and also routing the hot plug event to host processor
> 
> These features will be added in future.
> 
> Sathya Prakash M R (2):
>   OMAPDSS: Add Sil9022 DPI-HDMI Encoder Driver
>   ARM: DTS: AM43x: Add sii9022 dt information
> 
>  arch/arm/boot/dts/am437x-gp-evm.dts                |   58 +-
>  arch/arm/boot/dts/am43x-epos-evm.dts               |   59 +-
>  drivers/video/omap2/displays-new/Kconfig           |    8 +
>  drivers/video/omap2/displays-new/Makefile          |    1 +
>  drivers/video/omap2/displays-new/encoder-sil9022.c |  748 ++++++++++++++++++++
>  drivers/video/omap2/displays-new/encoder-sil9022.h |  105 +++
>  6 files changed, 973 insertions(+), 6 deletions(-)
>  create mode 100644 drivers/video/omap2/displays-new/encoder-sil9022.c
>  create mode 100644 drivers/video/omap2/displays-new/encoder-sil9022.h

Is there already a binding document?

If not, please add one.

Cheers,
Mark.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] ARM: DTS: AM43x: Add sii9022 dt information
  2014-03-18 10:31   ` Tomi Valkeinen
@ 2014-03-18 10:57     ` Sathya Prakash
  2014-03-18 11:03       ` Tomi Valkeinen
  0 siblings, 1 reply; 8+ messages in thread
From: Sathya Prakash @ 2014-03-18 10:57 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: Sathya Prakash M R, tony, devicetree, linux-omap, pawel.moll,
	paul

On Tuesday 18 March 2014 04:01 PM, Tomi Valkeinen wrote:
> On 18/03/14 12:07, Sathya Prakash M R wrote:
>> AM43x-epos and AM437x-gp device use external sii9022
>> DPI to HDMI encoder.
>> Sii9022 use i2c for communication.
>> Sii9022 dt entries are added to corresponding dts.
>>
>> Signed-off-by: Sathya prakash M R <sathyap@ti.com>
>> ---
>>   arch/arm/boot/dts/am437x-gp-evm.dts  |   58 +++++++++++++++++++++++++++++++--
>>   arch/arm/boot/dts/am43x-epos-evm.dts |   59 ++++++++++++++++++++++++++++++++--
>>   2 files changed, 111 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
>> index a178e8d..c4225b1 100644
>> --- a/arch/arm/boot/dts/am437x-gp-evm.dts
>> +++ b/arch/arm/boot/dts/am437x-gp-evm.dts
>> @@ -51,6 +51,41 @@
>>   			remote-endpoint = <&dpi_out>;
>>   		};
>>   	};
>> +
>> +	sii9022: encoder@0 {
>> +		compatible = "sii,sii9022";
> See Documentation/devicetree/bindings/vendor-prefixes.txt
>
> The vendor prefix is "sil".
My bad. that was typo.
>
>> +		reset-gpio = <&gpio5 8 GPIO_ACTIVE_LOW>;/* 'SelLCDorHDMI' Gpio, LOW to select HDMI */
>> +
>> +		ports {
>> +			#address-cells = <1>;
>> +			#size-cells = <0>;
>> +
>> +			port@0 {
>> +				reg = <0>;
>> +
>> +				sii9022_in: endpoint@0 {
>> +					remote-endpoint = <&dpi_out>;
>> +				};
>> +			};
>> +
>> +			port@1 {
>> +				reg = <1>;
>> +
>> +				sii9022_out: endpoint@0 {
>> +					remote-endpoint = <&hdmi_connector_in>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	hdmi0: connector@0 {
>> +		compatible = "hdmi-connector";
>> +		label = "hdmi";
>> +
>> +		hdmi_connector_in: endpoint {
>> +			remote-endpoint = <&sil9022_out>;
>> +		};
>> +	};
>>   };
>>   
>>   &am43xx_pinmux {
>> @@ -119,6 +154,9 @@
>>           status = "okay";
>>           pinctrl-names = "default";
>>           pinctrl-0 = <&i2c1_pins>;
>> +	&sii9022 {
>> +		reg = <0x3b>;
>> +	}
> This looks very very odd... The whole sii9022 node should be here.
ok. i was also bit confused with this placement.

>
>>   };
>>   
>>   &epwmss0 {
>> @@ -141,8 +179,22 @@
>>   	pinctrl-names = "default";
>>   	pinctrl-0 = <&dss_pinctrl>;
>>   
>> -	dpi_out: endpoint@0 {
>> -		remote-endpoint = <&lcd_in>;
>> -		data-lines = <24>;
>> +	ports {
>> +		#address-cells = <1>;
>> +		#size-cells = <0>;
>> +
>> +		port@0 {
>> +			reg = <0>;
>> +			dpi_out: endpoint@0 {
>> +				remote-endpoint = <&lcd_in>;
>> +				data-lines = <24>;
>> +			};
>> +
>> +			dpi_out:endpoint@1 {
>> +				remote-endpoint = <&sii9022_in>;
>> +				data-lines = <24>;
>> +
>> +			};
> You add the same label, "dpi_out" to both endpoints. Does this even compile?
>
> As there's just one port, you can leave out the 'ports' node.
Will check. the ports was added as per documentation in video-interfaces.txt
Can you suggest how to add the 2 dpi_out endpoints?
Thanks

>
>   Tomi
>
Sathya


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] ARM: DTS: AM43x: Add sii9022 dt information
  2014-03-18 10:57     ` Sathya Prakash
@ 2014-03-18 11:03       ` Tomi Valkeinen
  0 siblings, 0 replies; 8+ messages in thread
From: Tomi Valkeinen @ 2014-03-18 11:03 UTC (permalink / raw)
  To: Sathya Prakash
  Cc: Sathya Prakash M R, tony, devicetree, linux-omap, pawel.moll,
	paul

[-- Attachment #1: Type: text/plain, Size: 897 bytes --]

On 18/03/14 12:57, Sathya Prakash wrote:

>> You add the same label, "dpi_out" to both endpoints. Does this even
>> compile?
>>
>> As there's just one port, you can leave out the 'ports' node.
> Will check. the ports was added as per documentation in
> video-interfaces.txt

It mentions that the 'ports' is optional.

> Can you suggest how to add the 2 dpi_out endpoints?

Didn't try, but:

port {
	#address-cells = <1>;
	#size-cells = <0>;

	dpi_lcd_out: endpoint@0 {
		reg = <0>;
		remote-endpoint = <&lcd_in>;
		data-lines = <24>;
	};

	dpi_sii_out: endpoint@1 {
		reg = <1>;
		remote-endpoint = <&sii9022_in>;
		data-lines = <24>;
	};
};

However, we still need to handle the GPIO which is used to select the
LCD or HDMI. So, maybe the above works, but we should try the
encoder-gpio-switch to handle the GPIO, which we discussed about earlier.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] OMAPDSS: Add Sil9022 DPI-HDMI Encoder Driver
  2014-03-18 10:07 ` [PATCH 1/2] OMAPDSS: Add Sil9022 DPI-HDMI Encoder Driver Sathya Prakash M R
@ 2014-03-18 11:20   ` Tomi Valkeinen
  0 siblings, 0 replies; 8+ messages in thread
From: Tomi Valkeinen @ 2014-03-18 11:20 UTC (permalink / raw)
  To: Sathya Prakash M R; +Cc: tony, devicetree, linux-omap, pawel.moll, paul

[-- Attachment #1: Type: text/plain, Size: 22398 bytes --]

Hi Sathya,

On 18/03/14 12:07, Sathya Prakash M R wrote:
> Sil9022 DPI to HDMI Encoder driver is part of
> AM43xx SOC. Adding the basic Sil9022 driver

Umm it's not part of AM43xx SoC...

> HPD and Audio support is not present yet.
> 
> Signed-off-by: Sathya Prakash M R <sathyap@ti.com>
> ---
>  drivers/video/omap2/displays-new/Kconfig           |    8 +
>  drivers/video/omap2/displays-new/Makefile          |    1 +
>  drivers/video/omap2/displays-new/encoder-sil9022.c |  748 ++++++++++++++++++++
>  drivers/video/omap2/displays-new/encoder-sil9022.h |  105 +++
>  4 files changed, 862 insertions(+)
>  create mode 100644 drivers/video/omap2/displays-new/encoder-sil9022.c
>  create mode 100644 drivers/video/omap2/displays-new/encoder-sil9022.h
> 
> diff --git a/drivers/video/omap2/displays-new/Kconfig b/drivers/video/omap2/displays-new/Kconfig
> index e6cfc38..9243dd7 100644
> --- a/drivers/video/omap2/displays-new/Kconfig
> +++ b/drivers/video/omap2/displays-new/Kconfig
> @@ -12,6 +12,14 @@ config DISPLAY_ENCODER_TPD12S015
>  	  Driver for TPD12S015, which offers HDMI ESD protection and level
>  	  shifting.
>  
> +config DISPLAY_ENCODER_SIL9022
> +        tristate "Sil9022 DPI to HDMI Encoder"

Use a tab there.

> +	depends on I2C
> +	help
> +	  Driver for Silicon Image Sil9022 DPI to HDMI encoder and
> +	  a brief about Sil9022 can be found here:
> +	  http://www.semiconductorstore.com/pdf/newsite/siliconimage/SiI9022a_pb.pdf
> +
>  config DISPLAY_CONNECTOR_DVI
>          tristate "DVI Connector"
>  	depends on I2C
> diff --git a/drivers/video/omap2/displays-new/Makefile b/drivers/video/omap2/displays-new/Makefile
> index 0323a8a..f3c8997 100644
> --- a/drivers/video/omap2/displays-new/Makefile
> +++ b/drivers/video/omap2/displays-new/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
>  obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
> +obj-$(CONFIG_DISPLAY_ENCODER_SIL9022) += encoder-sil9022.o
>  obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
>  obj-$(CONFIG_DISPLAY_CONNECTOR_HDMI) += connector-hdmi.o
>  obj-$(CONFIG_DISPLAY_CONNECTOR_ANALOG_TV) += connector-analog-tv.o
> diff --git a/drivers/video/omap2/displays-new/encoder-sil9022.c b/drivers/video/omap2/displays-new/encoder-sil9022.c
> new file mode 100644
> index 0000000..411867b
> --- /dev/null
> +++ b/drivers/video/omap2/displays-new/encoder-sil9022.c
> @@ -0,0 +1,748 @@
> +/*
> + * Silicon image Sil9022 DPI-to-HDMI encoder driver

The chip is SiI9022, not Sil, according to the specs from Silicon Image.
I'm not sure what would be the best naming all around, but at least in
the comments and Kconfig help texts it would be best to use the correct
names to help finding the chip with google.

> + *
> + * Copyright (C) 2013 Texas Instruments
> + * Author: Sathya Prakash M R <sathyap@ti.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/types.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/i2c.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/gpio.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/of_gpio.h>
> +
> +#include <video/omapdss.h>
> +#include <video/omap-panel-data.h>
> +#include "encoder-sil9022.h"

You should quickly go though the includes, and remove unneeded ones.
There are no platform devices here, nor is video/omap-panel-data.h needed.

> +struct panel_drv_data {
> +	struct omap_dss_device dssdev;
> +	struct omap_dss_device *in;
> +	struct i2c_client *i2c_client;
> +	int reset_gpio;
> +	int data_lines;
> +	struct regmap *regmap;
> +	struct omap_video_timings timings;
> +};
> +
> +static struct regmap_config sil9022_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +};

Can this be const?

> +
> +
> +#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
> +
> +static int sil9022_ddc_read(struct i2c_client *client,
> +		unsigned char *buf, u16 count, u8 offset)
> +{
> +	int r, retries;
> +
> +	for (retries = 3; retries > 0; retries--) {
> +		struct i2c_msg msgs[] = {
> +			{
> +				.addr   = 0x50,
> +				.flags  = 0,
> +				.len    = 1,
> +				.buf    = &offset,
> +			}, {
> +				.addr   = 0x50,
> +				.flags  = I2C_M_RD,
> +				.len    = count,
> +				.buf    = buf,
> +			}
> +		};
> +
> +		r = i2c_transfer(client->adapter, msgs, 2);
> +		if (r == 2)
> +			return 0;
> +
> +		if (r != -EAGAIN)
> +			break;
> +	}
> +
> +	return r < 0 ? r : -EIO;
> +}
> +
> +static int sil9022_hw_enable(struct omap_dss_device *dssdev)
> +{
> +	int		r = 0;
> +	u8		vals[8];
> +	unsigned int val;
> +	u16		xres;
> +	u16		yres;
> +	u16		pclk;
> +
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct omap_video_timings *hdmi_timings = &ddata->timings;
> +	struct i2c_client *sil9022_client = ddata->i2c_client;
> +	struct regmap *map = ddata->regmap;

Use a consistent style. If you align variable names like you do for
xres, yes, etc., use it for everything. I think personally it's cleaner
to not align them.

> +
> +	xres = hdmi_timings->x_res;
> +	yres = hdmi_timings->y_res;
> +	pclk = hdmi_timings->pixel_clock;
> +
> +	dev_info(dssdev->dev,

In the minimum change the dev_info()s to dev_dbg(). Even better, have a
bit thought and see if they are needed at all or were they only useful
for early device bring-up.

> +			 "sii9022_ENABLE -> Timings\n"
> +			 "pixel_clk			= %d\n"
> +			 "horizontal res		= %d\n"
> +			 "vertical res			= %d\n",
> +			 pclk, xres, yres);
> +
> +	/*  Fill the TPI Video Mode Data structure */
> +	vals[0] = (pclk & 0xFF);                  /* Pixel clock */
> +	vals[1] = ((pclk & 0xFF00) >> 8);
> +	vals[2] = VERTICAL_FREQ;                    /* Vertical freq */
> +	/* register programming information on how vertical freq is to be
> +	programmed to Sil9022 not clear. Hence setting to 60 for now */

Use the comment formatting according to kernel's coding style.

> +	vals[3] = 0x00;
> +	vals[4] = (xres & 0xFF);         /* Horizontal pixels*/
> +	vals[5] = ((xres & 0xFF00) >> 8);
> +	vals[6] = (yres & 0xFF);           /* Vertical pixels */
> +	vals[7] = ((yres & 0xFF00) >> 8);
> +
> +	/*  Write out the TPI Video Mode Data */
> +	r = regmap_raw_write(map, HDMI_TPI_VIDEO_DATA_BASE_REG, vals, 8);
> +
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR: writing TPI video mode data\n");
> +		return r;
> +	}
> +
> +	/* Write out the TPI Input bus and pixel repetition Data:
> +	(24 bit wide bus, falling edge, no pixel replication, 1:1 CLK ratio) */
> +	r = regmap_write(map,
> +			HDMI_TPI_PIXEL_REPETITION_REG,
> +			TPI_AVI_PIXEL_REP_BUS_24BIT |
> +			TPI_AVI_PIXEL_REP_FALLING_EDGE |
> +			TPI_AVI_PIXEL_REP_NONE |
> +			TPI_CLK_RATIO_1X);
> +
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR: writing TPI pixel repetition data\n");
> +		return r;
> +	}
> +
> +	 /*  Write out the TPI AVI Input Format */
> +	r = regmap_write(map,
> +			HDMI_TPI_AVI_IN_FORMAT_REG,
> +			TPI_AVI_INPUT_BITMODE_8BIT |
> +			TPI_AVI_INPUT_RANGE_AUTO |
> +			TPI_AVI_INPUT_COLORSPACE_RGB);
> +
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR: writing TPI AVI Input format\n");
> +		return r;
> +	}
> +
> +	/*  Write out the TPI AVI Output Format */
> +	r = regmap_write(map,
> +			HDMI_TPI_AVI_OUT_FORMAT_REG,
> +			TPI_AVI_OUTPUT_CONV_BT709 |
> +			TPI_AVI_OUTPUT_RANGE_AUTO |
> +			TPI_AVI_OUTPUT_COLORSPACE_RGBHDMI);
> +
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR: writing TPI AVI output format\n");
> +		return r;
> +	}
> +
> +	/* Write out the TPI System Control Data to power down */
> +	r = regmap_write(map,
> +			HDMI_SYS_CTRL_DATA_REG,
> +			TPI_SYS_CTRL_POWER_DOWN);
> +
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR: writing TPI power down control data\n");
> +		return r;
> +	}
> +
> +	/* Move from ENABLED -> FULLY ENABLED Power State  */
> +	r = regmap_write(map,
> +			HDMI_TPI_POWER_STATE_CTRL_REG,
> +			TPI_AVI_POWER_STATE_D0);
> +
> +	if (r < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Setting device power state to D0\n",
> +			__func__);

No need to print __func__. dyndbg will allow the user to either print or
not print the function name.

You could store &sil9022_client->dev to variable 'dev', reducing the
code quite a bit. And if you change the texts a bit, maybe many of them
even fit into one line (say, "ERROR: Setting device power state to D0"
-> "Failed to set power state to D0").

> +		return r;
> +	}
> +
> +	/* Write out the TPI System Control Data to power up and
> +	 * select output mode
> +	 */
> +
> +	r = regmap_write(map,
> +			HDMI_SYS_CTRL_DATA_REG,
> +			TPI_SYS_CTRL_POWER_ACTIVE |
> +			TPI_SYS_CTRL_OUTPUT_MODE_HDMI);
> +
> +	if (r < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Writing system control data\n", __func__);
> +		return r;
> +	}
> +
> +	/*  Read back TPI System Control Data to latch settings */
> +	r = regmap_read(map, HDMI_SYS_CTRL_DATA_REG, &val);
> +
> +	if (r < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Reading back system control data\n",
> +			__func__);
> +		return r;
> +	}
> +
> +	/* HDCP */
> +	r = regmap_write(map,
> +				HDMI_TPI_HDCP_CONTROLDATA_REG,
> +				HDCP_DISABLE);
> +
> +	if (r < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Writing HDCP information",
> +			__func__);
> +		return r;
> +	}
> +
> +	dev_info(&sil9022_client->dev,
> +		"<%s> hdmi over sil9022 is now enabled\n", __func__);
> +	return 0;
> +
> +}
> +
> +static int sil9022_hw_disable(struct omap_dss_device *dssdev)
> +{
> +	unsigned int val = 0;
> +	int r = 0;
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct regmap *map = ddata->regmap;
> +
> +	/*  Write out the TPI System Control Data to power down  */
> +	r = regmap_write(map,
> +			HDMI_SYS_CTRL_DATA_REG,
> +			TPI_SYS_CTRL_POWER_DOWN);
> +
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR: writing control data - power down\n");
> +		return r;
> +	}
> +
> +	/*  Move from FULLY ENABLED -> ENABLED Power state */
> +	r = regmap_write(map,
> +			HDMI_TPI_POWER_STATE_CTRL_REG,
> +			TPI_AVI_POWER_STATE_D2);
> +
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR: Setting device power state to D2\n");
> +		return r;
> +	}
> +
> +	/*  Read back TPI System Control Data to latch settings */
> +	r = regmap_read(map, HDMI_SYS_CTRL_DATA_REG, &val);
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR:  Reading System control data "
> +			"- latch settings\n");
> +		return r;
> +	}
> +
> +	dev_info(dssdev->dev, "hdmi disabled\n");
> +	return 0;
> +
> +}
> +
> +static int sil9022_probe_chip_version(struct omap_dss_device *dssdev)
> +{
> +	int r = 0;

Here, and also elsewhere in this driver, assigning initial 0 to the
return value is not needed.

> +	unsigned int ver;
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct regmap *map = ddata->regmap;
> +
> +	/* probe for sil9022 chip version*/
> +	r = regmap_write(map, SIL9022_REG_TPI_RQB, 0x00);
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR: Writing HDMI configuration to "
> +			"reg - SI9022_REG_TPI_RQB\n");
> +		return r;
> +	}
> +
> +	r = regmap_read(map, SIL9022_REG_CHIPID0, &ver);
> +	if (r < 0) {
> +		dev_err(dssdev->dev,
> +			"ERROR: Reading HDMI version Id\n");
> +	} else if (ver != SIL9022_CHIPID_902x) {
> +		dev_err(dssdev->dev,
> +			"Not a valid verId: 0x%x\n", ver);
> +	} else {
> +		dev_info(dssdev->dev,
> +			 "sil9022 HDMI Chip version = %x\n", ver);
> +	}
> +	return r;
> +}
> +
> +/* Hdmi ops */
> +
> +static int sil9022_connect(struct omap_dss_device *dssdev,
> +		struct omap_dss_device *dst)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct omap_dss_device *in = ddata->in;
> +	struct regmap *map = ddata->regmap;
> +	int r = 0;
> +
> +	if (omapdss_device_is_connected(dssdev))
> +		return -EBUSY;
> +
> +	r = in->ops.dpi->connect(in, dssdev);
> +	if (r)
> +		return r;
> +
> +	dst->src = dssdev;
> +	dssdev->dst = dst;
> +
> +	/* Move from LOW -> ENABLED Power state */
> +	r = regmap_write(map, HDMI_TPI_POWER_STATE_CTRL_REG,
> +			TPI_AVI_POWER_STATE_D2);
> +	if (r < 0) {
> +		dev_err(dssdev->dev, "ERROR: Setting device power state to D2\n");
> +		goto err_pwr;
> +	}
> +
> +	return 0;
> +err_pwr:
> +		dst->src = NULL;
> +		dssdev->dst = NULL;
> +		in->ops.dpi->disconnect(in, dssdev);
> +		return r;
> +
> +}
> +
> +static void sil9022_disconnect(struct omap_dss_device *dssdev,
> +		struct omap_dss_device *dst)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct omap_dss_device *in = ddata->in;
> +
> +	WARN_ON(!omapdss_device_is_connected(dssdev));
> +	if (!omapdss_device_is_connected(dssdev))
> +		return;
> +
> +	WARN_ON(dst != dssdev->dst);
> +	if (dst != dssdev->dst)
> +		return;
> +
> +	/* we don't control the RESET pin, so we can't wake up from D3 */
> +	/* Hence we dont move to D3 state when disconnect is done */

So, this hacky reset handling, which wasn't switching reset but a GPIO
to switch HDMI/LCD, was ok for testing purposes, but we need to clean
this up before this can be merged to mainline.

The driver should be made to handle the reset gpio properly. However,
having the reset gpio should be optional for cases where the reset pin
is not controllable (like it is on the current AM4 boards). So the
driver should get the reset gpio from th DT, but if it's missing, then
act as it can't be controlled.

> +
> +	dst->src = NULL;
> +	dssdev->dst = NULL;
> +	in->ops.dpi->disconnect(in, &ddata->dssdev);
> +}
> +
> +static int sil9022_enable(struct omap_dss_device *dssdev)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct omap_dss_device *in = ddata->in;
> +	int r;
> +
> +	if (!omapdss_device_is_connected(dssdev))
> +		return -ENODEV;
> +
> +	if (omapdss_device_is_enabled(dssdev))
> +		return 0;
> +
> +	in->ops.dpi->set_timings(in, &ddata->timings);
> +	in->ops.dpi->set_data_lines(in, ddata->data_lines);
> +
> +	r = in->ops.dpi->enable(in);
> +	if (r)
> +		return r;
> +
> +	if (gpio_is_valid(ddata->reset_gpio))
> +		gpio_set_value_cansleep(ddata->reset_gpio, 0);
> +
> +	r = sil9022_hw_enable(dssdev);
> +	if (r)
> +		goto err_hw_en;
> +
> +	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
> +
> +	return 0;
> +
> +err_hw_en:
> +		if (gpio_is_valid(ddata->reset_gpio))
> +			gpio_set_value_cansleep(ddata->reset_gpio, 1);
> +
> +		in->ops.dpi->disable(in);
> +		return r;

Indentation is wrong here.

> +}
> +
> +static void sil9022_disable(struct omap_dss_device *dssdev)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct omap_dss_device *in = ddata->in;
> +
> +	if (!omapdss_device_is_enabled(dssdev))
> +		return;
> +
> +	sil9022_hw_disable(dssdev);
> +
> +	if (gpio_is_valid(ddata->reset_gpio))
> +		gpio_set_value_cansleep(ddata->reset_gpio, 1);
> +
> +	in->ops.dpi->disable(in);
> +
> +	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
> +}
> +
> +static void sil9022_set_timings(struct omap_dss_device *dssdev,
> +		struct omap_video_timings *timings)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct omap_dss_device *in = ddata->in;
> +	struct omap_video_timings *sil9022_timings = timings;
> +
> +       /* update DPI specific timing info */
> +	sil9022_timings->data_pclk_edge  = OMAPDSS_DRIVE_SIG_RISING_EDGE;
> +	sil9022_timings->de_level		  = OMAPDSS_SIG_ACTIVE_HIGH;

Extra spaces/tabs.

> +	sil9022_timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
> +	ddata->timings = *sil9022_timings;
> +	dssdev->panel.timings = *sil9022_timings;
> +
> +	in->ops.dpi->set_timings(in, sil9022_timings);
> +}
> +
> +static void sil9022_get_timings(struct omap_dss_device *dssdev,
> +		struct omap_video_timings *timings)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	*timings = ddata->timings;
> +}
> +
> +static int sil9022_check_timings(struct omap_dss_device *dssdev,
> +		struct omap_video_timings *timings)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct omap_dss_device *in = ddata->in;
> +	struct omap_video_timings *sil9022_timings = timings;
> +
> +	/* update DPI specific timing info */
> +	sil9022_timings->data_pclk_edge  = OMAPDSS_DRIVE_SIG_RISING_EDGE;
> +	sil9022_timings->de_level		  = OMAPDSS_SIG_ACTIVE_HIGH;

And here.

> +	sil9022_timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
> +
> +	return in->ops.dpi->check_timings(in, sil9022_timings);
> +}
> +
> +static int sil9022_read_edid(struct omap_dss_device *dssdev,
> +	       u8 *edid, int len)
> +{
> +
> +	int r =  0;
> +	unsigned int val = 0;
> +	int retries = 0;
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +	struct i2c_client *client = ddata->i2c_client;
> +	struct regmap *map = ddata->regmap;
> +
> +	len = (len < HDMI_EDID_MAX_LENGTH) ? len : HDMI_EDID_MAX_LENGTH;
> +
> +	/* Request DDC bus access to read EDID info */
> +
> +	/* Disable TMDS clock */
> +
> +	r = regmap_write(map, HDMI_SYS_CTRL_DATA_REG, 0x11);
> +	if (r < 0) {
> +		dev_err(&client->dev,
> +			"ERROR: Failed to disable TMDS clock\n");
> +		return r;
> +	}
> +
> +	val = 0;
> +
> +	/* Read TPI system control register*/
> +	r = regmap_read(map, HDMI_SYS_CTRL_DATA_REG, &val);
> +	if (r < 0) {
> +		dev_err(&client->dev,
> +			"ERROR: Reading DDC BUS REQUEST\n");
> +		return r;
> +	}
> +
> +	/* The host writes 0x1A[2]=1 to request the
> +	 * DDC(Display Data Channel) bus
> +	 */
> +	r = regmap_write(map, HDMI_SYS_CTRL_DATA_REG,
> +				val | TPI_SYS_CTRL_DDC_BUS_REQUEST);
> +	if (r < 0) {
> +		dev_err(&client->dev,
> +			"ERROR: Writing DDC BUS REQUEST\n");
> +		return r;
> +	}
> +
> +	/*  Poll for bus DDC Bus control to be granted */
> +	val = 0;
> +
> +	/* Through trial and error, to get DDC BUS we need around 3 tries */
> +	/* Hence keeping it rounded at 5 tries - a max of 4 retries allowed */
> +	do {
> +		r = regmap_read(map, HDMI_SYS_CTRL_DATA_REG, &val);
> +		if (retries++ > 5) {
> +			dev_err(&client->dev, "ERROR: Acquiring DDC Bus\n");
> +			return r;
> +		}
> +	} while ((val & TPI_SYS_CTRL_DDC_BUS_GRANTED) == 0);
> +
> +	/*  Close the switch to the DDC */
> +	r = regmap_write(map, HDMI_SYS_CTRL_DATA_REG,
> +		val | TPI_SYS_CTRL_DDC_BUS_REQUEST |
> +		TPI_SYS_CTRL_DDC_BUS_GRANTED);
> +
> +	if (r < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Close switch to DDC BUS REQUEST\n",
> +			__func__);
> +		return r;
> +	}
> +
> +	r = sil9022_ddc_read(client, edid, len, 0);
> +	if (r < 0) {
> +		dev_err(&client->dev, "ERROR: Reading EDID\n");
> +		return r;
> +	}
> +
> +	/* Release DDC bus access */
> +	val &= ~(TPI_SYS_CTRL_DDC_BUS_REQUEST | TPI_SYS_CTRL_DDC_BUS_GRANTED);
> +
> +	/*Through trial and error, seen that releasing BUS needed 3 tries */
> +	/* Hence keeping it rounded at 5 tries - a max of 4 retries allowed */
> +	retries = 0;
> +	do {
> +		r = regmap_write(map, HDMI_SYS_CTRL_DATA_REG, val);
> +		if (r >= 0)
> +			break;
> +		retries++;
> +	} while (retries < 5);
> +	if (r < 0) {
> +		dev_err(&client->dev, "ERROR: Releasing DDC Bus Access\n");
> +		return r;
> +		}
> +	return 0;
> +}
> +
> +static bool sil9022_detect(struct omap_dss_device *dssdev)
> +{
> +	/* Hot plug detection is not implemented */
> +	/* Hence we assume monitor connected */
> +	/* This will be fixed once HPD / polling is implemented */
> +	return true;
> +}
> +
> +static bool sil9022_audio_supported(struct omap_dss_device *dssdev)
> +{
> +	/* Audio configuration not present, hence returning false */
> +	return false;
> +}
> +
> +static const struct omapdss_hdmi_ops sil9022_hdmi_ops = {
> +	.connect			= sil9022_connect,
> +	.disconnect		= sil9022_disconnect,
> +
> +	.enable			= sil9022_enable,
> +	.disable			= sil9022_disable,
> +
> +	.check_timings	= sil9022_check_timings,
> +	.set_timings		= sil9022_set_timings,
> +	.get_timings		= sil9022_get_timings,
> +
> +	.read_edid		= sil9022_read_edid,
> +	.detect			= sil9022_detect,
> +
> +	.audio_supported	= sil9022_audio_supported,
> +	/* Yet to implement audio ops */
> +	/* For now audio_supported ops to return false */
> +};
> +
> +
> +static int sil9022_probe_of(struct i2c_client *client)
> +{
> +	struct panel_drv_data *ddata = dev_get_drvdata(&client->dev);
> +	struct device_node *node = client->dev.of_node;
> +	struct device_node *src_node;
> +	struct omap_dss_device *dssdev, *in;
> +
> +	int r, reset_gpio, datalines;
> +
> +	src_node = of_parse_phandle(node, "video-source", 0);
> +	if (!src_node) {
> +		dev_err(&client->dev, "failed to parse video source\n");
> +		return -ENODEV;
> +	}

There is no "video-source" property any more, and the endpoint handling
is missing, so I think it's clear you have not tested this driver with
the bindings you have in the patch 2/2.

> +
> +	in = omap_dss_find_output_by_node(src_node);
> +	if (in == NULL) {
> +		dev_err(&client->dev, "failed to find video source\n");
> +		return -EPROBE_DEFER;
> +	}
> +	ddata->in = in;
> +
> +	reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
> +
> +	if (gpio_is_valid(reset_gpio) || reset_gpio == -ENOENT) {
> +		ddata->reset_gpio = reset_gpio;
> +	} else {
> +		dev_err(&client->dev, "failed to parse lcdorhdmi gpio\n");
> +		return reset_gpio;
> +	}
> +
> +	r = of_property_read_u32(node, "data-lines", &datalines);

This driver doesn't use datalines information for anything, so this is
not needed.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-03-18 11:20 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-18 10:07 [RFC PATCH 0/2] Sil9022 DPI to HDMI Encoder Sathya Prakash M R
2014-03-18 10:07 ` [PATCH 1/2] OMAPDSS: Add Sil9022 DPI-HDMI Encoder Driver Sathya Prakash M R
2014-03-18 11:20   ` Tomi Valkeinen
2014-03-18 10:07 ` [PATCH 2/2] ARM: DTS: AM43x: Add sii9022 dt information Sathya Prakash M R
2014-03-18 10:31   ` Tomi Valkeinen
2014-03-18 10:57     ` Sathya Prakash
2014-03-18 11:03       ` Tomi Valkeinen
2014-03-18 10:56 ` [RFC PATCH 0/2] Sil9022 DPI to HDMI Encoder Mark Rutland

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).