Tool/software: Linux
Hi,
Can anyone provide me linux driver for SN65DSI83 bridge? The one I found on this forum (0602.panel-dsi85.c in attachment) compiles only with older version of kernel (3.8).
I need to run it on msm8953 platform (kernel 3.18). Does anyone can help me with that?
Cheers
/*
*
* Copyright 2011 Texas Instruments, Inc.
* Author: Archit Taneja <archit@ti.com>
*
* based on d2l panel driver by Jerry Alexander <x0135174@ti.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <video/omapdss.h>
#include <video/mipi_display.h>
#include <video/omap-panel-dsi85.h>
#include "panel-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 i2c_device_id dsi85_i2c_id[] = {
{ "dsi85_i2c_driver", 0 },
};
#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,
};
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 int dsi85_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct dsi85_i2c_data *dsi85_i2c_data;
printk(KERN_INFO "DSI85-I2C: Probe called!\n");
dsi85_i2c_data = kzalloc(sizeof(struct dsi85_i2c_data), GFP_KERNEL);
if (!dsi85_i2c_data) {
printk(KERN_ERR "DSI85-I2C: memory allocation failed!\n");
return -ENOMEM;
}
mutex_init(&dsi85_i2c_data->xfer_lock);
i2c_set_clientdata(client, dsi85_i2c_data);
return 0;
}
static int dsi85_i2c_remove(struct i2c_client *client)
{
struct dsi85_i2c_data *dsi85_i2c_data =
i2c_get_clientdata(client);
kfree(dsi85_i2c_data);
return 0;
}
static struct i2c_driver dsi85_i2c_driver = {
.driver = {
.name = "dsi85_i2c_driver",
},
.probe = dsi85_i2c_probe,
.remove = dsi85_i2c_remove,
.id_table = dsi85_i2c_id,
};
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
/**
* dsi85_config - Configure dsi85
*
* Initial configuration for dsi85 configuration registers
*/
static void dsi85_config(struct omap_dss_device *dssdev)
{
printk(KERN_INFO "Now Configuring\n");
struct dsi85_data *dsi85_d = dev_get_drvdata(&dssdev->dev);
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, \
// (dssdev->panel.timings.hbp & 0x00FF));
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, \
// (dssdev->panel.timings.hbp & 0x00FF));
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, \
// (dssdev->panel.timings.hfp & 0x00FF));
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, \
// (dssdev->panel.timings.hfp & 0x00FF));
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;
}
static void dsi85_test(struct omap_dss_device *dssdev)
{
printk(KERN_INFO "Now Configuring Test Pattern\n");
struct dsi85_data *dsi85_d = dev_get_drvdata(&dssdev->dev);
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);
}
//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, (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);
/*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, \
((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, \
// (dssdev->panel.timings.hbp & 0x00FF));
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, \
// (dssdev->panel.timings.hbp & 0x00FF));
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, \
// (dssdev->panel.timings.hfp & 0x00FF));
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, \
// (dssdev->panel.timings.hfp & 0x00FF));
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_power_on(struct omap_dss_device *dssdev)
{
struct dsi85_data *dsi85_d = dev_get_drvdata(&dssdev->dev);
int ret = 0;
if (dsi85_d->enabled != 1) {
if (dsi85_d->pdata->set_power)
dsi85_d->pdata->set_power(true);
ret = omapdss_dsi_display_enable(dssdev);
if (ret) {
dev_err(&dssdev->dev, "failed to enable DSI\n");
goto err;
}
omapdss_dsi_vc_enable_hs(dssdev, dsi85_d->pixel_channel, true);
dsi_videomode_panel_preinit(dssdev, dsi85_d->pixel_channel);
msleep(100);
//LADLDL
dsi85_config(dssdev);
//dsi85_test(dssdev);
#ifdef DSI85DEBUG
dsi85_dumpconfig(dssdev);
#endif
dsi_video_mode_enable(dssdev, dsi85_d->pixel_channel);
dsi85_d->enabled = 1;
}
err:
return ret;
}
static void dsi85_power_off(struct omap_dss_device *dssdev)
{
struct dsi85_data *dsi85_d = dev_get_drvdata(&dssdev->dev);
gpio_set_value(dsi85_d->pdata->reset_gpio, 0);
msleep(20);
dsi85_d->enabled = 0;
omapdss_dsi_display_disable(dssdev, 0, 0);
if (dsi85_d->pdata->set_power)
dsi85_d->pdata->set_power(false);
}
static int dsi85_start(struct omap_dss_device *dssdev)
{
struct dsi85_data *dsi85_d = dev_get_drvdata(&dssdev->dev);
int r = 0;
mutex_lock(&dsi85_d->lock);
dsi_bus_lock(dssdev);
r = dsi85_power_on(dssdev);
dsi_bus_unlock(dssdev);
if (r) {
dev_dbg(&dssdev->dev, "enable failed\n");
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
} else {
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
dssdev->manager->enable(dssdev->manager);
}
mutex_unlock(&dsi85_d->lock);
return r;
}
static void dsi85_stop(struct omap_dss_device *dssdev)
{
struct dsi85_data *dsi85_d = dev_get_drvdata(&dssdev->dev);
mutex_lock(&dsi85_d->lock);
dssdev->manager->disable(dssdev->manager);
dsi_bus_lock(dssdev);
dsi85_power_off(dssdev);
dsi_bus_unlock(dssdev);
mutex_unlock(&dsi85_d->lock);
}
static void dsi85_disable(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "disable\n");
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
dsi85_stop(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int dsi85_enable(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "enable\n");
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
return -EINVAL;
return dsi85_start(dssdev);
}
static int dsi85_sync(struct omap_dss_device *dssdev)
{
return 0;
}
static int dsi85_resume(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "resume\n");
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
return -EINVAL;
return dsi85_start(dssdev);
}
static int dsi85_suspend(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "suspend\n");
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return -EINVAL;
dsi85_stop(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static struct omap_dss_driver dsi85_driver = {
.probe = dsi85_probe,
.remove = dsi85_remove,
.enable = dsi85_enable,
.enable = dsi85_enable,
.disable = dsi85_disable,
.suspend = dsi85_suspend,
.resume = dsi85_resume,
.sync = dsi85_sync,
.get_resolution = dsi85_get_resolution,
.get_recommended_bpp = omapdss_default_get_recommended_bpp,
.get_timings = dsi85_get_timings,
.set_timings = dsi85_set_timings,
.check_timings = dsi85_check_timings,
.driver = {
.name = "dsi85",
.owner = THIS_MODULE,
},
};
static int __init dsi85_init(void)
{
int r = 0;
r = i2c_add_driver(&dsi85_i2c_driver);
if (r) {
printk(KERN_WARNING "dsi85_i2c_driver" \
" registration failed\n");
return r;
} else
printk("DSI85-I2C: registered!\n");
r = omap_dss_register_driver(&dsi85_driver);
if (r){
i2c_del_driver(&dsi85_i2c_driver);
printk("DSI85-DSS: failed!\n");
}else
printk("DSI85-DSS: registered!\n");
return 0;
}
static void __exit dsi85_exit(void)
{
i2c_del_driver(&dsi85_i2c_driver);
omap_dss_unregister_driver(&dsi85_driver);
}
module_init(dsi85_init);
module_exit(dsi85_exit);