diff options
Diffstat (limited to 'drivers/hwmon/lm75.c')
| -rw-r--r-- | drivers/hwmon/lm75.c | 601 |
1 files changed, 409 insertions, 192 deletions
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 115f4090b98..479ffbeed3f 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -1,22 +1,22 @@ /* - lm75.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * lm75.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -27,17 +27,40 @@ #include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> +#include <linux/of.h> +#include <linux/thermal.h> #include "lm75.h" -/* Addresses to scan */ +/* + * This driver handles the LM75 and compatible digital temperature sensors. + */ + +enum lm75_type { /* keep sorted in alphabetical order */ + adt75, + ds1775, + ds75, + ds7505, + g751, + lm75, + lm75a, + max6625, + max6626, + mcp980x, + stds75, + tcn75, + tmp100, + tmp101, + tmp105, + tmp175, + tmp275, + tmp75, +}; + +/* Addresses scanned */ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -/* Insmod parameters */ -I2C_CLIENT_INSMOD_1(lm75); - -/* Many LM75 constants specified below */ /* The LM75 registers */ #define LM75_REG_CONF 0x01 @@ -49,55 +72,89 @@ static const u8 LM75_REG_TEMP[3] = { /* Each client has this additional data */ struct lm75_data { - struct i2c_client client; - struct device *hwmon_dev; + struct i2c_client *client; + struct device *hwmon_dev; + struct thermal_zone_device *tz; struct mutex update_lock; - char valid; /* !=0 if following fields are valid */ + u8 orig_conf; + u8 resolution; /* In bits, between 9 and 12 */ + u8 resolution_limits; + char valid; /* !=0 if registers are valid */ unsigned long last_updated; /* In jiffies */ - u16 temp[3]; /* Register values, + unsigned long sample_time; /* In jiffies */ + s16 temp[3]; /* Register values, 0 = input 1 = max 2 = hyst */ }; -static int lm75_attach_adapter(struct i2c_adapter *adapter); -static int lm75_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm75_init_client(struct i2c_client *client); -static int lm75_detach_client(struct i2c_client *client); static int lm75_read_value(struct i2c_client *client, u8 reg); static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); static struct lm75_data *lm75_update_device(struct device *dev); -/* This is the driver that will be inserted */ -static struct i2c_driver lm75_driver = { - .driver = { - .name = "lm75", - }, - .attach_adapter = lm75_attach_adapter, - .detach_client = lm75_detach_client, -}; +/*-----------------------------------------------------------------------*/ + +static inline long lm75_reg_to_mc(s16 temp, u8 resolution) +{ + return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8); +} + +/* sysfs attributes for hwmon */ + +static int lm75_read_temp(void *dev, long *temp) +{ + struct lm75_data *data = lm75_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + *temp = lm75_reg_to_mc(data->temp[0], data->resolution); + + return 0; +} static ssize_t show_temp(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm75_data *data = lm75_update_device(dev); - return sprintf(buf, "%d\n", - LM75_TEMP_FROM_REG(data->temp[attr->index])); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%ld\n", lm75_reg_to_mc(data->temp[attr->index], + data->resolution)); } static ssize_t set_temp(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - struct lm75_data *data = i2c_get_clientdata(client); + struct lm75_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = attr->index; - long temp = simple_strtol(buf, NULL, 10); + long temp; + int error; + u8 resolution; + + error = kstrtol(buf, 10, &temp); + if (error) + return error; + + /* + * Resolution of limit registers is assumed to be the same as the + * temperature input register resolution unless given explicitly. + */ + if (attr->index && data->resolution_limits) + resolution = data->resolution_limits; + else + resolution = data->resolution; mutex_lock(&data->update_lock); - data->temp[nr] = LM75_TEMP_TO_REG(temp); + temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); + data->temp[nr] = DIV_ROUND_CLOSEST(temp << (resolution - 8), + 1000) << (16 - resolution); lm75_write_value(client, LM75_REG_TEMP[nr], data->temp[nr]); mutex_unlock(&data->update_lock); return count; @@ -109,212 +166,372 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp, set_temp, 2); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); -static int lm75_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_probe(adapter, &addr_data, lm75_detect); -} - -static struct attribute *lm75_attributes[] = { +static struct attribute *lm75_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, NULL }; +ATTRIBUTE_GROUPS(lm75); -static const struct attribute_group lm75_group = { - .attrs = lm75_attributes, -}; +/*-----------------------------------------------------------------------*/ + +/* device probe and removal */ -/* This function is called by i2c_probe */ -static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) +static int +lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int i; - struct i2c_client *new_client; + struct device *dev = &client->dev; struct lm75_data *data; - int err = 0; - const char *name = ""; + int status; + u8 set_mask, clr_mask; + int new; + enum lm75_type kind = id->driver_data; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm75_{read,write}_value. */ - if (!(data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -EIO; - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm75_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. There is no identification- - dedicated register so we have to rely on several tricks: - unused bits, registers cycling over 8-address boundaries, - addresses 0x04-0x07 returning the last read value. - The cycling+unused addresses combination is not tested, - since it would significantly slow the detection down and would - hardly add any value. */ - if (kind < 0) { - int cur, conf, hyst, os; + data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); + if (!data) + return -ENOMEM; - /* Unused addresses */ - cur = i2c_smbus_read_word_data(new_client, 0); - conf = i2c_smbus_read_byte_data(new_client, 1); - hyst = i2c_smbus_read_word_data(new_client, 2); - if (i2c_smbus_read_word_data(new_client, 4) != hyst - || i2c_smbus_read_word_data(new_client, 5) != hyst - || i2c_smbus_read_word_data(new_client, 6) != hyst - || i2c_smbus_read_word_data(new_client, 7) != hyst) - goto exit_free; - os = i2c_smbus_read_word_data(new_client, 3); - if (i2c_smbus_read_word_data(new_client, 4) != os - || i2c_smbus_read_word_data(new_client, 5) != os - || i2c_smbus_read_word_data(new_client, 6) != os - || i2c_smbus_read_word_data(new_client, 7) != os) - goto exit_free; - - /* Unused bits */ - if (conf & 0xe0) - goto exit_free; - - /* Addresses cycling */ - for (i = 8; i < 0xff; i += 8) - if (i2c_smbus_read_byte_data(new_client, i + 1) != conf - || i2c_smbus_read_word_data(new_client, i + 2) != hyst - || i2c_smbus_read_word_data(new_client, i + 3) != os) - goto exit_free; - } + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm75; + /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. + * Then tweak to be more precise when appropriate. + */ + set_mask = 0; + clr_mask = LM75_SHUTDOWN; /* continuous conversions */ + + switch (kind) { + case adt75: + clr_mask |= 1 << 5; /* not one-shot mode */ + data->resolution = 12; + data->sample_time = HZ / 8; + break; + case ds1775: + case ds75: + case stds75: + clr_mask |= 3 << 5; + set_mask |= 2 << 5; /* 11-bit mode */ + data->resolution = 11; + data->sample_time = HZ; + break; + case ds7505: + set_mask |= 3 << 5; /* 12-bit mode */ + data->resolution = 12; + data->sample_time = HZ / 4; + break; + case g751: + case lm75: + case lm75a: + data->resolution = 9; + data->sample_time = HZ / 2; + break; + case max6625: + data->resolution = 9; + data->sample_time = HZ / 4; + break; + case max6626: + data->resolution = 12; + data->resolution_limits = 9; + data->sample_time = HZ / 4; + break; + case tcn75: + data->resolution = 9; + data->sample_time = HZ / 8; + break; + case mcp980x: + data->resolution_limits = 9; + /* fall through */ + case tmp100: + case tmp101: + set_mask |= 3 << 5; /* 12-bit mode */ + data->resolution = 12; + data->sample_time = HZ; + clr_mask |= 1 << 7; /* not one-shot mode */ + break; + case tmp105: + case tmp175: + case tmp275: + case tmp75: + set_mask |= 3 << 5; /* 12-bit mode */ + clr_mask |= 1 << 7; /* not one-shot mode */ + data->resolution = 12; + data->sample_time = HZ / 2; + break; + } - if (kind == lm75) { - name = "lm75"; + /* configure as specified */ + status = lm75_read_value(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(dev, "Can't read config? %d\n", status); + return status; } + data->orig_conf = status; + new = status & ~clr_mask; + new |= set_mask; + if (status != new) + lm75_write_value(client, LM75_REG_CONF, new); + dev_dbg(dev, "Config %02x\n", new); + + data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, + data, lm75_groups); + if (IS_ERR(data->hwmon_dev)) + return PTR_ERR(data->hwmon_dev); + + data->tz = thermal_zone_of_sensor_register(data->hwmon_dev, + 0, + data->hwmon_dev, + lm75_read_temp, NULL); + if (IS_ERR(data->tz)) + data->tz = NULL; + + dev_info(dev, "%s: sensor '%s'\n", + dev_name(data->hwmon_dev), client->name); - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - mutex_init(&data->update_lock); + return 0; +} + +static int lm75_remove(struct i2c_client *client) +{ + struct lm75_data *data = i2c_get_clientdata(client); - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM75 chip */ - lm75_init_client(new_client); - - /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group))) - goto exit_detach; - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; + thermal_zone_of_sensor_unregister(data->hwmon_dev, data->tz); + hwmon_device_unregister(data->hwmon_dev); + lm75_write_value(client, LM75_REG_CONF, data->orig_conf); + return 0; +} + +static const struct i2c_device_id lm75_ids[] = { + { "adt75", adt75, }, + { "ds1775", ds1775, }, + { "ds75", ds75, }, + { "ds7505", ds7505, }, + { "g751", g751, }, + { "lm75", lm75, }, + { "lm75a", lm75a, }, + { "max6625", max6625, }, + { "max6626", max6626, }, + { "mcp980x", mcp980x, }, + { "stds75", stds75, }, + { "tcn75", tcn75, }, + { "tmp100", tmp100, }, + { "tmp101", tmp101, }, + { "tmp105", tmp105, }, + { "tmp175", tmp175, }, + { "tmp275", tmp275, }, + { "tmp75", tmp75, }, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, lm75_ids); + +#define LM75A_ID 0xA1 + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int lm75_detect(struct i2c_client *new_client, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = new_client->adapter; + int i; + int conf, hyst, os; + bool is_lm75a = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + /* + * Now, we do the remaining detection. There is no identification- + * dedicated register so we have to rely on several tricks: + * unused bits, registers cycling over 8-address boundaries, + * addresses 0x04-0x07 returning the last read value. + * The cycling+unused addresses combination is not tested, + * since it would significantly slow the detection down and would + * hardly add any value. + * + * The National Semiconductor LM75A is different than earlier + * LM75s. It has an ID byte of 0xaX (where X is the chip + * revision, with 1 being the only revision in existence) in + * register 7, and unused registers return 0xff rather than the + * last read value. + * + * Note that this function only detects the original National + * Semiconductor LM75 and the LM75A. Clones from other vendors + * aren't detected, on purpose, because they are typically never + * found on PC hardware. They are found on embedded designs where + * they can be instantiated explicitly so detection is not needed. + * The absence of identification registers on all these clones + * would make their exhaustive detection very difficult and weak, + * and odds are that the driver would bind to unsupported devices. + */ + + /* Unused bits */ + conf = i2c_smbus_read_byte_data(new_client, 1); + if (conf & 0xe0) + return -ENODEV; + + /* First check for LM75A */ + if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) { + /* LM75A returns 0xff on unused registers so + just to be sure we check for that too. */ + if (i2c_smbus_read_byte_data(new_client, 4) != 0xff + || i2c_smbus_read_byte_data(new_client, 5) != 0xff + || i2c_smbus_read_byte_data(new_client, 6) != 0xff) + return -ENODEV; + is_lm75a = 1; + hyst = i2c_smbus_read_byte_data(new_client, 2); + os = i2c_smbus_read_byte_data(new_client, 3); + } else { /* Traditional style LM75 detection */ + /* Unused addresses */ + hyst = i2c_smbus_read_byte_data(new_client, 2); + if (i2c_smbus_read_byte_data(new_client, 4) != hyst + || i2c_smbus_read_byte_data(new_client, 5) != hyst + || i2c_smbus_read_byte_data(new_client, 6) != hyst + || i2c_smbus_read_byte_data(new_client, 7) != hyst) + return -ENODEV; + os = i2c_smbus_read_byte_data(new_client, 3); + if (i2c_smbus_read_byte_data(new_client, 4) != os + || i2c_smbus_read_byte_data(new_client, 5) != os + || i2c_smbus_read_byte_data(new_client, 6) != os + || i2c_smbus_read_byte_data(new_client, 7) != os) + return -ENODEV; } + /* Addresses cycling */ + for (i = 8; i <= 248; i += 40) { + if (i2c_smbus_read_byte_data(new_client, i + 1) != conf + || i2c_smbus_read_byte_data(new_client, i + 2) != hyst + || i2c_smbus_read_byte_data(new_client, i + 3) != os) + return -ENODEV; + if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7) + != LM75A_ID) + return -ENODEV; + } + + strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE); + return 0; +} -exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &lm75_group); -exit_detach: - i2c_detach_client(new_client); -exit_free: - kfree(data); -exit: - return err; +#ifdef CONFIG_PM +static int lm75_suspend(struct device *dev) +{ + int status; + struct i2c_client *client = to_i2c_client(dev); + status = lm75_read_value(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(&client->dev, "Can't read config? %d\n", status); + return status; + } + status = status | LM75_SHUTDOWN; + lm75_write_value(client, LM75_REG_CONF, status); + return 0; } -static int lm75_detach_client(struct i2c_client *client) +static int lm75_resume(struct device *dev) { - struct lm75_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm75_group); - i2c_detach_client(client); - kfree(data); + int status; + struct i2c_client *client = to_i2c_client(dev); + status = lm75_read_value(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(&client->dev, "Can't read config? %d\n", status); + return status; + } + status = status & ~LM75_SHUTDOWN; + lm75_write_value(client, LM75_REG_CONF, status); return 0; } -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ +static const struct dev_pm_ops lm75_dev_pm_ops = { + .suspend = lm75_suspend, + .resume = lm75_resume, +}; +#define LM75_DEV_PM_OPS (&lm75_dev_pm_ops) +#else +#define LM75_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + +static struct i2c_driver lm75_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm75", + .pm = LM75_DEV_PM_OPS, + }, + .probe = lm75_probe, + .remove = lm75_remove, + .id_table = lm75_ids, + .detect = lm75_detect, + .address_list = normal_i2c, +}; + +/*-----------------------------------------------------------------------*/ + +/* register access */ + +/* + * All registers are word-sized, except for the configuration register. + * LM75 uses a high-byte first convention, which is exactly opposite to + * the SMBus standard. + */ static int lm75_read_value(struct i2c_client *client, u8 reg) { if (reg == LM75_REG_CONF) return i2c_smbus_read_byte_data(client, reg); else - return swab16(i2c_smbus_read_word_data(client, reg)); + return i2c_smbus_read_word_swapped(client, reg); } -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) { if (reg == LM75_REG_CONF) return i2c_smbus_write_byte_data(client, reg, value); else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void lm75_init_client(struct i2c_client *client) -{ - int reg; - - /* Enable if in shutdown mode */ - reg = lm75_read_value(client, LM75_REG_CONF); - if (reg >= 0 && (reg & 0x01)) - lm75_write_value(client, LM75_REG_CONF, reg & 0xfe); + return i2c_smbus_write_word_swapped(client, reg, value); } static struct lm75_data *lm75_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm75_data *data = i2c_get_clientdata(client); + struct lm75_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct lm75_data *ret = data; mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + if (time_after(jiffies, data->last_updated + data->sample_time) || !data->valid) { int i; dev_dbg(&client->dev, "Starting lm75 update\n"); - for (i = 0; i < ARRAY_SIZE(data->temp); i++) - data->temp[i] = lm75_read_value(client, - LM75_REG_TEMP[i]); + for (i = 0; i < ARRAY_SIZE(data->temp); i++) { + int status; + + status = lm75_read_value(client, LM75_REG_TEMP[i]); + if (unlikely(status < 0)) { + dev_dbg(dev, + "LM75: Failed to read value: reg %d, error %d\n", + LM75_REG_TEMP[i], status); + ret = ERR_PTR(status); + data->valid = 0; + goto abort; + } + data->temp[i] = status; + } data->last_updated = jiffies; data->valid = 1; } +abort: mutex_unlock(&data->update_lock); - - return data; + return ret; } -static int __init sensors_lm75_init(void) -{ - return i2c_add_driver(&lm75_driver); -} - -static void __exit sensors_lm75_exit(void) -{ - i2c_del_driver(&lm75_driver); -} +module_i2c_driver(lm75_driver); MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); MODULE_DESCRIPTION("LM75 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm75_init); -module_exit(sensors_lm75_exit); |
