/*
* Copyright (c) 2016, Sun Mi Electronics Co., Ltd
* Author: Yong Zhu
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* Some ideas are from chrome ec and fairchild GPL fusb302 driver.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MIPI2LVDS_I2C_DRIVER_NAME "TC358774XBG_75XBG"
#define MIPI2LVDS_I2C_DEVICETREE_NAME "TC358774XBG_75XBG"
#define ENDMARKER { 0xffff, 0xffffffff}
struct mipi2lvds_chip {
struct i2c_client *client;
struct device *dev;
struct regmap *regmap;
};
struct mipi2lvds_reg {
unsigned int reg;
unsigned int val;
unsigned int dly;
};
struct i2c_client *this_client;
struct regmap_config dsi2lvds_regmap_config = {
.reg_bits = 16,
.val_bits = 32,
.cache_type = REGCACHE_RBTREE,
//数据位,先发送低位,再发送高位
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
struct mipi2lvds_reg mipi2lvds_init_table[]=
{
{0x013C,0x000A000C,0},
{0x0114,0x00000008,0},
{0x0164,0x0000000D,0},
{0x0168,0x0000000D,0},
{0x016C,0x0000000D,0},
{0x0170,0x0000000D,0},
{0x0134,0x0000001F,0},
{0x0210,0x0000001F,0},
{0x0104,0x00000001,0},
{0x0204,0x00000001,0},
{0x0450,0x03F00120,0},
{0x0454,0x003C0014,0},
{0x0458,0x00C80780,0},
{0x045C,0x000C0008,0},
{0x0460,0x001A0438,0},
{0x0464,0x00000001,0},
{0x04A0,0x00448006,100},
{0x04A0,0x00048006,0},
{0x0504,0x00000004,0},
{0x0480,0x03020100,0},
{0x0484,0x08050704,0},
{0x0488,0x0F0E0A09,0},
{0x048C,0x100D0C0B,0},
{0x0490,0x12111716,0},
{0x0494,0x1B151413,0},
{0x0498,0x061A1918,0x14},
{0x049C,0x00000263,0x78},
ENDMARKER,
};
void dsi2lvds_init(void)
{
struct mipi2lvds_chip *chip;
int i = 0;
int ret = 0;
chip = i2c_get_clientdata(this_client);
while (mipi2lvds_init_table[i].reg != 0xffff) {
ret = regmap_write(chip->regmap, mipi2lvds_init_table[i].reg, mipi2lvds_init_table[i].val);
if(ret < 0)
{
printk("%s failed index = %d\n",__func__,i);
}
if(mipi2lvds_init_table[i].dly != 0x0)
udelay(mipi2lvds_init_table[i].dly);
i++;
}
}
static int dsi2lvds_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mipi2lvds_chip *chip;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->dev = &client->dev;
chip->regmap = devm_regmap_init_i2c(client, &dsi2lvds_regmap_config);
if (IS_ERR(chip->regmap)) {
dev_err(&client->dev, "Failed to allocate regmap!\n");
return PTR_ERR(chip->regmap);
}
this_client = client;
i2c_set_clientdata(client, chip);
dsi2lvds_init();
dev_info(chip->dev,"%s success\n",__func__);
return 0;
}
static const struct of_device_id dsi2lvds_dt_match[] = {
{ .compatible = MIPI2LVDS_I2C_DEVICETREE_NAME },
{},
};
MODULE_DEVICE_TABLE(of, dsi2lvds_dt_match);
static const struct i2c_device_id dsi2lvds_i2c_device_id[] = {
{ MIPI2LVDS_I2C_DRIVER_NAME, 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, dsi2lvds_i2c_device_id);
static struct i2c_driver dsi2lvds_driver = {
.driver = {
.name = MIPI2LVDS_I2C_DRIVER_NAME,
.of_match_table = of_match_ptr(dsi2lvds_dt_match),
},
.probe = dsi2lvds_probe,
.id_table = dsi2lvds_i2c_device_id,
};
module_i2c_driver(dsi2lvds_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("yong zhu " );
MODULE_DESCRIPTION("mipi2lvds driver");
&i2c4 {
status = "okay";
i2c-scl-rising-time-ns = <475>;
i2c-scl-falling-time-ns = <26>;
//这里的0xf是对应的7位I2C地址
lvds_bridge: tc358774X@f {
compatible = "TC358774XBG_75XBG";
reg = <0x0f>;
status = "okay";
};
};
这里面特别要留意下面:
struct regmap_config dsi2lvds_regmap_config = {
.reg_bits = 16,
.val_bits = 32,
.cache_type = REGCACHE_RBTREE,
//数据位,先发送低位,再发送高位
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
如果REGMAP_ENDIAN_LITTLE被配置意味着,寄存器的地址或者数据是先发送低位再发送高位。这个的配置需要查看芯片的Datasheet,如下:
从上面可以得知:
寄存器的地址发送保持默认,即先发送高位再发送低位; —–REGMAP_ENDIAN_BIG
寄存器的数据则是先发送低位再发送高位; ——REGMAP_ENDIAN_LITTLE
-