• 二、I.MX6Q I2C适配器驱动


      1 I.X6Q的I2C适配器驱动(3.0.35版本内核)
      2 入口函数(可以预知I2C总线内部也是platform总线)
      3 static int __init i2c_adap_imx_init(void)
      4 {
      5     return platform_driver_probe(&i2c_imx_driver, i2c_imx_probe);
      6 }
      7 
      8 static struct platform_driver i2c_imx_driver = {
      9     .remove        = __exit_p(i2c_imx_remove),
     10     .driver    = {
     11         .name    = DRIVER_NAME,
     12         .owner    = THIS_MODULE,
     13     }
     14     //这个驱动没有使用id匹配表吗??为什么?
     15 };
     16 
     17 跳转分析i2c_imx_probe(当设备和驱动得到匹配的时候,这个函数得到调用)
     18 static int __init i2c_imx_probe(struct platform_device *pdev)
     19 {
     20     ...
     21     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);    //获取资源
     22     ...
     23     irq = platform_get_irq(pdev, 0);                        //获取中断号
     24     ...
     25     //得到I2C适配器地址并映射成虚拟地址
     26     res_size = resource_size(res);
     27 
     28     if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
     29         ret = -EBUSY;
     30         goto fail0;
     31     }
     32 
     33     base = ioremap(res->start, res_size);
     34     ...
     35     //NXP使用imx_i2c_struct结构体来表示I.MX系列SOC的I2C控制器
     36     //设置adapter(控制器)
     37     strcpy(i2c_imx->adapter.name, pdev->name);
     38     i2c_imx->adapter.owner        = THIS_MODULE;
     39     i2c_imx->adapter.algo        = &i2c_imx_algo;//设置i2c通信算法函数
     40     i2c_imx->adapter.dev.parent    = &pdev->dev;
     41     i2c_imx->adapter.nr         = pdev->id;
     42     i2c_imx->irq                = irq;
     43     i2c_imx->base                = base;            //前面得到地址映射了(赋值I2C控制器的虚拟地址)
     44     i2c_imx->res                = res;
     45     ...
     46     /* Request IRQ *///注册中断,i2c_imx_isr是中断处理函数
     47     ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx);
     48     ...
     49     init_waitqueue_head(&i2c_imx->queue);        //初始化队列头
     50 
     51     /* Set up adapter data */
     52     i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
     53     ...
     54     /* Set up chip registers to defaults */
     55     writeb(0, i2c_imx->base + IMX_I2C_I2CR);
     56     writeb(0, i2c_imx->base + IMX_I2C_I2SR);
     57 
     58     /* Add I2C adapter */
     59     ret = i2c_add_numbered_adapter(&i2c_imx->adapter);//向内核注册初始化好的I2C适配器,这个函数在i2c-core.c文件里面定义(属于Linux平台的函数,跟具体的芯片无关)
     60     ...
     61     /* Set up platform driver data */
     62     platform_set_drvdata(pdev, i2c_imx);
     63     //4.0.15版本的内核,NXP是支持I2C使用DMA的,但是3.0.35好像不支持
     64     return 0;   /* Return OK */
     65 }
     66 整体上看,i2c_imx_probe函数就就只做了一件事情,就是获取I2C资源信息然后初始化I2C适配器,向内核注册初始化好的I2C适配器。
     67 前面i2c_imx->adapter.algo        = &i2c_imx_algo;//设置i2c通信算法函数
     68 我们转去看一下这个函数
     69 static struct i2c_algorithm i2c_imx_algo = {
     70     .master_xfer    = i2c_imx_xfer,//通过这个函数来完成和I2C器件的通信
     71     .functionality    = i2c_imx_func,//这个函数用于返回i2c支持什么通信协议
     72 };
     73 
     74 //看一下这个传输函数i2c_imx_xfer
     75 static int i2c_imx_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
     76 {
     77     ...
     78     //开启i2c通信
     79     result = i2c_imx_start(i2c_imx);
     80     ...
     81     /* read/write data *///没有看明白这个操作的含义
     82     for (i = 0; i < num; i++) {
     83         if (i) {
     84             temp = readb(i2c_imx->base + IMX_I2C_I2CR);
     85             temp |= I2CR_RSTA;
     86             writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
     87             result =  i2c_imx_bus_busy(i2c_imx, 1);
     88             if (result)
     89                 goto fail0;
     90         }
     91         ...
     92     }
     93 
     94     //NXP在4.0.15版本的内核还支持i2使用dma来写的方式
     95         if (msgs[i].flags & I2C_M_RD)                 //如果是读数据
     96             result = i2c_imx_read(i2c_imx, &msgs[i]);//读数据,数据类型是struct i2c_msg *msgs
     97         else
     98             result = i2c_imx_write(i2c_imx, &msgs[i]);//写数据,数据类型是struct i2c_msg *msgs
     99         if (result)
    100             goto fail0;
    101 
    102         /* Stop I2C transfer */
    103     i2c_imx_stop(i2c_imx);//停止i2c通信
    104 }
    105 //分析I2C读写函数
    106 static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
    107 {
    108     ...
    109     writeb((msgs->addr << 1) | 0x01, i2c_imx->base + IMX_I2C_I2DR);    //发送i2c器件地址,同时发送0x01,表示读数据
    110     result = i2c_imx_trx_complete(i2c_imx);                            //判断发送是否完成
    111     if (result)
    112         return result;
    113     result = i2c_imx_acked(i2c_imx);                                //等待应答
    114     if (result)
    115         return result;
    116     /* setup bus to read data */
    117     temp = readb(i2c_imx->base + IMX_I2C_I2CR);
    118     temp &= ~I2CR_MTX;
    119     if (msgs->len - 1)
    120         temp &= ~I2CR_TXAK;
    121     writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
    122     readb(i2c_imx->base + IMX_I2C_I2DR); /* dummy read */
    123 
    124     //使用循环来读取数据
    125     for (i = 0; i < msgs->len; i++) {
    126         result = i2c_imx_trx_complete(i2c_imx);
    127         if (result)
    128             return result;
    129         //如果读到最后一个数据,则先i2c_imx->stopped = 1;
    130         if (i == (msgs->len - 1)) {
    131             /* It must generate STOP before read I2DR to prevent
    132                controller from generating another clock cycle */
    133             temp = readb(i2c_imx->base + IMX_I2C_I2CR);
    134             temp &= ~(I2CR_MSTA | I2CR_MTX);
    135             writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
    136             i2c_imx_bus_busy(i2c_imx, 0);
    137             i2c_imx->stopped = 1;
    138         } else if (i == (msgs->len - 2)) {
    139             temp = readb(i2c_imx->base + IMX_I2C_I2CR);
    140             temp |= I2CR_TXAK;
    141             writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
    142         }
    143         //把数据读取到msgs->buf中
    144         msgs->buf[i] = readb(i2c_imx->base + IMX_I2C_I2DR);
    145     }
    146     return 0;
    147 }
    148 
    149 
    150 static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
    151 {
    152     ...
    153     writeb(msgs->addr << 1, i2c_imx->base + IMX_I2C_I2DR);    //发送要写入数据的寄存器地址
    154     result = i2c_imx_trx_complete(i2c_imx);                    //判断传输是否完成
    155     if (result)
    156         return result;
    157     result = i2c_imx_acked(i2c_imx);                        //等待应答
    158     if (result)
    159         return result;
    160 
    161     //使用循环来向数据寄存器写数据
    162     for (i = 0; i < msgs->len; i++) {
    163         writeb(msgs->buf[i], i2c_imx->base + IMX_I2C_I2DR);    //循环将数据写到数据I2C的数据寄存器当中
    164         result = i2c_imx_trx_complete(i2c_imx);                //判断传输是否完成
    165         if (result)
    166             return result;
    167         result = i2c_imx_acked(i2c_imx);                    //等待应答
    168         if (result)
    169             return result;
    170     }
    171     return 0;
    172 }
    173 //i2c传输的信息结构
    174 struct i2c_msg {
    175     __u16 addr;    //地址
    176     __u16 flags;//读写标志
    177     ...
    178     __u16 len;    //读写的长度
    179     __u8 *buf;    //指向要发送的数据地址
    180 };
    181 
    182 //下面这段代码是在4.0.15版本的内核出现的,3.0.35版本的内核并没有,请问怎么进行设备和驱动的匹配呢?
    183 static struct platform_device_id imx_i2c_devtype[] = {
    184     {
    185         .name = "imx1-i2c",
    186         .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
    187     },
    188     {
    189         .name = "imx21-i2c",
    190         .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
    191     },
    192     {
    193         /* sentinel */
    194     }
    195 };
  • 相关阅读:
    [Swift]数学库函数math.h | math.h -- mathematical library function
    [Swift]LeetCode492. 构造矩形 | Construct the Rectangle
    FansMail:邮件发送标准API与技术实现(Java)
    FansMail:邮件发送标准API与技术实现(Java)
    大话世界格局:春秋五霸与战国七雄
    大话世界格局:春秋五霸与战国七雄
    大家好,我是FansUnion,雷文
    大家好,我是FansUnion,雷文
    2013年总结(2)-财务收入与支出
    2013年总结(2)-财务收入与支出
  • 原文地址:https://www.cnblogs.com/timemachine213/p/12823562.html
Copyright © 2020-2023  润新知