1add77c64SKrzysztof Helt /* 24d387df7SGuenter Roeck * thmc50.c - Part of lm_sensors, Linux kernel modules for hardware 34d387df7SGuenter Roeck * monitoring 44d387df7SGuenter Roeck * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl> 54d387df7SGuenter Roeck * Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and 64d387df7SGuenter Roeck * Philip Edelbrock <phil@netroedge.com> 74d387df7SGuenter Roeck * 84d387df7SGuenter Roeck * This program is free software; you can redistribute it and/or modify 94d387df7SGuenter Roeck * it under the terms of the GNU General Public License as published by 104d387df7SGuenter Roeck * the Free Software Foundation; either version 2 of the License, or 114d387df7SGuenter Roeck * (at your option) any later version. 124d387df7SGuenter Roeck * 134d387df7SGuenter Roeck * This program is distributed in the hope that it will be useful, 144d387df7SGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 154d387df7SGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 164d387df7SGuenter Roeck * GNU General Public License for more details. 174d387df7SGuenter Roeck * 184d387df7SGuenter Roeck * You should have received a copy of the GNU General Public License 194d387df7SGuenter Roeck * along with this program; if not, write to the Free Software 204d387df7SGuenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21add77c64SKrzysztof Helt */ 22add77c64SKrzysztof Helt 23add77c64SKrzysztof Helt #include <linux/module.h> 24add77c64SKrzysztof Helt #include <linux/init.h> 25add77c64SKrzysztof Helt #include <linux/slab.h> 26add77c64SKrzysztof Helt #include <linux/i2c.h> 27add77c64SKrzysztof Helt #include <linux/hwmon.h> 28add77c64SKrzysztof Helt #include <linux/hwmon-sysfs.h> 29add77c64SKrzysztof Helt #include <linux/err.h> 30add77c64SKrzysztof Helt #include <linux/mutex.h> 31dcd8f392SJean Delvare #include <linux/jiffies.h> 32add77c64SKrzysztof Helt 33add77c64SKrzysztof Helt MODULE_LICENSE("GPL"); 34add77c64SKrzysztof Helt 35add77c64SKrzysztof Helt /* Addresses to scan */ 3625e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; 37add77c64SKrzysztof Helt 38add77c64SKrzysztof Helt /* Insmod parameters */ 39e5e9f44cSJean Delvare enum chips { thmc50, adm1022 }; 40f95f0b4cSJean Delvare 41f95f0b4cSJean Delvare static unsigned short adm1022_temp3[16]; 42f95f0b4cSJean Delvare static unsigned int adm1022_temp3_num; 43f95f0b4cSJean Delvare module_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0); 44b55f3757SGuenter Roeck MODULE_PARM_DESC(adm1022_temp3, 45b55f3757SGuenter Roeck "List of adapter,address pairs to enable 3rd temperature (ADM1022 only)"); 46add77c64SKrzysztof Helt 47add77c64SKrzysztof Helt /* Many THMC50 constants specified below */ 48add77c64SKrzysztof Helt 49add77c64SKrzysztof Helt /* The THMC50 registers */ 50add77c64SKrzysztof Helt #define THMC50_REG_CONF 0x40 51add77c64SKrzysztof Helt #define THMC50_REG_COMPANY_ID 0x3E 52add77c64SKrzysztof Helt #define THMC50_REG_DIE_CODE 0x3F 53add77c64SKrzysztof Helt #define THMC50_REG_ANALOG_OUT 0x19 54dcf3b5fbSKrzysztof Helt /* 55bba891c2SKrzysztof Helt * The mirror status register cannot be used as 56bba891c2SKrzysztof Helt * reading it does not clear alarms. 57dcf3b5fbSKrzysztof Helt */ 58bba891c2SKrzysztof Helt #define THMC50_REG_INTR 0x41 59add77c64SKrzysztof Helt 605910a9b2STobias Klauser static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 }; 615910a9b2STobias Klauser static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C }; 625910a9b2STobias Klauser static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B }; 6384f768c1SKrzysztof Helt static const u8 THMC50_REG_TEMP_CRITICAL[] = { 0x13, 0x14, 0x14 }; 6484f768c1SKrzysztof Helt static const u8 THMC50_REG_TEMP_DEFAULT[] = { 0x17, 0x18, 0x18 }; 65add77c64SKrzysztof Helt 66add77c64SKrzysztof Helt #define THMC50_REG_CONF_nFANOFF 0x20 6784f768c1SKrzysztof Helt #define THMC50_REG_CONF_PROGRAMMED 0x08 68add77c64SKrzysztof Helt 69add77c64SKrzysztof Helt /* Each client has this additional data */ 70add77c64SKrzysztof Helt struct thmc50_data { 7186fd260eSAxel Lin struct i2c_client *client; 7286fd260eSAxel Lin const struct attribute_group *groups[3]; 73add77c64SKrzysztof Helt 74add77c64SKrzysztof Helt struct mutex update_lock; 75add77c64SKrzysztof Helt enum chips type; 76add77c64SKrzysztof Helt unsigned long last_updated; /* In jiffies */ 77add77c64SKrzysztof Helt char has_temp3; /* !=0 if it is ADM1022 in temp3 mode */ 78add77c64SKrzysztof Helt char valid; /* !=0 if following fields are valid */ 79add77c64SKrzysztof Helt 80add77c64SKrzysztof Helt /* Register values */ 81add77c64SKrzysztof Helt s8 temp_input[3]; 82add77c64SKrzysztof Helt s8 temp_max[3]; 83add77c64SKrzysztof Helt s8 temp_min[3]; 8484f768c1SKrzysztof Helt s8 temp_critical[3]; 85add77c64SKrzysztof Helt u8 analog_out; 86dcf3b5fbSKrzysztof Helt u8 alarms; 87add77c64SKrzysztof Helt }; 88add77c64SKrzysztof Helt 899b38a66eSAxel Lin static struct thmc50_data *thmc50_update_device(struct device *dev) 909b38a66eSAxel Lin { 9186fd260eSAxel Lin struct thmc50_data *data = dev_get_drvdata(dev); 9286fd260eSAxel Lin struct i2c_client *client = data->client; 939b38a66eSAxel Lin int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0); 94add77c64SKrzysztof Helt 959b38a66eSAxel Lin mutex_lock(&data->update_lock); 96ccf37488SJean Delvare 979b38a66eSAxel Lin if (time_after(jiffies, data->last_updated + timeout) 989b38a66eSAxel Lin || !data->valid) { 999b38a66eSAxel Lin 1009b38a66eSAxel Lin int temps = data->has_temp3 ? 3 : 2; 1019b38a66eSAxel Lin int i; 1029b38a66eSAxel Lin int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 1039b38a66eSAxel Lin 1049b38a66eSAxel Lin prog &= THMC50_REG_CONF_PROGRAMMED; 1059b38a66eSAxel Lin 1069b38a66eSAxel Lin for (i = 0; i < temps; i++) { 1079b38a66eSAxel Lin data->temp_input[i] = i2c_smbus_read_byte_data(client, 1089b38a66eSAxel Lin THMC50_REG_TEMP[i]); 1099b38a66eSAxel Lin data->temp_max[i] = i2c_smbus_read_byte_data(client, 1109b38a66eSAxel Lin THMC50_REG_TEMP_MAX[i]); 1119b38a66eSAxel Lin data->temp_min[i] = i2c_smbus_read_byte_data(client, 1129b38a66eSAxel Lin THMC50_REG_TEMP_MIN[i]); 1139b38a66eSAxel Lin data->temp_critical[i] = 1149b38a66eSAxel Lin i2c_smbus_read_byte_data(client, 1159b38a66eSAxel Lin prog ? THMC50_REG_TEMP_CRITICAL[i] 1169b38a66eSAxel Lin : THMC50_REG_TEMP_DEFAULT[i]); 1179b38a66eSAxel Lin } 1189b38a66eSAxel Lin data->analog_out = 1199b38a66eSAxel Lin i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT); 1209b38a66eSAxel Lin data->alarms = 1219b38a66eSAxel Lin i2c_smbus_read_byte_data(client, THMC50_REG_INTR); 1229b38a66eSAxel Lin data->last_updated = jiffies; 1239b38a66eSAxel Lin data->valid = 1; 1249b38a66eSAxel Lin } 1259b38a66eSAxel Lin 1269b38a66eSAxel Lin mutex_unlock(&data->update_lock); 1279b38a66eSAxel Lin 1289b38a66eSAxel Lin return data; 1299b38a66eSAxel Lin } 130add77c64SKrzysztof Helt 131*29168f30SGuenter Roeck static ssize_t analog_out_show(struct device *dev, 132add77c64SKrzysztof Helt struct device_attribute *attr, char *buf) 133add77c64SKrzysztof Helt { 134add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 135add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->analog_out); 136add77c64SKrzysztof Helt } 137add77c64SKrzysztof Helt 138*29168f30SGuenter Roeck static ssize_t analog_out_store(struct device *dev, 139add77c64SKrzysztof Helt struct device_attribute *attr, 140add77c64SKrzysztof Helt const char *buf, size_t count) 141add77c64SKrzysztof Helt { 14286fd260eSAxel Lin struct thmc50_data *data = dev_get_drvdata(dev); 14386fd260eSAxel Lin struct i2c_client *client = data->client; 144add77c64SKrzysztof Helt int config; 1454d387df7SGuenter Roeck unsigned long tmp; 1464d387df7SGuenter Roeck int err; 1474d387df7SGuenter Roeck 1484d387df7SGuenter Roeck err = kstrtoul(buf, 10, &tmp); 1494d387df7SGuenter Roeck if (err) 1504d387df7SGuenter Roeck return err; 151add77c64SKrzysztof Helt 152add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 1532a844c14SGuenter Roeck data->analog_out = clamp_val(tmp, 0, 255); 154add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT, 155add77c64SKrzysztof Helt data->analog_out); 156add77c64SKrzysztof Helt 157add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 158add77c64SKrzysztof Helt if (data->analog_out == 0) 159add77c64SKrzysztof Helt config &= ~THMC50_REG_CONF_nFANOFF; 160add77c64SKrzysztof Helt else 161add77c64SKrzysztof Helt config |= THMC50_REG_CONF_nFANOFF; 162add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); 163add77c64SKrzysztof Helt 164add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 165add77c64SKrzysztof Helt return count; 166add77c64SKrzysztof Helt } 167add77c64SKrzysztof Helt 168add77c64SKrzysztof Helt /* There is only one PWM mode = DC */ 169*29168f30SGuenter Roeck static ssize_t pwm_mode_show(struct device *dev, 170*29168f30SGuenter Roeck struct device_attribute *attr, char *buf) 171add77c64SKrzysztof Helt { 172add77c64SKrzysztof Helt return sprintf(buf, "0\n"); 173add77c64SKrzysztof Helt } 174add77c64SKrzysztof Helt 175add77c64SKrzysztof Helt /* Temperatures */ 176*29168f30SGuenter Roeck static ssize_t temp_show(struct device *dev, struct device_attribute *attr, 177add77c64SKrzysztof Helt char *buf) 178add77c64SKrzysztof Helt { 179add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 180add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 181add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_input[nr] * 1000); 182add77c64SKrzysztof Helt } 183add77c64SKrzysztof Helt 184*29168f30SGuenter Roeck static ssize_t temp_min_show(struct device *dev, 185*29168f30SGuenter Roeck struct device_attribute *attr, char *buf) 186add77c64SKrzysztof Helt { 187add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 188add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 189add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_min[nr] * 1000); 190add77c64SKrzysztof Helt } 191add77c64SKrzysztof Helt 192*29168f30SGuenter Roeck static ssize_t temp_min_store(struct device *dev, 193*29168f30SGuenter Roeck struct device_attribute *attr, const char *buf, 194*29168f30SGuenter Roeck size_t count) 195add77c64SKrzysztof Helt { 196add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 19786fd260eSAxel Lin struct thmc50_data *data = dev_get_drvdata(dev); 19886fd260eSAxel Lin struct i2c_client *client = data->client; 1994d387df7SGuenter Roeck long val; 2004d387df7SGuenter Roeck int err; 2014d387df7SGuenter Roeck 2024d387df7SGuenter Roeck err = kstrtol(buf, 10, &val); 2034d387df7SGuenter Roeck if (err) 2044d387df7SGuenter Roeck return err; 205add77c64SKrzysztof Helt 206add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 2072a844c14SGuenter Roeck data->temp_min[nr] = clamp_val(val / 1000, -128, 127); 208add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr], 209add77c64SKrzysztof Helt data->temp_min[nr]); 210add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 211add77c64SKrzysztof Helt return count; 212add77c64SKrzysztof Helt } 213add77c64SKrzysztof Helt 214*29168f30SGuenter Roeck static ssize_t temp_max_show(struct device *dev, 215*29168f30SGuenter Roeck struct device_attribute *attr, char *buf) 216add77c64SKrzysztof Helt { 217add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 218add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 219add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_max[nr] * 1000); 220add77c64SKrzysztof Helt } 221add77c64SKrzysztof Helt 222*29168f30SGuenter Roeck static ssize_t temp_max_store(struct device *dev, 223*29168f30SGuenter Roeck struct device_attribute *attr, const char *buf, 224*29168f30SGuenter Roeck size_t count) 225add77c64SKrzysztof Helt { 226add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 22786fd260eSAxel Lin struct thmc50_data *data = dev_get_drvdata(dev); 22886fd260eSAxel Lin struct i2c_client *client = data->client; 2294d387df7SGuenter Roeck long val; 2304d387df7SGuenter Roeck int err; 2314d387df7SGuenter Roeck 2324d387df7SGuenter Roeck err = kstrtol(buf, 10, &val); 2334d387df7SGuenter Roeck if (err) 2344d387df7SGuenter Roeck return err; 235add77c64SKrzysztof Helt 236add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 2372a844c14SGuenter Roeck data->temp_max[nr] = clamp_val(val / 1000, -128, 127); 238add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr], 239add77c64SKrzysztof Helt data->temp_max[nr]); 240add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 241add77c64SKrzysztof Helt return count; 242add77c64SKrzysztof Helt } 243add77c64SKrzysztof Helt 244*29168f30SGuenter Roeck static ssize_t temp_critical_show(struct device *dev, 245*29168f30SGuenter Roeck struct device_attribute *attr, char *buf) 24684f768c1SKrzysztof Helt { 24784f768c1SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 24884f768c1SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 24984f768c1SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_critical[nr] * 1000); 25084f768c1SKrzysztof Helt } 25184f768c1SKrzysztof Helt 252*29168f30SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, 253dcf3b5fbSKrzysztof Helt char *buf) 254dcf3b5fbSKrzysztof Helt { 255dcf3b5fbSKrzysztof Helt int index = to_sensor_dev_attr(attr)->index; 256dcf3b5fbSKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 257dcf3b5fbSKrzysztof Helt 258dcf3b5fbSKrzysztof Helt return sprintf(buf, "%u\n", (data->alarms >> index) & 1); 259dcf3b5fbSKrzysztof Helt } 260dcf3b5fbSKrzysztof Helt 261*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); 262*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0); 263*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0); 264*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_crit, temp_critical, 0); 265*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1); 266*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1); 267*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1); 268*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_crit, temp_critical, 1); 269*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2); 270*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2); 271*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2); 272*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_crit, temp_critical, 2); 273add77c64SKrzysztof Helt 274*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 0); 275*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 5); 276*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 1); 277*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_fault, alarm, 7); 278*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_fault, alarm, 2); 279add77c64SKrzysztof Helt 280*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(pwm1, analog_out, 0); 281*29168f30SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(pwm1_mode, pwm_mode, 0); 282add77c64SKrzysztof Helt 283add77c64SKrzysztof Helt static struct attribute *thmc50_attributes[] = { 284add77c64SKrzysztof Helt &sensor_dev_attr_temp1_max.dev_attr.attr, 285add77c64SKrzysztof Helt &sensor_dev_attr_temp1_min.dev_attr.attr, 286add77c64SKrzysztof Helt &sensor_dev_attr_temp1_input.dev_attr.attr, 28784f768c1SKrzysztof Helt &sensor_dev_attr_temp1_crit.dev_attr.attr, 288dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp1_alarm.dev_attr.attr, 289add77c64SKrzysztof Helt &sensor_dev_attr_temp2_max.dev_attr.attr, 290add77c64SKrzysztof Helt &sensor_dev_attr_temp2_min.dev_attr.attr, 291add77c64SKrzysztof Helt &sensor_dev_attr_temp2_input.dev_attr.attr, 29284f768c1SKrzysztof Helt &sensor_dev_attr_temp2_crit.dev_attr.attr, 293dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp2_alarm.dev_attr.attr, 294dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp2_fault.dev_attr.attr, 295add77c64SKrzysztof Helt &sensor_dev_attr_pwm1.dev_attr.attr, 296add77c64SKrzysztof Helt &sensor_dev_attr_pwm1_mode.dev_attr.attr, 297add77c64SKrzysztof Helt NULL 298add77c64SKrzysztof Helt }; 299add77c64SKrzysztof Helt 300add77c64SKrzysztof Helt static const struct attribute_group thmc50_group = { 301add77c64SKrzysztof Helt .attrs = thmc50_attributes, 302add77c64SKrzysztof Helt }; 303add77c64SKrzysztof Helt 304add77c64SKrzysztof Helt /* for ADM1022 3rd temperature mode */ 305894c00cfSJean Delvare static struct attribute *temp3_attributes[] = { 306add77c64SKrzysztof Helt &sensor_dev_attr_temp3_max.dev_attr.attr, 307add77c64SKrzysztof Helt &sensor_dev_attr_temp3_min.dev_attr.attr, 308add77c64SKrzysztof Helt &sensor_dev_attr_temp3_input.dev_attr.attr, 30984f768c1SKrzysztof Helt &sensor_dev_attr_temp3_crit.dev_attr.attr, 310dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp3_alarm.dev_attr.attr, 311dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp3_fault.dev_attr.attr, 312add77c64SKrzysztof Helt NULL 313add77c64SKrzysztof Helt }; 314add77c64SKrzysztof Helt 315894c00cfSJean Delvare static const struct attribute_group temp3_group = { 316894c00cfSJean Delvare .attrs = temp3_attributes, 317add77c64SKrzysztof Helt }; 318add77c64SKrzysztof Helt 319ccf37488SJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */ 320310ec792SJean Delvare static int thmc50_detect(struct i2c_client *client, 321ccf37488SJean Delvare struct i2c_board_info *info) 322add77c64SKrzysztof Helt { 323add77c64SKrzysztof Helt unsigned company; 324add77c64SKrzysztof Helt unsigned revision; 325add77c64SKrzysztof Helt unsigned config; 326ccf37488SJean Delvare struct i2c_adapter *adapter = client->adapter; 327cc28a610SJean Delvare const char *type_name; 328add77c64SKrzysztof Helt 329add77c64SKrzysztof Helt if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 330b55f3757SGuenter Roeck pr_debug("thmc50: detect failed, smbus byte data not supported!\n"); 331ccf37488SJean Delvare return -ENODEV; 332add77c64SKrzysztof Helt } 333add77c64SKrzysztof Helt 334add77c64SKrzysztof Helt pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n", 335add77c64SKrzysztof Helt client->addr, i2c_adapter_id(client->adapter)); 336add77c64SKrzysztof Helt 337add77c64SKrzysztof Helt company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID); 338add77c64SKrzysztof Helt revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE); 339add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 34052df6440SJean Delvare if (revision < 0xc0 || (config & 0x10)) 34152df6440SJean Delvare return -ENODEV; 342add77c64SKrzysztof Helt 34352df6440SJean Delvare if (company == 0x41) { 344add77c64SKrzysztof Helt int id = i2c_adapter_id(client->adapter); 345add77c64SKrzysztof Helt int i; 346add77c64SKrzysztof Helt 347add77c64SKrzysztof Helt type_name = "adm1022"; 348add77c64SKrzysztof Helt for (i = 0; i + 1 < adm1022_temp3_num; i += 2) 349add77c64SKrzysztof Helt if (adm1022_temp3[i] == id && 350ccf37488SJean Delvare adm1022_temp3[i + 1] == client->addr) { 351add77c64SKrzysztof Helt /* enable 2nd remote temp */ 352ccf37488SJean Delvare config |= (1 << 7); 353ccf37488SJean Delvare i2c_smbus_write_byte_data(client, 354ccf37488SJean Delvare THMC50_REG_CONF, 355ccf37488SJean Delvare config); 356add77c64SKrzysztof Helt break; 357add77c64SKrzysztof Helt } 35852df6440SJean Delvare } else if (company == 0x49) { 359cc28a610SJean Delvare type_name = "thmc50"; 36052df6440SJean Delvare } else { 36152df6440SJean Delvare pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n"); 36252df6440SJean Delvare return -ENODEV; 363add77c64SKrzysztof Helt } 36452df6440SJean Delvare 365cc28a610SJean Delvare pr_debug("thmc50: Detected %s (version %x, revision %x)\n", 366cc28a610SJean Delvare type_name, (revision >> 4) - 0xc, revision & 0xf); 367add77c64SKrzysztof Helt 368ccf37488SJean Delvare strlcpy(info->type, type_name, I2C_NAME_SIZE); 369add77c64SKrzysztof Helt 370ccf37488SJean Delvare return 0; 371ccf37488SJean Delvare } 372ccf37488SJean Delvare 37386fd260eSAxel Lin static void thmc50_init_client(struct thmc50_data *data) 3749b38a66eSAxel Lin { 37586fd260eSAxel Lin struct i2c_client *client = data->client; 3769b38a66eSAxel Lin int config; 3779b38a66eSAxel Lin 3789b38a66eSAxel Lin data->analog_out = i2c_smbus_read_byte_data(client, 3799b38a66eSAxel Lin THMC50_REG_ANALOG_OUT); 3809b38a66eSAxel Lin /* set up to at least 1 */ 3819b38a66eSAxel Lin if (data->analog_out == 0) { 3829b38a66eSAxel Lin data->analog_out = 1; 3839b38a66eSAxel Lin i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT, 3849b38a66eSAxel Lin data->analog_out); 3859b38a66eSAxel Lin } 3869b38a66eSAxel Lin config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 3879b38a66eSAxel Lin config |= 0x1; /* start the chip if it is in standby mode */ 3889b38a66eSAxel Lin if (data->type == adm1022 && (config & (1 << 7))) 3899b38a66eSAxel Lin data->has_temp3 = 1; 3909b38a66eSAxel Lin i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); 3919b38a66eSAxel Lin } 3929b38a66eSAxel Lin 393ccf37488SJean Delvare static int thmc50_probe(struct i2c_client *client, 394ccf37488SJean Delvare const struct i2c_device_id *id) 395ccf37488SJean Delvare { 39686fd260eSAxel Lin struct device *dev = &client->dev; 397ccf37488SJean Delvare struct thmc50_data *data; 39886fd260eSAxel Lin struct device *hwmon_dev; 39986fd260eSAxel Lin int idx = 0; 400ccf37488SJean Delvare 40186fd260eSAxel Lin data = devm_kzalloc(dev, sizeof(struct thmc50_data), GFP_KERNEL); 402bd91d3baSGuenter Roeck if (!data) 403bd91d3baSGuenter Roeck return -ENOMEM; 404ccf37488SJean Delvare 40586fd260eSAxel Lin data->client = client; 406ccf37488SJean Delvare data->type = id->driver_data; 407ccf37488SJean Delvare mutex_init(&data->update_lock); 408add77c64SKrzysztof Helt 40986fd260eSAxel Lin thmc50_init_client(data); 410add77c64SKrzysztof Helt 41186fd260eSAxel Lin /* sysfs hooks */ 41286fd260eSAxel Lin data->groups[idx++] = &thmc50_group; 413add77c64SKrzysztof Helt 41486fd260eSAxel Lin /* Register additional ADM1022 sysfs hooks */ 415894c00cfSJean Delvare if (data->has_temp3) 41686fd260eSAxel Lin data->groups[idx++] = &temp3_group; 417add77c64SKrzysztof Helt 41886fd260eSAxel Lin hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 41986fd260eSAxel Lin data, data->groups); 42086fd260eSAxel Lin return PTR_ERR_OR_ZERO(hwmon_dev); 421add77c64SKrzysztof Helt } 422add77c64SKrzysztof Helt 4239b38a66eSAxel Lin static const struct i2c_device_id thmc50_id[] = { 4249b38a66eSAxel Lin { "adm1022", adm1022 }, 4259b38a66eSAxel Lin { "thmc50", thmc50 }, 4269b38a66eSAxel Lin { } 4279b38a66eSAxel Lin }; 4289b38a66eSAxel Lin MODULE_DEVICE_TABLE(i2c, thmc50_id); 429add77c64SKrzysztof Helt 4309b38a66eSAxel Lin static struct i2c_driver thmc50_driver = { 4319b38a66eSAxel Lin .class = I2C_CLASS_HWMON, 4329b38a66eSAxel Lin .driver = { 4339b38a66eSAxel Lin .name = "thmc50", 4349b38a66eSAxel Lin }, 4359b38a66eSAxel Lin .probe = thmc50_probe, 4369b38a66eSAxel Lin .id_table = thmc50_id, 4379b38a66eSAxel Lin .detect = thmc50_detect, 4389b38a66eSAxel Lin .address_list = normal_i2c, 4399b38a66eSAxel Lin }; 440add77c64SKrzysztof Helt 441f0967eeaSAxel Lin module_i2c_driver(thmc50_driver); 442add77c64SKrzysztof Helt 443add77c64SKrzysztof Helt MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>"); 444add77c64SKrzysztof Helt MODULE_DESCRIPTION("THMC50 driver"); 445