int i2c_add_adapter(struct i2c_adapter *adap);
int i2c_del_adapter(struct i2c_adapter *adap);
增加、刪除i2c_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
int i2c_del_driver(struct i2c_driver *driver);
inline int i2c_add_driver(struct i2c_driver *driver);
i2c_client依附/脫離
int i2c_attach_client(struct i2c_client *client);
int i2c_detach_client(struct i2c_client *client);
當一個具體的client被偵測到並被關聯的時候,設備和sysfs文件將被注冊。相反地,在client被取消關聯的時候,sysfs文件和設備也被注銷
代碼清單15.6 I2C核心client attach/detach函數
1 int i2c_attach_client(struct i2c_client *client)
2 {
3 ...
4 device_register(&client->dev);
5 device_create_file(&client->dev, &dev_attr_client_name);
6
7 return 0;
8 }
9
10 int i2c_detach_client(struct i2c_client *client)
11 {
12 ...
13 device_remove_file(&client->dev, &dev_attr_client_name);
14 device_unregister(&client->dev);
15 ...
16 }
I2C傳輸、發送和接收
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num);
int i2c_master_send(struct i2c_client *client,const char *buf ,int count);
int i2c_master_recv(struct i2c_client *client, char *buf ,int count);
i2c_transfer ()函數用於進行I2C適配器和I2C設備之間的一組消息交互,i2c_master_send()函數和i2c_master_recv()函數內部會 調用i2c_transfer()函數分別完成一條寫消息和一條讀消
例如:
代碼清單15.7 I2C核心i2c_master_send函數
1 int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
2 {
3 int ret;
4 struct i2c_adapter *adap=client->adapter;
5 struct i2c_msg msg;
6 /*構造一個寫消息*/
7 msg.addr = client->addr;
8 msg.flags = client->flags & I2C_M_TEN;
9 msg.len = count;
10 msg.buf = (char *)buf;
11 /*傳輸消息*/
12 ret = i2c_transfer(adap, &msg, 1);
13
14 return (ret == 1) ? count : ret;
15 }
代碼清單15.8 I2C核心i 2c_master_recv函數
1 int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
2 {
3 struct i2c_adapter *adap=client->adapter;
4 struct i2c_msg msg;
5 int ret;
6 /*構造一個讀消息*/
7 msg.addr = client->addr;
8 msg.flags = client->flags & I2C_M_TEN;
9 msg.flags |= I2C_M_RD;
10 msg.len = count;
11 msg.buf = buf;
12 /*傳輸消息*/
13 ret = i2c_transfer(adap, &msg, 1);
14
15 /* 成功(1條消息被處理), 返回讀的字節數 */
16 return (ret == 1) ? count : ret;
17 }
i2c_transfer()函數本身不具備驅動適配器物理硬件完成消息交互的能力,它只是尋找到i2c_adapter對應的i2c_algorithm,並使用i2c_algorithm的master_xfer()函數真正驅動硬件流程,如下例程:
I2C核心i 2c_transfer函數
1 int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
2 {
3 int ret;
4
5 if (adap->algo->master_xfer) {
6 down(&adap->bus_lock);
7 ret = adap->algo->master_xfer(adap,msgs,num); /* 消息傳輸 */
8 up(&adap->bus_lock);
9 return ret;
10 } else {
11 dev_dbg(&adap->dev, "I2C level transfers not supported\n");
12 return -ENOSYS;
13 }
14 }
I2C總線驅動模塊加載和卸載函數模板
1 static int __init i2c_adapter_xxx_init(void)
2 {
3 xxx_adpater_hw_init();
4 i2c_add_adapter(&xxx_adapter);
5 }
6
7 static void __exit i2c_adapter_xxx_exit(void)
8 {
9 xxx_adpater_hw_free();
10 i2c_del_adapter(&xxx_adapter);
11 }
- 上述代碼中xxx_adpater_hw_init()和xxx_adpater_hw_free()函數的實現都與具體的CPU和I2C設備硬件直接相關。
I2C總線驅動master_xfer函數模板
1 static int i2c_adapter_xxx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
2 int num)
3 {
4 ...
5 for (i = 0; i < num; i++)
6 {
7 i2c_adapter_xxx_start(); /*產生開始位*/
8 /*是讀消息*/
9 if (msgs[i]->flags &I2C_M_RD)
10 {
11 i2c_adapter_xxx_setaddr((msg->addr << 1) | 1); /*發送從設備讀地址*/
12 i2c_adapter_xxx_wait_ack(); /*獲得從設備的ack*/
13 i2c_adapter_xxx_readbytes(msgs[i]->buf, msgs[i]->len); /*讀取msgs[i]
14 ->len長的數據到msgs[i]->buf*/
15 }
16 else
17 /*是寫消息*/
18 {
19 i2c_adapter_xxx_setaddr(msg->addr << 1); /*發送從設備寫地址*/
20 i2c_adapter_xxx_wait_ack(); /*獲得從設備的ack*/
21 i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len); /*讀取msgs[i]
22 ->len長的數據到msgs[i]->buf*/
23 }
24 }
25 i2c_adapter_xxx_stop(); /*產生停止位*/
26 }
- 上述代碼實際上給出了一個master_xfer()函數處理I2C消息數組的流程,對於數組中的每個消息,判斷消息類型,若為讀消息,則賦從設備地址為 (msg->addr << 1) | 1,否則為msg->addr << 1。對每個消息產生1個開始位,緊接著傳送從設備地址,然後開始數據的發送或接收,對最後的消息還需產生1個停止位。圖15.3描述了整個master_xfer()完成的時序。
多數I2C總線驅動會定義一個xxx_i2c結構體,作為i2c_adapter的algo_data(類似“私有數據”)
1 struct xxx_i2c
2 {
3 spinlock_t lock;
4 wait_queue_head_t wait;
5 struct i2c_msg *msg;
6 unsigned int msg_num;
7 unsigned int msg_idx;
8 unsigned int msg_ptr;
9 ...
10 struct i2c_adapter adap;
11 };
1 static int __init yyy_init(void)
2 {
3 int res;
4 /*注冊字符設備*/
5 res = register_chrdev(YYY_MAJOR, "yyy", &yyy_fops); //老內核接口
6 if (res)
7 goto out;
8 /*添加i2c_driver*/
9 res = i2c_add_driver(&yyy_driver);
10 if (res)
11 goto out_unreg_class;
12 return 0;
13
14 out_unreg_chrdev: unregister_chrdev(I2C_MAJOR, "i2c");
15 out: printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
16 return res;
17 }
18
19 static void __exit yyy_exit(void)
20 {
21 i2c_del_driver(&i2cdev_driver);
22 unregister_chrdev(YYY_MAJOR, "yyy");
23 }
1 static int yyy_cmd1(struct i2c_client *client, struct rtc_time *dt)
2 {
3 struct i2c_msg msg[2];
4 /*第一條消息是寫消息*/
5 msg[0].addr = client->addr;
6 msg[0].flags = 0;
7 msg[0].len = 1;
8 msg[0].buf = &offs;
9 /*第二條消息是讀消息*/
10 msg[1].addr = client->addr;
11 msg[1].flags = I2C_M_RD;
12 msg[1].len = sizeof(buf);
13 msg[1].buf = &buf[0];
14
15 i2c_transfer(client->adapter, msg, 2);
16 ...
17 }
i2c-dev.c文件可以被看作一個I2C設 備驅動,它實現的一個i2c_client是虛擬的、臨時的,隨著設備文件的打開而產生,並隨設備文件的關閉而撤銷,並沒有被添加到i2c_adapter的clients鏈表中。
i2c-dev.c針對每個I2C適配器生成一個主設備為89的設備文件,實現了i2c_driver的成員函數以及文件操作接口
i2c-dev.c的主體是“i2c_driver成員函數 + 字符設備驅動”。
i2c-dev.c中提供i2cdev_read()、i2cdev_write()函數來對應用戶空間要使用的read()和 write()文件操作接口,這兩個函數分別調用I2C核心的i2c_master_recv()和i2c_master_send()函數來構造1條 I2C消息並引發適配器algorithm通信函數的調用,完成消息的傳輸
i2c-dev.c中i2cdev_read()和i2cdev_write()函數不具備太強的通用性,沒有太大的實用價值,只能適用於非RepStart模式的情況。
對於2條以上消息組成的讀寫,在用戶空間需要組織i2c_msg消息數組並調用I2C_RDWR IOCTL命令。
代碼給出了i2cdev_ioctl()函數的框架,其中詳細列出了I2C_RDWR命令的處理過程。
i2c-dev.c中的i2cdev_ioctl函數
1 static int i2cdev_ioctl(struct inode *inode, struct file *file,
2 unsigned int cmd, unsigned long arg)
3 {
4 struct i2c_client *client = (struct i2c_client *)file->private_data;
5 ...
6 switch ( cmd ) {
7 case I2C_SLAVE:
8 case I2C_SLAVE_FORCE:
9 ... /*設置從設備地址*/
10 case I2C_TENBIT:
11 ...
12 case I2C_PEC:
13 ...
14 case I2C_FUNCS:
15 ...
16 case I2C_RDWR:
17 if (copy_from_user(&rdwr_arg,
18 (struct i2c_rdwr_ioctl_data __user *)arg,
19 sizeof(rdwr_arg)))
20 return -EFAULT;
21 /* 一次傳入的消息太多 */
22 if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
23 return -EINVAL;
24 /*獲得用戶空間傳入的消息數組
25 rdwr_pa = (struct i2c_msg *)
26 kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
27 GFP_KERNEL);
28 if (rdwr_pa == NULL) return -ENOMEM;
29 if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
30 rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
31 kfree(rdwr_pa);
32 return -EFAULT;
33 }
34 data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
35 if (data_ptrs == NULL) {
36 kfree(rdwr_pa);
37 return -ENOMEM;
38 }
39 res = 0;
40 for( i=0; i41 /* 限制消息的長度 */
42 if (rdwr_pa[i].len > 8192) {
43 res = -EINVAL;
44 break;
45 }
46 data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
47 rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
48 if(rdwr_pa[i].buf == NULL) {
49 res = -ENOMEM;
50 break;
51 }
52 if(copy_from_user(rdwr_pa[i].buf,
53 data_ptrs[i],
54 rdwr_pa[i].len)) {
55 ++i; /* Needs to be kfreed too */
56 res = -EFAULT;
57 break;
58 }
59 }
60 if (res < 0) {
61 int j;
62 for (j = 0; j < i; ++j)
63 kfree(rdwr_pa[j].buf);
64 kfree(data_ptrs);
65 kfree(rdwr_pa);
66 return res;
67 }
68 /*把這些消息交給通信方法去處理*/
69 res = i2c_transfer(client->adapter,
70 rdwr_pa,
71 rdwr_arg.nmsgs);
72 while(i-- > 0) { /*如果是讀消息,把值拷貝到用戶空間*/
73 if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
74 if(copy_to_user(
75 data_ptrs[i],
76 rdwr_pa[i].buf,
77 rdwr_pa[i].len)) {
78 res = -EFAULT;
79 }
80 }
81 kfree(rdwr_pa[i].buf);
82 }
83 kfree(data_ptrs);
84 kfree(rdwr_pa);
85 return res;
86 case I2C_SMBUS:
87 ...
88 default:
89 return i2c_control(client,cmd,arg);
90 }
91 return 0;
92 }
- 常用的IOCTL包括I2C_SLAVE(設置從設備地址)、I2C_RETRIES(沒有收到設備ACK情況下的重試次數,缺省為1)、I2C_TIMEOU(超時)以及I2C_RDWR。
下面兩個代碼分別演示了直接通過read()、write()接口和O_RDWR IOCTL讀寫I2C設備的例子。
代碼清單15.23 直接通過read()/write()讀寫I2C設備
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8
9 #define I2C_RETRIES 0x0701
10 #define I2C_TIMEOUT 0x0702
11 #define I2C_SLAVE 0x0703
12
13 int main(int argc, char **argv)
14 {
15 unsigned int fd;
16 unsigned short mem_addr;
17 unsigned short size;
18 unsigned short idx;
19 #define BUFF_SIZE 32
20 char buf[BUFF_SIZE];
21 char cswap;
22 union
23 {
24 unsigned short addr;
25 char bytes[2];
26 } tmp;
27
28 if (argc < 3)
29 {
30 printf("Use:\n%s /dev/i2c-x mem_addr size\n", argv[0]);
31 return 0;
32 }
33 sscanf(argv[2], "%d", &mem_addr);
34 sscanf(argv[3], "%d", &size);
35
36 if (size > BUFF_SIZE)
37 size = BUFF_SIZE;
38
39 fd = open(argv[1], O_RDWR);
40
41 if (!fd)
42 {
43 printf("Error on opening the device file\n");
44 return 0;
45 }
46
47 ioctl(fd, I2C_SLAVE, 0x50); /* 設置eeprom地址 */
48 ioctl(fd, I2C_TIMEOUT, 1); /* 設置超時 */
49 ioctl(fd, I2C_RETRIES, 1); /* 設置重試次數 */
50
51 for (idx = 0; idx < size; ++idx, ++mem_addr)
52 {
53 tmp.addr = mem_addr;
54 cswap = tmp.bytes[0];
55 tmp.bytes[0] = tmp.bytes[1];
56 tmp.bytes[1] = cswap;
57 write(fd, &tmp.addr, 2);
58 read(fd, &buf[idx], 1);
59 }
60 buf[size] = 0;
61 close(fd);
62 printf("Read %d char: %s\n", size, buf);
63 return 0;
64 }
代碼清單15.24 通過O_RDWR IOCTL讀寫I2C設備
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11
12 #define MAX_I2C_MSG 2
13
14 #define I2C_RETRIES 0x0701
15 #define I2C_TIMEOUT 0x0702
16 #define I2C_RDWR 0x0707
17
18 struct i2c_msg
19 {
20 __u16 addr; /* 從地址 */
21 __u16 flags;
22 #define I2C_M_RD 0x01
23 __u8 *buf; /* 消息數據指針 */
24 };
25 struct i2c_rdwr_ioctl_data
26 {
27 struct i2c_msg *msgs; /* i2c_msg[]指針 */
28 int nmsgs; /* i2c_msg數量 */
29 };
30
31 int main(int argc, char **argv)
32 {
33 struct i2c_rdwr_ioctl_data work_queue;
34 unsigned int idx;
35 unsigned int fd;
36 unsigned short start_address;
37 int ret;
38
39 if (argc < 4)
40 {
41 printf("Usage:\n%s /dev/i2c-x start_addr\n", argv[0]);
42 return 0;
43 }
44
45 fd = open(argv[1], O_RDWR);
46
47 if (!fd)
48 {
49 printf("Error on opening the device file\n");
50 return 0;
51 }
52 sscanf(argv[2], "%x", &start_address);
53 work_queue.nmsgs = MAX_I2C_MSG; /* 消息數量 */
54
55 work_queue.msgs = (struct i2c_msg*)malloc(work_queue.nmsgs *sizeof(struct
56 i2c_msg));
57 if (!work_queue.msgs)
58 {
59 printf("Memory alloc error\n");
60 close(fd);
61 return 0;
62 }
63
64 for (idx = 0; idx < work_queue.nmsgs; ++idx)
65 {
66 (work_queue.msgs[idx]).len = 0;
67 (work_queue.msgs[idx]).addr = start_address + idx;
68 (work_queue.msgs[idx]).buf = NULL;
69 }
70
71 ioctl(fd, I2C_TIMEOUT, 2); /* 設置超時 */
72 ioctl(fd, I2C_RETRIES, 1); /* 設置重試次數 */
73
74 ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);
75
76 if (ret < 0)
77 {
78 printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
79 }
80
81 close(fd);
82 return ;
83 }