二、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 };

猜你喜欢

转载自www.cnblogs.com/timemachine213/p/12823562.html