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@xxxxxx> --- 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@xxxxxx> + * + * 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@xxxxxx>"); +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@xxxxxx> + * + * 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 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html