Catalogue of series articles
1. A linux i2c driver
2. linux i2c driver II
preface
I've been looking at things related to VFS and compilation recently. The whole thing is nodding. Many things haven't been sorted out in a hurry.
This time I mainly want to summarize the serial bus iic. In fact, iic and spi are Low-speed serial buses. Generally, sensors (temperature, optical module, eeprom, etc.) will be mounted under the iic bus. They are often used and have a relatively simple bus operation.
SPI will generally mount ad class (such as RF device adc9009) clock chip (such as ad9543) SPI will be used for GPS, LCD, etc
Originally, I was going to finish writing at one time and found that more and more things were written. This time, I will write a brief introduction to the hardware principle driver Driver code
The next section describes iic debugging mode and kernel iic framework analysis (I think it's good to understand this part, because it's not easy to understand VFS device driver bus).
Tip: the following is the main content of this article. The following cases are for reference only. You are welcome to point out any questions.
1, Brief description of i2c protocol
Baidu made it clear how this protocol came from. I'll talk about how to connect the i2c protocol hardware and access the device.
iic principle:
It's good to find a picture on the Internet. There are three equipment slave 1 slave 2 slave 3; R It is a pull-up resistor iic bus, which is SDA (serial data bus) and SCL (serial clock bus). The master control chip and slave devices are connected through SCL and SDA;
Since Rp is a pull-up resistor, SCL and SDA are at high level when idle; Or when SCL SDA is not connected to the slave device, it is also high level.
1. How to communicate through SCL SDA?
2. With so many slaves, how does the master device know to communicate with that device?
With questions:
Just look for a schematic diagram: TMP401 temperature sensing chip of TI company
Chip data can be downloaded from the official website: TMP401 data sheet, product information and support| TI.com.cn Section 7
According to the schematic diagram, you can see SCL SDA is connected to i2c1 on our board respectively_ SCL I2C1_SDA is the I2C bus on the board;
Generally, the datesheet of the chip supports IIC or SPI. There is such a section, Programming This is to introduce the bus protocol, including the read-write sequence diagram Start end signal duration setting parameters, etc.
There is a saying that matters: it is the serial bus address, which is actually your device address. As we have written on the schematic diagram) 0x4c, what's the use of this?
In this way, iic communication is initiated by the master controller. Whether it is written or not, our write driver will save the device address of the slave device in advance. When the master controller needs to communicate with the specified device, it will send this address on the bus, such as (0x4c). Then all devices will receive this (0x4c) data, but only the device of 0x4c will give a response (term ACK), so that even if you have established a link with the main controller, you can send data. This is the timing diagram I mentioned above. Let's have a look.
This diagram is the sequence diagram of write operation. It can be seen that there are nine clocks (bytes) involved in each interaction between the master controller and the slave,
The first 1-7 indicates the 8th read / write bit of the address 1001100 of the device (1 indicates read and 0 indicates write) At this time, the master controller sends the first byte of data and waits for the matching slave to respond, that is, ACK BY Device. If the matching is successful, the master controller sends the second byte of data that we need to send. The data may be 8 bits or 16 bits different from each chip. After sending, wait for the slave to respond to ack. This is a data transmission Of course, the data is actually the end signal. This may be used for MCU debugging, but it is generally less for linux debugging. You can understand it by looking at the timing diagram in the chip manual.
The above two questions are explained,
1. How to communicate through SCL SDA?
It is initiated by the master controller to send the address to the slave, and the slave feeds back the response. Then the master controller sends the data, and the slave response cycles successively until the stop signal is received. The stop signal sda is represented by a jump edge from low to high.
2. With so many slaves, how does the master device know to communicate with that device?
Send the slave device address through the master device. If the slave replies to the ACK, the matching is successful. When idle, both SCL and SDA are at high level. When the host sends the address, the master controller will pull up the SDA. As for the idle state, the ack of the slave device will pull down the bus, so other devices cannot operate. Once the SDA is pulled down, it means that it is in the busy state.
The above is iic hardware or basic principle;
2, i2c driver framework under linux
1. First, master how to use
Steps:
1. Configure device tree
2. Register iic device driver to kernel module_i2c_driver(static struct i2c_driver) is generally used;
3. Set the struct i2c_driver structure to match the device tree
4. Define its own structure, allocate space and initialize in i2c_driver - > probe function.
5. Multiple ways
1-1. Register a character device and control the reading and writing of the device through FOPS - > read write IOCTL of the character device.
1-2. Register a hwmon device (generally used for temperature sensing), create a property file under / sys/class / through the interface devm_hwmon_device_register_with_groups provided by the kernel, and provide show store two properties for user space access.
2. Understand the principle
1,module_i2c_driver(MY_IIC_DRV) be equal to Define entry and exit functions
i2c_add_driver(MY_IIC_DRV); i2c_del_driver(MY_IIC_DRV);
2. struct i2c_driver registers the structure of the driver with the kernel.
static struct i2c_driver tmp401_driver = { .class = I2C_CLASS_HWMON, //Category. If not applicable, hwmon mode will not be written .driver = { // Driver, which is used to match the devices defined in the device tree .name = "tmp401", .of_match_table = of_match_ptr(tmp401_of_match), }, .probe = tmp401_probe, //When the device and driver match successfully, the function is called. .id_table = tmp401_id, //Used to initialize board_info .detect = tmp401_detect, //Detecting whether the device exists is to send the device address to each device on the bus .address_list = normal_i2c, //Storage equipment address };
3. We need to achieve tmp401_probe If the tmp401(u detect function uses a character device to read and write, the general framework is as follows. The operation of the device can be realized in the read-write function.
struct IIC_myData{ struct i2c_client *client; // The sending and receiving interfaces are stored here struct mutex update_lock; //lock u8 status; //Some flag States u8 data; // Read and write data u8 flag; // }; struct IIC_myData * my_data; int major_ret ; static const struct file_operations capi_fops = { .owner = THIS_MODULE, .read = myiic_read, .write = myiic_write, .unlocked_ioctl = myiic_unlocked_ioctl, .open = myiic_open, .release = myiic_release, }; static int tmp401_probe(struct i2c_client *client, const struct i2c_device_id *id) { /* Assign self-defined structures */ my_data = devm_kzalloc(client->dev, sizeof(struct IIC_myData), GFP_KERNEL); /* initialization */ my_data->client = client; mutex_init(&my_data->update_lock); ..... /* Register character device to create fops*/ major_ret = register_chrdev(0, "myiic", &myiic_fops); //Create device class myiic_class = class_create(THIS_MODULE, "myiicClass"); device_create(myiic_class, NULL, MKDEV(major_ret, 0), NULL, "myiicDev"); } /* After that, you can realize functions such as reading, writing and opening */
3, Instance
1. Device tree
tmp401: tmp401@4c { /* u23 */ compatible = "ti,tmp401"; //The name used to match the driver reg = <0x4c>; //Device address }; /* Ambient temperature temp1_input */ lm75_4f: lm75@4f { compatible = "lm75"; reg = <0x4f>; };
2. Driver code
The second method is used, which is implemented by HWMON
#include <linux/module.h> #include <linux/init.h> #include <linux/bitops.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> #include <linux/sysfs.h> /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; enum chips { tmp401, tmp411, tmp431, tmp432, tmp435, tmp461 }; /* * The TMP401 registers, note some registers have different addresses for * reading and writing */ #define TMP401_STATUS 0x02 #define TMP401_CONFIG_READ 0x03 #define TMP401_CONFIG_WRITE 0x09 #define TMP401_CONVERSION_RATE_READ 0x04 #define TMP401_CONVERSION_RATE_WRITE 0x0A #define TMP401_TEMP_CRIT_HYST 0x21 #define TMP401_MANUFACTURER_ID_REG 0xFE #define TMP401_DEVICE_ID_REG 0xFF static const u8 TMP401_TEMP_MSB_READ[7][2] = { { 0x00, 0x01 }, /* temp */ { 0x06, 0x08 }, /* low limit */ { 0x05, 0x07 }, /* high limit */ { 0x20, 0x19 }, /* therm (crit) limit */ { 0x30, 0x34 }, /* lowest */ { 0x32, 0x36 }, /* highest */ { 0, 0x11 }, /* offset */ }; static const u8 TMP401_TEMP_MSB_WRITE[7][2] = { { 0, 0 }, /* temp (unused) */ { 0x0C, 0x0E }, /* low limit */ { 0x0B, 0x0D }, /* high limit */ { 0x20, 0x19 }, /* therm (crit) limit */ { 0x30, 0x34 }, /* lowest */ { 0x32, 0x36 }, /* highest */ { 0, 0x11 }, /* offset */ }; static const u8 TMP432_TEMP_MSB_READ[4][3] = { { 0x00, 0x01, 0x23 }, /* temp */ { 0x06, 0x08, 0x16 }, /* low limit */ { 0x05, 0x07, 0x15 }, /* high limit */ { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ }; static const u8 TMP432_TEMP_MSB_WRITE[4][3] = { { 0, 0, 0 }, /* temp - unused */ { 0x0C, 0x0E, 0x16 }, /* low limit */ { 0x0B, 0x0D, 0x15 }, /* high limit */ { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ }; /* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */ static const u8 TMP432_STATUS_REG[] = { 0x1b, 0x36, 0x35, 0x37 }; /* Flags */ #define TMP401_CONFIG_RANGE BIT(2) #define TMP401_CONFIG_SHUTDOWN BIT(6) #define TMP401_STATUS_LOCAL_CRIT BIT(0) #define TMP401_STATUS_REMOTE_CRIT BIT(1) #define TMP401_STATUS_REMOTE_OPEN BIT(2) #define TMP401_STATUS_REMOTE_LOW BIT(3) #define TMP401_STATUS_REMOTE_HIGH BIT(4) #define TMP401_STATUS_LOCAL_LOW BIT(5) #define TMP401_STATUS_LOCAL_HIGH BIT(6) /* On TMP432, each status has its own register */ #define TMP432_STATUS_LOCAL BIT(0) #define TMP432_STATUS_REMOTE1 BIT(1) #define TMP432_STATUS_REMOTE2 BIT(2) /* Manufacturer / Device ID's */ #define TMP401_MANUFACTURER_ID 0x55 #define TMP401_DEVICE_ID 0x11 #define TMP411A_DEVICE_ID 0x12 #define TMP411B_DEVICE_ID 0x13 #define TMP411C_DEVICE_ID 0x10 #define TMP431_DEVICE_ID 0x31 #define TMP432_DEVICE_ID 0x32 #define TMP435_DEVICE_ID 0x35 /* * Driver data (common to all clients) */ static const struct i2c_device_id tmp401_id[] = { { "tmp401", tmp401 }, { "tmp411", tmp411 }, { "tmp431", tmp431 }, { "tmp432", tmp432 }, { "tmp435", tmp435 }, { "tmp461", tmp461 }, { } }; MODULE_DEVICE_TABLE(i2c, tmp401_id); static const struct of_device_id tmp401_of_match[] = { { .compatible = "ti,tmp401", //This is the compatible field in the matching device tree, which should be consistent .data = (void *)tmp401 //Private data; }, { }, }; MODULE_DEVICE_TABLE(of, tmp401_of_match); /* * Client data (each client gets its own) */ struct tmp401_data { struct i2c_client *client; const struct attribute_group *groups[3]; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ enum chips kind; unsigned int update_interval; /* in milliseconds */ /* register values */ u8 status[4]; u8 config; u16 temp[7][3]; u8 temp_crit_hyst; }; /* * Sysfs attr show / store functions */ static int tmp401_register_to_temp(u16 reg, u8 config) { int temp = reg; if (config & TMP401_CONFIG_RANGE) //Difference between positive and negative temperature measurement ranges temp -= 64 * 256; return DIV_ROUND_CLOSEST(temp * 125, 32); } static u16 tmp401_temp_to_register(long temp, u8 config, int zbits) { if (config & TMP401_CONFIG_RANGE) { temp = clamp_val(temp, -64000, 191000); temp += 64000; } else temp = clamp_val(temp, 0, 127000); return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits; } //The register address for temperature reading is stored in tmp401_ TEMP_ MSB_ READ TMP432_ TEMP_ MSB_ In read array static int tmp401_update_device_reg16(struct i2c_client *client, struct tmp401_data *data) { int i, j, val; int num_regs = data->kind == tmp411 ? 6 : 4; int num_sensors = data->kind == tmp432 ? 3 : 2; for (i = 0; i < num_sensors; i++) { /* local / r1 / r2 */ for (j = 0; j < num_regs; j++) { /* temp / low / ... */ u8 regaddr; regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_READ[j][i] : TMP401_TEMP_MSB_READ[j][i]; if (j == 3) { /* crit is msb only */ val = i2c_smbus_read_byte_data(client, regaddr); } else { val = i2c_smbus_read_word_swapped(client, regaddr); } if (val < 0) return val; data->temp[j][i] = j == 3 ? val << 8 : val; } } return 0; } static struct tmp401_data *tmp401_update_device(struct device *dev) { struct tmp401_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; struct tmp401_data *ret = data; int i, val; unsigned long next_update; mutex_lock(&data->update_lock); next_update = data->last_updated + msecs_to_jiffies(data->update_interval); if (time_after(jiffies, next_update) || !data->valid) { if (data->kind != tmp432) { /* * The driver uses the TMP432 status format internally. * Convert status to TMP432 format for other chips. */ val = i2c_smbus_read_byte_data(client, TMP401_STATUS); if (val < 0) { ret = ERR_PTR(val); goto abort; } data->status[0] = (val & TMP401_STATUS_REMOTE_OPEN) >> 1; data->status[1] = ((val & TMP401_STATUS_REMOTE_LOW) >> 2) | ((val & TMP401_STATUS_LOCAL_LOW) >> 5); data->status[2] = ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) | ((val & TMP401_STATUS_LOCAL_HIGH) >> 6); data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT | TMP401_STATUS_REMOTE_CRIT); } else { for (i = 0; i < ARRAY_SIZE(data->status); i++) { val = i2c_smbus_read_byte_data(client, TMP432_STATUS_REG[i]); if (val < 0) { ret = ERR_PTR(val); goto abort; } data->status[i] = val; } } val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); if (val < 0) { ret = ERR_PTR(val); goto abort; } data->config = val; val = tmp401_update_device_reg16(client, data); if (val < 0) { ret = ERR_PTR(val); goto abort; } val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST); if (val < 0) { ret = ERR_PTR(val); goto abort; } data->temp_crit_hyst = val; data->last_updated = jiffies; data->valid = 1; } abort: mutex_unlock(&data->update_lock); return ret; } static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) { //SENSOR_DEVICE_ATTR_2(0, 0); The last two parameters represent nr and index int nr = to_sensor_dev_attr_2(devattr)->nr; int index = to_sensor_dev_attr_2(devattr)->index; struct tmp401_data *data = tmp401_update_device(dev); if (IS_ERR(data)) return PTR_ERR(data); return sprintf(buf, "%d\n", tmp401_register_to_temp(data->temp[nr][index], data->config)); } static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *devattr, char *buf) { int temp, index = to_sensor_dev_attr(devattr)->index; struct tmp401_data *data = tmp401_update_device(dev); if (IS_ERR(data)) return PTR_ERR(data); mutex_lock(&data->update_lock); temp = tmp401_register_to_temp(data->temp[3][index], data->config); temp -= data->temp_crit_hyst * 1000; mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", temp); } static ssize_t show_status(struct device *dev, struct device_attribute *devattr, char *buf) { int nr = to_sensor_dev_attr_2(devattr)->nr; int mask = to_sensor_dev_attr_2(devattr)->index; struct tmp401_data *data = tmp401_update_device(dev); if (IS_ERR(data)) return PTR_ERR(data); return sprintf(buf, "%d\n", !!(data->status[nr] & mask)); } static ssize_t store_temp(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { int nr = to_sensor_dev_attr_2(devattr)->nr; int index = to_sensor_dev_attr_2(devattr)->index; struct tmp401_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; u16 reg; u8 regaddr; if (kstrtol(buf, 10, &val)) return -EINVAL; reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4); mutex_lock(&data->update_lock); regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index] : TMP401_TEMP_MSB_WRITE[nr][index]; if (nr == 3) { /* crit is msb only */ i2c_smbus_write_byte_data(client, regaddr, reg >> 8); } else { /* Hardware expects big endian data --> use _swapped */ i2c_smbus_write_word_swapped(client, regaddr, reg); } data->temp[nr][index] = reg; mutex_unlock(&data->update_lock); return count; } static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { int temp, index = to_sensor_dev_attr(devattr)->index; struct tmp401_data *data = tmp401_update_device(dev); long val; u8 reg; if (IS_ERR(data)) return PTR_ERR(data); if (kstrtol(buf, 10, &val)) return -EINVAL; if (data->config & TMP401_CONFIG_RANGE) val = clamp_val(val, -64000, 191000); else val = clamp_val(val, 0, 127000); mutex_lock(&data->update_lock); temp = tmp401_register_to_temp(data->temp[3][index], data->config); val = clamp_val(val, temp - 255000, temp); reg = ((temp - val) + 500) / 1000; i2c_smbus_write_byte_data(data->client, TMP401_TEMP_CRIT_HYST, reg); data->temp_crit_hyst = reg; mutex_unlock(&data->update_lock); return count; } /* * Resets the historical measurements of minimum and maximum temperatures. * This is done by writing any value to any of the minimum/maximum registers * (0x30-0x37). */ static ssize_t reset_temp_history(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct tmp401_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; if (kstrtol(buf, 10, &val)) return -EINVAL; if (val != 1) { dev_err(dev, "temp_reset_history value %ld not supported. Use 1 to reset the history!\n", val); return -EINVAL; } mutex_lock(&data->update_lock); i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val); data->valid = 0; mutex_unlock(&data->update_lock); return count; } static ssize_t update_interval_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tmp401_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->update_interval); } static ssize_t update_interval_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tmp401_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; unsigned long val; int err, rate; err = kstrtoul(buf, 10, &val); if (err) return err; /* * For valid rates, interval can be calculated as * interval = (1 << (7 - rate)) * 125; * Rounded rate is therefore * rate = 7 - __fls(interval * 4 / (125 * 3)); * Use clamp_val() to avoid overflows, and to ensure valid input * for __fls. */ val = clamp_val(val, 125, 16000); rate = 7 - __fls(val * 4 / (125 * 3)); mutex_lock(&data->update_lock); i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate); data->update_interval = (1 << (7 - rate)) * 125; mutex_unlock(&data->update_lock); return count; } static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp, store_temp, 1, 0); static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp, store_temp, 2, 0); static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp, store_temp, 3, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_crit_hyst, store_temp_crit_hyst, 0); static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL, 1, TMP432_STATUS_LOCAL); static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL, 2, TMP432_STATUS_LOCAL); static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL, 3, TMP432_STATUS_LOCAL); static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1); static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp, store_temp, 1, 1); static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp, store_temp, 2, 1); static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp, store_temp, 3, 1); static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1); static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL, 0, TMP432_STATUS_REMOTE1); static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL, 1, TMP432_STATUS_REMOTE1); static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL, 2, TMP432_STATUS_REMOTE1); static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL, 3, TMP432_STATUS_REMOTE1); static DEVICE_ATTR_RW(update_interval); static struct attribute *tmp401_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, &sensor_dev_attr_temp2_fault.dev_attr.attr, &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, &dev_attr_update_interval.attr, NULL }; static const struct attribute_group tmp401_group = { .attrs = tmp401_attributes, }; /* * Additional features of the TMP411 chip. * The TMP411 stores the minimum and maximum * temperature measured since power-on, chip-reset, or * minimum and maximum register reset for both the local * and remote channels. */ static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0); static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0); static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1); static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1); static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, 0); static struct attribute *tmp411_attributes[] = { &sensor_dev_attr_temp1_highest.dev_attr.attr, &sensor_dev_attr_temp1_lowest.dev_attr.attr, &sensor_dev_attr_temp2_highest.dev_attr.attr, &sensor_dev_attr_temp2_lowest.dev_attr.attr, &sensor_dev_attr_temp_reset_history.dev_attr.attr, NULL }; static const struct attribute_group tmp411_group = { .attrs = tmp411_attributes, }; static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2); static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp, store_temp, 1, 2); static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp, store_temp, 2, 2); static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp, store_temp, 3, 2); static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 2); static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL, 0, TMP432_STATUS_REMOTE2); static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL, 1, TMP432_STATUS_REMOTE2); static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL, 2, TMP432_STATUS_REMOTE2); static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL, 3, TMP432_STATUS_REMOTE2); static struct attribute *tmp432_attributes[] = { &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_crit.dev_attr.attr, &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, &sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, NULL }; static const struct attribute_group tmp432_group = { .attrs = tmp432_attributes, }; /* * Additional features of the TMP461 chip. * The TMP461 temperature offset for the remote channel. * show_temp Implement read store_temp implementation storage */ static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp, store_temp, 6, 1); //Create attribute list static struct attribute *tmp461_attributes[] = { &sensor_dev_attr_temp2_offset.dev_attr.attr, NULL }; //Attribute creation group static const struct attribute_group tmp461_group = { .attrs = tmp461_attributes, }; /* * Begin non sysfs callback code (aka Real code) */ static int tmp401_init_client(struct tmp401_data *data, struct i2c_client *client) { int config, config_orig, status = 0; /* Set the conversion rate to 2 Hz */ i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); data->update_interval = 500; /* Start conversions (disable shutdown if necessary) */ config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); if (config < 0) return config; config_orig = config; config &= ~TMP401_CONFIG_SHUTDOWN; config |= (1<<2); //Modify the measurement range. By default, only positive temperature can be measured if (config != config_orig) status = i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config); return status; } static int tmp401_detect(struct i2c_client *client, struct i2c_board_info *info) { enum chips kind; //i2c_ The structure of adapter is very important. It is defined in the registration device, including algorithms and lock operations struct i2c_adapter *adapter = client->adapter; u8 reg; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; /* Detect and identify the chip */ reg = i2c_smbus_read_byte_data(client, TMP401_MANUFACTURER_ID_REG); if (reg != TMP401_MANUFACTURER_ID) return -ENODEV; reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); switch (reg) { case TMP401_DEVICE_ID: if (client->addr != 0x4c) return -ENODEV; kind = tmp401; break; case TMP411A_DEVICE_ID: if (client->addr != 0x4c) return -ENODEV; kind = tmp411; break; case TMP411B_DEVICE_ID: if (client->addr != 0x4d) return -ENODEV; kind = tmp411; break; case TMP411C_DEVICE_ID: if (client->addr != 0x4e) return -ENODEV; kind = tmp411; break; case TMP431_DEVICE_ID: if (client->addr != 0x4c && client->addr != 0x4d) return -ENODEV; kind = tmp431; break; case TMP432_DEVICE_ID: if (client->addr != 0x4c && client->addr != 0x4d) return -ENODEV; kind = tmp432; break; case TMP435_DEVICE_ID: kind = tmp435; break; default: return -ENODEV; } reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); if (reg & 0x1b) return -ENODEV; reg = i2c_smbus_read_byte_data(client, TMP401_CONVERSION_RATE_READ); /* Datasheet says: 0x1-0x6 */ if (reg > 15) return -ENODEV; strlcpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE); return 0; } static int tmp401_probe(struct i2c_client *client, const struct i2c_device_id *id) { static const char * const names[] = { "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461" }; struct device *dev = &client->dev; struct device *hwmon_dev; struct tmp401_data *data; int groups = 0, status; //Allocate space for private data data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL); if (!data) return -ENOMEM; //Initialize private data and locks data->client = client; mutex_init(&data->update_lock); data->kind = id->driver_data; /* Initialize the TMP401 chip */ status = tmp401_init_client(data, client); if (status < 0) return status; /* Register sysfs hooks */ data->groups[groups++] = &tmp401_group; /* Register additional tmp411 sysfs hooks */ if (data->kind == tmp411) data->groups[groups++] = &tmp411_group; /* Register additional tmp432 sysfs hooks */ if (data->kind == tmp432) data->groups[groups++] = &tmp432_group; if (data->kind == tmp461) data->groups[groups++] = &tmp461_group; //Register HWMON device to create property file hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, data, data->groups); if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); dev_info(dev, "Detected TI %s chip\n", names[data->kind]); return 0; } //Define an iic driver structure static struct i2c_driver tmp401_driver = { //I2C is also defined in the declaration hwmon class i2c.h_ CLASS_ DDC I2C_ CLASS_ SPD .class = I2C_CLASS_HWMON, .driver = { .name = "tmp401", //Don't say the driver name .of_match_table = of_match_ptr(tmp401_of_match), }, .probe = tmp401_probe, .id_table = tmp401_id, //Store the device name list when multiple devices .detect = tmp401_detect, //Probe function, send the device address to the bus before calling probe, and wait for slave feedback .address_list = normal_i2c, //Store the slave device address list, such as 0x4c }; module_i2c_driver(tmp401_driver);
summary
It's a little long. I'll master the use of iic this time. How to initialize the iic device in the device tree in the kernel and how to match the device and driver to call the probe function are analyzed in the next section.