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 }; 58add77c64SKrzysztof Helt 59add77c64SKrzysztof Helt #define THMC50_REG_CONF_nFANOFF 0x20 60add77c64SKrzysztof Helt 61add77c64SKrzysztof Helt /* Each client has this additional data */ 62add77c64SKrzysztof Helt struct thmc50_data { 631beeffe4STony Jones struct device *hwmon_dev; 64add77c64SKrzysztof Helt 65add77c64SKrzysztof Helt struct mutex update_lock; 66add77c64SKrzysztof Helt enum chips type; 67add77c64SKrzysztof Helt unsigned long last_updated; /* In jiffies */ 68add77c64SKrzysztof Helt char has_temp3; /* !=0 if it is ADM1022 in temp3 mode */ 69add77c64SKrzysztof Helt char valid; /* !=0 if following fields are valid */ 70add77c64SKrzysztof Helt 71add77c64SKrzysztof Helt /* Register values */ 72add77c64SKrzysztof Helt s8 temp_input[3]; 73add77c64SKrzysztof Helt s8 temp_max[3]; 74add77c64SKrzysztof Helt s8 temp_min[3]; 75add77c64SKrzysztof Helt u8 analog_out; 76dcf3b5fbSKrzysztof Helt u8 alarms; 77add77c64SKrzysztof Helt }; 78add77c64SKrzysztof Helt 79*ccf37488SJean Delvare static int thmc50_detect(struct i2c_client *client, int kind, 80*ccf37488SJean Delvare struct i2c_board_info *info); 81*ccf37488SJean Delvare static int thmc50_probe(struct i2c_client *client, 82*ccf37488SJean Delvare const struct i2c_device_id *id); 83*ccf37488SJean Delvare static int thmc50_remove(struct i2c_client *client); 84add77c64SKrzysztof Helt static void thmc50_init_client(struct i2c_client *client); 85add77c64SKrzysztof Helt static struct thmc50_data *thmc50_update_device(struct device *dev); 86add77c64SKrzysztof Helt 87*ccf37488SJean Delvare static const struct i2c_device_id thmc50_id[] = { 88*ccf37488SJean Delvare { "adm1022", adm1022 }, 89*ccf37488SJean Delvare { "thmc50", thmc50 }, 90*ccf37488SJean Delvare { } 91*ccf37488SJean Delvare }; 92*ccf37488SJean Delvare MODULE_DEVICE_TABLE(i2c, thmc50_id); 93*ccf37488SJean Delvare 94add77c64SKrzysztof Helt static struct i2c_driver thmc50_driver = { 95*ccf37488SJean Delvare .class = I2C_CLASS_HWMON, 96add77c64SKrzysztof Helt .driver = { 97add77c64SKrzysztof Helt .name = "thmc50", 98add77c64SKrzysztof Helt }, 99*ccf37488SJean Delvare .probe = thmc50_probe, 100*ccf37488SJean Delvare .remove = thmc50_remove, 101*ccf37488SJean Delvare .id_table = thmc50_id, 102*ccf37488SJean Delvare .detect = thmc50_detect, 103*ccf37488SJean Delvare .address_data = &addr_data, 104add77c64SKrzysztof Helt }; 105add77c64SKrzysztof Helt 106add77c64SKrzysztof Helt static ssize_t show_analog_out(struct device *dev, 107add77c64SKrzysztof Helt struct device_attribute *attr, char *buf) 108add77c64SKrzysztof Helt { 109add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 110add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->analog_out); 111add77c64SKrzysztof Helt } 112add77c64SKrzysztof Helt 113add77c64SKrzysztof Helt static ssize_t set_analog_out(struct device *dev, 114add77c64SKrzysztof Helt struct device_attribute *attr, 115add77c64SKrzysztof Helt const char *buf, size_t count) 116add77c64SKrzysztof Helt { 117add77c64SKrzysztof Helt struct i2c_client *client = to_i2c_client(dev); 118add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 119add77c64SKrzysztof Helt int tmp = simple_strtoul(buf, NULL, 10); 120add77c64SKrzysztof Helt int config; 121add77c64SKrzysztof Helt 122add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 123add77c64SKrzysztof Helt data->analog_out = SENSORS_LIMIT(tmp, 0, 255); 124add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT, 125add77c64SKrzysztof Helt data->analog_out); 126add77c64SKrzysztof Helt 127add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 128add77c64SKrzysztof Helt if (data->analog_out == 0) 129add77c64SKrzysztof Helt config &= ~THMC50_REG_CONF_nFANOFF; 130add77c64SKrzysztof Helt else 131add77c64SKrzysztof Helt config |= THMC50_REG_CONF_nFANOFF; 132add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); 133add77c64SKrzysztof Helt 134add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 135add77c64SKrzysztof Helt return count; 136add77c64SKrzysztof Helt } 137add77c64SKrzysztof Helt 138add77c64SKrzysztof Helt /* There is only one PWM mode = DC */ 139add77c64SKrzysztof Helt static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr, 140add77c64SKrzysztof Helt char *buf) 141add77c64SKrzysztof Helt { 142add77c64SKrzysztof Helt return sprintf(buf, "0\n"); 143add77c64SKrzysztof Helt } 144add77c64SKrzysztof Helt 145add77c64SKrzysztof Helt /* Temperatures */ 146add77c64SKrzysztof Helt static ssize_t show_temp(struct device *dev, struct device_attribute *attr, 147add77c64SKrzysztof Helt char *buf) 148add77c64SKrzysztof Helt { 149add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 150add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 151add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_input[nr] * 1000); 152add77c64SKrzysztof Helt } 153add77c64SKrzysztof Helt 154add77c64SKrzysztof Helt static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, 155add77c64SKrzysztof Helt char *buf) 156add77c64SKrzysztof Helt { 157add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 158add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 159add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_min[nr] * 1000); 160add77c64SKrzysztof Helt } 161add77c64SKrzysztof Helt 162add77c64SKrzysztof Helt static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, 163add77c64SKrzysztof Helt const char *buf, size_t count) 164add77c64SKrzysztof Helt { 165add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 166add77c64SKrzysztof Helt struct i2c_client *client = to_i2c_client(dev); 167add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 168add77c64SKrzysztof Helt int val = simple_strtol(buf, NULL, 10); 169add77c64SKrzysztof Helt 170add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 171add77c64SKrzysztof Helt data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127); 172add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr], 173add77c64SKrzysztof Helt data->temp_min[nr]); 174add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 175add77c64SKrzysztof Helt return count; 176add77c64SKrzysztof Helt } 177add77c64SKrzysztof Helt 178add77c64SKrzysztof Helt static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, 179add77c64SKrzysztof Helt char *buf) 180add77c64SKrzysztof Helt { 181add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 182add77c64SKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 183add77c64SKrzysztof Helt return sprintf(buf, "%d\n", data->temp_max[nr] * 1000); 184add77c64SKrzysztof Helt } 185add77c64SKrzysztof Helt 186add77c64SKrzysztof Helt static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, 187add77c64SKrzysztof Helt const char *buf, size_t count) 188add77c64SKrzysztof Helt { 189add77c64SKrzysztof Helt int nr = to_sensor_dev_attr(attr)->index; 190add77c64SKrzysztof Helt struct i2c_client *client = to_i2c_client(dev); 191add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 192add77c64SKrzysztof Helt int val = simple_strtol(buf, NULL, 10); 193add77c64SKrzysztof Helt 194add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 195add77c64SKrzysztof Helt data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127); 196add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr], 197add77c64SKrzysztof Helt data->temp_max[nr]); 198add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 199add77c64SKrzysztof Helt return count; 200add77c64SKrzysztof Helt } 201add77c64SKrzysztof Helt 202dcf3b5fbSKrzysztof Helt static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, 203dcf3b5fbSKrzysztof Helt char *buf) 204dcf3b5fbSKrzysztof Helt { 205dcf3b5fbSKrzysztof Helt int index = to_sensor_dev_attr(attr)->index; 206dcf3b5fbSKrzysztof Helt struct thmc50_data *data = thmc50_update_device(dev); 207dcf3b5fbSKrzysztof Helt 208dcf3b5fbSKrzysztof Helt return sprintf(buf, "%u\n", (data->alarms >> index) & 1); 209dcf3b5fbSKrzysztof Helt } 210dcf3b5fbSKrzysztof Helt 211add77c64SKrzysztof Helt #define temp_reg(offset) \ 212add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ 213add77c64SKrzysztof Helt NULL, offset - 1); \ 214add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ 215add77c64SKrzysztof Helt show_temp_min, set_temp_min, offset - 1); \ 216add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ 217add77c64SKrzysztof Helt show_temp_max, set_temp_max, offset - 1); 218add77c64SKrzysztof Helt 219add77c64SKrzysztof Helt temp_reg(1); 220add77c64SKrzysztof Helt temp_reg(2); 221add77c64SKrzysztof Helt temp_reg(3); 222add77c64SKrzysztof Helt 223dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0); 224dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); 225dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1); 226dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7); 227dcf3b5fbSKrzysztof Helt static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2); 228dcf3b5fbSKrzysztof Helt 229add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out, 230add77c64SKrzysztof Helt set_analog_out, 0); 231add77c64SKrzysztof Helt static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0); 232add77c64SKrzysztof Helt 233add77c64SKrzysztof Helt static struct attribute *thmc50_attributes[] = { 234add77c64SKrzysztof Helt &sensor_dev_attr_temp1_max.dev_attr.attr, 235add77c64SKrzysztof Helt &sensor_dev_attr_temp1_min.dev_attr.attr, 236add77c64SKrzysztof Helt &sensor_dev_attr_temp1_input.dev_attr.attr, 237dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp1_alarm.dev_attr.attr, 238add77c64SKrzysztof Helt &sensor_dev_attr_temp2_max.dev_attr.attr, 239add77c64SKrzysztof Helt &sensor_dev_attr_temp2_min.dev_attr.attr, 240add77c64SKrzysztof Helt &sensor_dev_attr_temp2_input.dev_attr.attr, 241dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp2_alarm.dev_attr.attr, 242dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp2_fault.dev_attr.attr, 243add77c64SKrzysztof Helt &sensor_dev_attr_pwm1.dev_attr.attr, 244add77c64SKrzysztof Helt &sensor_dev_attr_pwm1_mode.dev_attr.attr, 245add77c64SKrzysztof Helt NULL 246add77c64SKrzysztof Helt }; 247add77c64SKrzysztof Helt 248add77c64SKrzysztof Helt static const struct attribute_group thmc50_group = { 249add77c64SKrzysztof Helt .attrs = thmc50_attributes, 250add77c64SKrzysztof Helt }; 251add77c64SKrzysztof Helt 252add77c64SKrzysztof Helt /* for ADM1022 3rd temperature mode */ 253894c00cfSJean Delvare static struct attribute *temp3_attributes[] = { 254add77c64SKrzysztof Helt &sensor_dev_attr_temp3_max.dev_attr.attr, 255add77c64SKrzysztof Helt &sensor_dev_attr_temp3_min.dev_attr.attr, 256add77c64SKrzysztof Helt &sensor_dev_attr_temp3_input.dev_attr.attr, 257dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp3_alarm.dev_attr.attr, 258dcf3b5fbSKrzysztof Helt &sensor_dev_attr_temp3_fault.dev_attr.attr, 259add77c64SKrzysztof Helt NULL 260add77c64SKrzysztof Helt }; 261add77c64SKrzysztof Helt 262894c00cfSJean Delvare static const struct attribute_group temp3_group = { 263894c00cfSJean Delvare .attrs = temp3_attributes, 264add77c64SKrzysztof Helt }; 265add77c64SKrzysztof Helt 266*ccf37488SJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */ 267*ccf37488SJean Delvare static int thmc50_detect(struct i2c_client *client, int kind, 268*ccf37488SJean Delvare struct i2c_board_info *info) 269add77c64SKrzysztof Helt { 270add77c64SKrzysztof Helt unsigned company; 271add77c64SKrzysztof Helt unsigned revision; 272add77c64SKrzysztof Helt unsigned config; 273*ccf37488SJean Delvare struct i2c_adapter *adapter = client->adapter; 274add77c64SKrzysztof Helt int err = 0; 275cc28a610SJean Delvare const char *type_name; 276add77c64SKrzysztof Helt 277add77c64SKrzysztof Helt if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 278add77c64SKrzysztof Helt pr_debug("thmc50: detect failed, " 279add77c64SKrzysztof Helt "smbus byte data not supported!\n"); 280*ccf37488SJean Delvare return -ENODEV; 281add77c64SKrzysztof Helt } 282add77c64SKrzysztof Helt 283add77c64SKrzysztof Helt pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n", 284add77c64SKrzysztof Helt client->addr, i2c_adapter_id(client->adapter)); 285add77c64SKrzysztof Helt 286add77c64SKrzysztof Helt /* Now, we do the remaining detection. */ 287add77c64SKrzysztof Helt company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID); 288add77c64SKrzysztof Helt revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE); 289add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 290add77c64SKrzysztof Helt 291add77c64SKrzysztof Helt if (kind == 0) 292add77c64SKrzysztof Helt kind = thmc50; 293add77c64SKrzysztof Helt else if (kind < 0) { 294add77c64SKrzysztof Helt err = -ENODEV; 295add77c64SKrzysztof Helt if (revision >= 0xc0 && ((config & 0x10) == 0)) { 296add77c64SKrzysztof Helt if (company == 0x49) { 297add77c64SKrzysztof Helt kind = thmc50; 298add77c64SKrzysztof Helt err = 0; 299add77c64SKrzysztof Helt } else if (company == 0x41) { 300add77c64SKrzysztof Helt kind = adm1022; 301add77c64SKrzysztof Helt err = 0; 302add77c64SKrzysztof Helt } 303add77c64SKrzysztof Helt } 304add77c64SKrzysztof Helt } 305add77c64SKrzysztof Helt if (err == -ENODEV) { 306add77c64SKrzysztof Helt pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n"); 307*ccf37488SJean Delvare return err; 308add77c64SKrzysztof Helt } 309add77c64SKrzysztof Helt 310cc28a610SJean Delvare if (kind == adm1022) { 311add77c64SKrzysztof Helt int id = i2c_adapter_id(client->adapter); 312add77c64SKrzysztof Helt int i; 313add77c64SKrzysztof Helt 314add77c64SKrzysztof Helt type_name = "adm1022"; 315add77c64SKrzysztof Helt for (i = 0; i + 1 < adm1022_temp3_num; i += 2) 316add77c64SKrzysztof Helt if (adm1022_temp3[i] == id && 317*ccf37488SJean Delvare adm1022_temp3[i + 1] == client->addr) { 318add77c64SKrzysztof Helt /* enable 2nd remote temp */ 319*ccf37488SJean Delvare config |= (1 << 7); 320*ccf37488SJean Delvare i2c_smbus_write_byte_data(client, 321*ccf37488SJean Delvare THMC50_REG_CONF, 322*ccf37488SJean Delvare config); 323add77c64SKrzysztof Helt break; 324add77c64SKrzysztof Helt } 325cc28a610SJean Delvare } else { 326cc28a610SJean Delvare type_name = "thmc50"; 327add77c64SKrzysztof Helt } 328cc28a610SJean Delvare pr_debug("thmc50: Detected %s (version %x, revision %x)\n", 329cc28a610SJean Delvare type_name, (revision >> 4) - 0xc, revision & 0xf); 330add77c64SKrzysztof Helt 331*ccf37488SJean Delvare strlcpy(info->type, type_name, I2C_NAME_SIZE); 332add77c64SKrzysztof Helt 333*ccf37488SJean Delvare return 0; 334*ccf37488SJean Delvare } 335*ccf37488SJean Delvare 336*ccf37488SJean Delvare static int thmc50_probe(struct i2c_client *client, 337*ccf37488SJean Delvare const struct i2c_device_id *id) 338*ccf37488SJean Delvare { 339*ccf37488SJean Delvare struct thmc50_data *data; 340*ccf37488SJean Delvare int err; 341*ccf37488SJean Delvare 342*ccf37488SJean Delvare data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL); 343*ccf37488SJean Delvare if (!data) { 344*ccf37488SJean Delvare pr_debug("thmc50: detect failed, kzalloc failed!\n"); 345*ccf37488SJean Delvare err = -ENOMEM; 346*ccf37488SJean Delvare goto exit; 347*ccf37488SJean Delvare } 348*ccf37488SJean Delvare 349*ccf37488SJean Delvare i2c_set_clientdata(client, data); 350*ccf37488SJean Delvare data->type = id->driver_data; 351*ccf37488SJean Delvare mutex_init(&data->update_lock); 352add77c64SKrzysztof Helt 353add77c64SKrzysztof Helt thmc50_init_client(client); 354add77c64SKrzysztof Helt 355add77c64SKrzysztof Helt /* Register sysfs hooks */ 356add77c64SKrzysztof Helt if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group))) 357*ccf37488SJean Delvare goto exit_free; 358add77c64SKrzysztof Helt 359add77c64SKrzysztof Helt /* Register ADM1022 sysfs hooks */ 360894c00cfSJean Delvare if (data->has_temp3) 361add77c64SKrzysztof Helt if ((err = sysfs_create_group(&client->dev.kobj, 362894c00cfSJean Delvare &temp3_group))) 363add77c64SKrzysztof Helt goto exit_remove_sysfs_thmc50; 364add77c64SKrzysztof Helt 365add77c64SKrzysztof Helt /* Register a new directory entry with module sensors */ 3661beeffe4STony Jones data->hwmon_dev = hwmon_device_register(&client->dev); 3671beeffe4STony Jones if (IS_ERR(data->hwmon_dev)) { 3681beeffe4STony Jones err = PTR_ERR(data->hwmon_dev); 369add77c64SKrzysztof Helt goto exit_remove_sysfs; 370add77c64SKrzysztof Helt } 371add77c64SKrzysztof Helt 372add77c64SKrzysztof Helt return 0; 373add77c64SKrzysztof Helt 374add77c64SKrzysztof Helt exit_remove_sysfs: 375894c00cfSJean Delvare if (data->has_temp3) 376894c00cfSJean Delvare sysfs_remove_group(&client->dev.kobj, &temp3_group); 377add77c64SKrzysztof Helt exit_remove_sysfs_thmc50: 378add77c64SKrzysztof Helt sysfs_remove_group(&client->dev.kobj, &thmc50_group); 379add77c64SKrzysztof Helt exit_free: 380add77c64SKrzysztof Helt kfree(data); 381add77c64SKrzysztof Helt exit: 382add77c64SKrzysztof Helt return err; 383add77c64SKrzysztof Helt } 384add77c64SKrzysztof Helt 385*ccf37488SJean Delvare static int thmc50_remove(struct i2c_client *client) 386add77c64SKrzysztof Helt { 387add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 388add77c64SKrzysztof Helt 3891beeffe4STony Jones hwmon_device_unregister(data->hwmon_dev); 390add77c64SKrzysztof Helt sysfs_remove_group(&client->dev.kobj, &thmc50_group); 391894c00cfSJean Delvare if (data->has_temp3) 392894c00cfSJean Delvare sysfs_remove_group(&client->dev.kobj, &temp3_group); 393add77c64SKrzysztof Helt 394add77c64SKrzysztof Helt kfree(data); 395add77c64SKrzysztof Helt 396add77c64SKrzysztof Helt return 0; 397add77c64SKrzysztof Helt } 398add77c64SKrzysztof Helt 399add77c64SKrzysztof Helt static void thmc50_init_client(struct i2c_client *client) 400add77c64SKrzysztof Helt { 401add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 402add77c64SKrzysztof Helt int config; 403add77c64SKrzysztof Helt 404add77c64SKrzysztof Helt data->analog_out = i2c_smbus_read_byte_data(client, 405add77c64SKrzysztof Helt THMC50_REG_ANALOG_OUT); 406add77c64SKrzysztof Helt /* set up to at least 1 */ 407add77c64SKrzysztof Helt if (data->analog_out == 0) { 408add77c64SKrzysztof Helt data->analog_out = 1; 409add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT, 410add77c64SKrzysztof Helt data->analog_out); 411add77c64SKrzysztof Helt } 412add77c64SKrzysztof Helt config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); 413add77c64SKrzysztof Helt config |= 0x1; /* start the chip if it is in standby mode */ 414*ccf37488SJean Delvare if (data->type == adm1022 && (config & (1 << 7))) 415*ccf37488SJean Delvare data->has_temp3 = 1; 416add77c64SKrzysztof Helt i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); 417add77c64SKrzysztof Helt } 418add77c64SKrzysztof Helt 419add77c64SKrzysztof Helt static struct thmc50_data *thmc50_update_device(struct device *dev) 420add77c64SKrzysztof Helt { 421add77c64SKrzysztof Helt struct i2c_client *client = to_i2c_client(dev); 422add77c64SKrzysztof Helt struct thmc50_data *data = i2c_get_clientdata(client); 423add77c64SKrzysztof Helt int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0); 424add77c64SKrzysztof Helt 425add77c64SKrzysztof Helt mutex_lock(&data->update_lock); 426add77c64SKrzysztof Helt 427add77c64SKrzysztof Helt if (time_after(jiffies, data->last_updated + timeout) 428add77c64SKrzysztof Helt || !data->valid) { 429add77c64SKrzysztof Helt 430add77c64SKrzysztof Helt int temps = data->has_temp3 ? 3 : 2; 431add77c64SKrzysztof Helt int i; 432add77c64SKrzysztof Helt for (i = 0; i < temps; i++) { 433add77c64SKrzysztof Helt data->temp_input[i] = i2c_smbus_read_byte_data(client, 434add77c64SKrzysztof Helt THMC50_REG_TEMP[i]); 435add77c64SKrzysztof Helt data->temp_max[i] = i2c_smbus_read_byte_data(client, 436add77c64SKrzysztof Helt THMC50_REG_TEMP_MAX[i]); 437add77c64SKrzysztof Helt data->temp_min[i] = i2c_smbus_read_byte_data(client, 438add77c64SKrzysztof Helt THMC50_REG_TEMP_MIN[i]); 439add77c64SKrzysztof Helt } 440add77c64SKrzysztof Helt data->analog_out = 441add77c64SKrzysztof Helt i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT); 442dcf3b5fbSKrzysztof Helt data->alarms = 443bba891c2SKrzysztof Helt i2c_smbus_read_byte_data(client, THMC50_REG_INTR); 444add77c64SKrzysztof Helt data->last_updated = jiffies; 445add77c64SKrzysztof Helt data->valid = 1; 446add77c64SKrzysztof Helt } 447add77c64SKrzysztof Helt 448add77c64SKrzysztof Helt mutex_unlock(&data->update_lock); 449add77c64SKrzysztof Helt 450add77c64SKrzysztof Helt return data; 451add77c64SKrzysztof Helt } 452add77c64SKrzysztof Helt 453add77c64SKrzysztof Helt static int __init sm_thmc50_init(void) 454add77c64SKrzysztof Helt { 455add77c64SKrzysztof Helt return i2c_add_driver(&thmc50_driver); 456add77c64SKrzysztof Helt } 457add77c64SKrzysztof Helt 458add77c64SKrzysztof Helt static void __exit sm_thmc50_exit(void) 459add77c64SKrzysztof Helt { 460add77c64SKrzysztof Helt i2c_del_driver(&thmc50_driver); 461add77c64SKrzysztof Helt } 462add77c64SKrzysztof Helt 463add77c64SKrzysztof Helt MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>"); 464add77c64SKrzysztof Helt MODULE_DESCRIPTION("THMC50 driver"); 465add77c64SKrzysztof Helt 466add77c64SKrzysztof Helt module_init(sm_thmc50_init); 467add77c64SKrzysztof Helt module_exit(sm_thmc50_exit); 468