54 OrangePi linux内核里的i2c控制器驱动

在全志H3平台里的”TWI Controller”就是I2C控制器. 共有4个i2c控制器

54 OrangePi linux内核里的i2c控制器驱动_第1张图片

  script.bin里的i2c控制器配置 :
[twi0]
twi_used = 1
twi_scl = port:PA11<2><default><default><default>
twi_sda = port:PA12<2><default><default><default>

[twi1]
twi_used = 1
twi_scl = port:PA18<3><default><default><default>
twi_sda = port:PA19<3><default><default><default>

[twi2]
twi_used = 0
twi_scl = port:PE12<3><default><default><default>
twi_sda = port:PE13<3><default><default><default>

在linux内核里控制器的驱动是由芯片厂商负责, 而且控制器的驱动都是平台驱动来的.需要用平台设备来描述i2c控制器的硬件信息,如控制器的配置寄存器基地址, 中断号等. 在内核里,可能只会驱动好部分控制器.如SOC里共有4个控制器,需要4个平台设备来分别描述每个控制器的硬件资源, 内核里有可能只写两个相关的平台设备,如需用额外两个控制器,我们则需用平台设备描述好额外两个控制器才可以.

   make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

   Device Drivers  --->
    <*> I2C support  ---> 
        I2C Hardware Bus support  --->  
            <*> SUNXI I2C controller  //全志twi控制器的驱动
            <*>   I2C device interface //选上此项,i2c控制器驱动好后会在/dev目录下有设备文件i2c-*, 供应用程序调用控制器用. 我们也可以通过产生的设备文件得知相应的控制器是否驱动好

/
控制器的驱动源码在”drivers/i2c/busses/i2c-sunxi.c”
全志控制器的驱动代码不是很规范,控制器的平台驱动与平台设备都在i2c-sunxi.c里,并没有按驱动模型分层的实现.

1589 subsys_initcall(sunxi_i2c_adap_init); //初始化函数

