18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * lm92 - Hardware monitoring driver 48c2ecf20Sopenharmony_ci * Copyright (C) 2005-2008 Jean Delvare <jdelvare@suse.de> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on the lm90 driver, with some ideas taken from the lm_sensors 78c2ecf20Sopenharmony_ci * lm92 driver as well. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * The LM92 is a sensor chip made by National Semiconductor. It reports 108c2ecf20Sopenharmony_ci * its own temperature with a 0.0625 deg resolution and a 0.33 deg 118c2ecf20Sopenharmony_ci * accuracy. Complete datasheet can be obtained from National's website 128c2ecf20Sopenharmony_ci * at: 138c2ecf20Sopenharmony_ci * http://www.national.com/pf/LM/LM92.html 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * This driver also supports the MAX6635 sensor chip made by Maxim. 168c2ecf20Sopenharmony_ci * This chip is compatible with the LM92, but has a lesser accuracy 178c2ecf20Sopenharmony_ci * (1.0 deg). Complete datasheet can be obtained from Maxim's website 188c2ecf20Sopenharmony_ci * at: 198c2ecf20Sopenharmony_ci * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Since the LM92 was the first chipset supported by this driver, most 228c2ecf20Sopenharmony_ci * comments will refer to this chipset, but are actually general and 238c2ecf20Sopenharmony_ci * concern all supported chipsets, unless mentioned otherwise. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Support could easily be added for the National Semiconductor LM76 268c2ecf20Sopenharmony_ci * and Maxim MAX6633 and MAX6634 chips, which are mostly compatible 278c2ecf20Sopenharmony_ci * with the LM92. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci#include <linux/init.h> 328c2ecf20Sopenharmony_ci#include <linux/slab.h> 338c2ecf20Sopenharmony_ci#include <linux/i2c.h> 348c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 358c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 368c2ecf20Sopenharmony_ci#include <linux/err.h> 378c2ecf20Sopenharmony_ci#include <linux/mutex.h> 388c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * The LM92 and MAX6635 have 2 two-state pins for address selection, 428c2ecf20Sopenharmony_ci * resulting in 4 possible addresses. 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 458c2ecf20Sopenharmony_ci I2C_CLIENT_END }; 468c2ecf20Sopenharmony_cienum chips { lm92, max6635 }; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* The LM92 registers */ 498c2ecf20Sopenharmony_ci#define LM92_REG_CONFIG 0x01 /* 8-bit, RW */ 508c2ecf20Sopenharmony_ci#define LM92_REG_TEMP 0x00 /* 16-bit, RO */ 518c2ecf20Sopenharmony_ci#define LM92_REG_TEMP_HYST 0x02 /* 16-bit, RW */ 528c2ecf20Sopenharmony_ci#define LM92_REG_TEMP_CRIT 0x03 /* 16-bit, RW */ 538c2ecf20Sopenharmony_ci#define LM92_REG_TEMP_LOW 0x04 /* 16-bit, RW */ 548c2ecf20Sopenharmony_ci#define LM92_REG_TEMP_HIGH 0x05 /* 16-bit, RW */ 558c2ecf20Sopenharmony_ci#define LM92_REG_MAN_ID 0x07 /* 16-bit, RO, LM92 only */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, 598c2ecf20Sopenharmony_ci * left-justified in 16-bit registers. No rounding is done, with such 608c2ecf20Sopenharmony_ci * a resolution it's just not worth it. Note that the MAX6635 doesn't 618c2ecf20Sopenharmony_ci * make use of the 4 lower bits for limits (i.e. effective resolution 628c2ecf20Sopenharmony_ci * for limits is 1 degree Celsius). 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistatic inline int TEMP_FROM_REG(s16 reg) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci return reg / 8 * 625 / 10; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic inline s16 TEMP_TO_REG(long val) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci val = clamp_val(val, -60000, 160000); 728c2ecf20Sopenharmony_ci return val * 10 / 625 * 8; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* Alarm flags are stored in the 3 LSB of the temperature register */ 768c2ecf20Sopenharmony_cistatic inline u8 ALARMS_FROM_REG(s16 reg) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci return reg & 0x0007; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cienum temp_index { 828c2ecf20Sopenharmony_ci t_input, 838c2ecf20Sopenharmony_ci t_crit, 848c2ecf20Sopenharmony_ci t_min, 858c2ecf20Sopenharmony_ci t_max, 868c2ecf20Sopenharmony_ci t_hyst, 878c2ecf20Sopenharmony_ci t_num_regs 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic const u8 regs[t_num_regs] = { 918c2ecf20Sopenharmony_ci [t_input] = LM92_REG_TEMP, 928c2ecf20Sopenharmony_ci [t_crit] = LM92_REG_TEMP_CRIT, 938c2ecf20Sopenharmony_ci [t_min] = LM92_REG_TEMP_LOW, 948c2ecf20Sopenharmony_ci [t_max] = LM92_REG_TEMP_HIGH, 958c2ecf20Sopenharmony_ci [t_hyst] = LM92_REG_TEMP_HYST, 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* Client data (each client gets its own) */ 998c2ecf20Sopenharmony_cistruct lm92_data { 1008c2ecf20Sopenharmony_ci struct i2c_client *client; 1018c2ecf20Sopenharmony_ci struct mutex update_lock; 1028c2ecf20Sopenharmony_ci char valid; /* zero until following fields are valid */ 1038c2ecf20Sopenharmony_ci unsigned long last_updated; /* in jiffies */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* registers values */ 1068c2ecf20Sopenharmony_ci s16 temp[t_num_regs]; /* index with enum temp_index */ 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* 1108c2ecf20Sopenharmony_ci * Sysfs attributes and callback functions 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic struct lm92_data *lm92_update_device(struct device *dev) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct lm92_data *data = dev_get_drvdata(dev); 1168c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 1178c2ecf20Sopenharmony_ci int i; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (time_after(jiffies, data->last_updated + HZ) || 1228c2ecf20Sopenharmony_ci !data->valid) { 1238c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "Updating lm92 data\n"); 1248c2ecf20Sopenharmony_ci for (i = 0; i < t_num_regs; i++) { 1258c2ecf20Sopenharmony_ci data->temp[i] = 1268c2ecf20Sopenharmony_ci i2c_smbus_read_word_swapped(client, regs[i]); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci data->last_updated = jiffies; 1298c2ecf20Sopenharmony_ci data->valid = 1; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return data; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic ssize_t temp_show(struct device *dev, struct device_attribute *devattr, 1388c2ecf20Sopenharmony_ci char *buf) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 1418c2ecf20Sopenharmony_ci struct lm92_data *data = lm92_update_device(dev); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic ssize_t temp_store(struct device *dev, 1478c2ecf20Sopenharmony_ci struct device_attribute *devattr, const char *buf, 1488c2ecf20Sopenharmony_ci size_t count) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 1518c2ecf20Sopenharmony_ci struct lm92_data *data = dev_get_drvdata(dev); 1528c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 1538c2ecf20Sopenharmony_ci int nr = attr->index; 1548c2ecf20Sopenharmony_ci long val; 1558c2ecf20Sopenharmony_ci int err; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci err = kstrtol(buf, 10, &val); 1588c2ecf20Sopenharmony_ci if (err) 1598c2ecf20Sopenharmony_ci return err; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 1628c2ecf20Sopenharmony_ci data->temp[nr] = TEMP_TO_REG(val); 1638c2ecf20Sopenharmony_ci i2c_smbus_write_word_swapped(client, regs[nr], data->temp[nr]); 1648c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 1658c2ecf20Sopenharmony_ci return count; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic ssize_t temp_hyst_show(struct device *dev, 1698c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 1728c2ecf20Sopenharmony_ci struct lm92_data *data = lm92_update_device(dev); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]) 1758c2ecf20Sopenharmony_ci - TEMP_FROM_REG(data->temp[t_hyst])); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic ssize_t temp1_min_hyst_show(struct device *dev, 1798c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct lm92_data *data = lm92_update_device(dev); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min]) 1848c2ecf20Sopenharmony_ci + TEMP_FROM_REG(data->temp[t_hyst])); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic ssize_t temp_hyst_store(struct device *dev, 1888c2ecf20Sopenharmony_ci struct device_attribute *devattr, 1898c2ecf20Sopenharmony_ci const char *buf, size_t count) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 1928c2ecf20Sopenharmony_ci struct lm92_data *data = dev_get_drvdata(dev); 1938c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 1948c2ecf20Sopenharmony_ci long val; 1958c2ecf20Sopenharmony_ci int err; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci err = kstrtol(buf, 10, &val); 1988c2ecf20Sopenharmony_ci if (err) 1998c2ecf20Sopenharmony_ci return err; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci val = clamp_val(val, -120000, 220000); 2028c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 2038c2ecf20Sopenharmony_ci data->temp[t_hyst] = 2048c2ecf20Sopenharmony_ci TEMP_TO_REG(TEMP_FROM_REG(data->temp[attr->index]) - val); 2058c2ecf20Sopenharmony_ci i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST, 2068c2ecf20Sopenharmony_ci data->temp[t_hyst]); 2078c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 2088c2ecf20Sopenharmony_ci return count; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic ssize_t alarms_show(struct device *dev, struct device_attribute *attr, 2128c2ecf20Sopenharmony_ci char *buf) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct lm92_data *data = lm92_update_device(dev); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input])); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic ssize_t alarm_show(struct device *dev, struct device_attribute *attr, 2208c2ecf20Sopenharmony_ci char *buf) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci int bitnr = to_sensor_dev_attr(attr)->index; 2238c2ecf20Sopenharmony_ci struct lm92_data *data = lm92_update_device(dev); 2248c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", (data->temp[t_input] >> bitnr) & 1); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, temp, t_input); 2288c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_crit, temp, t_crit); 2298c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_crit_hyst, temp_hyst, t_crit); 2308c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_min, temp, t_min); 2318c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(temp1_min_hyst); 2328c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, temp, t_max); 2338c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_max_hyst, temp_hyst, t_max); 2348c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(alarms); 2358c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 2); 2368c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, 0); 2378c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 1); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* 2408c2ecf20Sopenharmony_ci * Detection and registration 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void lm92_init_client(struct i2c_client *client) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci u8 config; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* Start the conversions if needed */ 2488c2ecf20Sopenharmony_ci config = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); 2498c2ecf20Sopenharmony_ci if (config & 0x01) 2508c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(client, LM92_REG_CONFIG, 2518c2ecf20Sopenharmony_ci config & 0xFE); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic struct attribute *lm92_attrs[] = { 2558c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 2568c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_crit.dev_attr.attr, 2578c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, 2588c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_min.dev_attr.attr, 2598c2ecf20Sopenharmony_ci &dev_attr_temp1_min_hyst.attr, 2608c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_max.dev_attr.attr, 2618c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, 2628c2ecf20Sopenharmony_ci &dev_attr_alarms.attr, 2638c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, 2648c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 2658c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 2668c2ecf20Sopenharmony_ci NULL 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(lm92); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */ 2718c2ecf20Sopenharmony_cistatic int lm92_detect(struct i2c_client *new_client, 2728c2ecf20Sopenharmony_ci struct i2c_board_info *info) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = new_client->adapter; 2758c2ecf20Sopenharmony_ci u8 config; 2768c2ecf20Sopenharmony_ci u16 man_id; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA 2798c2ecf20Sopenharmony_ci | I2C_FUNC_SMBUS_WORD_DATA)) 2808c2ecf20Sopenharmony_ci return -ENODEV; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci config = i2c_smbus_read_byte_data(new_client, LM92_REG_CONFIG); 2838c2ecf20Sopenharmony_ci man_id = i2c_smbus_read_word_data(new_client, LM92_REG_MAN_ID); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if ((config & 0xe0) == 0x00 && man_id == 0x0180) 2868c2ecf20Sopenharmony_ci pr_info("lm92: Found National Semiconductor LM92 chip\n"); 2878c2ecf20Sopenharmony_ci else 2888c2ecf20Sopenharmony_ci return -ENODEV; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci strlcpy(info->type, "lm92", I2C_NAME_SIZE); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int lm92_probe(struct i2c_client *new_client) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct device *hwmon_dev; 2988c2ecf20Sopenharmony_ci struct lm92_data *data; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data), 3018c2ecf20Sopenharmony_ci GFP_KERNEL); 3028c2ecf20Sopenharmony_ci if (!data) 3038c2ecf20Sopenharmony_ci return -ENOMEM; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci data->client = new_client; 3068c2ecf20Sopenharmony_ci mutex_init(&data->update_lock); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Initialize the chipset */ 3098c2ecf20Sopenharmony_ci lm92_init_client(new_client); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, 3128c2ecf20Sopenharmony_ci new_client->name, 3138c2ecf20Sopenharmony_ci data, lm92_groups); 3148c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* 3188c2ecf20Sopenharmony_ci * Module and driver stuff 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic const struct i2c_device_id lm92_id[] = { 3228c2ecf20Sopenharmony_ci { "lm92", lm92 }, 3238c2ecf20Sopenharmony_ci { "max6635", max6635 }, 3248c2ecf20Sopenharmony_ci { } 3258c2ecf20Sopenharmony_ci}; 3268c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lm92_id); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic struct i2c_driver lm92_driver = { 3298c2ecf20Sopenharmony_ci .class = I2C_CLASS_HWMON, 3308c2ecf20Sopenharmony_ci .driver = { 3318c2ecf20Sopenharmony_ci .name = "lm92", 3328c2ecf20Sopenharmony_ci }, 3338c2ecf20Sopenharmony_ci .probe_new = lm92_probe, 3348c2ecf20Sopenharmony_ci .id_table = lm92_id, 3358c2ecf20Sopenharmony_ci .detect = lm92_detect, 3368c2ecf20Sopenharmony_ci .address_list = normal_i2c, 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cimodule_i2c_driver(lm92_driver); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); 3428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LM92/MAX6635 driver"); 3438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 344