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 };
原文:https://www.cnblogs.com/timemachine213/p/12823562.html