内核默认支持模拟i2c,那应该怎么用呢,参考i2c-gpio.txt « i2c « bindings « devicetree « Documentation - kernel/git/torvalds/linux.git - Linux kernel source tree 是不是跟平常用的硬件i2c dts配置很类似呢
aliases {
i2c8 = &i2c8;
}
i2c8:i2c8 {
compatible = "i2c-gpio";
gpios = <&pio 23 0 /* sda */
&pio 24 0 /* scl */
>;
i2c-gpio,sda-open-drain;
i2c-gpio,scl-open-drain;
i2c-gpio,delay-us = <2>; /* ~100 kHz */
#address-cells = <1>;
#size-cells = <0>;
rv3029c2@56 {
compatible = "rv3029c2";
reg = <0x56>;
};
};
如果平台也有i2c8,需要将平台对应的i2c屏蔽掉,同时引脚配置成普通gpio模式,主要引脚还是要上拉哦。
i2c8的应该根据实际的主板情况配置而来,因为系统可能默认有了i2c0,i2c1等,如果这里不指定第几条总线,系统原本的硬件i2c注册会有问题。
同时加上
CONFIG_I2C_GPIO=y
CONFIG_I2C_ALGOBIT=y
i2c8 = &i2c8这个有什么作用呢,看pdeev->id默认是-1,然后获取i2c属性或者具体的总线。
#define PLATFORM_DEVID_NONE (-1)
int of_device_add(struct platform_device *ofdev)
{
...
ofdev->id = PLATFORM_DEVID_NONE;
...
}
static int i2c_gpio_probe(struct platform_device *pdev)
{
...
adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
...
}
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
...
if (adap->nr == -1) /* -1 means dynamically assign bus id */
return i2c_add_adapter(adap);
...
}
int i2c_add_adapter(struct i2c_adapter *adapter)
{
struct device *dev = &adapter->dev;
int id;
if (dev->of_node) {
id = of_alias_get_id(dev->of_node, "i2c");
if (id >= 0) {
adapter->nr = id;
return __i2c_add_numbered_adapter(adapter);
}
}
...
}
drivers/i2c/busses/i2c-gpio.c 注册i2c总线
drivers/i2c/algos/i2c-algo-bit.c 实现模拟i2c协议
const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
.functionality = bit_func,
};
static int __i2c_bit_add_bus(struct i2c_adapter *adap,int (*add_adapter)(struct i2c_adapter *))
{
adap->algo = &i2c_bit_algo;
ret = add_adapter(adap);
}
int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
{
return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
}
EXPORT_SYMBOL(i2c_bit_add_numbered_bus);
使用平台的有点差异(sprd/mtk),要获取sda的电平,先要设置成输入状态,按如下修改
static int i2c_gpio_getsda(void *data)
{
struct i2c_gpio_platform_data *pdata = data;
-
- return gpio_get_value(pdata->sda_pin);
+ int state;
+ gpio_direction_input(pdata->sda_pin);
+ state=gpio_get_value(pdata->sda_pin);
+ gpio_direction_output(pdata->sda_pin,1);
+ return state;
}
是不是瞬间就搞定了呢,i2c驱动用硬件的i2c驱动就行了。