commit 4aef94c06412f8fd1a5398d3cb805596a055e089 Author: Moritz Bitsch Date: Mon Feb 6 16:03:41 2017 +0100 initial import of dsi85 driver this driver is based on the omap dss dsi85 driver diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000..a8ddca9 --- /dev/null +++ b/Kbuild @@ -0,0 +1,2 @@ +obj-m := dsi85.o +dsi85-y := dsi85_main.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1669d2e --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +ifneq ($(KERNELRELEASE),) +# kbuild part of makefile +include Kbuild +else +# normal makefile +KDIR ?= /lib/modules/`uname -r`/build + +default: + $(MAKE) -C $(KDIR) M=$$PWD + +endif diff --git a/dsi85_main.c b/dsi85_main.c new file mode 100755 index 0000000..18b875e --- /dev/null +++ b/dsi85_main.c @@ -0,0 +1,787 @@ +/* + * + * Copyright 2011 Texas Instruments, Inc. + * Author: Archit Taneja + * + * based on d2l panel driver by Jerry Alexander + * + * This program iss free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#if 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dsi85.h" + +#define DSI85DEBUG + +static struct i2c_board_info dsi85_i2c_board_info = +{ + I2C_BOARD_INFO("dsi85_i2c_driver", 0x2d /*0x2c*/), +}; + +struct dsi85_i2c_data +{ + struct mutex xfer_lock; +}; + + + +static struct omap_video_timings dsi85_timings = +{ + .x_res = 1024, + .y_res = 600, + .pixel_clock = 50000, + .hfp = 36, //42 128 38 - 100 1 107 chido es 36 128 45 + .hsw = 128, + .hbp = 45, + .vfp = 1, + .vsw = 4, + .vbp = 9, +}; + +static const struct omap_dss_dsi_videomode_data vm_data = +{ + .hsa = 1, + .hfp = 20, // Set to 4/3 of the DISPC porch value. + .hbp = 20, // Set to 4/3 of the DISPC porch value. + .vsa = 4, + .vfp = 6, + .vbp = 4, + + .blanking_mode = 1, + .hsa_blanking_mode = 1, + .hbp_blanking_mode = 1, + .hfp_blanking_mode = 1, + + .vp_de_pol = true, + .vp_vsync_pol = false, + .vp_hsync_pol = false, + .vp_hsync_end = false, + .vp_vsync_end = false, + + .window_sync = 4, + .ddr_clk_always_on = true, +}; + +struct dsi85_data +{ + struct mutex lock; + + struct omap_dss_device* dssdev; + struct backlight_device* bldev; + struct dentry* debug_dir; + bool enabled; + u8 rotate; + bool mirror; + bool use_dsi_bl; + unsigned int bl; + unsigned long hw_guard_end; /* next value of jiffies when we can + * issue the next sleep in/out command + */ + unsigned long hw_guard_wait; /* max guard time in jiffies */ + + int config_channel; + int pixel_channel; + + struct omap_video_timings* timings; + + struct panel_dsi85_data* pdata; + struct i2c_client* dsi85_i2c_client; +}; + +struct dsi85_reg +{ + /* Address and register value */ + u8 data[10]; + int len; +}; + + +static void dsi85_get_timings(struct omap_dss_device* dssdev, + struct omap_video_timings* timings) +{ + *timings = dssdev->panel.timings; +} + +static void dsi85_set_timings(struct omap_dss_device* dssdev, + struct omap_video_timings* timings) +{ + dssdev->panel.timings.x_res = timings->x_res; + dssdev->panel.timings.y_res = timings->y_res; + dssdev->panel.timings.pixel_clock = timings->pixel_clock; + dssdev->panel.timings.hsw = timings->hsw; + dssdev->panel.timings.hfp = timings->hfp; + dssdev->panel.timings.hbp = timings->hbp; + dssdev->panel.timings.vsw = timings->vsw; + dssdev->panel.timings.vfp = timings->vfp; + dssdev->panel.timings.vbp = timings->vbp; +} + +static int dsi85_check_timings(struct omap_dss_device* dssdev, + struct omap_video_timings* timings) +{ + return 0; +} + +static void dsi85_get_resolution(struct omap_dss_device* dssdev, + u16* xres, u16* yres) +{ + struct dsi85_data* dsi85_d = dev_get_drvdata(&dssdev->dev); + + if (dsi85_d->rotate == 0 || dsi85_d->rotate == 2) + { + *xres = dssdev->panel.timings.x_res; + *yres = dssdev->panel.timings.y_res; + } + else + { + *yres = dssdev->panel.timings.x_res; + *xres = dssdev->panel.timings.y_res; + } +} + +static int dsi85_probe(struct omap_dss_device* dssdev) +{ + struct i2c_adapter* adapter; + struct i2c_client* dsi85_i2c_client; + int ret = 0; + struct dsi85_data* dsi85_d = NULL; + dev_dbg(&dssdev->dev, "dsi85_probe\n"); + + if (dssdev->data == NULL) + { + dev_err(&dssdev->dev, "no platform data!\n"); + return -EINVAL; + } + + dssdev->panel.config = OMAP_DSS_LCD_TFT; + dssdev->panel.timings = dsi85_timings; + dssdev->panel.dsi_vm_data = vm_data; + dssdev->ctrl.pixel_size = 24; + dssdev->panel.acbi = 0; + dssdev->panel.acb = 40; + dsi85_d = kzalloc(sizeof(*dsi85_d), GFP_KERNEL); + + if (!dsi85_d) + { + return -ENOMEM; + } + + dsi85_d->dssdev = dssdev; + dsi85_d->pdata = dssdev->data; + + if (!dsi85_d->pdata) + { + dev_err(&dssdev->dev, "Invalid platform data\n"); + ret = -EINVAL; + goto err; + } + + mutex_init(&dsi85_d->lock); + dev_set_drvdata(&dssdev->dev, dsi85_d); + dsi85_d->debug_dir = debugfs_create_dir("dsi85", NULL); + + if (!dsi85_d->debug_dir) + { + dev_err(&dssdev->dev, "failed to create debug dir\n"); + goto err_debugfs; + } + + ret = omap_dsi_request_vc(dssdev, &dsi85_d->pixel_channel); + + if (ret) + { + dev_err(&dssdev->dev, "failed to request pixel update " + "channel\n"); + goto err_debugfs; + } + else + printk(KERN_INFO "pixel channel setup for %d\n", \ + dsi85_d->pixel_channel); + + printk(KERN_INFO "pixel channel %d\n", dsi85_d->pixel_channel); + ret = omap_dsi_set_vc_id(dssdev, dsi85_d->pixel_channel, 0); + + if (ret) + { + dev_err(&dssdev->dev, "failed to set VC_ID for pixel data" + " virtual channel\n"); + goto err_pixel_vc; + } + + adapter = i2c_get_adapter(2); + + if (!adapter) + { + printk(KERN_INFO "DSI85-I2C: can't get i2c adapter 2\n"); +// ret = -ENODEV; +// goto err_pixel_vc; + } + + dsi85_i2c_client = i2c_new_device(adapter, &dsi85_i2c_board_info); + + if (!dsi85_i2c_client) + { + printk(KERN_INFO "DSI85-I2C: can't add i2c device\n"); +// ret = -ENODEV; +// goto err_pixel_vc; + } + + dsi85_d->dsi85_i2c_client = dsi85_i2c_client; + ret = i2c_smbus_read_byte_data(dsi85_i2c_client, 0x00); + printk(KERN_INFO "DSI85-I2C: reading 0x00 returned - 0x%x\n", ret); + dev_dbg(&dssdev->dev, "dsi85_probe\n"); + return 0; +err_pixel_vc: + omap_dsi_release_vc(dssdev, dsi85_d->pixel_channel); +err_debugfs: + mutex_destroy(&dsi85_d->lock); + gpio_free(dsi85_d->pdata->reset_gpio); +err: + kfree(dsi85_d); + return ret; +} + +static void dsi85_remove(struct omap_dss_device* dssdev) +{ + struct dsi85_data* dsi85_d = dev_get_drvdata(&dssdev->dev); + debugfs_remove_recursive(dsi85_d->debug_dir); + mutex_destroy(&dsi85_d->lock); + gpio_free(dsi85_d->pdata->reset_gpio); + kfree(dsi85_d); +} + +#ifdef DSI85DEBUG +static void dsi85_dumpconfig(struct omap_dss_device* dssdev) +{ + struct dsi85_data* dsi85_d = dev_get_drvdata(&dssdev->dev); + struct i2c_client* dsi85_i2c_client = dsi85_d->dsi85_i2c_client; + printk(KERN_INFO "luis' message"); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x00, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x00)); + /* + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x01, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x01)); + + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x02, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x02)); + + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x03, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x03)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x04, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x04)); + + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x05, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x05)); + */ + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x0D, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x0D)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x0A, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x0A)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x0B, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x0B)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x10, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x10)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x18, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x18)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x1A, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x1A)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x20, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x20)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x21, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x21)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x22, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x22)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x23, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x23)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x24, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x24)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x25, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x25)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x26, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x26)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x27, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x27)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x28, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x28)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x29, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x29)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x2A, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x2A)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x2B, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x2B)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x2C, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x2C)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x2D, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x2D)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x2E, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x2E)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x2F, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x2F)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x30, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x30)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x31, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x31)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x32, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x32)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x33, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x33)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x34, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x34)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x35, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x35)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x36, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x32)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x37, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x33)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x38, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x34)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x39, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x35)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x3A, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x35)); + printk(KERN_INFO "DSI85-I2C: read 0x%02x - 0x%02x\n", 0x3B, \ + i2c_smbus_read_byte_data(dsi85_i2c_client, 0x3B)); +} + +#endif + + + + + +#endif + +#include +#include + +/* DSI85 registers */ +#define DSI85_SOFT_RESET 0x09 +#define DSI85_CORE_PLL 0x0A +#define DSI85_PLL_DIV 0x0B +#define DSI85_PLL_EN 0x0D +#define DSI85_DSI_CFG 0x10 +#define DSI85_DSI_EQ 0x11 +#define DSI85_CHA_DSI_CLK_RNG 0x12 +#define DSI85_CHB_DSI_CLK_RNG 0x13 +#define DSI85_LVDS_MODE 0x18 +#define DSI85_LVDS_SIGN 0x19 +#define DSI85_LVDS_TERM 0x1A +#define DSI85_CHA_LINE_LEN_LO 0x20 +#define DSI85_CHA_LINE_LEN_HI 0x21 +#define DSI85_CHB_LINE_LEN_LO 0x22 +#define DSI85_CHB_LINE_LEN_HI 0x23 +#define DSI85_CHA_VERT_LINES_LO 0x24 +#define DSI85_CHA_VERT_LINES_HI 0x25 +#define DSI85_CHB_VERT_LINES_LO 0x26 +#define DSI85_CHB_VERT_LINES_HI 0x27 +#define DSI85_CHA_SYNC_DELAY_LO 0x28 +#define DSI85_CHA_SYNC_DELAY_HI 0x29 +#define DSI85_CHB_SYNC_DELAY_LO 0x2A +#define DSI85_CHB_SYNC_DELAY_HI 0x2B +#define DSI85_CHA_HSYNC_WIDTH_LO 0x2C +#define DSI85_CHA_HSYNC_WIDTH_HI 0x2D +#define DSI85_CHB_HSYNC_WIDTH_LO 0x2E +#define DSI85_CHB_HSYNC_WIDTH_HI 0x2F +#define DSI85_CHA_VSYNC_WIDTH_LO 0x30 +#define DSI85_CHA_VSYNC_WIDTH_HI 0x31 +#define DSI85_CHB_VSYNC_WIDTH_LO 0x32 +#define DSI85_CHB_VSYNC_WIDTH_HI 0x33 +#define DSI85_CHA_HORZ_BACKPORCH 0x34 +#define DSI85_CHB_HORZ_BACKPORCH 0x35 +#define DSI85_CHA_VERT_BACKPORCH 0x36 +#define DSI85_CHB_VERT_BACKPORCH 0x37 +#define DSI85_CHA_HORZ_FRONTPORCH 0x38 +#define DSI85_CHB_HORZ_FRONTPORCH 0x39 +#define DSI85_CHA_VERT_FRONTPORCH 0x3A +#define DSI85_CHB_VERT_FRONTPORCH 0x3B + +#define LVDS_CLK_FROM_DSI_CLK 1 + +struct dsi85_lvds_timings +{ + u16 hfp; + u16 hsw; + u16 hbp; + u16 vfp; + u16 vsw; + u16 vbp; +}; + +static struct dsi85_lvds_timings lvds_timings = +{ + .hfp = 40, + .hsw = 128, + .hbp = 40, + .vfp = 1, + .vsw = 4, + .vbp = 9, +}; + +#if 0 +/** + * dsi85_config - Configure dsi85 + * + * Initial configuration for dsi85 configuration registers + */ +static void dsi85_config(struct dsi85_data* dsi85_d) +{ + printk(KERN_INFO "Now Configuring\n"); + struct i2c_client* dsi85_i2c_client = dsi85_d->dsi85_i2c_client; + u8 val = 0; + /* Soft reset and disable PLL */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_SOFT_RESET, 0x01); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_PLL_EN, 0x00); +#if LVDS_CLK_FROM_DSI_CLK + val = 0x1; +#endif + + /* user external clock reference with no muliplier */ + if (dssdev->panel.timings.pixel_clock <= 37500) + { + // Do nothing. + } + else if (dssdev->panel.timings.pixel_clock <= 62500) + { + val |= (0x01 << 1); + } + else if (dssdev->panel.timings.pixel_clock <= 87500) + { + val |= (0x02 << 1); + } + else if (dssdev->panel.timings.pixel_clock <= 112500) + { + val |= (0x03 << 1); + } + else if (dssdev->panel.timings.pixel_clock <= 137500) + { + val |= (0x04 << 1); + } + else + { + val |= (0x05 << 1); + } + + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CORE_PLL, val); +#if LVDS_CLK_FROM_DSI_CLK + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_PLL_DIV, 0x10); // Divide DSI_CLK by 3. +#else + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_PLL_DIV, 0x00); // Multiply REFCLK by 1. +#endif + /* four DSI lanes with single channel*/ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_DSI_CFG, 0x20); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_DSI_EQ, 0x00); + /* set DSI clock range */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_DSI_CLK_RNG, (dssdev->panel.timings.pixel_clock * 3 / 5000)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_DSI_CLK_RNG, (dssdev->panel.timings.pixel_clock * 3 / 5000)); + /* set LVDS for single channel, 24 bit mode, HS/VS low, DE high */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_LVDS_MODE, 0x7F); + /* set LVDS 200 Ohm termination and max differential swing voltage */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_LVDS_SIGN, 0x00); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_LVDS_TERM, 0x00); + /* x resolution high/low for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_LINE_LEN_LO, \ + ((dssdev->panel.timings.x_res) & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_LINE_LEN_HI, \ + ((dssdev->panel.timings.x_res) & 0xFF00) >> 8); + /* x resolution high/low for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_LINE_LEN_LO, \ + (dssdev->panel.timings.x_res & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_LINE_LEN_HI, \ + (dssdev->panel.timings.x_res & 0xFF00) >> 8); + /* y resolution high/low for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VERT_LINES_LO, \ + (dssdev->panel.timings.y_res & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VERT_LINES_HI, \ + (dssdev->panel.timings.y_res & 0xFF00) >> 8); + /* y resolution high/low for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VERT_LINES_LO, \ + (dssdev->panel.timings.y_res & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VERT_LINES_HI, \ + (dssdev->panel.timings.y_res & 0xFF00) >> 8); + /* SYNC delay high/low for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, \ + DSI85_CHA_SYNC_DELAY_LO, 0x00); + i2c_smbus_write_byte_data(dsi85_i2c_client, \ + DSI85_CHA_SYNC_DELAY_HI, 0x02); + /* SYNC delay high/low for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, \ + DSI85_CHB_SYNC_DELAY_LO, 0x00); + i2c_smbus_write_byte_data(dsi85_i2c_client, \ + DSI85_CHB_SYNC_DELAY_HI, 0x02); + /* HSYNC width high/low for channel A */ + /* i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HSYNC_WIDTH_LO, \ + (dssdev->panel.timings.hsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HSYNC_WIDTH_HI, \ + (dssdev->panel.timings.hsw & 0xFF00)>>8); */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HSYNC_WIDTH_LO, \ + (lvds_timings.hsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HSYNC_WIDTH_HI, \ + (lvds_timings.hsw & 0xFF00) >> 8); + /* HSYNC width high/low for channel B */ + /* i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HSYNC_WIDTH_LO, \ + (dssdev->panel.timings.hsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HSYNC_WIDTH_HI, \ + (dssdev->panel.timings.hsw & 0xFF00)>>8); */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HSYNC_WIDTH_LO, \ + (lvds_timings.hsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HSYNC_WIDTH_HI, \ + (lvds_timings.hsw & 0xFF00) >> 8); + /* VSYNC width high/low for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VSYNC_WIDTH_LO, \ + (lvds_timings.vsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VSYNC_WIDTH_HI, \ + (lvds_timings.vsw & 0xFF00) >> 8); + /* VSYNC width high/low for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VSYNC_WIDTH_LO, \ + (lvds_timings.vsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VSYNC_WIDTH_HI, \ + (lvds_timings.vsw & 0xFF00) >> 8); + /* Horizontal BackPorch for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HORZ_BACKPORCH, \ + (lvds_timings.hbp & 0x00FF)); + /* Horizontal BackPorch for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HORZ_BACKPORCH, \ + (lvds_timings.hbp & 0x00FF)); + /* Vertical BackPorch for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VERT_BACKPORCH, \ + (lvds_timings.vbp & 0x00FF)); + /* Vertical BackPorch for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VERT_BACKPORCH, \ + (lvds_timings.vbp & 0x00FF)); + /* Horizontal FrontPorch for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HORZ_FRONTPORCH, \ + (lvds_timings.hfp & 0x00FF)); + /* Horizontal FrontPorch for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HORZ_FRONTPORCH, \ + (lvds_timings.hfp & 0x00FF)); + /* Vertical FrontPorch for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VERT_FRONTPORCH, \ + (lvds_timings.vbp & 0x00FF)); + /* Vertical FrontPorch for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VERT_FRONTPORCH, \ + (lvds_timings.vbp & 0x00FF)); + /* Soft reset and enable PLL */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_SOFT_RESET, 0x01); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_PLL_EN, 0x01); + return; +} +#endif + +static void dsi85_test(struct i2c_client* dsi85_i2c_client, u32 pixel_clock, u16 x_res, u16 y_res) +{ + u8 val = 0; + printk(KERN_INFO "Now Configuring Test Pattern\n"); + /* Soft reset and disable PLL */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_SOFT_RESET, 0x01); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_PLL_EN, 0x00); +#if LVDS_CLK_FROM_DSI_CLK + val = 0x1; +#endif + + /* user external clock reference with no muliplier */ + if (pixel_clock <= 37500) + { + // Do nothing. + } + else if (pixel_clock <= 62500) + { + val |= (0x01 << 1); + } + else if (pixel_clock <= 87500) + { + val |= (0x02 << 1); + } + else if (pixel_clock <= 112500) + { + val |= (0x03 << 1); + } + else if (pixel_clock <= 137500) + { + val |= (0x04 << 1); + } + else + { + val |= (0x05 << 1); + } + + //LADLDL + printk(KERN_INFO "Pixel CLK value was %d\n", val); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CORE_PLL, val); +#if LVDS_CLK_FROM_DSI_CLK + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_PLL_DIV, 0x10); // Divide DSI_CLK by 3. +#else + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_PLL_DIV, 0x00); // Multiply REFCLK by 1. +#endif + //LADLDL PLL enable after address A and B configured + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_PLL_EN, 0x01); + /* four DSI lanes with single channel*/ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_DSI_CFG, 0x20); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_DSI_EQ, 0x00); + /* set DSI clock range */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_DSI_CLK_RNG, (pixel_clock * 3 / 5000)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_DSI_CLK_RNG, (pixel_clock * 3 / 5000)); + /* set LVDS for single channel, 24 bit mode, HS/VS low, DE high */ + //i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_LVDS_MODE, 0x7F); + /*LADLD set LVDS for single channel, 24 bit mode, HS/VS low, DE high */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_LVDS_MODE, 0x60); + /* set LVDS 200 Ohm termination and max differential swing voltage */ + //LADLDL + //i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_LVDS_SIGN, 0x00); + //i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_LVDS_TERM, 0x00); + /* x resolution high/low for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_LINE_LEN_LO, \ + ((x_res) & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_LINE_LEN_HI, \ + ((x_res) & 0xFF00) >> 8); + /* x resolution high/low for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_LINE_LEN_LO, \ + (x_res & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_LINE_LEN_HI, \ + (x_res & 0xFF00) >> 8); + /* y resolution high/low for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VERT_LINES_LO, \ + (y_res & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VERT_LINES_HI, \ + (y_res & 0xFF00) >> 8); + /* y resolution high/low for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VERT_LINES_LO, \ + (y_res & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VERT_LINES_HI, \ + (y_res & 0xFF00) >> 8); + /* SYNC delay high/low for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, \ + DSI85_CHA_SYNC_DELAY_LO, 0x00); + i2c_smbus_write_byte_data(dsi85_i2c_client, \ + DSI85_CHA_SYNC_DELAY_HI, 0x02); + /* SYNC delay high/low for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, \ + DSI85_CHB_SYNC_DELAY_LO, 0x00); + i2c_smbus_write_byte_data(dsi85_i2c_client, \ + DSI85_CHB_SYNC_DELAY_HI, 0x02); + /* HSYNC width high/low for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HSYNC_WIDTH_LO, \ + (lvds_timings.hsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HSYNC_WIDTH_HI, \ + (lvds_timings.hsw & 0xFF00) >> 8); + /* HSYNC width high/low for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HSYNC_WIDTH_LO, \ + (lvds_timings.hsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HSYNC_WIDTH_HI, \ + (lvds_timings.hsw & 0xFF00) >> 8); + /* VSYNC width high/low for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VSYNC_WIDTH_LO, \ + (lvds_timings.vsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VSYNC_WIDTH_HI, \ + (lvds_timings.vsw & 0xFF00) >> 8); + /* VSYNC width high/low for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VSYNC_WIDTH_LO, \ + (lvds_timings.vsw & 0x00FF)); + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VSYNC_WIDTH_HI, \ + (lvds_timings.vsw & 0xFF00) >> 8); + /* Horizontal BackPorch for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HORZ_BACKPORCH, \ + (lvds_timings.hbp & 0x00FF)); + /* Horizontal BackPorch for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HORZ_BACKPORCH, \ + (lvds_timings.hbp & 0x00FF)); + /* Vertical BackPorch for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VERT_BACKPORCH, \ + (lvds_timings.vbp & 0x00FF)); + /* Vertical BackPorch for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VERT_BACKPORCH, \ + (lvds_timings.vbp & 0x00FF)); + /* Horizontal FrontPorch for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_HORZ_FRONTPORCH, \ + (lvds_timings.hfp & 0x00FF)); + /* Horizontal FrontPorch for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_HORZ_FRONTPORCH, \ + (lvds_timings.hfp & 0x00FF)); + /* Vertical FrontPorch for channel A */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHA_VERT_FRONTPORCH, \ + (lvds_timings.vbp & 0x00FF)); + /* Vertical FrontPorch for channel B */ + i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_CHB_VERT_FRONTPORCH, \ + (lvds_timings.vbp & 0x00FF)); + //Test Pattern + i2c_smbus_write_byte_data(dsi85_i2c_client, 0x3C, 0x11); + //LADLDL + /* Soft reset and enable PLL */ + //i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_SOFT_RESET, 0x01); + //i2c_smbus_write_byte_data(dsi85_i2c_client, DSI85_PLL_EN, 0x01); + return; +} + +static int dsi85_probe(struct i2c_client* client, const struct i2c_device_id* id) +{ + dsi85_test(client, 137500, 1920, 1080); + return 0; +} + +static int dsi85_remove(struct i2c_client* client) +{ + return 0; +} + +static const struct i2c_device_id dsi85_id[] = +{ + { "dsi85", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, dsi85_id); + +#ifdef CONFIG_OF +static const struct of_device_id of_dsi85_match[] = +{ + { .compatible = "ti,dsi85", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_dsi85_match); +#endif + +static struct i2c_driver dsi85_driver = +{ + .driver = { + .name = "dsi85_i2c_driver", +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(of_dsi85_match), +#endif + }, + .probe = dsi85_probe, + .remove = dsi85_remove, + .id_table = dsi85_id, +}; + +module_i2c_driver(dsi85_driver); + +MODULE_DESCRIPTION("Texas DSI85 dsi to lvds driver"); +MODULE_AUTHOR("Moritz Bitsch"); +MODULE_LICENSE("GPL"); +