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