- 论坛徽章:
- 0
|
这也是个I2C 驱动,挂接在 I2C_2 总线上。
初始化如下:
- /* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_bridge_init
-
*
-
* DESCRIPTION: Driver Init function for lvds bridge
-
*
-
\* ************************************************************************* */
-
static int __init dsi_lvds_bridge_init(void)
-
{
-
int ret = 0;
-
struct i2c_adapter *adapter = NULL;
-
struct i2c_client *client = NULL;
-
struct i2c_board_info info;
-
-
printk(KERN_INFO "[DISPLAY] %s: Enter\n", __func__);
-
-
ret = misc_register(&dsi_lvds_bridge_dev);
-
if (ret) {
-
printk(KERN_ERR "[DISPLAY] %s: Can not register misc device.\n", __func__);
-
return ret;
-
}
-
-
adapter = i2c_get_adapter(2); /*DV0 is on I2C bus 2 */
-
if (!adapter) {
-
printk(KERN_ERR "[DISPLAY] %s: Can not get bridge i2c adapter.\n", __func__);
-
return 0;
-
}
-
-
/* Setup the i2c board info with the device type and
-
the device address. */
-
memset(&info, 0, sizeof(info));
-
strlcpy(info.type, "i2c_disp_brig", sizeof(info.type));
-
-
info.addr = 0x0F; /*I2C2 address 0x0F */
-
-
/* Create the i2c client */
-
client = i2c_new_device(adapter, &info);
-
if (!client) {
-
printk(KERN_ERR "[DISPLAY] %s: ERROR, i2c client=NULL\n", __func__);
-
return -1;
-
}
-
-
ret = i2c_add_driver(&dsi_lvds_bridge_i2c_driver);
-
-
printk(KERN_INFO "[DISPLAY] %s: Exit, ret = %d\n", __func__, ret);
-
-
return 0;
-
}
- /* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_bridge_exit
-
*
-
* DESCRIPTION: Driver exit function for lvds bridge
-
*
-
\* ************************************************************************* */
-
static void __exit dsi_lvds_bridge_exit(void)
-
{
-
printk(KERN_INFO "[DISPLAY] %s\n", __func__);
-
-
misc_deregister(&dsi_lvds_bridge_dev);
-
-
i2c_del_driver(&dsi_lvds_bridge_i2c_driver);
-
}
-
-
-
module_init(dsi_lvds_bridge_init);
-
module_exit(dsi_lvds_bridge_exit);
初始化用到的几个结构体:
- static const struct i2c_device_id dsi_lvds_bridge_id[] = {
-
{ "i2c_disp_brig", 0 },
-
{ }
-
};
-
MODULE_DEVICE_TABLE(i2c, dsi_lvds_bridge_id);
-
-
static struct i2c_driver dsi_lvds_bridge_i2c_driver = {
-
.driver = {
-
.name = "i2c_disp_brig",
-
},
-
.id_table = dsi_lvds_bridge_id,
-
.probe = dsi_lvds_bridge_probe,
-
.remove = dsi_lvds_bridge_remove,
-
};
- static const struct file_operations mipi_dsi_dev_fops = {
-
.owner = THIS_MODULE,
-
.unlocked_ioctl = dsi_lvds_dev_ioctl,
-
};
-
-
static struct miscdevice dsi_lvds_bridge_dev = {
-
.minor = MISC_DYNAMIC_MINOR,
-
.name = "mipi_dsi",
-
.fops = &mipi_dsi_dev_fops,
-
};
dsi_lvds_bridge_probe()
- /* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_bridge_probe
-
*
-
* DESCRIPTION: Probe function for LVDS bridge.
-
*
-
\* ************************************************************************* */
-
static int dsi_lvds_bridge_probe(struct i2c_client *client, const struct i2c_device_id *id)
-
{
-
printk(KERN_INFO "[DISPLAY] %s: Enter\n", __func__);
-
-
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-
printk(KERN_ERR "[DISPLAY] %s: Check I2C functionality failed.\n", __func__);
-
return -ENODEV;
-
}
-
-
dsi_lvds_inst = kzalloc(sizeof(struct dsi_lvds_bridge_instance), GFP_KERNEL);
-
-
if (dsi_lvds_inst == NULL) {
-
printk(KERN_ERR "[DISPLAY] %s: Can not allocate memory.\n", __func__);
-
return -ENOMEM;
-
}
-
-
dsi_lvds_inst->client = client;
-
-
i2c_set_clientdata(client, dsi_lvds_inst);
-
-
dsi_lvds_inst->client->addr = 0x0F;
-
-
printk(KERN_INFO "[DISPLAY] %s: Exit\n", __func__);
-
-
return 0;
-
}
1. use GPIO to reset lvds state
- /* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_set_bridge_reset_state
-
*
-
* DESCRIPTION: This function uses GPIO to force in and out of reset state.
-
\* ************************************************************************* */
-
void dsi_lvds_set_bridge_reset_state(int state)
-
{
-
printk(KERN_INFO "[DISPLAY ] %s: state = %d, gpio = %d\n", __func__, state, gpio_get_value(GPIO_MIPI_BRIDGE_RESET));
-
-
if (state) {
-
gpio_direction_output(GPIO_MIPI_BRIDGE_RESET, 0);
-
gpio_set_value_cansleep(GPIO_MIPI_BRIDGE_RESET, 0);
-
mdelay(10);
-
} else {
-
-
gpio_direction_output(GPIO_MIPI_BRIDGE_RESET, 0);
-
gpio_set_value_cansleep(GPIO_MIPI_BRIDGE_RESET, 0); /*Pull MIPI Bridge reset pin to Low */
-
mdelay(20);
-
gpio_direction_output(GPIO_MIPI_BRIDGE_RESET, 1);
-
gpio_set_value_cansleep(GPIO_MIPI_BRIDGE_RESET, 1); /*Pull MIPI Bridge reset pin to High */
-
mdelay(40);
-
}
-
}
2. dsi_lvds_configure_lvds_bridge () , 用I2C总线,配置lvds bridge设备。
- /* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_configure_lvds_bridge
-
*
-
* DESCRIPTION: This function uses I2C interface to set bridge registers.
-
* to configure timings and MIPI lanes.
-
\* ************************************************************************* */
-
void dsi_lvds_configure_lvds_bridge(struct drm_device *dev)
-
{
-
if (lvds_disp_init) {
-
printk(KERN_ALERT "[DISPLAY ] %s is already initialized\n", __func__);
-
return;
-
}
-
-
printk(KERN_INFO "[DISPLAY ]%s: Enter\n", __func__);
-
-
DSI_I2C_ByteWrite(0x013C, 0x00050006, 6); /*PPI_TX_RX_TA, BTA parameters */
-
DSI_I2C_ByteRead(0x013C, 4);
-
DSI_I2C_ByteWrite(0x0114, 0x00000004, 6); /*PPI_LPTXTIMCNT */
-
-
#ifdef FIXME_MLD // DV0.9 changes
-
DSI_I2C_ByteWrite(0x0164, 0x00000007, 6); /*PPI_D0S_CLRSIPOCOUNT */
-
DSI_I2C_ByteWrite(0x0168, 0x00000007, 6); /*PPI_D1S_CLRSIPOCOUNT */
-
DSI_I2C_ByteWrite(0x016c, 0x00000007, 6); /*PPI_D2S_CLRSIPOCOUNT */
-
DSI_I2C_ByteWrite(0x0170, 0x00000007, 6); /*PPI_D3S_CLRSIPOCOUNT */
-
#else
-
DSI_I2C_ByteWrite(0x0164, 0x00000001, 6); /*PPI_D0S_CLRSIPOCOUNT */
-
DSI_I2C_ByteWrite(0x0168, 0x00000001, 6); /*PPI_D1S_CLRSIPOCOUNT */
-
DSI_I2C_ByteWrite(0x016c, 0x00000001, 6); /*PPI_D2S_CLRSIPOCOUNT */
-
DSI_I2C_ByteWrite(0x0170, 0x00000001, 6); /*PPI_D3S_CLRSIPOCOUNT */
-
#endif
-
/*Enabling MIPI & PPI lanes, Enable 4 lanes */
-
DSI_I2C_ByteWrite(0x0134, 0x0000001F, 6); /*PPI_LANEENABLE */
-
DSI_I2C_ByteWrite(0x0210, 0x0000001F, 6); /*DSI_LANEENABLE */
-
DSI_I2C_ByteWrite(0x0104, 0x00000001, 6); /*PPI_SARTPPI */
-
DSI_I2C_ByteWrite(0x0204, 0x00000001, 6); /*DSI_SARTPPI */
-
-
#ifdef FIXME_MLD
-
/*Setting LVDS output frequency */
-
DSI_I2C_ByteWrite(0x04A0, 0x00000006, 6); /*LVDS PHY Register 0 (LVPHY0) */
-
-
/*Calculating video panel control settings */
-
/*Setting video panel control register */
-
DSI_I2C_ByteWrite(0x0450, 0x00000130, 6); /*VPCTRL, Video Path Control, VTGen=ON */
-
-
/*Setting display timing registers */
-
DSI_I2C_ByteWrite(0x0454, 0x0064000A, 6); /*HTIM1, HBPR=100, HPW=10 */
-
-
DSI_I2C_ByteWrite(0x0458, 0x00BE0400, 6); /*HTIM2, HFPR=190, HDISPR=1024 */
-
DSI_I2C_ByteWrite(0x045c, 0x000F0005, 6); /*VTIM1, VBPR=15, VPW=5 */
-
DSI_I2C_ByteWrite(0x0460, 0x000F0258, 6); /*VTIM2, VFPR=15, VDISPR=600 */
- #else
-
/*Setting LVDS output frequency */
-
DSI_I2C_ByteWrite(0x04A0, 0x00048006, 6); /*LVDS PHY Register 0 (LVPHY0) */
-
-
/*Calculating video panel control settings */
-
/*Setting video panel control register */
-
DSI_I2C_ByteWrite(0x0450, 0x00000120, 6); /*VPCTRL, Video Path Control, VTGen=ON */
-
-
/*Setting display timing registers */
-
DSI_I2C_ByteWrite(0x0454, 0x00280028, 6); /*HTIM1, HBPR=100, HPW=10 */
-
-
DSI_I2C_ByteWrite(0x0458, 0x00500500, 6); /*HTIM2, HFPR=190, HDISPR=1024 */
-
DSI_I2C_ByteWrite(0x045c, 0x000e000a, 6); /*VTIM1, VBPR=15, VPW=5 */
-
DSI_I2C_ByteWrite(0x0460, 0x000e0320, 6); /*VTIM2, VFPR=15, VDISPR=600 */
-
#endif
-
-
DSI_I2C_ByteWrite(0x0464, 0x00000001, 6); /*VFUEN */
-
-
/*Setting LVDS bit arrangement */
-
DSI_I2C_ByteWrite(0x0480, 0x03020100, 6); /*LVMX0003 */
-
DSI_I2C_ByteWrite(0x0484, 0x08050704, 6); /*LVMX0407 */
-
DSI_I2C_ByteWrite(0x0488, 0x0F0E0A09, 6); /*LVMX0811 */
-
DSI_I2C_ByteWrite(0x048C, 0x100D0C0B, 6); /*LVMX1215 */
-
DSI_I2C_ByteWrite(0x0490, 0x12111716, 6); /*LVMX1619 */
-
DSI_I2C_ByteWrite(0x0494, 0x1B151413, 6); /*LVMX2023 */
-
DSI_I2C_ByteWrite(0x0498, 0x061A1918, 6); /*LVMX2427 */
-
-
#ifdef FIXME_MLD //DV0.9 changes
-
DSI_I2C_ByteWrite(0x049c, 0x00000101, 6); /*LVCFG */
-
#else
-
DSI_I2C_ByteWrite(0x049c, 0x00000001, 6); /*LVCFG */
-
#endif
-
-
DSI_I2C_ByteWrite(0x0288, 0xFFFFFFFF, 6); /*DSI_INTCLR */
-
-
lvds_disp_init = 1;
-
-
printk(KERN_INFO "[DISPLAY]%s: Exit\n", __func__);
-
-
}
3. panel on/off
- /* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_toshiba_bridge_panel_off
-
*
-
* DESCRIPTION: This function uses GPIO to turn OFF panel.
-
\* ************************************************************************* */
-
void dsi_lvds_toshiba_bridge_panel_off(void)
-
{
-
printk(KERN_INFO "[DISPLAY ] %s\n", __func__);
-
-
gpio_direction_output(GPIO_MIPI_LCD_STBYB, 0);
-
gpio_set_value_cansleep(GPIO_MIPI_LCD_STBYB, 0); /*Pull LCD_STBYB pin to Low */
-
mdelay(1);
-
-
gpio_direction_output(GPIO_MIPI_PANEL_RESET, 0);
-
gpio_set_value_cansleep(GPIO_MIPI_PANEL_RESET, 0);
-
mdelay(1);
-
}
-
-
/* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_toshiba_bridge_panel_on
-
*
-
* DESCRIPTION: This function uses GPIO to turn ON panel.
-
\* ************************************************************************* */
-
void dsi_lvds_toshiba_bridge_panel_on(void)
-
{
-
printk(KERN_INFO "[DISPLAY ] %s\n", __func__);
-
-
/* set following pin to low */
-
gpio_direction_output(GPIO_MIPI_LCD_STBYB, 0);
-
gpio_set_value_cansleep(GPIO_MIPI_LCD_STBYB, 0); /*Pull LCD_STBYB pin to Low */
-
-
gpio_direction_output(GPIO_MIPI_PANEL_RESET, 0);
-
gpio_set_value_cansleep(GPIO_MIPI_PANEL_RESET, 0);
-
-
gpio_direction_output(GPIO_MIPI_LCD_VADD, 0);
-
gpio_set_value_cansleep(GPIO_MIPI_LCD_VADD, 0);
-
-
gpio_direction_output(GPIO_MIPI_LCD_BIAS_EN, 0);
-
gpio_set_value_cansleep(GPIO_MIPI_LCD_BIAS_EN, 0);
-
mdelay(10);
-
-
/* STBYB */
-
gpio_direction_output(GPIO_MIPI_LCD_STBYB, 1);
-
gpio_set_value_cansleep(GPIO_MIPI_LCD_STBYB, 1); /*Pull LCD_STBYB pin to High */
-
mdelay(10);
-
-
/* VADD */
-
gpio_direction_output(GPIO_MIPI_LCD_VADD, 1);
- mdelay(50);
-
-
/* RESET */
-
gpio_direction_output(GPIO_MIPI_PANEL_RESET, 1);
-
gpio_set_value_cansleep(GPIO_MIPI_PANEL_RESET, 1);
-
mdelay(100);
-
-
/* BIAS */
-
gpio_direction_output(GPIO_MIPI_LCD_BIAS_EN, 1);
-
gpio_set_value_cansleep(GPIO_MIPI_LCD_BIAS_EN, 1);
-
-
}
4. init / deinit
- /* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_init_lvds_bridge
-
*
-
* DESCRIPTION: This function does all one time init. Currently defining
-
* GPIOs only.
-
\* ************************************************************************* */
-
void dsi_lvds_init_lvds_bridge(struct drm_device *dev)
-
{
-
/* request GPIOs */
-
gpio_request(GPIO_MIPI_BRIDGE_RESET, "display");
-
gpio_request(GPIO_MIPI_PANEL_RESET , "display");
-
gpio_request(GPIO_MIPI_LCD_STBYB, "display");
-
gpio_request(GPIO_MIPI_LCD_BIAS_EN, "display");
-
gpio_request(GPIO_MIPI_LCD_VADD, "display");
-
}
-
-
/* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_deinit_lvds_bridge
-
*
-
* DESCRIPTION: This function does is called during deinit time.
-
*
-
\* ************************************************************************* */
-
void dsi_lvds_deinit_lvds_bridge(struct drm_device *dev)
-
{
-
if (!lvds_disp_init) {
-
printk(KERN_ALERT "[DISPLAY ] %s has not initialized\n", __func__);
-
return;
-
}
-
-
printk(KERN_INFO "[DISPLAY ] Enter %s\n", __func__);
-
-
-
lvds_disp_init = 0;
-
}
5. get params
- /* ************************************************************************* *\
-
* FUNCTION: dsi_lvds_bridge_get_display_params
-
*
-
* DESCRIPTION: This function is a callback to get the panel resolution and
-
* timing settings.
-
*
-
\* ************************************************************************* */
-
void dsi_lvds_bridge_get_display_params(struct drm_display_mode *mode)
-
{
-
#ifdef FIXME_MLD // Changes for DV0.9 display
-
/* This settings is for 1024*600 panel*/
-
mode->hdisplay = 1024;
-
mode->vdisplay = 600;
-
mode->hsync_start = 1655;
-
mode->hsync_end = 1665;
-
mode->htotal = 1765;
-
mode->vsync_start = 615;
-
mode->vsync_end = 620;
-
mode->vtotal = 635;
-
mode->clock = 33324;
-
#else
-
mode->hdisplay = 1200;
-
mode->vdisplay = 800;
-
mode->hsync_start = 1360;
-
mode->hsync_end = 1400;
-
mode->htotal = 1440;
-
mode->vsync_start = 814;
-
mode->vsync_end = 824;
-
mode->vtotal = 838;
-
mode->clock = 33324;
-
#endif //end FIXME_MLD
-
-
printk(KERN_INFO "[DISPLAY]: hdisplay(w) is %d\n", mode->hdisplay);
-
printk(KERN_INFO "[DISPLAY]: vdisplay(h) is %d\n", mode->vdisplay);
-
printk(KERN_INFO "[DISPLAY]: HSS is %d\n", mode->hsync_start);
-
printk(KERN_INFO "[DISPLAY]: HSE is %d\n", mode->hsync_end);
-
printk(KERN_INFO "[DISPLAY]: htotal is %d\n", mode->htotal);
-
printk(KERN_INFO "[DISPLAY]: VSS is %d\n", mode->vsync_start);
-
printk(KERN_INFO "[DISPLAY]: VSE is %d\n", mode->vsync_end);
-
printk(KERN_INFO "[DISPLAY]: vtotal is %d\n", mode->vtotal);
-
printk(KERN_INFO "[DISPLAY]: clock is %d\n", mode->clock);
-
}
7. 具体动作: read / write
- /* ************************************************************************* *\
-
* FUNCTION: DSI_I2C_ByteRead
-
*
-
* DESCRIPTION: Local functions to read I2C registers
-
*
-
\* ************************************************************************* */
-
static int DSI_I2C_ByteRead(u16 reg, int count)
-
{
-
if (dsi_lvds_inst->client)
-
return __DSI_I2C_ByteRead(reg, count);
-
else
-
return -EIO;
-
}
- /* ************************************************************************* *\
-
* FUNCTION: __DSI_I2C_ByteRead
-
*
-
* DESCRIPTION: Local functions to process read req for I2C registers
-
*
-
\* ************************************************************************* */
-
static int __DSI_I2C_ByteRead(u16 reg, int count)
-
{
-
char rxData[4] = {0};
-
char regData[2] = {0};
-
struct i2c_msg msgs[] = {
-
{
-
.addr = dsi_lvds_inst->client->addr,
-
.flags = 0,
-
.len = 2,
-
},
-
{
-
.addr = dsi_lvds_inst->client->addr,
-
.flags = I2C_M_RD,
-
.len = count - 2,
-
},
-
};
-
-
regData[0] = (reg & 0xFF00) >> 8;
-
regData[1] = reg & 0xFF;
-
-
msgs[0].buf = regData;
-
msgs[1].buf = rxData;
-
-
printk(KERN_INFO "Register: 0x%x\n", reg);
-
if (i2c_transfer(dsi_lvds_inst->client->adapter, msgs, 2) < 0) {
-
printk(KERN_ERR "[DISPLAY] %s: transfer error\n", __func__);
-
return -EIO;
-
} else if (count > 2) {
-
int i = 0;
-
for (i = count - 3; i > -1; --i)
-
printk(KERN_INFO "%02x ", rxData[i]);
-
printk(KERN_INFO "\n");
-
return rxData[0];
-
}
-
return 0;
-
}
- /* ************************************************************************* *\
-
* FUNCTION: DSI_I2C_ByteWrite
-
*
-
* DESCRIPTION: Local functions to issue write req for I2C registers
-
*
-
\* ************************************************************************* */
-
static int DSI_I2C_ByteWrite(u16 reg, u32 data, int count)
-
{
-
if (dsi_lvds_inst->client)
-
return __DSI_I2C_ByteWrite(reg, data, count);
-
else
-
return -EIO;
-
}
- /* ************************************************************************* *\
-
* FUNCTION: __DSI_I2C_ByteWrite
-
*
-
* DESCRIPTION: Local functions to process write req for I2C registers
-
*
-
\* ************************************************************************* */
-
static int __DSI_I2C_ByteWrite(u16 reg, u32 data, int count)
-
{
-
char txData[6] = {0};
-
struct i2c_msg msg[] = {
-
{
-
.addr = dsi_lvds_inst->client->addr,
-
.flags = 0,
-
.len = count,
-
},
-
};
-
-
/*Set the register */
-
txData[0] = (reg & 0xFF00) >> 8;
-
txData[1] = reg & 0xFF;
-
-
if (count == 6) {
-
/*Set the data */
-
txData[2] = (data & 0xFF);
-
txData[3] = (data & 0xFF00) >> 8;
-
txData[4] = (data & 0xFF0000) >> 16;
-
txData[5] = (data & 0xFF000000) >> 24;
-
} else {
-
/* Not valid for this bridge chipset */
-
}
-
-
printk(KERN_INFO "[DISPLAY] %s: addr = %x, reg = %x, data = %x\n",
-
__func__, dsi_lvds_inst->client->addr, reg, data);
-
-
msg[0].buf = txData;
-
-
if (i2c_transfer(dsi_lvds_inst->client->adapter, msg, 1) < 0) {
-
printk(KERN_ERR "[DISPLAY] %s: transfer error\n", __func__);
-
return -EIO;
-
} else {
-
return 0;
-
}
-
}
|
|