I2C使用参考


1. 概述

I2C Group DEV
HW I2C group0 /dev/i2c-0
HW I2C group1 /dev/i2c-1
HW I2C group2 /dev/i2c-2
HW I2C group3 /dev/i2c-3

设备节点和硬件组别的关系如上表所示。

2. DTS定义

1.  i2c0@0 {  
2.      compatible = "sstar,i2c";  
3.      reg = <0x1F222800 0x200>;  
4.      #address-cells = <1>;  
5.      #size-cells = <0>;  
6.      interrupts = <GIC_SPI INT_IRQ_MIIC IRQ_TYPE_LEVEL_HIGH>;  
7.      clocks = <&CLK_miic0>;  
8.      i2c-group = <0>;  
9.      i2c-en-dma = <1>;  
10.     i2c-speed = <400000>;  
11.     status = "ok";  
12. }

I2C master驱动中支持配置的属性如下表所示:

属性 描述 备注
compatible 用于匹配驱动进行驱动注册,需与代码中一致 禁止修改
reg 用于指定IIC寄存器bank的地址 不需要修改
interrupts 用于指定使用的硬件中断号及属性 不需要更改
clocks 用于指定使用的时钟源 不需要更改
#address-cells 用于指定子节点的地址位宽 不需要更改
#size-cells 用于指定子节点的大小位宽 不需要更改
i2c-group 用于指定IIC外设编号序列号 不需要修改
i2c-speed 用于选择IIC Speed无该属性时,默认设定为400kHz 可根据需要修改
i2c-en-dma 用于选择是否使用DMA模式 可根据需要修改
status 用于选择是否使能IIC master驱动 可根据需要修改

3. Padmux

3.1. 设定方法

[重要] 由于各外设驱动各自管理各自使用引脚的复用设置会引起某些引脚的复用关系冲突,故现已将引脚复用关系移至mercury6p-sscxxxx-s01a-padmux.dtsi中设定。

例:如使用 SSC025A-S01A-S 板时,对应请修改mercury6p-ssc023a-s01a-padmux.dtsi

1.  <PAD_I2C1_SCL      PINMUX_FOR_I2C1_MODE_1        MDRV_PUSE_I2C1_SCL>,
2.  <PAD_I2C1_SDA      PINMUX_FOR_I2C1_MODE_1        MDRV_PUSE_I2C1_SDA>,

如上所示,第一列为引脚索引号,可以在/drivers/sstar/inlcude/{chipname}/gpio.h中查到;第二列为模式定义,在/drivers/sstar/gpio/{chipname}/mhal_pinmux.c中m_stPadMuxTbl数组里,罗列了所有引脚的复用关系,查询该引脚支持哪些复用功能可以查询该数组;第三列为改组设定的索引号,可在/drivers/sstar/include/mdrv_puse.h里找到。

3.2. PAD罗列

Group Reg(16 bit) Padmod Pad Name Pin Name
I2C-0 bank h103C offset h6F bit[2:0] 1 PAD_I2C0_SCL I2C0_SCL
PAD_I2C0_SDA I2C0_SDA
2 PAD_PWM0 I2C0_SCL
PAD_PWM1 I2C0_SDA
3 PAD_UART1_RX I2C0_SCL
PAD_UART1_TX I2C0_SDA
4 PAD_SD_CLK I2C0_SCL
PAD_SD_CMD I2C0_SDA
I2C-1 bank h103C offset h53 bit[2:0] 1 PAD_I2C1_SCL I2C1_SCL0
PAD_I2C1_SDA I2C1_SDA0
2 PAD_PWM0 I2C1_SCL0
PAD_PWM1 I2C1_SDA0
3 PAD_PM_LED0 I2C1_SCL0
PAD_PM_LED1 I2C1_SDA0
4 PAD_I2C1_SCL I2C1_SCL0
PAD_I2C1_SDA I2C1_SDA0
PAD_SR_IO12 I2C1_SCL1
PAD_SR_IO13 I2C1_SDA1
I2C-2 bank h103C offset h6F bit[9:8] 1 PAD_SR_IO12 I2C2_SCL
PAD_SR_IO13 I2C2_SDA
2 PAD_PWM0 I2C2_SCL
PAD_PWM1 I2C2_SDA
3 PAD_SR_IO00 I2C2_SCL
PAD_SR_IO01 I2C2_SDA

4. 使用I2C

4.1. 用户态读写I2C

通过标准的/dev文件来读写I2C,以下是一个使用的小例子。

