174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2add77c64SKrzysztof Helt /* 34d387df7SGuenter Roeck * thmc50.c - Part of lm_sensors, Linux kernel modules for hardware 44d387df7SGuenter Roeck * monitoring 54d387df7SGuenter Roeck * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl> 64d387df7SGuenter Roeck * Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and 74d387df7SGuenter Roeck * Philip Edelbrock <phil@netroedge.com> 8add77c64SKrzysztof Helt */ 9add77c64SKrzysztof Helt 10add77c64SKrzysztof Helt #include <linux/module.h> 11add77c64SKrzysztof Helt #include <linux/init.h> 12add77c64SKrzysztof Helt #include <linux/slab.h> 13add77c64SKrzysztof Helt #include <linux/i2c.h> 14add77c64SKrzysztof Helt #include <linux/hwmon.h> 15add77c64SKrzysztof Helt #include <linux/hwmon-sysfs.h> 16add77c64SKrzysztof Helt #include <linux/err.h> 17add77c64SKrzysztof Helt #include <linux/mutex.h> 18dcd8f392SJean Delvare #include <linux/jiffies.h> 19add77c64SKrzysztof Helt 20add77c64SKrzysztof Helt MODULE_LICENSE("GPL"); 21add77c64SKrzysztof Helt 22add77c64SKrzysztof Helt /* Addresses to scan */ 2325e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; 24add77c64SKrzysztof Helt 25add77c64SKrzysztof Helt /* Insmod parameters */ 26e5e9f44cSJean Delvare enum chips { thmc50, adm1022 }; 27f95f0b4cSJean Delvare 28f95f0b4cSJean Delvare static unsigned short adm1022_temp3[16]; 29f95f0b4cSJean Delvare static unsigned int adm1022_temp3_num; 30f95f0b4cSJean Delvare module_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0); 31b55f3757SGuenter Roeck MODULE_PARM_DESC(adm1022_temp3, 32b55f3757SGuenter Roeck "List of adapter,address pairs to enable 3rd temperature (ADM1022 only)"); 33add77c64SKrzysztof Helt 34add77c64SKrzysztof Helt /* Many THMC50 constants specified below */ 35add77c64SKrzysztof Helt 36add77c64SKrzysztof Helt /* The THMC50 registers */ 37add77c64SKrzysztof Helt #define THMC50_REG_CONF 0x40 38add77c64SKrzysztof Helt #define THMC50_REG_COMPANY_ID 0x3E 39add77c64SKrzysztof Helt #define THMC50_REG_DIE_CODE 0x3F 40add77c64SKrzysztof Helt #define THMC50_REG_ANALOG_OUT 0x19 41dcf3b5fbSKrzysztof Helt /* 42bba891c2SKrzysztof Helt * The mirror status register cannot be used as 43bba891c2SKrzysztof Helt * reading it does not clear alarms. 44dcf3b5fbSKrzysztof Helt */ 45bba891c2SKrzysztof Helt #define THMC50_REG_INTR 0x41 46add77c64SKrzysztof Helt 475910a9b2STobias Klauser static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 }; 485910a9b2STobias Klauser static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C }; 495910a9b2STobias Klauser static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B }; 5084f768c1SKrzysztof Helt static const u8 THMC50_REG_TEMP_CRITICAL[] = { 0x13, 0x14, 0x14 }; 5184f768c1SKrzysztof Helt static const u8 THMC50_REG_TEMP_DEFAULT[] = { 0x17, 0x18, 0x18 }; 52add77c64SKrzysztof Helt 53add77c64SKrzysztof Helt #define THMC50_REG_CONF_nFANOFF 0x20 5484f768c1SKrzysztof Helt #define THMC50_REG_CONF_PROGRAMMED 0x08 55add77c64SKrzysztof Helt 56add77c64SKrzysztof Helt /* Each client has this additional data */ 57add77c64SKrzysztof Helt struct thmc50_data { 5886fd260eSAxel Lin struct i2c_client *client; 5986fd260eSAxel Lin const struct attribute_group *groups[3]; 60add77c64SKrzysztof Helt 61add77c64SKrzysztof Helt struct mutex update_lock; 62add77c64SKrzysztof Helt enum chips type; 63add77c64SKrzysztof Helt unsigned long last_updated; /* In jiffies */ 64add77c64SKrzysztof Helt char has_temp3; /* !=0 if it is ADM1022 in temp3 mode */ 65*952a11caSPaul Fertser bool valid; /* true if following fields are valid */ 66add77c64SKrzysztof Helt 67add77c64SKrzysztof Helt /* Register values */ 68add77c64SKrzysztof Helt s8 temp_input[3]; 69add77c64SKrzysztof Helt s8 temp_max[3]; 70add77c64SKrzysztof Helt s8 temp_min[3]; 7184f768c1SKrzysztof Helt s8 temp_critical[3]; 72add77c64SKrzysztof Helt u8 analog_out; 73dcf3b5fbSKrzysztof Helt u8 alarms; 74add77c64SKrzysztof Helt }; 75add77c64SKrzysztof Helt 769b38a66eSAxel Lin static struct thmc50_data *thmc50_update_device(struct device *dev) 779b38a66eSAxel Lin { 7886fd260eSAxel Lin struct thmc50_data *data = dev_get_drvdata(dev); 7986fd260eSAxel Lin struct i2c_client *client = data->client; 809b38a66eSAxel Lin int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0); 81add77c64SKrzysztof Helt 829b38a66eSAxel Lin mutex_lock(&data->update_lock); 83ccf37488SJean Delvare 849b38a66eSAxel Lin if (time_after(jiffies, data->last_updated + timeout) 859b38a66eSAxel Lin || !data->valid) { 869b38a66eSAxel Lin 879b38a66eSAxel Lin int temps = data->has_temp3 ? 3 : 2; 889b38a66eSAxel Lin int i; 899b38a66eSAxel Lin int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 909b38a66eSAxel Lin 919b38a66eSAxel Lin prog &= THMC50_REG_CONF_PROGRAMMED; 929b38a66eSAxel Lin 939b38a66eSAxel Lin for (i = 0; i < temps; i++) { 949b38a66eSAxel Lin data->temp_input[i] = i2c_smbus_read_byte_data(client, 959b38a66eSAxel Lin THMC50_REG_TEMP[i]); 969b38a66eSAxel Lin data->temp_max[i] = i2c_smbus_read_byte_data(client, 979b38a66eSAxel Lin THMC50_REG_TEMP_MAX[i]); 989b38a66eSAxel Lin data->temp_min[i] = i2c_smbus_read_byte_data(client, 999b38a66eSAxel Lin THMC50_REG_TEMP_MIN[i]); 1009b38a66eSAxel Lin data->temp_critical[i] = 1019b38a66eSAxel Lin i2c_smbus_read_byte_data(client, 1029b38a66eSAxel Lin prog ? THMC50_REG_TEMP_CRITICAL[i] 1039b38a66eSAxel Lin : THMC50_REG_TEMP_DEFAULT[i]); 1049b38a66eSAxel Lin } 1059b38a66eSAxel Lin data->analog_out = 1069b38a66eSAxel Lin i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT); 1079b38a66eSAxel Lin data->alarms = 1089b38a66eSAxel Lin i2c_smbus_read_byte_data(client, THMC50_REG_INTR); 1099b38a66eSAxel Lin data->last_updated = jiffies; 110*952a11caSPaul Fertser data->valid = true; 1119b38a66eSAxel Lin } 1129b38a66eSAxel Lin 1139b38a66eSAxel Lin mutex_unlock(&data->update_lock); 1149b38a66eSAxel Lin 1159b38a66eSAxel Lin return data; 1169b38a66eSAxel Lin } 117add77c64SKrzysztof Helt 11829168f30SGuenter Roeck static ssize_t analog_out_show(struct device *dev, 119add77c64SKrzysztof Helt struct device_attribute *attr, char *buf) 120add77c64SKrzysztof Helt { 121add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 122add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->analog_out); 123add77c64SKrzysztof Helt } 124add77c64SKrzysztof Helt 12529168f30SGuenter Roeck static ssize_t analog_out_store(struct device *dev, 126add77c64SKrzysztof Helt struct device_attribute *attr, 127add77c64SKrzysztof Helt const char *buf, size_t count) 128add77c64SKrzysztof Helt { 12986fd260eSAxel Lin struct thmc50_data *data = dev_get_drvdata(dev); 13086fd260eSAxel Lin struct i2c_client *client = data->client; 131add77c64SKrzysztof Helt int config; 1324d387df7SGuenter Roeck unsigned long tmp; 1334d387df7SGuenter Roeck int err; 1344d387df7SGuenter Roeck 1354d387df7SGuenter Roeck err = kstrtoul(buf, 10, &tmp); 1364d387df7SGuenter Roeck if (err) 1374d387df7SGuenter Roeck return err; 138add77c64SKrzysztof Helt 139add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 1402a844c14SGuenter Roeck data->analog_out = clamp_val(tmp, 0, 255); 141add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT, 142add77c64SKrzysztof Helt data->analog_out); 143add77c64SKrzysztof Helt 144add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 145add77c64SKrzysztof Helt if (data->analog_out == 0) 146add77c64SKrzysztof Helt config &= ~THMC50_REG_CONF_nFANOFF; 147add77c64SKrzysztof Helt else 148add77c64SKrzysztof Helt config |= THMC50_REG_CONF_nFANOFF; 149add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); 150add77c64SKrzysztof Helt 151add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 152add77c64SKrzysztof Helt return count; 153add77c64SKrzysztof Helt } 154add77c64SKrzysztof Helt 155add77c64SKrzysztof Helt /* There is only one PWM mode = DC */ 15629168f30SGuenter Roeck static ssize_t pwm_mode_show(struct device *dev, 15729168f30SGuenter Roeck struct device_attribute *attr, char *buf) 158add77c64SKrzysztof Helt { 159add77c64SKrzysztof Helt return sprintf(buf, "0\n"); 160add77c64SKrzysztof Helt } 161add77c64SKrzysztof Helt 162add77c64SKrzysztof Helt /* Temperatures */ 16329168f30SGuenter Roeck static ssize_t temp_show(struct device *dev, struct device_attribute *attr, 164add77c64SKrzysztof Helt char *buf) 165add77c64SKrzysztof Helt { 166add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 167add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 168add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_input[nr] * 1000); 169add77c64SKrzysztof Helt } 170add77c64SKrzysztof Helt 17129168f30SGuenter Roeck static ssize_t temp_min_show(struct device *dev, 17229168f30SGuenter Roeck struct device_attribute *attr, char *buf) 173add77c64SKrzysztof Helt { 174add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 175add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 176add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_min[nr] * 1000); 177add77c64SKrzysztof Helt } 178add77c64SKrzysztof Helt 17929168f30SGuenter Roeck static ssize_t temp_min_store(struct device *dev, 18029168f30SGuenter Roeck struct device_attribute *attr, const char *buf, 18129168f30SGuenter Roeck size_t count) 182add77c64SKrzysztof Helt { 183add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 18486fd260eSAxel Lin struct thmc50_data *data = dev_get_drvdata(dev); 18586fd260eSAxel Lin struct i2c_client *client = data->client; 1864d387df7SGuenter Roeck long val; 1874d387df7SGuenter Roeck int err; 1884d387df7SGuenter Roeck 1894d387df7SGuenter Roeck err = kstrtol(buf, 10, &val); 1904d387df7SGuenter Roeck if (err) 1914d387df7SGuenter Roeck return err; 192add77c64SKrzysztof Helt 193add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 1942a844c14SGuenter Roeck data->temp_min[nr] = clamp_val(val / 1000, -128, 127); 195add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr], 196add77c64SKrzysztof Helt data->temp_min[nr]); 197add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 198add77c64SKrzysztof Helt return count; 199add77c64SKrzysztof Helt } 200add77c64SKrzysztof Helt 20129168f30SGuenter Roeck static ssize_t temp_max_show(struct device *dev, 20229168f30SGuenter Roeck struct device_attribute *attr, char *buf) 203add77c64SKrzysztof Helt { 204add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 205add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 206add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_max[nr] * 1000); 207add77c64SKrzysztof Helt } 208add77c64SKrzysztof Helt 20929168f30SGuenter Roeck static ssize_t temp_max_store(struct device *dev, 21029168f30SGuenter Roeck struct device_attribute *attr, const char *buf, 21129168f30SGuenter Roeck size_t count) 212add77c64SKrzysztof Helt { 213add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 21486fd260eSAxel Lin struct thmc50_data *data = dev_get_drvdata(dev); 21586fd260eSAxel Lin struct i2c_client *client = data->client; 2164d387df7SGuenter Roeck long val; 2174d387df7SGuenter Roeck int err; 2184d387df7SGuenter Roeck 2194d387df7SGuenter Roeck err = kstrtol(buf, 10, &val); 2204d387df7SGuenter Roeck if (err) 2214d387df7SGuenter Roeck return err; 222add77c64SKrzysztof Helt 223add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 2242a844c14SGuenter Roeck data->temp_max[nr] = clamp_val(val / 1000, -128, 127); 225add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr], 226add77c64SKrzysztof Helt data->temp_max[nr]); 227add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 228add77c64SKrzysztof Helt return count; 229add77c64SKrzysztof Helt } 230add77c64SKrzysztof Helt 23129168f30SGuenter Roeck static ssize_t temp_critical_show(struct device *dev, 23229168f30SGuenter Roeck struct device_attribute *attr, char *buf) 23384f768c1SKrzysztof Helt { 23484f768c1SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 23584f768c1SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 23684f768c1SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_critical[nr] * 1000); 23784f768c1SKrzysztof Helt } 23884f768c1SKrzysztof Helt 23929168f30SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, 240dcf3b5fbSKrzysztof Helt char *buf) 241dcf3b5fbSKrzysztof Helt { 242dcf3b5fbSKrzysztof Helt int index = to_sensor_dev_attr(attr)->index; 243dcf3b5fbSKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 244dcf3b5fbSKrzysztof Helt 245dcf3b5fbSKrzysztof Helt return sprintf(buf, "%u\n", (data->alarms >> index) & 1); 246dcf3b5fbSKrzysztof Helt } 247dcf3b5fbSKrzysztof Helt 24829168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); 24929168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0); 25029168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0); 25129168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_crit, temp_critical, 0); 25229168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1); 25329168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1); 25429168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1); 25529168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_crit, temp_critical, 1); 25629168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2); 25729168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2); 25829168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2); 25929168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_crit, temp_critical, 2); 260add77c64SKrzysztof Helt 26129168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 0); 26229168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 5); 26329168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 1); 26429168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_fault, alarm, 7); 26529168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_fault, alarm, 2); 266add77c64SKrzysztof Helt 26729168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(pwm1, analog_out, 0); 26829168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(pwm1_mode, pwm_mode, 0); 269add77c64SKrzysztof Helt 270add77c64SKrzysztof Helt static struct attribute *thmc50_attributes[] = { 271add77c64SKrzysztof Helt &sensor_dev_attr_temp1_max.dev_attr.attr, 272add77c64SKrzysztof Helt &sensor_dev_attr_temp1_min.dev_attr.attr, 273add77c64SKrzysztof Helt &sensor_dev_attr_temp1_input.dev_attr.attr, 27484f768c1SKrzysztof Helt &sensor_dev_attr_temp1_crit.dev_attr.attr, 275dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp1_alarm.dev_attr.attr, 276add77c64SKrzysztof Helt &sensor_dev_attr_temp2_max.dev_attr.attr, 277add77c64SKrzysztof Helt &sensor_dev_attr_temp2_min.dev_attr.attr, 278add77c64SKrzysztof Helt &sensor_dev_attr_temp2_input.dev_attr.attr, 27984f768c1SKrzysztof Helt &sensor_dev_attr_temp2_crit.dev_attr.attr, 280dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp2_alarm.dev_attr.attr, 281dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp2_fault.dev_attr.attr, 282add77c64SKrzysztof Helt &sensor_dev_attr_pwm1.dev_attr.attr, 283add77c64SKrzysztof Helt &sensor_dev_attr_pwm1_mode.dev_attr.attr, 284add77c64SKrzysztof Helt NULL 285add77c64SKrzysztof Helt }; 286add77c64SKrzysztof Helt 287add77c64SKrzysztof Helt static const struct attribute_group thmc50_group = { 288add77c64SKrzysztof Helt .attrs = thmc50_attributes, 289add77c64SKrzysztof Helt }; 290add77c64SKrzysztof Helt 291add77c64SKrzysztof Helt /* for ADM1022 3rd temperature mode */ 292894c00cfSJean Delvare static struct attribute *temp3_attributes[] = { 293add77c64SKrzysztof Helt &sensor_dev_attr_temp3_max.dev_attr.attr, 294add77c64SKrzysztof Helt &sensor_dev_attr_temp3_min.dev_attr.attr, 295add77c64SKrzysztof Helt &sensor_dev_attr_temp3_input.dev_attr.attr, 29684f768c1SKrzysztof Helt &sensor_dev_attr_temp3_crit.dev_attr.attr, 297dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp3_alarm.dev_attr.attr, 298dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp3_fault.dev_attr.attr, 299add77c64SKrzysztof Helt NULL 300add77c64SKrzysztof Helt }; 301add77c64SKrzysztof Helt 302894c00cfSJean Delvare static const struct attribute_group temp3_group = { 303894c00cfSJean Delvare .attrs = temp3_attributes, 304add77c64SKrzysztof Helt }; 305add77c64SKrzysztof Helt 306ccf37488SJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */ 307310ec792SJean Delvare static int thmc50_detect(struct i2c_client *client, 308ccf37488SJean Delvare struct i2c_board_info *info) 309add77c64SKrzysztof Helt { 310add77c64SKrzysztof Helt unsigned company; 311add77c64SKrzysztof Helt unsigned revision; 312add77c64SKrzysztof Helt unsigned config; 313ccf37488SJean Delvare struct i2c_adapter *adapter = client->adapter; 314cc28a610SJean Delvare const char *type_name; 315add77c64SKrzysztof Helt 316add77c64SKrzysztof Helt if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 317b55f3757SGuenter Roeck pr_debug("thmc50: detect failed, smbus byte data not supported!\n"); 318ccf37488SJean Delvare return -ENODEV; 319add77c64SKrzysztof Helt } 320add77c64SKrzysztof Helt 321add77c64SKrzysztof Helt pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n", 322add77c64SKrzysztof Helt client->addr, i2c_adapter_id(client->adapter)); 323add77c64SKrzysztof Helt 324add77c64SKrzysztof Helt company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID); 325add77c64SKrzysztof Helt revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE); 326add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 32752df6440SJean Delvare if (revision < 0xc0 || (config & 0x10)) 32852df6440SJean Delvare return -ENODEV; 329add77c64SKrzysztof Helt 33052df6440SJean Delvare if (company == 0x41) { 331add77c64SKrzysztof Helt int id = i2c_adapter_id(client->adapter); 332add77c64SKrzysztof Helt int i; 333add77c64SKrzysztof Helt 334add77c64SKrzysztof Helt type_name = "adm1022"; 335add77c64SKrzysztof Helt for (i = 0; i + 1 < adm1022_temp3_num; i += 2) 336add77c64SKrzysztof Helt if (adm1022_temp3[i] == id && 337ccf37488SJean Delvare adm1022_temp3[i + 1] == client->addr) { 338add77c64SKrzysztof Helt /* enable 2nd remote temp */ 339ccf37488SJean Delvare config |= (1 << 7); 340ccf37488SJean Delvare i2c_smbus_write_byte_data(client, 341ccf37488SJean Delvare THMC50_REG_CONF, 342ccf37488SJean Delvare config); 343add77c64SKrzysztof Helt break; 344add77c64SKrzysztof Helt } 34552df6440SJean Delvare } else if (company == 0x49) { 346cc28a610SJean Delvare type_name = "thmc50"; 34752df6440SJean Delvare } else { 34852df6440SJean Delvare pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n"); 34952df6440SJean Delvare return -ENODEV; 350add77c64SKrzysztof Helt } 35152df6440SJean Delvare 352cc28a610SJean Delvare pr_debug("thmc50: Detected %s (version %x, revision %x)\n", 353cc28a610SJean Delvare type_name, (revision >> 4) - 0xc, revision & 0xf); 354add77c64SKrzysztof Helt 355ccf37488SJean Delvare strlcpy(info->type, type_name, I2C_NAME_SIZE); 356add77c64SKrzysztof Helt 357ccf37488SJean Delvare return 0; 358ccf37488SJean Delvare } 359ccf37488SJean Delvare 36086fd260eSAxel Lin static void thmc50_init_client(struct thmc50_data *data) 3619b38a66eSAxel Lin { 36286fd260eSAxel Lin struct i2c_client *client = data->client; 3639b38a66eSAxel Lin int config; 3649b38a66eSAxel Lin 3659b38a66eSAxel Lin data->analog_out = i2c_smbus_read_byte_data(client, 3669b38a66eSAxel Lin THMC50_REG_ANALOG_OUT); 3679b38a66eSAxel Lin /* set up to at least 1 */ 3689b38a66eSAxel Lin if (data->analog_out == 0) { 3699b38a66eSAxel Lin data->analog_out = 1; 3709b38a66eSAxel Lin i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT, 3719b38a66eSAxel Lin data->analog_out); 3729b38a66eSAxel Lin } 3739b38a66eSAxel Lin config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 3749b38a66eSAxel Lin config |= 0x1; /* start the chip if it is in standby mode */ 3759b38a66eSAxel Lin if (data->type == adm1022 && (config & (1 << 7))) 3769b38a66eSAxel Lin data->has_temp3 = 1; 3779b38a66eSAxel Lin i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); 3789b38a66eSAxel Lin } 3799b38a66eSAxel Lin 38067487038SStephen Kitt static const struct i2c_device_id thmc50_id[]; 38167487038SStephen Kitt 38267487038SStephen Kitt static int thmc50_probe(struct i2c_client *client) 383ccf37488SJean Delvare { 38486fd260eSAxel Lin struct device *dev = &client->dev; 385ccf37488SJean Delvare struct thmc50_data *data; 38686fd260eSAxel Lin struct device *hwmon_dev; 38786fd260eSAxel Lin int idx = 0; 388ccf37488SJean Delvare 38986fd260eSAxel Lin data = devm_kzalloc(dev, sizeof(struct thmc50_data), GFP_KERNEL); 390bd91d3baSGuenter Roeck if (!data) 391bd91d3baSGuenter Roeck return -ENOMEM; 392ccf37488SJean Delvare 39386fd260eSAxel Lin data->client = client; 39467487038SStephen Kitt data->type = i2c_match_id(thmc50_id, client)->driver_data; 395ccf37488SJean Delvare mutex_init(&data->update_lock); 396add77c64SKrzysztof Helt 39786fd260eSAxel Lin thmc50_init_client(data); 398add77c64SKrzysztof Helt 39986fd260eSAxel Lin /* sysfs hooks */ 40086fd260eSAxel Lin data->groups[idx++] = &thmc50_group; 401add77c64SKrzysztof Helt 40286fd260eSAxel Lin /* Register additional ADM1022 sysfs hooks */ 403894c00cfSJean Delvare if (data->has_temp3) 40486fd260eSAxel Lin data->groups[idx++] = &temp3_group; 405add77c64SKrzysztof Helt 40686fd260eSAxel Lin hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 40786fd260eSAxel Lin data, data->groups); 40886fd260eSAxel Lin return PTR_ERR_OR_ZERO(hwmon_dev); 409add77c64SKrzysztof Helt } 410add77c64SKrzysztof Helt 4119b38a66eSAxel Lin static const struct i2c_device_id thmc50_id[] = { 4129b38a66eSAxel Lin { "adm1022", adm1022 }, 4139b38a66eSAxel Lin { "thmc50", thmc50 }, 4149b38a66eSAxel Lin { } 4159b38a66eSAxel Lin }; 4169b38a66eSAxel Lin MODULE_DEVICE_TABLE(i2c, thmc50_id); 417add77c64SKrzysztof Helt 4189b38a66eSAxel Lin static struct i2c_driver thmc50_driver = { 4199b38a66eSAxel Lin .class = I2C_CLASS_HWMON, 4209b38a66eSAxel Lin .driver = { 4219b38a66eSAxel Lin .name = "thmc50", 4229b38a66eSAxel Lin }, 42367487038SStephen Kitt .probe_new = thmc50_probe, 4249b38a66eSAxel Lin .id_table = thmc50_id, 4259b38a66eSAxel Lin .detect = thmc50_detect, 4269b38a66eSAxel Lin .address_list = normal_i2c, 4279b38a66eSAxel Lin }; 428add77c64SKrzysztof Helt 429f0967eeaSAxel Lin module_i2c_driver(thmc50_driver); 430add77c64SKrzysztof Helt 431add77c64SKrzysztof Helt MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>"); 432add77c64SKrzysztof Helt MODULE_DESCRIPTION("THMC50 driver"); 433