1add77c64SKrzysztof Helt /* 2add77c64SKrzysztof Helt thmc50.c - Part of lm_sensors, Linux kernel modules for hardware 3add77c64SKrzysztof Helt monitoring 4add77c64SKrzysztof Helt Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl> 5add77c64SKrzysztof Helt Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and 6add77c64SKrzysztof Helt Philip Edelbrock <phil@netroedge.com> 7add77c64SKrzysztof Helt 8add77c64SKrzysztof Helt This program is free software; you can redistribute it and/or modify 9add77c64SKrzysztof Helt it under the terms of the GNU General Public License as published by 10add77c64SKrzysztof Helt the Free Software Foundation; either version 2 of the License, or 11add77c64SKrzysztof Helt (at your option) any later version. 12add77c64SKrzysztof Helt 13add77c64SKrzysztof Helt This program is distributed in the hope that it will be useful, 14add77c64SKrzysztof Helt but WITHOUT ANY WARRANTY; without even the implied warranty of 15add77c64SKrzysztof Helt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16add77c64SKrzysztof Helt GNU General Public License for more details. 17add77c64SKrzysztof Helt 18add77c64SKrzysztof Helt You should have received a copy of the GNU General Public License 19add77c64SKrzysztof Helt along with this program; if not, write to the Free Software 20add77c64SKrzysztof Helt 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> 31add77c64SKrzysztof Helt 32add77c64SKrzysztof Helt MODULE_LICENSE("GPL"); 33add77c64SKrzysztof Helt 34add77c64SKrzysztof Helt /* Addresses to scan */ 3525e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; 36add77c64SKrzysztof Helt 37add77c64SKrzysztof Helt /* Insmod parameters */ 38add77c64SKrzysztof Helt I2C_CLIENT_INSMOD_2(thmc50, adm1022); 39add77c64SKrzysztof Helt I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs " 40add77c64SKrzysztof Helt "to enable 3rd temperature (ADM1022 only)"); 41add77c64SKrzysztof Helt 42add77c64SKrzysztof Helt /* Many THMC50 constants specified below */ 43add77c64SKrzysztof Helt 44add77c64SKrzysztof Helt /* The THMC50 registers */ 45add77c64SKrzysztof Helt #define THMC50_REG_CONF 0x40 46add77c64SKrzysztof Helt #define THMC50_REG_COMPANY_ID 0x3E 47add77c64SKrzysztof Helt #define THMC50_REG_DIE_CODE 0x3F 48add77c64SKrzysztof Helt #define THMC50_REG_ANALOG_OUT 0x19 49dcf3b5fbSKrzysztof Helt /* 50bba891c2SKrzysztof Helt * The mirror status register cannot be used as 51bba891c2SKrzysztof Helt * reading it does not clear alarms. 52dcf3b5fbSKrzysztof Helt */ 53bba891c2SKrzysztof Helt #define THMC50_REG_INTR 0x41 54add77c64SKrzysztof Helt 555910a9b2STobias Klauser static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 }; 565910a9b2STobias Klauser static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C }; 575910a9b2STobias Klauser static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B }; 5884f768c1SKrzysztof Helt static const u8 THMC50_REG_TEMP_CRITICAL[] = { 0x13, 0x14, 0x14 }; 5984f768c1SKrzysztof Helt static const u8 THMC50_REG_TEMP_DEFAULT[] = { 0x17, 0x18, 0x18 }; 60add77c64SKrzysztof Helt 61add77c64SKrzysztof Helt #define THMC50_REG_CONF_nFANOFF 0x20 6284f768c1SKrzysztof Helt #define THMC50_REG_CONF_PROGRAMMED 0x08 63add77c64SKrzysztof Helt 64add77c64SKrzysztof Helt /* Each client has this additional data */ 65add77c64SKrzysztof Helt struct thmc50_data { 661beeffe4STony Jones struct device *hwmon_dev; 67add77c64SKrzysztof Helt 68add77c64SKrzysztof Helt struct mutex update_lock; 69add77c64SKrzysztof Helt enum chips type; 70add77c64SKrzysztof Helt unsigned long last_updated; /* In jiffies */ 71add77c64SKrzysztof Helt char has_temp3; /* !=0 if it is ADM1022 in temp3 mode */ 72add77c64SKrzysztof Helt char valid; /* !=0 if following fields are valid */ 73add77c64SKrzysztof Helt 74add77c64SKrzysztof Helt /* Register values */ 75add77c64SKrzysztof Helt s8 temp_input[3]; 76add77c64SKrzysztof Helt s8 temp_max[3]; 77add77c64SKrzysztof Helt s8 temp_min[3]; 7884f768c1SKrzysztof Helt s8 temp_critical[3]; 79add77c64SKrzysztof Helt u8 analog_out; 80dcf3b5fbSKrzysztof Helt u8 alarms; 81add77c64SKrzysztof Helt }; 82add77c64SKrzysztof Helt 83ccf37488SJean Delvare static int thmc50_detect(struct i2c_client *client, int kind, 84ccf37488SJean Delvare struct i2c_board_info *info); 85ccf37488SJean Delvare static int thmc50_probe(struct i2c_client *client, 86ccf37488SJean Delvare const struct i2c_device_id *id); 87ccf37488SJean Delvare static int thmc50_remove(struct i2c_client *client); 88add77c64SKrzysztof Helt static void thmc50_init_client(struct i2c_client *client); 89add77c64SKrzysztof Helt static struct thmc50_data *thmc50_update_device(struct device *dev); 90add77c64SKrzysztof Helt 91ccf37488SJean Delvare static const struct i2c_device_id thmc50_id[] = { 92ccf37488SJean Delvare { "adm1022", adm1022 }, 93ccf37488SJean Delvare { "thmc50", thmc50 }, 94ccf37488SJean Delvare { } 95ccf37488SJean Delvare }; 96ccf37488SJean Delvare MODULE_DEVICE_TABLE(i2c, thmc50_id); 97ccf37488SJean Delvare 98add77c64SKrzysztof Helt static struct i2c_driver thmc50_driver = { 99ccf37488SJean Delvare .class = I2C_CLASS_HWMON, 100add77c64SKrzysztof Helt .driver = { 101add77c64SKrzysztof Helt .name = "thmc50", 102add77c64SKrzysztof Helt }, 103ccf37488SJean Delvare .probe = thmc50_probe, 104ccf37488SJean Delvare .remove = thmc50_remove, 105ccf37488SJean Delvare .id_table = thmc50_id, 106ccf37488SJean Delvare .detect = thmc50_detect, 107ccf37488SJean Delvare .address_data = &addr_data, 108add77c64SKrzysztof Helt }; 109add77c64SKrzysztof Helt 110add77c64SKrzysztof Helt static ssize_t show_analog_out(struct device *dev, 111add77c64SKrzysztof Helt struct device_attribute *attr, char *buf) 112add77c64SKrzysztof Helt { 113add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 114add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->analog_out); 115add77c64SKrzysztof Helt } 116add77c64SKrzysztof Helt 117add77c64SKrzysztof Helt static ssize_t set_analog_out(struct device *dev, 118add77c64SKrzysztof Helt struct device_attribute *attr, 119add77c64SKrzysztof Helt const char *buf, size_t count) 120add77c64SKrzysztof Helt { 121add77c64SKrzysztof Helt struct i2c_client *client = to_i2c_client(dev); 122add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 123add77c64SKrzysztof Helt int tmp = simple_strtoul(buf, NULL, 10); 124add77c64SKrzysztof Helt int config; 125add77c64SKrzysztof Helt 126add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 127add77c64SKrzysztof Helt data->analog_out = SENSORS_LIMIT(tmp, 0, 255); 128add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT, 129add77c64SKrzysztof Helt data->analog_out); 130add77c64SKrzysztof Helt 131add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 132add77c64SKrzysztof Helt if (data->analog_out == 0) 133add77c64SKrzysztof Helt config &= ~THMC50_REG_CONF_nFANOFF; 134add77c64SKrzysztof Helt else 135add77c64SKrzysztof Helt config |= THMC50_REG_CONF_nFANOFF; 136add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); 137add77c64SKrzysztof Helt 138add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 139add77c64SKrzysztof Helt return count; 140add77c64SKrzysztof Helt } 141add77c64SKrzysztof Helt 142add77c64SKrzysztof Helt /* There is only one PWM mode = DC */ 143add77c64SKrzysztof Helt static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr, 144add77c64SKrzysztof Helt char *buf) 145add77c64SKrzysztof Helt { 146add77c64SKrzysztof Helt return sprintf(buf, "0\n"); 147add77c64SKrzysztof Helt } 148add77c64SKrzysztof Helt 149add77c64SKrzysztof Helt /* Temperatures */ 150add77c64SKrzysztof Helt static ssize_t show_temp(struct device *dev, struct device_attribute *attr, 151add77c64SKrzysztof Helt char *buf) 152add77c64SKrzysztof Helt { 153add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 154add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 155add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_input[nr] * 1000); 156add77c64SKrzysztof Helt } 157add77c64SKrzysztof Helt 158add77c64SKrzysztof Helt static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, 159add77c64SKrzysztof Helt char *buf) 160add77c64SKrzysztof Helt { 161add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 162add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 163add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_min[nr] * 1000); 164add77c64SKrzysztof Helt } 165add77c64SKrzysztof Helt 166add77c64SKrzysztof Helt static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, 167add77c64SKrzysztof Helt const char *buf, size_t count) 168add77c64SKrzysztof Helt { 169add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 170add77c64SKrzysztof Helt struct i2c_client *client = to_i2c_client(dev); 171add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 172add77c64SKrzysztof Helt int val = simple_strtol(buf, NULL, 10); 173add77c64SKrzysztof Helt 174add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 175add77c64SKrzysztof Helt data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127); 176add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr], 177add77c64SKrzysztof Helt data->temp_min[nr]); 178add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 179add77c64SKrzysztof Helt return count; 180add77c64SKrzysztof Helt } 181add77c64SKrzysztof Helt 182add77c64SKrzysztof Helt static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, 183add77c64SKrzysztof Helt char *buf) 184add77c64SKrzysztof Helt { 185add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 186add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 187add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_max[nr] * 1000); 188add77c64SKrzysztof Helt } 189add77c64SKrzysztof Helt 190add77c64SKrzysztof Helt static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, 191add77c64SKrzysztof Helt const char *buf, size_t count) 192add77c64SKrzysztof Helt { 193add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 194add77c64SKrzysztof Helt struct i2c_client *client = to_i2c_client(dev); 195add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 196add77c64SKrzysztof Helt int val = simple_strtol(buf, NULL, 10); 197add77c64SKrzysztof Helt 198add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 199add77c64SKrzysztof Helt data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127); 200add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr], 201add77c64SKrzysztof Helt data->temp_max[nr]); 202add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 203add77c64SKrzysztof Helt return count; 204add77c64SKrzysztof Helt } 205add77c64SKrzysztof Helt 20684f768c1SKrzysztof Helt static ssize_t show_temp_critical(struct device *dev, 20784f768c1SKrzysztof Helt struct device_attribute *attr, 20884f768c1SKrzysztof Helt char *buf) 20984f768c1SKrzysztof Helt { 21084f768c1SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 21184f768c1SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 21284f768c1SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_critical[nr] * 1000); 21384f768c1SKrzysztof Helt } 21484f768c1SKrzysztof Helt 215dcf3b5fbSKrzysztof Helt static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, 216dcf3b5fbSKrzysztof Helt char *buf) 217dcf3b5fbSKrzysztof Helt { 218dcf3b5fbSKrzysztof Helt int index = to_sensor_dev_attr(attr)->index; 219dcf3b5fbSKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 220dcf3b5fbSKrzysztof Helt 221dcf3b5fbSKrzysztof Helt return sprintf(buf, "%u\n", (data->alarms >> index) & 1); 222dcf3b5fbSKrzysztof Helt } 223dcf3b5fbSKrzysztof Helt 224add77c64SKrzysztof Helt #define temp_reg(offset) \ 225add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ 226add77c64SKrzysztof Helt NULL, offset - 1); \ 227add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ 228add77c64SKrzysztof Helt show_temp_min, set_temp_min, offset - 1); \ 229add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ 23084f768c1SKrzysztof Helt show_temp_max, set_temp_max, offset - 1); \ 23184f768c1SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO, \ 23284f768c1SKrzysztof Helt show_temp_critical, NULL, offset - 1); 233add77c64SKrzysztof Helt 234add77c64SKrzysztof Helt temp_reg(1); 235add77c64SKrzysztof Helt temp_reg(2); 236add77c64SKrzysztof Helt temp_reg(3); 237add77c64SKrzysztof Helt 238dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0); 239dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); 240dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1); 241dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7); 242dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2); 243dcf3b5fbSKrzysztof Helt 244add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out, 245add77c64SKrzysztof Helt set_analog_out, 0); 246add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0); 247add77c64SKrzysztof Helt 248add77c64SKrzysztof Helt static struct attribute *thmc50_attributes[] = { 249add77c64SKrzysztof Helt &sensor_dev_attr_temp1_max.dev_attr.attr, 250add77c64SKrzysztof Helt &sensor_dev_attr_temp1_min.dev_attr.attr, 251add77c64SKrzysztof Helt &sensor_dev_attr_temp1_input.dev_attr.attr, 25284f768c1SKrzysztof Helt &sensor_dev_attr_temp1_crit.dev_attr.attr, 253dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp1_alarm.dev_attr.attr, 254add77c64SKrzysztof Helt &sensor_dev_attr_temp2_max.dev_attr.attr, 255add77c64SKrzysztof Helt &sensor_dev_attr_temp2_min.dev_attr.attr, 256add77c64SKrzysztof Helt &sensor_dev_attr_temp2_input.dev_attr.attr, 25784f768c1SKrzysztof Helt &sensor_dev_attr_temp2_crit.dev_attr.attr, 258dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp2_alarm.dev_attr.attr, 259dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp2_fault.dev_attr.attr, 260add77c64SKrzysztof Helt &sensor_dev_attr_pwm1.dev_attr.attr, 261add77c64SKrzysztof Helt &sensor_dev_attr_pwm1_mode.dev_attr.attr, 262add77c64SKrzysztof Helt NULL 263add77c64SKrzysztof Helt }; 264add77c64SKrzysztof Helt 265add77c64SKrzysztof Helt static const struct attribute_group thmc50_group = { 266add77c64SKrzysztof Helt .attrs = thmc50_attributes, 267add77c64SKrzysztof Helt }; 268add77c64SKrzysztof Helt 269add77c64SKrzysztof Helt /* for ADM1022 3rd temperature mode */ 270894c00cfSJean Delvare static struct attribute *temp3_attributes[] = { 271add77c64SKrzysztof Helt &sensor_dev_attr_temp3_max.dev_attr.attr, 272add77c64SKrzysztof Helt &sensor_dev_attr_temp3_min.dev_attr.attr, 273add77c64SKrzysztof Helt &sensor_dev_attr_temp3_input.dev_attr.attr, 27484f768c1SKrzysztof Helt &sensor_dev_attr_temp3_crit.dev_attr.attr, 275dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp3_alarm.dev_attr.attr, 276dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp3_fault.dev_attr.attr, 277add77c64SKrzysztof Helt NULL 278add77c64SKrzysztof Helt }; 279add77c64SKrzysztof Helt 280894c00cfSJean Delvare static const struct attribute_group temp3_group = { 281894c00cfSJean Delvare .attrs = temp3_attributes, 282add77c64SKrzysztof Helt }; 283add77c64SKrzysztof Helt 284ccf37488SJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */ 285ccf37488SJean Delvare static int thmc50_detect(struct i2c_client *client, int kind, 286ccf37488SJean Delvare struct i2c_board_info *info) 287add77c64SKrzysztof Helt { 288add77c64SKrzysztof Helt unsigned company; 289add77c64SKrzysztof Helt unsigned revision; 290add77c64SKrzysztof Helt unsigned config; 291ccf37488SJean Delvare struct i2c_adapter *adapter = client->adapter; 292cc28a610SJean Delvare const char *type_name; 293add77c64SKrzysztof Helt 294add77c64SKrzysztof Helt if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 295add77c64SKrzysztof Helt pr_debug("thmc50: detect failed, " 296add77c64SKrzysztof Helt "smbus byte data not supported!\n"); 297ccf37488SJean Delvare return -ENODEV; 298add77c64SKrzysztof Helt } 299add77c64SKrzysztof Helt 300add77c64SKrzysztof Helt pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n", 301add77c64SKrzysztof Helt client->addr, i2c_adapter_id(client->adapter)); 302add77c64SKrzysztof Helt 303add77c64SKrzysztof Helt company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID); 304add77c64SKrzysztof Helt revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE); 305add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 306*52df6440SJean Delvare if (revision < 0xc0 || (config & 0x10)) 307*52df6440SJean Delvare return -ENODEV; 308add77c64SKrzysztof Helt 309*52df6440SJean Delvare if (company == 0x41) { 310add77c64SKrzysztof Helt int id = i2c_adapter_id(client->adapter); 311add77c64SKrzysztof Helt int i; 312add77c64SKrzysztof Helt 313add77c64SKrzysztof Helt type_name = "adm1022"; 314add77c64SKrzysztof Helt for (i = 0; i + 1 < adm1022_temp3_num; i += 2) 315add77c64SKrzysztof Helt if (adm1022_temp3[i] == id && 316ccf37488SJean Delvare adm1022_temp3[i + 1] == client->addr) { 317add77c64SKrzysztof Helt /* enable 2nd remote temp */ 318ccf37488SJean Delvare config |= (1 << 7); 319ccf37488SJean Delvare i2c_smbus_write_byte_data(client, 320ccf37488SJean Delvare THMC50_REG_CONF, 321ccf37488SJean Delvare config); 322add77c64SKrzysztof Helt break; 323add77c64SKrzysztof Helt } 324*52df6440SJean Delvare } else if (company == 0x49) { 325cc28a610SJean Delvare type_name = "thmc50"; 326*52df6440SJean Delvare } else { 327*52df6440SJean Delvare pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n"); 328*52df6440SJean Delvare return -ENODEV; 329add77c64SKrzysztof Helt } 330*52df6440SJean Delvare 331cc28a610SJean Delvare pr_debug("thmc50: Detected %s (version %x, revision %x)\n", 332cc28a610SJean Delvare type_name, (revision >> 4) - 0xc, revision & 0xf); 333add77c64SKrzysztof Helt 334ccf37488SJean Delvare strlcpy(info->type, type_name, I2C_NAME_SIZE); 335add77c64SKrzysztof Helt 336ccf37488SJean Delvare return 0; 337ccf37488SJean Delvare } 338ccf37488SJean Delvare 339ccf37488SJean Delvare static int thmc50_probe(struct i2c_client *client, 340ccf37488SJean Delvare const struct i2c_device_id *id) 341ccf37488SJean Delvare { 342ccf37488SJean Delvare struct thmc50_data *data; 343ccf37488SJean Delvare int err; 344ccf37488SJean Delvare 345ccf37488SJean Delvare data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL); 346ccf37488SJean Delvare if (!data) { 347ccf37488SJean Delvare pr_debug("thmc50: detect failed, kzalloc failed!\n"); 348ccf37488SJean Delvare err = -ENOMEM; 349ccf37488SJean Delvare goto exit; 350ccf37488SJean Delvare } 351ccf37488SJean Delvare 352ccf37488SJean Delvare i2c_set_clientdata(client, data); 353ccf37488SJean Delvare data->type = id->driver_data; 354ccf37488SJean Delvare mutex_init(&data->update_lock); 355add77c64SKrzysztof Helt 356add77c64SKrzysztof Helt thmc50_init_client(client); 357add77c64SKrzysztof Helt 358add77c64SKrzysztof Helt /* Register sysfs hooks */ 359add77c64SKrzysztof Helt if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group))) 360ccf37488SJean Delvare goto exit_free; 361add77c64SKrzysztof Helt 362add77c64SKrzysztof Helt /* Register ADM1022 sysfs hooks */ 363894c00cfSJean Delvare if (data->has_temp3) 364add77c64SKrzysztof Helt if ((err = sysfs_create_group(&client->dev.kobj, 365894c00cfSJean Delvare &temp3_group))) 366add77c64SKrzysztof Helt goto exit_remove_sysfs_thmc50; 367add77c64SKrzysztof Helt 368add77c64SKrzysztof Helt /* Register a new directory entry with module sensors */ 3691beeffe4STony Jones data->hwmon_dev = hwmon_device_register(&client->dev); 3701beeffe4STony Jones if (IS_ERR(data->hwmon_dev)) { 3711beeffe4STony Jones err = PTR_ERR(data->hwmon_dev); 372add77c64SKrzysztof Helt goto exit_remove_sysfs; 373add77c64SKrzysztof Helt } 374add77c64SKrzysztof Helt 375add77c64SKrzysztof Helt return 0; 376add77c64SKrzysztof Helt 377add77c64SKrzysztof Helt exit_remove_sysfs: 378894c00cfSJean Delvare if (data->has_temp3) 379894c00cfSJean Delvare sysfs_remove_group(&client->dev.kobj, &temp3_group); 380add77c64SKrzysztof Helt exit_remove_sysfs_thmc50: 381add77c64SKrzysztof Helt sysfs_remove_group(&client->dev.kobj, &thmc50_group); 382add77c64SKrzysztof Helt exit_free: 383add77c64SKrzysztof Helt kfree(data); 384add77c64SKrzysztof Helt exit: 385add77c64SKrzysztof Helt return err; 386add77c64SKrzysztof Helt } 387add77c64SKrzysztof Helt 388ccf37488SJean Delvare static int thmc50_remove(struct i2c_client *client) 389add77c64SKrzysztof Helt { 390add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 391add77c64SKrzysztof Helt 3921beeffe4STony Jones hwmon_device_unregister(data->hwmon_dev); 393add77c64SKrzysztof Helt sysfs_remove_group(&client->dev.kobj, &thmc50_group); 394894c00cfSJean Delvare if (data->has_temp3) 395894c00cfSJean Delvare sysfs_remove_group(&client->dev.kobj, &temp3_group); 396add77c64SKrzysztof Helt 397add77c64SKrzysztof Helt kfree(data); 398add77c64SKrzysztof Helt 399add77c64SKrzysztof Helt return 0; 400add77c64SKrzysztof Helt } 401add77c64SKrzysztof Helt 402add77c64SKrzysztof Helt static void thmc50_init_client(struct i2c_client *client) 403add77c64SKrzysztof Helt { 404add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 405add77c64SKrzysztof Helt int config; 406add77c64SKrzysztof Helt 407add77c64SKrzysztof Helt data->analog_out = i2c_smbus_read_byte_data(client, 408add77c64SKrzysztof Helt THMC50_REG_ANALOG_OUT); 409add77c64SKrzysztof Helt /* set up to at least 1 */ 410add77c64SKrzysztof Helt if (data->analog_out == 0) { 411add77c64SKrzysztof Helt data->analog_out = 1; 412add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT, 413add77c64SKrzysztof Helt data->analog_out); 414add77c64SKrzysztof Helt } 415add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 416add77c64SKrzysztof Helt config |= 0x1; /* start the chip if it is in standby mode */ 417ccf37488SJean Delvare if (data->type == adm1022 && (config & (1 << 7))) 418ccf37488SJean Delvare data->has_temp3 = 1; 419add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); 420add77c64SKrzysztof Helt } 421add77c64SKrzysztof Helt 422add77c64SKrzysztof Helt static struct thmc50_data *thmc50_update_device(struct device *dev) 423add77c64SKrzysztof Helt { 424add77c64SKrzysztof Helt struct i2c_client *client = to_i2c_client(dev); 425add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 426add77c64SKrzysztof Helt int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0); 427add77c64SKrzysztof Helt 428add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 429add77c64SKrzysztof Helt 430add77c64SKrzysztof Helt if (time_after(jiffies, data->last_updated + timeout) 431add77c64SKrzysztof Helt || !data->valid) { 432add77c64SKrzysztof Helt 433add77c64SKrzysztof Helt int temps = data->has_temp3 ? 3 : 2; 434add77c64SKrzysztof Helt int i; 43584f768c1SKrzysztof Helt int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 43684f768c1SKrzysztof Helt 43784f768c1SKrzysztof Helt prog &= THMC50_REG_CONF_PROGRAMMED; 43884f768c1SKrzysztof Helt 439add77c64SKrzysztof Helt for (i = 0; i < temps; i++) { 440add77c64SKrzysztof Helt data->temp_input[i] = i2c_smbus_read_byte_data(client, 441add77c64SKrzysztof Helt THMC50_REG_TEMP[i]); 442add77c64SKrzysztof Helt data->temp_max[i] = i2c_smbus_read_byte_data(client, 443add77c64SKrzysztof Helt THMC50_REG_TEMP_MAX[i]); 444add77c64SKrzysztof Helt data->temp_min[i] = i2c_smbus_read_byte_data(client, 445add77c64SKrzysztof Helt THMC50_REG_TEMP_MIN[i]); 44684f768c1SKrzysztof Helt data->temp_critical[i] = 44784f768c1SKrzysztof Helt i2c_smbus_read_byte_data(client, 44884f768c1SKrzysztof Helt prog ? THMC50_REG_TEMP_CRITICAL[i] 44984f768c1SKrzysztof Helt : THMC50_REG_TEMP_DEFAULT[i]); 450add77c64SKrzysztof Helt } 451add77c64SKrzysztof Helt data->analog_out = 452add77c64SKrzysztof Helt i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT); 453dcf3b5fbSKrzysztof Helt data->alarms = 454bba891c2SKrzysztof Helt i2c_smbus_read_byte_data(client, THMC50_REG_INTR); 455add77c64SKrzysztof Helt data->last_updated = jiffies; 456add77c64SKrzysztof Helt data->valid = 1; 457add77c64SKrzysztof Helt } 458add77c64SKrzysztof Helt 459add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 460add77c64SKrzysztof Helt 461add77c64SKrzysztof Helt return data; 462add77c64SKrzysztof Helt } 463add77c64SKrzysztof Helt 464add77c64SKrzysztof Helt static int __init sm_thmc50_init(void) 465add77c64SKrzysztof Helt { 466add77c64SKrzysztof Helt return i2c_add_driver(&thmc50_driver); 467add77c64SKrzysztof Helt } 468add77c64SKrzysztof Helt 469add77c64SKrzysztof Helt static void __exit sm_thmc50_exit(void) 470add77c64SKrzysztof Helt { 471add77c64SKrzysztof Helt i2c_del_driver(&thmc50_driver); 472add77c64SKrzysztof Helt } 473add77c64SKrzysztof Helt 474add77c64SKrzysztof Helt MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>"); 475add77c64SKrzysztof Helt MODULE_DESCRIPTION("THMC50 driver"); 476add77c64SKrzysztof Helt 477add77c64SKrzysztof Helt module_init(sm_thmc50_init); 478add77c64SKrzysztof Helt module_exit(sm_thmc50_exit); 479