1.  #include <stdio.h>    
2.  #include <linux/types.h>    
3.  #include <stdlib.h>    
4.  #include <fcntl.h>    
5.  #include <unistd.h>    
6.  #include <sys/types.h>    
7.  #include <sys/ioctl.h>    
8.  #include <errno.h>    
9.  #include <assert.h>    
10. #include <string.h>    
11. #include <linux/i2c.h>    
12. #include <linux/i2c-dev.h>   
13.   
14. #define FILE_NAME "/dev/i2c-0"  
15.   
16. static int i2c_write(int fd,unsigned char slave_addr, unsigned char reg_addr, unsigned char value)   
17. {  
18.     unsigned char outbuf[2];  
19.     struct i2c_rdwr_ioctl_data packets;  
20.     struct i2c_msg messages[1];  
21.   
22.     messages[0].addr  = slave_addr;  
23.     messages[0].flags = 0;  
24.     messages[0].len   = sizeof(outbuf);  
25.     messages[0].buf   = outbuf;  
26.   
27.     /* The first byte indicates which register we‘ll write */  
28.     outbuf[0] = reg_addr;  
29.   
30.     /*  
31.      * The second byte indicates the value to write.  Note that for many 
32.      * devices, we can write multiple, sequential registers at once by 
33.      * simply making outbuf bigger. 
34.      */  
35.     outbuf[1] = value;  
36.   
37.     /* Transfer the i2c packets to the kernel and verify it worked */  
38.     packets.msgs  = messages;  
39.     packets.nmsgs = 1;  
40.     if(ioctl(fd, I2C_RDWR, &packets) < 0)   
41.     {  
42.         perror("Unable to send data");  
43.         return 1;  
44.     }  
45.   
46.     return 0;  
47. }  
48.   
49. static int i2c_read(int fd, unsigned char slave_addr, unsigned char reg_addr, unsigned char *value)   
50. {  
51.     unsigned char inbuf, outbuf;  
52.     struct i2c_rdwr_ioctl_data packets;  
53.     struct i2c_msg messages[2];  
54.   
55.     /* 
56.      * In order to read a register, we first do a "dummy write" by writing 
57.      * 0 bytes to the register we want to read from.  This is similar to 
58.      * the packet in set_i2c_register, except it‘s 1 byte rather than 2. 
59.      */  
60.     outbuf = reg_addr;  
61.     messages[0].addr  = slave_addr;  
62.     messages[0].flags = 0; //if you need stop msg before restart msg,
63.                               //set messages[0].flags |= 0x02; 
64.     messages[0].len   = sizeof(outbuf);  
65.     messages[0].buf   = &outbuf;  
66.   
67.     /* The data will get returned in this structure */  
68.     messages[1].addr  = slave_addr;  
69.     messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;  
70.     messages[1].len   = sizeof(inbuf);  
71.     messages[1].buf   = &inbuf;  
72.   
73.     /* Send the request to the kernel and get the result back */  
74.     packets.msgs      = messages;  
75.     packets.nmsgs     = 2;  
76.     if(ioctl(fd, I2C_RDWR, &packets) < 0)   
77.     {  
78.         perror("Unable to send data");  
79.         return 1;  
80.     }  
81.     *value = inbuf;  
82.   
83.     return 0;  
84. }  
85.   
86. int main(int argc, char **argv)    
87. {    
88.     int fd;    
89.     unsigned int slave_addr=0, reg_addr=0, value = 0;      
90.         
91.     if (argc < 4){    
92.         printf("Usage:\n%s r[w] start_addr reg_addr [value]\n",argv[0]);    
93.         return 0;    
94.     }    
95.         
96.     fd = open(FILE_NAME, O_RDWR);        
97.     if (!fd)  
98.     {    
99.         printf("can not open file %s\n", FILE_NAME);    
100.            return 0;    
101.        }    
102.        
103.        sscanf(argv[2], "%x", &slave_addr);    
104.        sscanf(argv[3], "%x", ®_addr);    
105.           
106.        if(!strcmp(argv[1],"r"))   
107.        {  
108.            i2c_read(fd, slave_addr, reg_addr, (unsigned char*)&value);  
109.        }  
110.        else if(argc>4&&!strcmp(argv[1],"w"))   
111.        {  
112.            sscanf(argv[4], "%x", &value);    
113.            i2c_write(fd, slave_addr, reg_addr, value);  
114.        }  
115.          
116.        close(fd);  
117.        return 0;  
118.    }

4.2. 内核态读写I2C

通过内核标准接口操作I2C,下面是个小例子:

1.  struct i2c_adapter* adpa = NULL;  
2.  struct i2c_msg msg;  
3.  u8 data[4] = {0};  
4.    
5.  adpa = i2c_get_adapter(nr); // 获取i2c-0 adapter  
6.    
7.  data[0] = reg & 0xff;  
8.  data[1] = value & 0xff;  
9.    
10. msg.addr = slaveAddr>>1;  
11. msg.flags = 0;  
12. msg.buf = data;  
13. msg.len = 2;  
14.   
15. i2c_transfer(adpa, &msg, 1);