18d5d45fbSJean Delvare /* 28d5d45fbSJean Delvare lm75.c - Part of lm_sensors, Linux kernel modules for hardware 38d5d45fbSJean Delvare monitoring 48d5d45fbSJean Delvare Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> 58d5d45fbSJean Delvare 68d5d45fbSJean Delvare This program is free software; you can redistribute it and/or modify 78d5d45fbSJean Delvare it under the terms of the GNU General Public License as published by 88d5d45fbSJean Delvare the Free Software Foundation; either version 2 of the License, or 98d5d45fbSJean Delvare (at your option) any later version. 108d5d45fbSJean Delvare 118d5d45fbSJean Delvare This program is distributed in the hope that it will be useful, 128d5d45fbSJean Delvare but WITHOUT ANY WARRANTY; without even the implied warranty of 138d5d45fbSJean Delvare MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 148d5d45fbSJean Delvare GNU General Public License for more details. 158d5d45fbSJean Delvare 168d5d45fbSJean Delvare You should have received a copy of the GNU General Public License 178d5d45fbSJean Delvare along with this program; if not, write to the Free Software 188d5d45fbSJean Delvare Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 198d5d45fbSJean Delvare */ 208d5d45fbSJean Delvare 218d5d45fbSJean Delvare #include <linux/module.h> 228d5d45fbSJean Delvare #include <linux/init.h> 238d5d45fbSJean Delvare #include <linux/slab.h> 248d5d45fbSJean Delvare #include <linux/jiffies.h> 258d5d45fbSJean Delvare #include <linux/i2c.h> 26943b0830SMark M. Hoffman #include <linux/hwmon.h> 279ca8e40cSJean Delvare #include <linux/hwmon-sysfs.h> 28943b0830SMark M. Hoffman #include <linux/err.h> 299a61bf63SIngo Molnar #include <linux/mutex.h> 308d5d45fbSJean Delvare #include "lm75.h" 318d5d45fbSJean Delvare 328d5d45fbSJean Delvare 338d5d45fbSJean Delvare /* Addresses to scan */ 348d5d45fbSJean Delvare static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 358d5d45fbSJean Delvare 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; 368d5d45fbSJean Delvare 378d5d45fbSJean Delvare /* Insmod parameters */ 38f4b50261SJean Delvare I2C_CLIENT_INSMOD_1(lm75); 398d5d45fbSJean Delvare 408d5d45fbSJean Delvare /* Many LM75 constants specified below */ 418d5d45fbSJean Delvare 428d5d45fbSJean Delvare /* The LM75 registers */ 438d5d45fbSJean Delvare #define LM75_REG_CONF 0x01 449ca8e40cSJean Delvare static const u8 LM75_REG_TEMP[3] = { 459ca8e40cSJean Delvare 0x00, /* input */ 469ca8e40cSJean Delvare 0x03, /* max */ 479ca8e40cSJean Delvare 0x02, /* hyst */ 489ca8e40cSJean Delvare }; 498d5d45fbSJean Delvare 508d5d45fbSJean Delvare /* Each client has this additional data */ 518d5d45fbSJean Delvare struct lm75_data { 528d5d45fbSJean Delvare struct i2c_client client; 531beeffe4STony Jones struct device *hwmon_dev; 549a61bf63SIngo Molnar struct mutex update_lock; 558d5d45fbSJean Delvare char valid; /* !=0 if following fields are valid */ 568d5d45fbSJean Delvare unsigned long last_updated; /* In jiffies */ 579ca8e40cSJean Delvare u16 temp[3]; /* Register values, 589ca8e40cSJean Delvare 0 = input 599ca8e40cSJean Delvare 1 = max 609ca8e40cSJean Delvare 2 = hyst */ 618d5d45fbSJean Delvare }; 628d5d45fbSJean Delvare 638d5d45fbSJean Delvare static int lm75_attach_adapter(struct i2c_adapter *adapter); 648d5d45fbSJean Delvare static int lm75_detect(struct i2c_adapter *adapter, int address, int kind); 658d5d45fbSJean Delvare static void lm75_init_client(struct i2c_client *client); 668d5d45fbSJean Delvare static int lm75_detach_client(struct i2c_client *client); 678d5d45fbSJean Delvare static int lm75_read_value(struct i2c_client *client, u8 reg); 688d5d45fbSJean Delvare static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); 698d5d45fbSJean Delvare static struct lm75_data *lm75_update_device(struct device *dev); 708d5d45fbSJean Delvare 718d5d45fbSJean Delvare 728d5d45fbSJean Delvare /* This is the driver that will be inserted */ 738d5d45fbSJean Delvare static struct i2c_driver lm75_driver = { 74cdaf7934SLaurent Riffard .driver = { 758d5d45fbSJean Delvare .name = "lm75", 76cdaf7934SLaurent Riffard }, 778d5d45fbSJean Delvare .id = I2C_DRIVERID_LM75, 788d5d45fbSJean Delvare .attach_adapter = lm75_attach_adapter, 798d5d45fbSJean Delvare .detach_client = lm75_detach_client, 808d5d45fbSJean Delvare }; 818d5d45fbSJean Delvare 829ca8e40cSJean Delvare static ssize_t show_temp(struct device *dev, struct device_attribute *da, 839ca8e40cSJean Delvare char *buf) 849ca8e40cSJean Delvare { 859ca8e40cSJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 869ca8e40cSJean Delvare struct lm75_data *data = lm75_update_device(dev); 879ca8e40cSJean Delvare return sprintf(buf, "%d\n", 889ca8e40cSJean Delvare LM75_TEMP_FROM_REG(data->temp[attr->index])); 898d5d45fbSJean Delvare } 908d5d45fbSJean Delvare 919ca8e40cSJean Delvare static ssize_t set_temp(struct device *dev, struct device_attribute *da, 929ca8e40cSJean Delvare const char *buf, size_t count) 939ca8e40cSJean Delvare { 949ca8e40cSJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 959ca8e40cSJean Delvare struct i2c_client *client = to_i2c_client(dev); 969ca8e40cSJean Delvare struct lm75_data *data = i2c_get_clientdata(client); 979ca8e40cSJean Delvare int nr = attr->index; 985bfedac0SChristian Hohnstaedt long temp = simple_strtol(buf, NULL, 10); 999ca8e40cSJean Delvare 1009ca8e40cSJean Delvare mutex_lock(&data->update_lock); 1019ca8e40cSJean Delvare data->temp[nr] = LM75_TEMP_TO_REG(temp); 1029ca8e40cSJean Delvare lm75_write_value(client, LM75_REG_TEMP[nr], data->temp[nr]); 1039ca8e40cSJean Delvare mutex_unlock(&data->update_lock); 1049ca8e40cSJean Delvare return count; 1058d5d45fbSJean Delvare } 1068d5d45fbSJean Delvare 1079ca8e40cSJean Delvare static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, 1089ca8e40cSJean Delvare show_temp, set_temp, 1); 1099ca8e40cSJean Delvare static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, 1109ca8e40cSJean Delvare show_temp, set_temp, 2); 1119ca8e40cSJean Delvare static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); 1128d5d45fbSJean Delvare 1138d5d45fbSJean Delvare static int lm75_attach_adapter(struct i2c_adapter *adapter) 1148d5d45fbSJean Delvare { 1158d5d45fbSJean Delvare if (!(adapter->class & I2C_CLASS_HWMON)) 1168d5d45fbSJean Delvare return 0; 1172ed2dc3cSJean Delvare return i2c_probe(adapter, &addr_data, lm75_detect); 1188d5d45fbSJean Delvare } 1198d5d45fbSJean Delvare 120c1685f61SMark M. Hoffman static struct attribute *lm75_attributes[] = { 1219ca8e40cSJean Delvare &sensor_dev_attr_temp1_input.dev_attr.attr, 1229ca8e40cSJean Delvare &sensor_dev_attr_temp1_max.dev_attr.attr, 1239ca8e40cSJean Delvare &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, 124c1685f61SMark M. Hoffman 125c1685f61SMark M. Hoffman NULL 126c1685f61SMark M. Hoffman }; 127c1685f61SMark M. Hoffman 128c1685f61SMark M. Hoffman static const struct attribute_group lm75_group = { 129c1685f61SMark M. Hoffman .attrs = lm75_attributes, 130c1685f61SMark M. Hoffman }; 131c1685f61SMark M. Hoffman 1322ed2dc3cSJean Delvare /* This function is called by i2c_probe */ 1338d5d45fbSJean Delvare static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) 1348d5d45fbSJean Delvare { 1358d5d45fbSJean Delvare int i; 1368d5d45fbSJean Delvare struct i2c_client *new_client; 1378d5d45fbSJean Delvare struct lm75_data *data; 1388d5d45fbSJean Delvare int err = 0; 1398d5d45fbSJean Delvare const char *name = ""; 1408d5d45fbSJean Delvare 1418d5d45fbSJean Delvare if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | 1428d5d45fbSJean Delvare I2C_FUNC_SMBUS_WORD_DATA)) 1438d5d45fbSJean Delvare goto exit; 1448d5d45fbSJean Delvare 1458d5d45fbSJean Delvare /* OK. For now, we presume we have a valid client. We now create the 1468d5d45fbSJean Delvare client structure, even though we cannot fill it completely yet. 1478d5d45fbSJean Delvare But it allows us to access lm75_{read,write}_value. */ 148ba9c2e8dSDeepak Saxena if (!(data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL))) { 1498d5d45fbSJean Delvare err = -ENOMEM; 1508d5d45fbSJean Delvare goto exit; 1518d5d45fbSJean Delvare } 1528d5d45fbSJean Delvare 1538d5d45fbSJean Delvare new_client = &data->client; 1548d5d45fbSJean Delvare i2c_set_clientdata(new_client, data); 1558d5d45fbSJean Delvare new_client->addr = address; 1568d5d45fbSJean Delvare new_client->adapter = adapter; 1578d5d45fbSJean Delvare new_client->driver = &lm75_driver; 1588d5d45fbSJean Delvare new_client->flags = 0; 1598d5d45fbSJean Delvare 1608d5d45fbSJean Delvare /* Now, we do the remaining detection. There is no identification- 1618d5d45fbSJean Delvare dedicated register so we have to rely on several tricks: 1628d5d45fbSJean Delvare unused bits, registers cycling over 8-address boundaries, 1638d5d45fbSJean Delvare addresses 0x04-0x07 returning the last read value. 1648d5d45fbSJean Delvare The cycling+unused addresses combination is not tested, 1658d5d45fbSJean Delvare since it would significantly slow the detection down and would 1668d5d45fbSJean Delvare hardly add any value. */ 1678d5d45fbSJean Delvare if (kind < 0) { 1688d5d45fbSJean Delvare int cur, conf, hyst, os; 1698d5d45fbSJean Delvare 1708d5d45fbSJean Delvare /* Unused addresses */ 1718d5d45fbSJean Delvare cur = i2c_smbus_read_word_data(new_client, 0); 1728d5d45fbSJean Delvare conf = i2c_smbus_read_byte_data(new_client, 1); 1738d5d45fbSJean Delvare hyst = i2c_smbus_read_word_data(new_client, 2); 1748d5d45fbSJean Delvare if (i2c_smbus_read_word_data(new_client, 4) != hyst 1758d5d45fbSJean Delvare || i2c_smbus_read_word_data(new_client, 5) != hyst 1768d5d45fbSJean Delvare || i2c_smbus_read_word_data(new_client, 6) != hyst 1778d5d45fbSJean Delvare || i2c_smbus_read_word_data(new_client, 7) != hyst) 1788d5d45fbSJean Delvare goto exit_free; 1798d5d45fbSJean Delvare os = i2c_smbus_read_word_data(new_client, 3); 1808d5d45fbSJean Delvare if (i2c_smbus_read_word_data(new_client, 4) != os 1818d5d45fbSJean Delvare || i2c_smbus_read_word_data(new_client, 5) != os 1828d5d45fbSJean Delvare || i2c_smbus_read_word_data(new_client, 6) != os 1838d5d45fbSJean Delvare || i2c_smbus_read_word_data(new_client, 7) != os) 1848d5d45fbSJean Delvare goto exit_free; 1858d5d45fbSJean Delvare 1868d5d45fbSJean Delvare /* Unused bits */ 1878d5d45fbSJean Delvare if (conf & 0xe0) 1888d5d45fbSJean Delvare goto exit_free; 1898d5d45fbSJean Delvare 1908d5d45fbSJean Delvare /* Addresses cycling */ 1918d5d45fbSJean Delvare for (i = 8; i < 0xff; i += 8) 1928d5d45fbSJean Delvare if (i2c_smbus_read_byte_data(new_client, i + 1) != conf 1938d5d45fbSJean Delvare || i2c_smbus_read_word_data(new_client, i + 2) != hyst 1948d5d45fbSJean Delvare || i2c_smbus_read_word_data(new_client, i + 3) != os) 1958d5d45fbSJean Delvare goto exit_free; 1968d5d45fbSJean Delvare } 1978d5d45fbSJean Delvare 1988d5d45fbSJean Delvare /* Determine the chip type - only one kind supported! */ 1998d5d45fbSJean Delvare if (kind <= 0) 2008d5d45fbSJean Delvare kind = lm75; 2018d5d45fbSJean Delvare 2028d5d45fbSJean Delvare if (kind == lm75) { 2038d5d45fbSJean Delvare name = "lm75"; 2048d5d45fbSJean Delvare } 2058d5d45fbSJean Delvare 2068d5d45fbSJean Delvare /* Fill in the remaining client fields and put it into the global list */ 2078d5d45fbSJean Delvare strlcpy(new_client->name, name, I2C_NAME_SIZE); 2088d5d45fbSJean Delvare data->valid = 0; 2099a61bf63SIngo Molnar mutex_init(&data->update_lock); 2108d5d45fbSJean Delvare 2118d5d45fbSJean Delvare /* Tell the I2C layer a new client has arrived */ 2128d5d45fbSJean Delvare if ((err = i2c_attach_client(new_client))) 2138d5d45fbSJean Delvare goto exit_free; 2148d5d45fbSJean Delvare 2158d5d45fbSJean Delvare /* Initialize the LM75 chip */ 2168d5d45fbSJean Delvare lm75_init_client(new_client); 2178d5d45fbSJean Delvare 2188d5d45fbSJean Delvare /* Register sysfs hooks */ 219c1685f61SMark M. Hoffman if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group))) 220c1685f61SMark M. Hoffman goto exit_detach; 221c1685f61SMark M. Hoffman 2221beeffe4STony Jones data->hwmon_dev = hwmon_device_register(&new_client->dev); 2231beeffe4STony Jones if (IS_ERR(data->hwmon_dev)) { 2241beeffe4STony Jones err = PTR_ERR(data->hwmon_dev); 225c1685f61SMark M. Hoffman goto exit_remove; 226943b0830SMark M. Hoffman } 227943b0830SMark M. Hoffman 2288d5d45fbSJean Delvare return 0; 2298d5d45fbSJean Delvare 230c1685f61SMark M. Hoffman exit_remove: 231c1685f61SMark M. Hoffman sysfs_remove_group(&new_client->dev.kobj, &lm75_group); 232943b0830SMark M. Hoffman exit_detach: 233943b0830SMark M. Hoffman i2c_detach_client(new_client); 2348d5d45fbSJean Delvare exit_free: 2358d5d45fbSJean Delvare kfree(data); 2368d5d45fbSJean Delvare exit: 2378d5d45fbSJean Delvare return err; 2388d5d45fbSJean Delvare } 2398d5d45fbSJean Delvare 2408d5d45fbSJean Delvare static int lm75_detach_client(struct i2c_client *client) 2418d5d45fbSJean Delvare { 242943b0830SMark M. Hoffman struct lm75_data *data = i2c_get_clientdata(client); 2431beeffe4STony Jones hwmon_device_unregister(data->hwmon_dev); 244c1685f61SMark M. Hoffman sysfs_remove_group(&client->dev.kobj, &lm75_group); 2458d5d45fbSJean Delvare i2c_detach_client(client); 246943b0830SMark M. Hoffman kfree(data); 2478d5d45fbSJean Delvare return 0; 2488d5d45fbSJean Delvare } 2498d5d45fbSJean Delvare 2508d5d45fbSJean Delvare /* All registers are word-sized, except for the configuration register. 2518d5d45fbSJean Delvare LM75 uses a high-byte first convention, which is exactly opposite to 2528d5d45fbSJean Delvare the usual practice. */ 2538d5d45fbSJean Delvare static int lm75_read_value(struct i2c_client *client, u8 reg) 2548d5d45fbSJean Delvare { 2558d5d45fbSJean Delvare if (reg == LM75_REG_CONF) 2568d5d45fbSJean Delvare return i2c_smbus_read_byte_data(client, reg); 2578d5d45fbSJean Delvare else 2588d5d45fbSJean Delvare return swab16(i2c_smbus_read_word_data(client, reg)); 2598d5d45fbSJean Delvare } 2608d5d45fbSJean Delvare 2618d5d45fbSJean Delvare /* All registers are word-sized, except for the configuration register. 2628d5d45fbSJean Delvare LM75 uses a high-byte first convention, which is exactly opposite to 2638d5d45fbSJean Delvare the usual practice. */ 2648d5d45fbSJean Delvare static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) 2658d5d45fbSJean Delvare { 2668d5d45fbSJean Delvare if (reg == LM75_REG_CONF) 2678d5d45fbSJean Delvare return i2c_smbus_write_byte_data(client, reg, value); 2688d5d45fbSJean Delvare else 2698d5d45fbSJean Delvare return i2c_smbus_write_word_data(client, reg, swab16(value)); 2708d5d45fbSJean Delvare } 2718d5d45fbSJean Delvare 2728d5d45fbSJean Delvare static void lm75_init_client(struct i2c_client *client) 2738d5d45fbSJean Delvare { 274e647ecf1SJean Delvare int reg; 275e647ecf1SJean Delvare 276e647ecf1SJean Delvare /* Enable if in shutdown mode */ 277e647ecf1SJean Delvare reg = lm75_read_value(client, LM75_REG_CONF); 278e647ecf1SJean Delvare if (reg >= 0 && (reg & 0x01)) 279e647ecf1SJean Delvare lm75_write_value(client, LM75_REG_CONF, reg & 0xfe); 2808d5d45fbSJean Delvare } 2818d5d45fbSJean Delvare 2828d5d45fbSJean Delvare static struct lm75_data *lm75_update_device(struct device *dev) 2838d5d45fbSJean Delvare { 2848d5d45fbSJean Delvare struct i2c_client *client = to_i2c_client(dev); 2858d5d45fbSJean Delvare struct lm75_data *data = i2c_get_clientdata(client); 2868d5d45fbSJean Delvare 2879a61bf63SIngo Molnar mutex_lock(&data->update_lock); 2888d5d45fbSJean Delvare 2898d5d45fbSJean Delvare if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 2908d5d45fbSJean Delvare || !data->valid) { 2919ca8e40cSJean Delvare int i; 2928d5d45fbSJean Delvare dev_dbg(&client->dev, "Starting lm75 update\n"); 2938d5d45fbSJean Delvare 2949ca8e40cSJean Delvare for (i = 0; i < ARRAY_SIZE(data->temp); i++) 2959ca8e40cSJean Delvare data->temp[i] = lm75_read_value(client, 2969ca8e40cSJean Delvare LM75_REG_TEMP[i]); 2978d5d45fbSJean Delvare data->last_updated = jiffies; 2988d5d45fbSJean Delvare data->valid = 1; 2998d5d45fbSJean Delvare } 3008d5d45fbSJean Delvare 3019a61bf63SIngo Molnar mutex_unlock(&data->update_lock); 3028d5d45fbSJean Delvare 3038d5d45fbSJean Delvare return data; 3048d5d45fbSJean Delvare } 3058d5d45fbSJean Delvare 3068d5d45fbSJean Delvare static int __init sensors_lm75_init(void) 3078d5d45fbSJean Delvare { 3088d5d45fbSJean Delvare return i2c_add_driver(&lm75_driver); 3098d5d45fbSJean Delvare } 3108d5d45fbSJean Delvare 3118d5d45fbSJean Delvare static void __exit sensors_lm75_exit(void) 3128d5d45fbSJean Delvare { 3138d5d45fbSJean Delvare i2c_del_driver(&lm75_driver); 3148d5d45fbSJean Delvare } 3158d5d45fbSJean Delvare 3168d5d45fbSJean Delvare MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); 3178d5d45fbSJean Delvare MODULE_DESCRIPTION("LM75 driver"); 3188d5d45fbSJean Delvare MODULE_LICENSE("GPL"); 3198d5d45fbSJean Delvare 3208d5d45fbSJean Delvare module_init(sensors_lm75_init); 3218d5d45fbSJean Delvare module_exit(sensors_lm75_exit); 322