Linux I2C framework(3) -- I2C consumer driver

本文详细介绍了在嵌入式系统中I2C总线的两种设备形态及其DTS描述方法,重点讲解了如何根据设备形态编写I2C slave设备驱动程序,包括设备在DTS中的描述规范、驱动程序的编写步骤以及核心APIs的使用。
  • 编写I2C slave device驱动程序

1.i2c slave device形态

  嵌入式系统I2C总线上连接的slave device,有两种形态,如下:
在这里插入图片描述

  • CPU和设备之间的所有数据交互,都是通过I2C总线进行,没有其它方式,如PMIC、Audio codec等。

  • I2C只是CPU和设备之间进行数据交互的一种,例如HDMI,图像以及音频数据通过TDMS接口传输,EDID等信息的交互通过I2C总线(在HDMI协议中称作DDC接口)。

设备形态决定设备在设备模型中的位置:

  • 形态1,以PMIC为例,可以把它看作I2C bus上的一个设备;
  • 形态2,以TV为例,它一部分功能可看作I2C bus上的一个设备,另一部分是却是platform bus(HDMI Controller)上的一个设备,它的设备驱动要怎么写?一般是以其主要功能为准,TV的主要功能明显是音视频传输,因此应该当做一个platform设备。

2.DTSI settings

  在设备模型中的位置不同,最终体现在DTS的描述方式不同。

  • 形态1,pmic的DTS node是i2c1的一个child node,I2C core负责该设备的创建和注册,以及和其driver的probe等操作:
/* arch/arm/boot/dts/imx6dl-riotboard.dts */
&i2c1 { 
        clock-frequency = <100000>; 
        pinctrl-names = "default"; 
        pinctrl-0 = <&pinctrl_i2c1>; 
        status = "okay"; 
        … 
        pmic: pf0100@08 { 
                compatible = "fsl,pfuze100"; 
                … 
        }; 
        ... 
}; 
  • 形态2,hdmi的DTS node位于根目录,作为platform device存在,它的DDC功能所使用的i2c2,是以一个变量的形式引用的:
/* arch/arm/boot/dts/imx6dl-riotboard.dts */
&hdmi { 
       ddc-i2c-bus = <&i2c2>; 
       status = "okay"; 
};

3.编写步骤(形态1)

  • 根据硬件的连接方式,确定该设备所从属的I2C controller(即I2C adapter)。

  • 在I2C adapter的DTS node中,添加该设备的DTS描述,其格式和正常的platform device一致。

  • DTS描述中的compatible关键字用于设备和驱动的probe,如“compatible = “fsl,pfuze100”;”,其它字段根据实际情况自行添加。

  • 编写该设备的驱动程序,完成如下内容(如drivers/regulator/pfuze100-regulator.c):

    • 定义一个struct i2c_driver类型的变量,并调用module_i2c_driver接口将其注册到I2C core中。

    • 该变量包含应包含一个DTS中的“compatible ”字段相同的of_match_table,以及一个probe接口。

  • 由“Linux I2C framework(2)- I2C provider”的描述可知,I2C framework core会在每一个I2C adapter注册时,为它下面所有的slave device创建struct i2c_client结构,并匹配对应的struct i2c_driver变量,调用driver的probe接口

  • i2c_driver的probe接口的输入参数是struct i2c_client类型的指针(代表I2C slave device),以struct i2c_client指针为参数,可以调用i2c_master_send/i2c_master_recv接口进行简单的I2C传输,同时,也可以通过该指针获得所属的I2C adapter指针,然后通过i2c_transfer接口,进行更为复杂的read、write操作(可参考“drivers/base/regmap/regmap-i2c.c”中的regmap_i2c_read接口)。

4.相关APIs

  • i2c_register_driver
  • i2c_del_driver

4.1.i2c_register_driver

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
    int res;

    /* add the driver to the list of i2c drivers in the driver core */
    driver->driver.owner = owner;
    driver->driver.bus = &i2c_bus_type;    // 设置驱动的注册总线 i2c_bus_type

    /* When registration returns, the driver core
     * will have called probe() for all matching-but-unbound devices.
     */
    res = driver_register(&driver->driver);    // 注册进kernel设备驱动框架

    pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

    INIT_LIST_HEAD(&driver->clients);
    /* Walk the adapters that are already present */
    i2c_for_each_dev(driver, __process_new_driver);   // 轮询 i2c_bus_type 下的所有设备,并匹配驱动
    return 0;
}

分析 __process_new_driver:

static int __process_new_driver(struct device *dev, void *data)
{
    if (dev->type != &i2c_adapter_type)    // 非 i2c_adapter 不能进一步处理
        return 0;
    return i2c_do_add_adapter(data, to_i2c_adapter(dev));    // 根据该驱动支持的address list,探测,创建并注册相应的i2c_client
}

参考代码:

  • drivers/mfd/rk808.c
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值