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

来源:互联网 发布:veket linux安装 编辑:程序博客网 时间:2024/05/29 09:12

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

这里写图片描述

  script.bin里的i2c控制器配置 :[twi0]twi_used = 1twi_scl = port:PA11<2><default><default><default>twi_sda = port:PA12<2><default><default><default>[twi1]twi_used = 1twi_scl = port:PA18<3><default><default><default>twi_sda = port:PA19<3><default><default><default>[twi2]twi_used = 0twi_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; i<SUNXI_TWI_NUM; i++)  //SUNXI_TWI_NUM是表示twi控制器的个数, 现内核里宏的值是3#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; i<SUNXI_TWI_NUM; i++) { // 初始化每个平台设备,及它的资源,平台数据。 i表示第几个控制器        //准备平台设备所用的资源. twi控制器的配置寄存器的开始地址,结束地址.1391         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);
原创粉丝点击