static int __init sunxi_i2c_adap_init(void)
{
    ...
    sunxi_twi_device_scan(); //初始化平台设备 sunxi_twi_device[SUNXI_TWI_NUM]
    twi_chan_cfg(sunxi_twi_pdata); //根据script.bin里的twi_used子键的配置来用全局变量twi_used_mask来记录相应的控制器是否使用.

#ifdef CONFIG_EVB_PLATFORM  //此宏成立
    for (i=0; i3
#else
    i = CONFIG_TWI_CHAN_NUM; /* In FPGA, only one channel is available. */
#endif
    {    
        if (twi_chan_is_enable(i)) {  //如果第i个twi控制器需要使用,则注册相应的平台设备.
            I2C_DBG("Sunxi I2C init channel %d \n", i);
            ret = platform_device_register(&sunxi_twi_device[i]);
        ...
    }

    if (twi_used_mask) //只有一个以上的控制器的平台设备是使用,则注册控制器的平台驱动
        return platform_driver_register(&sunxi_i2c_driver); // sunxi_i2c_driver是控制器的平台驱动
    ...

    return 0;
}
内核里分别用三个数组来表示每个控制器的资源,平台数据,平台设备.
1378 static struct resource sunxi_twi_resources[SUNXI_TWI_NUM * SUNXI_TWI_RES_NUM];
1379 static struct sunxi_i2c_platform_data sunxi_twi_pdata[SUNXI_TWI_NUM];
1380 static struct platform_device sunxi_twi_device[SUNXI_TWI_NUM];
1382 static void sunxi_twi_device_scan(void)  //初始化平台设备 sunxi_twi_device[SUNXI_TWI_NUM]
1383 {
1384     int i;
        ...
1389 
1390     for (i=0; i1391         sunxi_twi_resources[i * SUNXI_TWI_RES_NUM].start = SUNXI_TWI_MEM_START(i);
1392         sunxi_twi_resources[i * SUNXI_TWI_RES_NUM].end   = SUNXI_TWI_MEM_END(i);
1393         sunxi_twi_resources[i * SUNXI_TWI_RES_NUM].flags = IORESOURCE_MEM;
        ...  

1398        //准备平台设备所用的平台数据
1399         sunxi_twi_pdata[i].bus_num   = i;
1400         sunxi_twi_pdata[i].frequency = SUNXI_TWI_SPEED(i); //i2c传输的标准速率100Kbsp, 高速400Kbsp.  这里的值是200Kbsp.
1401 
        //初始化平台设备
1402         sunxi_twi_device[i].name = SUNXI_TWI_DEV_NAME; // "twi"
1403         sunxi_twi_device[i].id   = i;
1404         sunxi_twi_device[i].resource = &sunxi_twi_resources[i * SUNXI_TWI_RES_NUM];
1405         sunxi_twi_device[i].num_resources = SUNXI_TWI_RES_NUM;
1406         sunxi_twi_device[i].dev.platform_data = &sunxi_twi_pdata[i];
1407         sunxi_twi_device[i].dev.release = sunxi_i2c_release;
1408     }

///

1368 static struct platform_driver sunxi_i2c_driver = { //控制器的平台驱动
1369     .probe      = sunxi_i2c_probe,
1370     .remove     = __devexit_p(sunxi_i2c_remove),
1371     .driver     = {
1372         .name   = SUNXI_TWI_DEV_NAME, // "twi",与平台设备是按名字匹配
1373         .owner  = THIS_MODULE,
1374         .pm     = SUNXI_I2C_DEV_PM_OPS,
1375     },
1376 };

/// 在linux内核里,i2c控制器驱动好后用struct i2c_adapter的一个对象来描述.
"include/linux/i2c.h"
struct i2c_adapter {
    struct module *owner;
    const struct i2c_algorithm *algo; //传输的协议,内核里已经实现好
    void *algo_data;

    ...
    int timeout;            /* in jiffies */
    int retries;    // i2c协议要求发出8位数据后,应由接收方回个应答。如没有收到应答,重新尝试的次数.
    struct device dev;      //i2c_adapter也是基于device结构体来扩展的. 所以每个i2c_adapter的对象也可以在/sys目录下有相应的子目录

    int nr; //控制器的序号,一般由控制器的平台设备的id指定
    ...
};


//基本上每个芯片厂家都会在i2c_adapter基础上扩展出一个自己封装的类型. 控制器的驱动是芯片厂商负责的,所以不用过多关注
  67 struct sunxi_i2c {
  68     int                 bus_num;
  69     unsigned int        status; /* start, running, idle */
  70     unsigned int        suspended:1;
  71     struct i2c_adapter  adap; //基于它扩展,内核里会管理adap成员的地址。只要得到此成员的地址,即可得出sunxi_i2c结构体对象的首地址
  72 
    ...
  92 };


1154 static int __devinit sunxi_i2c_probe(struct platform_device *pdev)
1155 {
1156     struct sunxi_i2c *i2c = NULL;
1157     struct resource *res = NULL;
1158     struct sunxi_i2c_platform_data *pdata = NULL;
1159     int ret, irq;
1160 
1161     pdata = pdev->dev.platform_data;

1166     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1167     irq = platform_get_irq(pdev, 0);
        ...
1172     if (!request_mem_region(res->start, resource_size(res), res->name)) {
1173         return -ENOMEM;
1174     }
1175 
1176     i2c = kzalloc(sizeof(struct sunxi_i2c), GFP_KERNEL);
        ... //i2c_adapter对象的初始化
1182     i2c->adap.owner   = THIS_MODULE;
1183     i2c->adap.nr      = pdata->bus_num; //
1184     i2c->adap.retries = 3;
1185     i2c->adap.timeout = 5*HZ;
1186     i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
1187     i2c->bus_freq     = pdata->frequency;
1188     i2c->irq          = irq;
1189     i2c->bus_num      = pdata->bus_num;
1190     i2c->status       = I2C_XFER_IDLE;
1191     i2c->suspended = 0;
        ...
1212 
1213     i2c->adap.algo = &sunxi_i2c_algorithm; //传输的具体实现方法由芯片厂商实现。
1221     i2c->adap.dev.parent = &pdev->dev;
1222 
1223     if (sunxi_i2c_hw_init(i2c, pdata)) {
1224         ret = -EIO;
1225         goto ehwinit;
1226     }
1227 
1228     ret = i2c_add_numbered_adapter(&i2c->adap); //里面就是调用i2c_register_adapter(&i2c->adap)注册i2c控制器对象
1229     if (ret < 0) {
1230         I2C_ERR( "[i2c%d] failed to add adapter\n", i2c->bus_num);
1231         goto eadapt;
1232     }
1233 


static int i2c_register_adapter(struct i2c_adapter *adap) //注册i2c_adapter对象时触发
{
    int res = 0;
    ...
    /* Set default timeout to 1 second if not already set */
    if (adap->timeout == 0)
        adap->timeout = HZ;

    dev_set_name(&adap->dev, "i2c-%d", adap->nr);
    adap->dev.bus = &i2c_bus_type; // i2c_adapter对象的device成员挂载到名为"i2c"的总线下, 所以在"/sys/bus/i2c/"目录下会有i2c_adapter对象的子目录, 目录名为"i2c-%d"

    adap->dev.type = &i2c_adapter_type;
    res = device_register(&adap->dev);
    ...
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);  

    /* Notify drivers */
    mutex_lock(&core_lock);
    bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
    mutex_unlock(&core_lock);

你可能感兴趣的:(OrangePi,H3,Linux设备驱动开发)