1 分析i2c設備的識別過程i2c_add_driver i2c_register_driver driver->driver.bus = &i2c_bus_type; driver_register(&driver->driver); list_for_each_entry(adapter, &a ...
1 分析i2c設備的識別過程
i2c_add_driver
i2c_register_driver
driver->driver.bus = &i2c_bus_type;
driver_register(&driver->driver);
list_for_each_entry(adapter, &adapters, list) {
driver->attach_adapter(adapter);
i2c_probe(adapter, &addr_data, eeprom_detect);
i2c_probe_address // 發出S信號,發出設備地址(來自addr_data)
i2c_smbus_xfer
i2c_smbus_xfer_emulated
i2c_transfer
adap->algo->master_xfer // s3c24xx_i2c_xfer
2 怎麼寫I2C設備驅動程式?
2.1 分配一個i2c_driver結構體
2.2 設置
attach_adapter // 它直接調用 i2c_probe(adap, 設備地址, 發現這個設備後要調用的函數);
detach_client // 卸載這個驅動後,如果之前發現能夠支持的設備,則調用它來清理
2.3 註冊:i2c_add_driver
3 寫代碼
1 #include <linux/kernel.h> 2 #include <linux/init.h> 3 #include <linux/module.h> 4 #include <linux/slab.h> 5 #include <linux/jiffies.h> 6 #include <linux/i2c.h> 7 #include <linux/mutex.h> 8 #include <linux/fs.h> 9 #include <asm/uaccess.h> 10 11 static unsigned short ignore[] = { I2C_CLIENT_END }; 12 static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END }; /* 地址值是7位 */ 13 /* 改為0x60的話, 由於不存在設備地址為0x60的設備, 所以at24cxx_detect不被調用 */ 14 15 static unsigned short force_addr[] = {ANY_I2C_BUS, 0x60, I2C_CLIENT_END}; 16 static unsigned short * forces[] = {force_addr, NULL}; 17 18 static struct i2c_client_address_data addr_data = { 19 .normal_i2c = normal_addr, /* 要發出S信號和設備地址並得到ACK信號,才能確定存在這個設備 */ 20 .probe = ignore, 21 .ignore = ignore, 22 //.forces = forces, /* 強制認為存在這個設備 */ 23 }; 24 25 static struct i2c_driver at24cxx_driver; 26 27 28 static int major; 29 static struct class *cls; 30 struct i2c_client *at24cxx_client; 31 32 static ssize_t at24cxx_read(struct file *file, char __user *buf, size_t size, loff_t * offset) 33 { 34 unsigned char address; 35 unsigned char data; 36 struct i2c_msg msg[2]; 37 int ret; 38 39 /* address = buf[0] 40 * data = buf[1] 41 */ 42 if (size != 1) 43 return -EINVAL; 44 45 copy_from_user(&address, buf, 1); 46 47 /* 數據傳輸三要素: 源,目的,長度 */ 48 49 /* 讀AT24CXX時,要先把要讀的存儲空間的地址發給它 */ 50 msg[0].addr = at24cxx_client->addr; /* 目的 */ 51 msg[0].buf = &address; /* 源 */ 52 msg[0].len = 1; /* 地址=1 byte */ 53 msg[0].flags = 0; /* 表示寫 */ 54 55 /* 然後啟動讀操作 */ 56 msg[1].addr = at24cxx_client->addr; /* 源 */ 57 msg[1].buf = &data; /* 目的 */ 58 msg[1].len = 1; /* 數據=1 byte */ 59 msg[1].flags = I2C_M_RD; /* 表示讀 */ 60 61 62 ret = i2c_transfer(at24cxx_client->adapter, msg, 2); 63 if (ret == 2) 64 { 65 copy_to_user(buf, &data, 1); 66 return 1; 67 } 68 else 69 return -EIO; 70 } 71 72 static ssize_t at24cxx_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) 73 { 74 unsigned char val[2]; 75 struct i2c_msg msg[1]; 76 int ret; 77 78 /* address = buf[0] 79 * data = buf[1] 80 */ 81 if (size != 2) 82 return -EINVAL; 83 84 copy_from_user(val, buf, 2); 85 86 /* 數據傳輸三要素: 源,目的,長度 */ 87 msg[0].addr = at24cxx_client->addr; /* 目的 */ 88 msg[0].buf = val; /* 源 */ 89 msg[0].len = 2; /* 地址+數據=2 byte */ 90 msg[0].flags = 0; /* 表示寫 */ 91 92 ret = i2c_transfer(at24cxx_client->adapter, msg, 1); 93 if (ret == 1) 94 return 2; 95 else 96 return -EIO; 97 } 98 99 100 static struct file_operations at24cxx_fops = { 101 .owner = THIS_MODULE, 102 .read = at24cxx_read, 103 .write = at24cxx_write, 104 }; 105 106 static int at24cxx_detect(struct i2c_adapter *adapter, int address, int kind) 107 { 108 printk("at24cxx_detect\n"); 109 110 /* 構構一個i2c_client結構體: 以後收改數據時會用到它 */ 111 at24cxx_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); 112 at24cxx_client->addr = address; 113 at24cxx_client->adapter = adapter; 114 at24cxx_client->driver = &at24cxx_driver; 115 strcpy(at24cxx_client->name, "at24cxx"); 116 i2c_attach_client(at24cxx_client); 117 118 major = register_chrdev(0, "at24cxx", &at24cxx_fops); 119 120 cls = class_create(THIS_MODULE, "at24cxx"); 121 class_device_create(cls, NULL, MKDEV(major, 0), NULL, "at24cxx"); /* /dev/at24cxx */ 122 123 return 0; 124 } 125 126 static int at24cxx_attach(struct i2c_adapter *adapter) 127 { 128 return i2c_probe(adapter, &addr_data, at24cxx_detect); 129 } 130 131 static int at24cxx_detach(struct i2c_client *client) 132 { 133 printk("at24cxx_detach\n"); 134 class_device_destroy(cls, MKDEV(major, 0)); 135 class_destroy(cls); 136 unregister_chrdev(major, "at24cxx"); 137 138 i2c_detach_client(client); 139 kfree(i2c_get_clientdata(client)); 140 141 return 0; 142 } 143 144 145 /* 1. 分配一個i2c_driver結構體 */ 146 /* 2. 設置i2c_driver結構體 */ 147 static struct i2c_driver at24cxx_driver = { 148 .driver = { 149 .name = "at24cxx", 150 }, 151 .attach_adapter = at24cxx_attach, 152 .detach_client = at24cxx_detach, 153 }; 154 155 static int at24cxx_init(void) 156 { 157 i2c_add_driver(&at24cxx_driver); 158 return 0; 159 } 160 161 static void at24cxx_exit(void) 162 { 163 i2c_del_driver(&at24cxx_driver); 164 } 165 166 module_init(at24cxx_init); 167 module_exit(at24cxx_exit); 168 169 MODULE_LICENSE("GPL");i2c設備驅動程式