From aa9bcddada9e6e6538ac44b3623bb23b802ba689 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 5 Apr 2014 21:44:47 -0700 Subject: hwmon: (lm70) Convert to use devm_hwmon_device_register_with_groups Use devm_hwmon_device_register_with_groups API to attach attributes to hwmon device, simplify code, and reduce code size. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm70.c | 62 ++++++++++++---------------------------------------- 1 file changed, 14 insertions(+), 48 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 505a59e100b0..97204dce162d 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -47,7 +47,7 @@ #define LM70_CHIP_LM74 3 /* NS LM74 */ struct lm70 { - struct device *hwmon_dev; + struct spi_device *spi; struct mutex lock; unsigned int chip; }; @@ -56,11 +56,11 @@ struct lm70 { static ssize_t lm70_sense_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct spi_device *spi = to_spi_device(dev); + struct lm70 *p_lm70 = dev_get_drvdata(dev); + struct spi_device *spi = p_lm70->spi; int status, val = 0; u8 rxbuf[2]; s16 raw = 0; - struct lm70 *p_lm70 = spi_get_drvdata(spi); if (mutex_lock_interruptible(&p_lm70->lock)) return -ERESTARTSYS; @@ -121,21 +121,20 @@ out: static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL); -static ssize_t lm70_show_name(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); -} +static struct attribute *lm70_attrs[] = { + &dev_attr_temp1_input.attr, + NULL +}; -static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL); +ATTRIBUTE_GROUPS(lm70); /*----------------------------------------------------------------------*/ static int lm70_probe(struct spi_device *spi) { int chip = spi_get_device_id(spi)->driver_data; + struct device *hwmon_dev; struct lm70 *p_lm70; - int status; /* signaling is SPI_MODE_0 */ if (spi->mode & (SPI_CPOL | SPI_CPHA)) @@ -149,46 +148,14 @@ static int lm70_probe(struct spi_device *spi) mutex_init(&p_lm70->lock); p_lm70->chip = chip; + p_lm70->spi = spi; - spi_set_drvdata(spi, p_lm70); - - status = device_create_file(&spi->dev, &dev_attr_temp1_input); - if (status) - goto out_dev_create_temp_file_failed; - status = device_create_file(&spi->dev, &dev_attr_name); - if (status) - goto out_dev_create_file_failed; - - /* sysfs hook */ - p_lm70->hwmon_dev = hwmon_device_register(&spi->dev); - if (IS_ERR(p_lm70->hwmon_dev)) { - dev_dbg(&spi->dev, "hwmon_device_register failed.\n"); - status = PTR_ERR(p_lm70->hwmon_dev); - goto out_dev_reg_failed; - } - - return 0; - -out_dev_reg_failed: - device_remove_file(&spi->dev, &dev_attr_name); -out_dev_create_file_failed: - device_remove_file(&spi->dev, &dev_attr_temp1_input); -out_dev_create_temp_file_failed: - return status; + hwmon_dev = devm_hwmon_device_register_with_groups(&spi->dev, + spi->modalias, + p_lm70, lm70_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } -static int lm70_remove(struct spi_device *spi) -{ - struct lm70 *p_lm70 = spi_get_drvdata(spi); - - hwmon_device_unregister(p_lm70->hwmon_dev); - device_remove_file(&spi->dev, &dev_attr_temp1_input); - device_remove_file(&spi->dev, &dev_attr_name); - - return 0; -} - - static const struct spi_device_id lm70_ids[] = { { "lm70", LM70_CHIP_LM70 }, { "tmp121", LM70_CHIP_TMP121 }, @@ -205,7 +172,6 @@ static struct spi_driver lm70_driver = { }, .id_table = lm70_ids, .probe = lm70_probe, - .remove = lm70_remove, }; module_spi_driver(lm70_driver); -- cgit v1.2.3-59-g8ed1b From fbd9af164c4a70e6f37b6985de8d481a6958cc2c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 2 Feb 2014 14:22:30 -0800 Subject: hwmon: (tmp102) Introduce dev variable in probe function The pointer to client->dev is used several times in the probe function. Simplify code by introducing a separate variable for it. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp102.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 6748b4583e7b..5ea99a25fdfe 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -162,17 +162,18 @@ static const struct attribute_group tmp102_attr_group = { static int tmp102_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct tmp102 *tmp102; int status; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_err(&client->dev, + dev_err(dev, "adapter doesn't support SMBus word transactions\n"); return -ENODEV; } - tmp102 = devm_kzalloc(&client->dev, sizeof(*tmp102), GFP_KERNEL); + tmp102 = devm_kzalloc(dev, sizeof(*tmp102), GFP_KERNEL); if (!tmp102) return -ENOMEM; @@ -180,54 +181,53 @@ static int tmp102_probe(struct i2c_client *client, status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { - dev_err(&client->dev, "error reading config register\n"); + dev_err(dev, "error reading config register\n"); return status; } tmp102->config_orig = status; status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, TMP102_CONFIG); if (status < 0) { - dev_err(&client->dev, "error writing config register\n"); + dev_err(dev, "error writing config register\n"); goto fail_restore_config; } status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { - dev_err(&client->dev, "error reading config register\n"); + dev_err(dev, "error reading config register\n"); goto fail_restore_config; } status &= ~TMP102_CONFIG_RD_ONLY; if (status != TMP102_CONFIG) { - dev_err(&client->dev, "config settings did not stick\n"); + dev_err(dev, "config settings did not stick\n"); status = -ENODEV; goto fail_restore_config; } tmp102->last_update = jiffies - HZ; mutex_init(&tmp102->lock); - status = sysfs_create_group(&client->dev.kobj, &tmp102_attr_group); + status = sysfs_create_group(&dev->kobj, &tmp102_attr_group); if (status) { - dev_dbg(&client->dev, "could not create sysfs files\n"); + dev_dbg(dev, "could not create sysfs files\n"); goto fail_restore_config; } - tmp102->hwmon_dev = hwmon_device_register(&client->dev); + tmp102->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(tmp102->hwmon_dev)) { - dev_dbg(&client->dev, "unable to register hwmon device\n"); + dev_dbg(dev, "unable to register hwmon device\n"); status = PTR_ERR(tmp102->hwmon_dev); goto fail_remove_sysfs; } - tmp102->tz = thermal_zone_of_sensor_register(&client->dev, 0, - &client->dev, + tmp102->tz = thermal_zone_of_sensor_register(dev, 0, dev, tmp102_read_temp, NULL); if (IS_ERR(tmp102->tz)) tmp102->tz = NULL; - dev_info(&client->dev, "initialized\n"); + dev_info(dev, "initialized\n"); return 0; fail_remove_sysfs: - sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group); + sysfs_remove_group(&dev->kobj, &tmp102_attr_group); fail_restore_config: i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, tmp102->config_orig); -- cgit v1.2.3-59-g8ed1b From ad9beea43f22f80217ac1850b0373718adce5fbc Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 2 Feb 2014 10:08:09 -0800 Subject: hwmon: (tmp102) Convert to use hwmon_device_register_with_groups Simplify code, reduce code size, and attach sysfs attributes to hwmon device. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp102.c | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 5ea99a25fdfe..51719956cc03 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -51,6 +51,7 @@ #define TMP102_THIGH_REG 0x03 struct tmp102 { + struct i2c_client *client; struct device *hwmon_dev; struct thermal_zone_device *tz; struct mutex lock; @@ -77,9 +78,10 @@ static const u8 tmp102_reg[] = { TMP102_THIGH_REG, }; -static struct tmp102 *tmp102_update_device(struct i2c_client *client) +static struct tmp102 *tmp102_update_device(struct device *dev) { - struct tmp102 *tmp102 = i2c_get_clientdata(client); + struct tmp102 *tmp102 = dev_get_drvdata(dev); + struct i2c_client *client = tmp102->client; mutex_lock(&tmp102->lock); if (time_after(jiffies, tmp102->last_update + HZ / 3)) { @@ -98,7 +100,7 @@ static struct tmp102 *tmp102_update_device(struct i2c_client *client) static int tmp102_read_temp(void *dev, long *temp) { - struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev)); + struct tmp102 *tmp102 = tmp102_update_device(dev); *temp = tmp102->temp[0]; @@ -110,7 +112,7 @@ static ssize_t tmp102_show_temp(struct device *dev, char *buf) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev)); + struct tmp102 *tmp102 = tmp102_update_device(dev); return sprintf(buf, "%d\n", tmp102->temp[sda->index]); } @@ -120,8 +122,8 @@ static ssize_t tmp102_set_temp(struct device *dev, const char *buf, size_t count) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - struct i2c_client *client = to_i2c_client(dev); - struct tmp102 *tmp102 = i2c_get_clientdata(client); + struct tmp102 *tmp102 = dev_get_drvdata(dev); + struct i2c_client *client = tmp102->client; long val; int status; @@ -145,16 +147,13 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp, static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp, tmp102_set_temp, 2); -static struct attribute *tmp102_attributes[] = { +static struct attribute *tmp102_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, NULL }; - -static const struct attribute_group tmp102_attr_group = { - .attrs = tmp102_attributes, -}; +ATTRIBUTE_GROUPS(tmp102); #define TMP102_CONFIG (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1) #define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL) @@ -163,6 +162,7 @@ static int tmp102_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; + struct device *hwmon_dev; struct tmp102 *tmp102; int status; @@ -178,6 +178,7 @@ static int tmp102_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, tmp102); + tmp102->client = client; status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { @@ -205,19 +206,15 @@ static int tmp102_probe(struct i2c_client *client, tmp102->last_update = jiffies - HZ; mutex_init(&tmp102->lock); - status = sysfs_create_group(&dev->kobj, &tmp102_attr_group); - if (status) { - dev_dbg(dev, "could not create sysfs files\n"); - goto fail_restore_config; - } - tmp102->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(tmp102->hwmon_dev)) { + hwmon_dev = hwmon_device_register_with_groups(dev, client->name, + tmp102, tmp102_groups); + if (IS_ERR(hwmon_dev)) { dev_dbg(dev, "unable to register hwmon device\n"); - status = PTR_ERR(tmp102->hwmon_dev); - goto fail_remove_sysfs; + status = PTR_ERR(hwmon_dev); + goto fail_restore_config; } - - tmp102->tz = thermal_zone_of_sensor_register(dev, 0, dev, + tmp102->hwmon_dev = hwmon_dev; + tmp102->tz = thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev, tmp102_read_temp, NULL); if (IS_ERR(tmp102->tz)) tmp102->tz = NULL; @@ -226,8 +223,6 @@ static int tmp102_probe(struct i2c_client *client, return 0; -fail_remove_sysfs: - sysfs_remove_group(&dev->kobj, &tmp102_attr_group); fail_restore_config: i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, tmp102->config_orig); @@ -238,9 +233,8 @@ static int tmp102_remove(struct i2c_client *client) { struct tmp102 *tmp102 = i2c_get_clientdata(client); - thermal_zone_of_sensor_unregister(&client->dev, tmp102->tz); + thermal_zone_of_sensor_unregister(tmp102->hwmon_dev, tmp102->tz); hwmon_device_unregister(tmp102->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group); /* Stop monitoring if device was stopped originally */ if (tmp102->config_orig & TMP102_CONF_SD) { -- cgit v1.2.3-59-g8ed1b From 276dac8039a70630e4dbf5c4c3b294c057e8cd42 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 5 Apr 2014 21:22:46 -0700 Subject: hwmon: (tmp421) Convert to use devm_hwmon_device_register_with_groups Use devm_hwmon_device_register_with_groups API to attach attributes to hwmon device, simplify code, and reduce code size. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp421.c | 47 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index ae26b06fa819..7bab7a9bedc6 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -69,7 +69,7 @@ static const struct i2c_device_id tmp421_id[] = { MODULE_DEVICE_TABLE(i2c, tmp421_id); struct tmp421_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; unsigned long last_updated; @@ -99,8 +99,8 @@ static int temp_from_u16(u16 reg) static struct tmp421_data *tmp421_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct tmp421_data *data = i2c_get_clientdata(client); + struct tmp421_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int i; mutex_lock(&data->update_lock); @@ -198,6 +198,11 @@ static const struct attribute_group tmp421_group = { .is_visible = tmp421_is_visible, }; +static const struct attribute_group *tmp421_groups[] = { + &tmp421_group, + NULL +}; + static int tmp421_init_client(struct i2c_client *client) { int config, config_orig; @@ -264,47 +269,26 @@ static int tmp421_detect(struct i2c_client *client, static int tmp421_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device *hwmon_dev; struct tmp421_data *data; int err; - data = devm_kzalloc(&client->dev, sizeof(struct tmp421_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct tmp421_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); mutex_init(&data->update_lock); data->channels = id->driver_data; + data->client = client; err = tmp421_init_client(client); if (err) return err; - err = sysfs_create_group(&client->dev.kobj, &tmp421_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - data->hwmon_dev = NULL; - goto exit_remove; - } - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &tmp421_group); - return err; -} - -static int tmp421_remove(struct i2c_client *client) -{ - struct tmp421_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &tmp421_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, tmp421_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static struct i2c_driver tmp421_driver = { @@ -313,7 +297,6 @@ static struct i2c_driver tmp421_driver = { .name = "tmp421", }, .probe = tmp421_probe, - .remove = tmp421_remove, .id_table = tmp421_id, .detect = tmp421_detect, .address_list = normal_i2c, -- cgit v1.2.3-59-g8ed1b From d9ee59751e616840e98ef0896efb43486e0f54d1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 08:46:29 -0700 Subject: hwmon: (lm77) Drop FSF mailing address The FSF mailing address changes over time, so drop it. No functional change. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm77.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 502771c06fd9..642216285814 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -19,10 +19,6 @@ * 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 -- cgit v1.2.3-59-g8ed1b From 9f9edcd4c32bf33255f8db7329c78a99baa94585 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 08:45:20 -0700 Subject: hwmon: (lm77) Rearrange code to no longer require forward declarations Forward declarations are easy to avoid and unnecessary. Rearrange code to avoid it. No functional change. Acked-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm77.c | 173 ++++++++++++++++++++++++--------------------------- 1 file changed, 81 insertions(+), 92 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 642216285814..4cd8a513c47b 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -57,36 +57,6 @@ struct lm77_data { u8 alarms; }; -static int lm77_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info); -static void lm77_init_client(struct i2c_client *client); -static int lm77_remove(struct i2c_client *client); -static u16 lm77_read_value(struct i2c_client *client, u8 reg); -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value); - -static struct lm77_data *lm77_update_device(struct device *dev); - - -static const struct i2c_device_id lm77_id[] = { - { "lm77", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm77_id); - -/* This is the driver that will be inserted */ -static struct i2c_driver lm77_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm77", - }, - .probe = lm77_probe, - .remove = lm77_remove, - .id_table = lm77_id, - .detect = lm77_detect, - .address_list = normal_i2c, -}; - /* straight from the datasheet */ #define LM77_TEMP_MIN (-55000) #define LM77_TEMP_MAX 125000 @@ -106,6 +76,62 @@ static inline int LM77_TEMP_FROM_REG(s16 reg) return (reg / 8) * 500; } +/* + * All registers are word-sized, except for the configuration register. + * The LM77 uses the high-byte first convention. + */ +static u16 lm77_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return i2c_smbus_read_word_swapped(client, reg); +} + +static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_swapped(client, reg, value); +} + +static struct lm77_data *lm77_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm77_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting lm77 update\n"); + data->temp_input = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP)); + data->temp_hyst = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_HYST)); + data->temp_crit = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_CRIT)); + data->temp_min = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_MIN)); + data->temp_max = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_MAX)); + data->alarms = + lm77_read_value(client, LM77_REG_TEMP) & 0x0007; + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + /* sysfs stuff */ /* read routines for temperature limits */ @@ -333,6 +359,14 @@ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } +static void lm77_init_client(struct i2c_client *client) +{ + /* Initialize the LM77 chip - turn off shutdown mode */ + int conf = lm77_read_value(client, LM77_REG_CONF); + if (conf & 1) + lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); +} + static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; @@ -375,69 +409,24 @@ static int lm77_remove(struct i2c_client *client) return 0; } -/* - * All registers are word-sized, except for the configuration register. - * The LM77 uses the high-byte first convention. - */ -static u16 lm77_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return i2c_smbus_read_word_swapped(client, reg); -} - -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_swapped(client, reg, value); -} - -static void lm77_init_client(struct i2c_client *client) -{ - /* Initialize the LM77 chip - turn off shutdown mode */ - int conf = lm77_read_value(client, LM77_REG_CONF); - if (conf & 1) - lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); -} - -static struct lm77_data *lm77_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting lm77 update\n"); - data->temp_input = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP)); - data->temp_hyst = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_HYST)); - data->temp_crit = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_CRIT)); - data->temp_min = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MIN)); - data->temp_max = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MAX)); - data->alarms = - lm77_read_value(client, LM77_REG_TEMP) & 0x0007; - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); +static const struct i2c_device_id lm77_id[] = { + { "lm77", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm77_id); - return data; -} +/* This is the driver that will be inserted */ +static struct i2c_driver lm77_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm77", + }, + .probe = lm77_probe, + .remove = lm77_remove, + .id_table = lm77_id, + .detect = lm77_detect, + .address_list = normal_i2c, +}; module_i2c_driver(lm77_driver); -- cgit v1.2.3-59-g8ed1b From 50bf46509f24c914562b4d818a155d8dc8f45e10 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 20 Apr 2014 08:07:42 -0700 Subject: hwmon: (lm77) Do not preserve hysteresis when updating critical temp limit Updating the hysteresis value when updating the critical temperature limit was following the rule of 'least surprise'. However, it had the undesirable side effect of changing the hysteresis for all other attributes, which defeats the purpose of least surprise. In addition, it could result in invalid hysteresis values if the resulting hysteresis was too large. In such cases the resulting hysteresis ended up changed anyway, which again defeats the purpose. So drop that code and document the new behavior. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/lm77 | 20 ++++++++++++++++++-- drivers/hwmon/lm77.c | 6 ------ 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'drivers/hwmon') diff --git a/Documentation/hwmon/lm77 b/Documentation/hwmon/lm77 index 57c3a46d6370..bfc915fe3639 100644 --- a/Documentation/hwmon/lm77 +++ b/Documentation/hwmon/lm77 @@ -18,5 +18,21 @@ sensor incorporates a band-gap type temperature sensor, 10-bit ADC, and a digital comparator with user-programmable upper and lower limit values. -Limits can be set through the Overtemperature Shutdown register and -Hysteresis register. +The LM77 implements 3 limits: low (temp1_min), high (temp1_max) and +critical (temp1_crit.) It also implements an hysteresis mechanism which +applies to all 3 limits. The relative difference is stored in a single +register on the chip, which means that the relative difference between +the limit and its hysteresis is always the same for all 3 limits. + +This implementation detail implies the following: +* When setting a limit, its hysteresis will automatically follow, the + difference staying unchanged. For example, if the old critical limit + was 80 degrees C, and the hysteresis was 75 degrees C, and you change + the critical limit to 90 degrees C, then the hysteresis will + automatically change to 85 degrees C. +* All 3 hysteresis can't be set independently. We decided to make + temp1_crit_hyst writable, while temp1_min_hyst and temp1_max_hyst are + read-only. Setting temp1_crit_hyst writes the difference between + temp1_crit_hyst and temp1_crit into the chip, and the same relative + hysteresis applies automatically to the low and high limits. +* The limits should be set before the hysteresis. diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 4cd8a513c47b..85e5b3355be4 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -216,13 +216,11 @@ static ssize_t set_temp_crit_hyst(struct device *dev, return count; } -/* preserve hysteresis when setting T_crit */ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm77_data *data = i2c_get_clientdata(client); - int oldcrithyst; unsigned long val; int err; @@ -231,13 +229,9 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - oldcrithyst = data->temp_crit - data->temp_hyst; data->temp_crit = val; - data->temp_hyst = data->temp_crit - oldcrithyst; lm77_write_value(client, LM77_REG_TEMP_CRIT, LM77_TEMP_TO_REG(data->temp_crit)); - lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); mutex_unlock(&data->update_lock); return count; } -- cgit v1.2.3-59-g8ed1b From 48dbd6ff142d518e01888d2addfab731ff65460e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 09:17:37 -0700 Subject: hwmon: (lm77) Drop function macros Function macros make the code harder to read and increase code size, so drop them. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm77.c | 182 +++++++++++++++++++++------------------------------ 1 file changed, 75 insertions(+), 107 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 85e5b3355be4..ab1752a5b46f 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -43,17 +43,30 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, #define LM77_REG_TEMP_MIN 0x04 #define LM77_REG_TEMP_MAX 0x05 +enum temp_index { + t_input = 0, + t_crit, + t_min, + t_max, + t_hyst, + t_num_temp +}; + +static const u8 temp_regs[t_num_temp] = { + [t_input] = LM77_REG_TEMP, + [t_min] = LM77_REG_TEMP_MIN, + [t_max] = LM77_REG_TEMP_MAX, + [t_crit] = LM77_REG_TEMP_CRIT, + [t_hyst] = LM77_REG_TEMP_HYST, +}; + /* Each client has this additional data */ struct lm77_data { struct device *hwmon_dev; struct mutex update_lock; char valid; unsigned long last_updated; /* In jiffies */ - int temp_input; /* Temperatures */ - int temp_crit; - int temp_min; - int temp_max; - int temp_hyst; + int temp[t_num_temp]; /* index using temp_index */ u8 alarms; }; @@ -100,27 +113,18 @@ static struct lm77_data *lm77_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct lm77_data *data = i2c_get_clientdata(client); + int i; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { dev_dbg(&client->dev, "Starting lm77 update\n"); - data->temp_input = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP)); - data->temp_hyst = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_HYST)); - data->temp_crit = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_CRIT)); - data->temp_min = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MIN)); - data->temp_max = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MAX)); + for (i = 0; i < t_num_temp; i++) { + data->temp[i] = + LM77_TEMP_FROM_REG(lm77_read_value(client, + temp_regs[i])); + } data->alarms = lm77_read_value(client, LM77_REG_TEMP) & 0x0007; data->last_updated = jiffies; @@ -134,89 +138,56 @@ static struct lm77_data *lm77_update_device(struct device *dev) /* sysfs stuff */ -/* read routines for temperature limits */ -#define show(value) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct lm77_data *data = lm77_update_device(dev); \ - return sprintf(buf, "%d\n", data->value); \ -} - -show(temp_input); -show(temp_crit); -show(temp_min); -show(temp_max); - -/* read routines for hysteresis values */ -static ssize_t show_temp_crit_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst); -} -static ssize_t show_temp_min_hyst(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst); + + return sprintf(buf, "%d\n", data->temp[attr->index]); } -static ssize_t show_temp_max_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +static ssize_t show_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst); -} + int nr = attr->index; + int temp; -/* write routines */ -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm77_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err) \ - return err; \ - \ - mutex_lock(&data->update_lock); \ - data->value = val; \ - lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} + temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] : + data->temp[nr] - data->temp[t_hyst]; -set(temp_min, LM77_REG_TEMP_MIN); -set(temp_max, LM77_REG_TEMP_MAX); + return sprintf(buf, "%d\n", temp); +} -/* - * hysteresis is stored as a relative value on the chip, so it has to be - * converted first - */ -static ssize_t set_temp_crit_hyst(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct lm77_data *data = i2c_get_clientdata(client); - unsigned long val; + int nr = attr->index; + long val; int err; - err = kstrtoul(buf, 10, &val); + err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); - data->temp_hyst = data->temp_crit - val; - lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); + data->temp[nr] = val; + lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val)); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, +/* + * hysteresis is stored as a relative value on the chip, so it has to be + * converted first. + */ +static ssize_t set_temp_hyst(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -229,9 +200,9 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->temp_crit = val; - lm77_write_value(client, LM77_REG_TEMP_CRIT, - LM77_TEMP_TO_REG(data->temp_crit)); + data->temp[t_hyst] = data->temp[t_crit] - val; + lm77_write_value(client, LM77_REG_TEMP_HYST, + LM77_TEMP_TO_REG(data->temp[t_hyst])); mutex_unlock(&data->update_lock); return count; } @@ -244,34 +215,31 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, - show_temp_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, - show_temp_crit, set_temp_crit); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, - show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp_max, set_temp_max); - -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, - show_temp_crit_hyst, set_temp_crit_hyst); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, - show_temp_min_hyst, NULL); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, - show_temp_max_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_crit); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_min); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_max); + +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, + set_temp_hyst, t_crit); +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_hyst, NULL, t_min); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); static struct attribute *lm77_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_crit_hyst.attr, - &dev_attr_temp1_min_hyst.attr, - &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, -- cgit v1.2.3-59-g8ed1b From 5975dfbf40bfb342db1b25a9b1e2c3b867773612 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 09:25:25 -0700 Subject: hwmon: (lm77) Convert to use devm_hwmon_device_register_with_groups Use devm_hwmon_device_register_with_groups API to attach attributes to hwmon device, simplify code, and reduce code size. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm77.c | 53 ++++++++++++++-------------------------------------- 1 file changed, 14 insertions(+), 39 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index ab1752a5b46f..5ceb443b938d 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -62,7 +62,7 @@ static const u8 temp_regs[t_num_temp] = { /* Each client has this additional data */ struct lm77_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; unsigned long last_updated; /* In jiffies */ @@ -111,8 +111,8 @@ static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) static struct lm77_data *lm77_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); + struct lm77_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int i; mutex_lock(&data->update_lock); @@ -165,8 +165,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); + struct lm77_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = attr->index; long val; int err; @@ -190,8 +190,8 @@ static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); + struct lm77_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int err; @@ -232,7 +232,7 @@ static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); -static struct attribute *lm77_attributes[] = { +static struct attribute *lm77_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, @@ -245,10 +245,7 @@ static struct attribute *lm77_attributes[] = { &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group lm77_group = { - .attrs = lm77_attributes, -}; +ATTRIBUTE_GROUPS(lm77); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info) @@ -332,43 +329,22 @@ static void lm77_init_client(struct i2c_client *client) static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; + struct device *hwmon_dev; struct lm77_data *data; - int err; data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the LM77 chip */ lm77_init_client(client); - /* Register sysfs hooks */ - err = sysfs_create_group(&dev->kobj, &lm77_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - sysfs_remove_group(&dev->kobj, &lm77_group); - return err; -} - -static int lm77_remove(struct i2c_client *client) -{ - struct lm77_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm77_group); - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, lm77_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id lm77_id[] = { @@ -384,7 +360,6 @@ static struct i2c_driver lm77_driver = { .name = "lm77", }, .probe = lm77_probe, - .remove = lm77_remove, .id_table = lm77_id, .detect = lm77_detect, .address_list = normal_i2c, -- cgit v1.2.3-59-g8ed1b From d663ec496d4a808b02ae10f85a55799b3c91fe7a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 13 Jan 2014 16:00:37 -0800 Subject: hwmon: (lm75) Convert to use hwmon_device_register_with_groups Simplify code and attach hwmon attributes to hwmon device. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm75.c | 51 ++++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 84a55eacd903..479ffbeed3f8 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -72,6 +72,7 @@ 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 thermal_zone_device *tz; struct mutex update_lock; @@ -130,8 +131,8 @@ 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; int error; @@ -165,17 +166,14 @@ 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 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 }; - -static const struct attribute_group lm75_group = { - .attrs = lm75_attributes, -}; +ATTRIBUTE_GROUPS(lm75); /*-----------------------------------------------------------------------*/ @@ -184,6 +182,7 @@ static const struct attribute_group lm75_group = { static int lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct lm75_data *data; int status; u8 set_mask, clr_mask; @@ -194,10 +193,11 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return -EIO; - data = devm_kzalloc(&client->dev, sizeof(struct lm75_data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); if (!data) return -ENOMEM; + data->client = client; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); @@ -269,7 +269,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) /* configure as specified */ status = lm75_read_value(client, LM75_REG_CONF); if (status < 0) { - dev_dbg(&client->dev, "Can't read config? %d\n", status); + dev_dbg(dev, "Can't read config? %d\n", status); return status; } data->orig_conf = status; @@ -277,43 +277,32 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) new |= set_mask; if (status != new) lm75_write_value(client, LM75_REG_CONF, new); - dev_dbg(&client->dev, "Config %02x\n", new); + dev_dbg(dev, "Config %02x\n", new); - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &lm75_group); - if (status) - return status; + 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->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - status = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - data->tz = thermal_zone_of_sensor_register(&client->dev, + data->tz = thermal_zone_of_sensor_register(data->hwmon_dev, 0, - &client->dev, + data->hwmon_dev, lm75_read_temp, NULL); if (IS_ERR(data->tz)) data->tz = NULL; - dev_info(&client->dev, "%s: sensor '%s'\n", + dev_info(dev, "%s: sensor '%s'\n", dev_name(data->hwmon_dev), client->name); return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &lm75_group); - return status; } static int lm75_remove(struct i2c_client *client) { struct lm75_data *data = i2c_get_clientdata(client); - thermal_zone_of_sensor_unregister(&client->dev, data->tz); + thermal_zone_of_sensor_unregister(data->hwmon_dev, data->tz); hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm75_group); lm75_write_value(client, LM75_REG_CONF, data->orig_conf); return 0; } @@ -507,8 +496,8 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 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); -- cgit v1.2.3-59-g8ed1b From ddfe44bfee176ac05c2b5185d62cc5b258ec6c72 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 12:50:27 -0700 Subject: hwmon: (lm92) Drop unnecessary forward declaration Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm92.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index b9022db6511a..5ca8e147c9f4 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -93,9 +93,6 @@ static inline u8 ALARMS_FROM_REG(s16 reg) return reg & 0x0007; } -/* Driver data (common to all clients) */ -static struct i2c_driver lm92_driver; - /* Client data (each client gets its own) */ struct lm92_data { struct device *hwmon_dev; -- cgit v1.2.3-59-g8ed1b From c6f1e7ab91b9cec14d4d3938cddafe371070e7ec Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 12:51:12 -0700 Subject: hwmon: (lm92) Drop FSF mailing address The FSF mailing address may change, so drop it. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm92.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 5ca8e147c9f4..7193a92dda9c 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -34,10 +34,6 @@ * 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 -- cgit v1.2.3-59-g8ed1b From b8fe58e9532d8cbaa8efcedf95a9c18f726e75ce Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 13:07:08 -0700 Subject: hwmon: (lm92) Drop function macros Function macros obfuscate code and increase code size, so drop them. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm92.c | 167 ++++++++++++++++++++++++++------------------------- 1 file changed, 84 insertions(+), 83 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 7193a92dda9c..42188a0fe6d1 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -89,6 +89,23 @@ static inline u8 ALARMS_FROM_REG(s16 reg) return reg & 0x0007; } +enum temp_index { + t_input, + t_crit, + t_min, + t_max, + t_hyst, + t_num_regs +}; + +static const u8 regs[t_num_regs] = { + [t_input] = LM92_REG_TEMP, + [t_crit] = LM92_REG_TEMP_CRIT, + [t_min] = LM92_REG_TEMP_LOW, + [t_max] = LM92_REG_TEMP_HIGH, + [t_hyst] = LM92_REG_TEMP_HYST, +}; + /* Client data (each client gets its own) */ struct lm92_data { struct device *hwmon_dev; @@ -97,10 +114,9 @@ struct lm92_data { unsigned long last_updated; /* in jiffies */ /* registers values */ - s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst; + s16 temp[t_num_regs]; /* index with enum temp_index */ }; - /* * Sysfs attributes and callback functions */ @@ -109,23 +125,17 @@ static struct lm92_data *lm92_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct lm92_data *data = i2c_get_clientdata(client); + int i; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { dev_dbg(&client->dev, "Updating lm92 data\n"); - data->temp1_input = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP); - data->temp1_hyst = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_HYST); - data->temp1_crit = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_CRIT); - data->temp1_min = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_LOW); - data->temp1_max = i2c_smbus_read_word_swapped(client, - LM92_REG_TEMP_HIGH); - + for (i = 0; i < t_num_regs; i++) { + data->temp[i] = + i2c_smbus_read_word_swapped(client, regs[i]); + } data->last_updated = jiffies; data->valid = 1; } @@ -135,66 +145,58 @@ static struct lm92_data *lm92_update_device(struct device *dev) return data; } -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct lm92_data *data = lm92_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show_temp(temp1_input); -show_temp(temp1_crit); -show_temp(temp1_min); -show_temp(temp1_max); - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ - const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm92_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err) \ - return err; \ -\ - mutex_lock(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_word_swapped(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm92_data *data = lm92_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -set_temp(temp1_crit, LM92_REG_TEMP_CRIT); -set_temp(temp1_min, LM92_REG_TEMP_LOW); -set_temp(temp1_max, LM92_REG_TEMP_HIGH); -static ssize_t show_temp1_crit_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) - - TEMP_FROM_REG(data->temp1_hyst)); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm92_data *data = i2c_get_clientdata(client); + int nr = attr->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + i2c_smbus_write_word_swapped(client, regs[nr], data->temp[nr]); + mutex_unlock(&data->update_lock); + return count; } -static ssize_t show_temp1_max_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +static ssize_t show_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) - - TEMP_FROM_REG(data->temp1_hyst)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]) + - TEMP_FROM_REG(data->temp[t_hyst])); } -static ssize_t show_temp1_min_hyst(struct device *dev, - struct device_attribute *attr, char *buf) + +static ssize_t show_temp_min_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) - + TEMP_FROM_REG(data->temp1_hyst)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min]) + + TEMP_FROM_REG(data->temp[t_hyst])); } -static ssize_t set_temp1_crit_hyst(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_temp_hyst(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct lm92_data *data = i2c_get_clientdata(client); long val; @@ -205,9 +207,9 @@ static ssize_t set_temp1_crit_hyst(struct device *dev, return err; mutex_lock(&data->update_lock); - data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; + data->temp[t_hyst] = TEMP_FROM_REG(data->temp[attr->index]) - val; i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST, - TEMP_TO_REG(data->temp1_hyst)); + TEMP_TO_REG(data->temp[t_hyst])); mutex_unlock(&data->update_lock); return count; } @@ -216,7 +218,7 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input])); } static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, @@ -224,26 +226,25 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, { int bitnr = to_sensor_dev_attr(attr)->index; struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", (data->temp1_input >> bitnr) & 1); + return sprintf(buf, "%d\n", (data->temp[t_input] >> bitnr) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit, - set_temp1_crit); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst, - set_temp1_crit_hyst); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min, - set_temp1_min); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max, - set_temp1_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_crit); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, + set_temp_hyst, t_crit); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_min); +static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_min_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_max); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); - /* * Detection and registration */ @@ -316,13 +317,13 @@ static int max6635_check(struct i2c_client *client) } static struct attribute *lm92_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_crit_hyst.attr, - &dev_attr_temp1_min.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, &dev_attr_temp1_min_hyst.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &dev_attr_alarms.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, -- cgit v1.2.3-59-g8ed1b From 030004b1edf1d3b7e7a0957b4cb11b28372b8d70 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 13:17:16 -0700 Subject: hwmon: (lm92) Convert to use devm_hwmon_device_register_with_groups Use devm_hwmon_device_register_with_groups API to attach attributes to hwmon device, simplify code, and reduce code size. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm92.c | 56 ++++++++++++++-------------------------------------- 1 file changed, 15 insertions(+), 41 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 42188a0fe6d1..d2060e245ff5 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -108,7 +108,7 @@ static const u8 regs[t_num_regs] = { /* Client data (each client gets its own) */ struct lm92_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -123,8 +123,8 @@ struct lm92_data { static struct lm92_data *lm92_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); + struct lm92_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int i; mutex_lock(&data->update_lock); @@ -158,8 +158,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); + struct lm92_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = attr->index; long val; int err; @@ -197,8 +197,8 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); + struct lm92_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; int err; @@ -316,7 +316,7 @@ static int max6635_check(struct i2c_client *client) return 1; } -static struct attribute *lm92_attributes[] = { +static struct attribute *lm92_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, @@ -330,10 +330,7 @@ static struct attribute *lm92_attributes[] = { &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group lm92_group = { - .attrs = lm92_attributes, -}; +ATTRIBUTE_GROUPS(lm92); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm92_detect(struct i2c_client *new_client, @@ -365,46 +362,24 @@ static int lm92_detect(struct i2c_client *new_client, static int lm92_probe(struct i2c_client *new_client, const struct i2c_device_id *id) { + struct device *hwmon_dev; struct lm92_data *data; - int err; data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); + data->client = new_client; mutex_init(&data->update_lock); /* Initialize the chipset */ lm92_init_client(new_client); - /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &lm92_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &lm92_group); - return err; -} - -static int lm92_remove(struct i2c_client *client) -{ - struct lm92_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm92_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, + new_client->name, + data, lm92_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } @@ -425,7 +400,6 @@ static struct i2c_driver lm92_driver = { .name = "lm92", }, .probe = lm92_probe, - .remove = lm92_remove, .id_table = lm92_id, .detect = lm92_detect, .address_list = normal_i2c, -- cgit v1.2.3-59-g8ed1b From b83207fddae08497771f6978c58ead0d0680fcd8 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:06:59 +0900 Subject: hwmon: (f71805f) remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/f71805f.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 32f5132c4652..9e57b77ecd34 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -1387,10 +1387,8 @@ static int f71805f_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(struct f71805f_data), GFP_KERNEL); - if (!data) { - pr_err("Out of memory\n"); + if (!data) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start + ADDR_REG_OFFSET, 2, -- cgit v1.2.3-59-g8ed1b From 6d33d304e24ba42886583ed5228083162554305f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:07:58 +0900 Subject: hwmon: (ibmpex) remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Jean Delvare Acked-by: Darrick J. Wong Signed-off-by: Guenter Roeck --- drivers/hwmon/ibmpex.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 20ab0fb85395..030e7ff589be 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -463,10 +463,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev) int err; data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(dev, "Insufficient memory for BMC interface.\n"); + if (!data) return; - } data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; data->address.channel = IPMI_BMC_CHANNEL; -- cgit v1.2.3-59-g8ed1b From 567817de8574dba2e78b4fe849c1261c70a10245 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:09:19 +0900 Subject: hwmon: (lm93) remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/lm93.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index adf23165a6a7..6c2df576f253 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -2747,10 +2747,8 @@ static int lm93_probe(struct i2c_client *client, } data = devm_kzalloc(&client->dev, sizeof(struct lm93_data), GFP_KERNEL); - if (!data) { - dev_dbg(&client->dev, "out of memory!\n"); + if (!data) return -ENOMEM; - } i2c_set_clientdata(client, data); /* housekeeping */ -- cgit v1.2.3-59-g8ed1b From 611cd8aec8d0514edfffde457f3e2ca625b242c7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:10:17 +0900 Subject: hwmon: (max1111) remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/max1111.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index eda077de8a9f..f67d71ee8386 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -192,10 +192,8 @@ static int max1111_probe(struct spi_device *spi) return err; data = devm_kzalloc(&spi->dev, sizeof(struct max1111_data), GFP_KERNEL); - if (data == NULL) { - dev_err(&spi->dev, "failed to allocate memory\n"); + if (data == NULL) return -ENOMEM; - } switch (chip) { case max1110: -- cgit v1.2.3-59-g8ed1b From 6122de8f8c6acbe16c2acd31e3334e87e82ae7ac Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:11:07 +0900 Subject: hwmon: (max197) remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/max197.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index 96dccaf919d1..82128ad79a91 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -275,10 +275,8 @@ static int max197_probe(struct platform_device *pdev) } data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "devm_kzalloc failed\n"); + if (!data) return -ENOMEM; - } data->pdata = pdata; mutex_init(&data->lock); -- cgit v1.2.3-59-g8ed1b From 2f89b072c9f845e8be746dcd9b14b7043c4f9a65 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:11:55 +0900 Subject: hwmon: (pc87427) remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/pc87427.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index d847e0a084e0..9e4684e747ea 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -1081,10 +1081,8 @@ static int pc87427_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(struct pc87427_data), GFP_KERNEL); - if (!data) { - pr_err("Out of memory\n"); + if (!data) return -ENOMEM; - } data->address[0] = sio_data->address[0]; data->address[1] = sio_data->address[1]; -- cgit v1.2.3-59-g8ed1b From eefb6b76b19bdf78a39062fae8cc22b8319b02b5 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:12:25 +0900 Subject: hwmon: (s3c-hwmon) remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/s3c-hwmon.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index 73bd64e8c30a..0674c13bbd4b 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -285,10 +285,8 @@ static int s3c_hwmon_probe(struct platform_device *dev) } hwmon = devm_kzalloc(&dev->dev, sizeof(struct s3c_hwmon), GFP_KERNEL); - if (hwmon == NULL) { - dev_err(&dev->dev, "no memory\n"); + if (hwmon == NULL) return -ENOMEM; - } platform_set_drvdata(dev, hwmon); -- cgit v1.2.3-59-g8ed1b From 5b20995ee7c5fc4fda8215301f86c7fa3faece27 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:13:50 +0900 Subject: hwmon: (vt1211) remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/vt1211.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 6b2f1a42b3ff..344b22ec2553 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -1152,10 +1152,8 @@ static int vt1211_probe(struct platform_device *pdev) int i, err; data = devm_kzalloc(dev, sizeof(struct vt1211_data), GFP_KERNEL); - if (!data) { - dev_err(dev, "Out of memory\n"); + if (!data) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(dev, res->start, resource_size(res), -- cgit v1.2.3-59-g8ed1b From 86b89d73f9f3648c9f3b375d7841bef18a27fd2a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 6 May 2014 16:51:36 -0700 Subject: hwmon: (ltc2945) Fix 1st comment line Somehow a couple of spaces got added to the first line. Remove them. No code change. Signed-off-by: Guenter Roeck --- drivers/hwmon/ltc2945.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index c9cddf5f056b..3701b329b6ae 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -1,4 +1,4 @@ - /* +/* * Driver for Linear Technology LTC2945 I2C Power Monitor * * Copyright (c) 2014 Guenter Roeck -- cgit v1.2.3-59-g8ed1b From adaa50b0dd8af52efae5da8c9d7860db8088ff08 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 17:25:14 +0900 Subject: hwmon: (g762) Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Guenter Roeck --- drivers/hwmon/g762.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index b4b8b5bef718..98a8618d8fbf 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -586,7 +586,7 @@ static int do_set_fan_startv(struct device *dev, unsigned long val) */ #ifdef CONFIG_OF -static struct of_device_id g762_dt_match[] = { +static const struct of_device_id g762_dt_match[] = { { .compatible = "gmt,g762" }, { .compatible = "gmt,g763" }, { }, -- cgit v1.2.3-59-g8ed1b From 6de709c5ee0d7e15afca5991af87e7462b65c527 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 17:27:54 +0900 Subject: hwmon: (gpio-fan) Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Guenter Roeck --- drivers/hwmon/gpio-fan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 73181be5b30b..ba35e4d530b5 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -482,7 +482,7 @@ static int gpio_fan_get_of_pdata(struct device *dev, return 0; } -static struct of_device_id of_gpio_fan_match[] = { +static const struct of_device_id of_gpio_fan_match[] = { { .compatible = "gpio-fan", }, {}, }; -- cgit v1.2.3-59-g8ed1b From cfe03d641ec294bfcbba23d32accfdf0db51aa8c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 17:29:02 +0900 Subject: hwmon: (iio_hwmon) Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Guenter Roeck --- drivers/hwmon/iio_hwmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 9fbb1b1fdff3..14c82daab019 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -163,7 +163,7 @@ static int iio_hwmon_remove(struct platform_device *pdev) return 0; } -static struct of_device_id iio_hwmon_of_match[] = { +static const struct of_device_id iio_hwmon_of_match[] = { { .compatible = "iio-hwmon", }, { } }; -- cgit v1.2.3-59-g8ed1b From 962a75a2d5c15ac98cc58139c0067708190c4d15 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Fri, 9 May 2014 14:04:01 +0200 Subject: hwmon: (adm1029) Update Corentin Labbe's email Signed-off-by: LABBE Corentin Signed-off-by: Guenter Roeck --- drivers/hwmon/adm1029.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index d19c790e410a..78339e880bd6 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -1,7 +1,7 @@ /* * adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring * - * Copyright (C) 2006 Corentin LABBE + * Copyright (C) 2006 Corentin LABBE * * Based on LM83 Driver by Jean Delvare * @@ -449,6 +449,6 @@ static struct adm1029_data *adm1029_update_device(struct device *dev) module_i2c_driver(adm1029_driver); -MODULE_AUTHOR("Corentin LABBE "); +MODULE_AUTHOR("Corentin LABBE "); MODULE_DESCRIPTION("adm1029 driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From be7f5c4d48e05cb6753d17eb09bea3c38db2ec6f Mon Sep 17 00:00:00 2001 From: Josef Gajdusek Date: Mon, 12 May 2014 14:34:09 +0200 Subject: hwmon: (emc1403) Add support for emc14x2 Add support for emc1402/emc1412/emc1422 temperature monitoring chips. This line of sensors only has 2 temperature channels (internal and external) in comparison to the emc14x3 (3 channels) and emc14x4 (4 channels). Signed-off-by: Josef Gajdusek [Guenter Roeck: ordered i2c address list, updated description/headline] Signed-off-by: Guenter Roeck --- drivers/hwmon/emc1403.c | 58 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 15 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 01723f04fe45..0bb0bab60163 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -38,9 +38,11 @@ #define THERMAL_SMSC_ID_REG 0xfe #define THERMAL_REVISION_REG 0xff +enum emc1403_chip { emc1402, emc1403, emc1404 }; + struct thermal_data { struct i2c_client *client; - const struct attribute_group *groups[3]; + const struct attribute_group *groups[4]; struct mutex mutex; /* * Cache the hyst value so we don't keep re-reading it. In theory @@ -252,23 +254,36 @@ static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR, show_bit, store_bit, 0x03, 0x40); -static struct attribute *emc1403_attrs[] = { +static struct attribute *emc1402_attrs[] = { &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + + &sensor_dev_attr_power_state.dev_attr.attr, + NULL +}; + +static const struct attribute_group emc1402_group = { + .attrs = emc1402_attrs, +}; + +static struct attribute *emc1403_attrs[] = { + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, - &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_crit.dev_attr.attr, @@ -277,7 +292,6 @@ static struct attribute *emc1403_attrs[] = { &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, - &sensor_dev_attr_power_state.dev_attr.attr, NULL }; @@ -313,9 +327,15 @@ static int emc1403_detect(struct i2c_client *client, id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG); switch (id) { + case 0x20: + strlcpy(info->type, "emc1402", I2C_NAME_SIZE); + break; case 0x21: strlcpy(info->type, "emc1403", I2C_NAME_SIZE); break; + case 0x22: + strlcpy(info->type, "emc1422", I2C_NAME_SIZE); + break; case 0x23: strlcpy(info->type, "emc1423", I2C_NAME_SIZE); break; @@ -351,9 +371,14 @@ static int emc1403_probe(struct i2c_client *client, mutex_init(&data->mutex); data->hyst_valid = jiffies - 1; /* Expired */ - data->groups[0] = &emc1403_group; - if (id->driver_data) - data->groups[1] = &emc1404_group; + switch (id->driver_data) { + case emc1404: + data->groups[2] = &emc1404_group; + case emc1403: + data->groups[1] = &emc1403_group; + case emc1402: + data->groups[0] = &emc1402_group; + } hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, client->name, data, @@ -366,14 +391,17 @@ static int emc1403_probe(struct i2c_client *client, } static const unsigned short emc1403_address_list[] = { - 0x18, 0x29, 0x4c, 0x4d, I2C_CLIENT_END + 0x18, 0x1c, 0x29, 0x4c, 0x4d, 0x5c, I2C_CLIENT_END }; +/* Last digit of chip name indicates number of channels */ static const struct i2c_device_id emc1403_idtable[] = { - { "emc1403", 0 }, - { "emc1404", 1 }, - { "emc1423", 0 }, - { "emc1424", 1 }, + { "emc1402", emc1402 }, + { "emc1403", emc1403 }, + { "emc1404", emc1404 }, + { "emc1422", emc1402 }, + { "emc1423", emc1403 }, + { "emc1424", emc1404 }, { } }; MODULE_DEVICE_TABLE(i2c, emc1403_idtable); -- cgit v1.2.3-59-g8ed1b From 4cab259f866ed33571c5f9e3f4bc2799ab64ba45 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 May 2014 10:44:48 -0700 Subject: hwmon: (emc1403) Convert to use regmap Convert to regmap to be able to use its register caching mechanism. Signed-off-by: Guenter Roeck --- drivers/hwmon/emc1403.c | 117 ++++++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 54 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 0bb0bab60163..3c9a8a94753f 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -18,9 +18,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * TODO - * - cache alarm and critical limit registers */ #include @@ -32,7 +29,7 @@ #include #include #include -#include +#include #define THERMAL_PID_REG 0xfd #define THERMAL_SMSC_ID_REG 0xfe @@ -41,15 +38,9 @@ enum emc1403_chip { emc1402, emc1403, emc1404 }; struct thermal_data { - struct i2c_client *client; - const struct attribute_group *groups[4]; + struct regmap *regmap; struct mutex mutex; - /* - * Cache the hyst value so we don't keep re-reading it. In theory - * we could cache it forever as nobody else should be writing it. - */ - u8 cached_hyst; - unsigned long hyst_valid; + const struct attribute_group *groups[4]; }; static ssize_t show_temp(struct device *dev, @@ -57,12 +48,13 @@ static ssize_t show_temp(struct device *dev, { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); struct thermal_data *data = dev_get_drvdata(dev); + unsigned int val; int retval; - retval = i2c_smbus_read_byte_data(data->client, sda->index); + retval = regmap_read(data->regmap, sda->index, &val); if (retval < 0) return retval; - return sprintf(buf, "%d000\n", retval); + return sprintf(buf, "%d000\n", val); } static ssize_t show_bit(struct device *dev, @@ -70,12 +62,13 @@ static ssize_t show_bit(struct device *dev, { struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); struct thermal_data *data = dev_get_drvdata(dev); + unsigned int val; int retval; - retval = i2c_smbus_read_byte_data(data->client, sda->nr); + retval = regmap_read(data->regmap, sda->nr, &val); if (retval < 0) return retval; - return sprintf(buf, "%d\n", !!(retval & sda->index)); + return sprintf(buf, "%d\n", !!(val & sda->index)); } static ssize_t store_temp(struct device *dev, @@ -88,8 +81,8 @@ static ssize_t store_temp(struct device *dev, if (kstrtoul(buf, 10, &val)) return -EINVAL; - retval = i2c_smbus_write_byte_data(data->client, sda->index, - DIV_ROUND_CLOSEST(val, 1000)); + retval = regmap_write(data->regmap, sda->index, + DIV_ROUND_CLOSEST(val, 1000)); if (retval < 0) return retval; return count; @@ -100,28 +93,17 @@ static ssize_t store_bit(struct device *dev, { struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); struct thermal_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; unsigned long val; int retval; if (kstrtoul(buf, 10, &val)) return -EINVAL; - mutex_lock(&data->mutex); - retval = i2c_smbus_read_byte_data(client, sda->nr); + retval = regmap_update_bits(data->regmap, sda->nr, sda->index, + val ? sda->index : 0); if (retval < 0) - goto fail; - - retval &= ~sda->index; - if (val) - retval |= sda->index; - - retval = i2c_smbus_write_byte_data(client, sda->index, retval); - if (retval == 0) - retval = count; -fail: - mutex_unlock(&data->mutex); - return retval; + return retval; + return count; } static ssize_t show_hyst(struct device *dev, @@ -129,22 +111,20 @@ static ssize_t show_hyst(struct device *dev, { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); struct thermal_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; + struct regmap *regmap = data->regmap; + unsigned int limit; + unsigned int hyst; int retval; - int hyst; - retval = i2c_smbus_read_byte_data(client, sda->index); + retval = regmap_read(regmap, sda->index, &limit); if (retval < 0) return retval; - if (time_after(jiffies, data->hyst_valid)) { - hyst = i2c_smbus_read_byte_data(client, 0x21); - if (hyst < 0) - return retval; - data->cached_hyst = hyst; - data->hyst_valid = jiffies + HZ; - } - return sprintf(buf, "%d000\n", retval - data->cached_hyst); + retval = regmap_read(regmap, 0x21, &hyst); + if (retval < 0) + return retval; + + return sprintf(buf, "%d000\n", limit - hyst); } static ssize_t store_hyst(struct device *dev, @@ -152,7 +132,8 @@ static ssize_t store_hyst(struct device *dev, { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); struct thermal_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; + struct regmap *regmap = data->regmap; + unsigned int limit; int retval; int hyst; unsigned long val; @@ -161,23 +142,20 @@ static ssize_t store_hyst(struct device *dev, return -EINVAL; mutex_lock(&data->mutex); - retval = i2c_smbus_read_byte_data(client, sda->index); + retval = regmap_read(regmap, sda->index, &limit); if (retval < 0) goto fail; - hyst = retval * 1000 - val; + hyst = limit * 1000 - val; hyst = DIV_ROUND_CLOSEST(hyst, 1000); if (hyst < 0 || hyst > 255) { retval = -ERANGE; goto fail; } - retval = i2c_smbus_write_byte_data(client, 0x21, hyst); - if (retval == 0) { + retval = regmap_write(regmap, 0x21, hyst); + if (retval == 0) retval = count; - data->cached_hyst = hyst; - data->hyst_valid = jiffies + HZ; - } fail: mutex_unlock(&data->mutex); return retval; @@ -356,6 +334,35 @@ static int emc1403_detect(struct i2c_client *client, return 0; } +static bool emc1403_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00: /* internal diode high byte */ + case 0x01: /* external diode 1 high byte */ + case 0x02: /* status */ + case 0x10: /* external diode 1 low byte */ + case 0x1b: /* external diode fault */ + case 0x23: /* external diode 2 high byte */ + case 0x24: /* external diode 2 low byte */ + case 0x29: /* internal diode low byte */ + case 0x2a: /* externl diode 3 high byte */ + case 0x2b: /* external diode 3 low byte */ + case 0x35: /* high limit status */ + case 0x36: /* low limit status */ + case 0x37: /* therm limit status */ + return true; + default: + return false; + } +} + +static struct regmap_config emc1403_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = emc1403_regmap_is_volatile, +}; + static int emc1403_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -367,9 +374,11 @@ static int emc1403_probe(struct i2c_client *client, if (data == NULL) return -ENOMEM; - data->client = client; + data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + mutex_init(&data->mutex); - data->hyst_valid = jiffies - 1; /* Expired */ switch (id->driver_data) { case emc1404: -- cgit v1.2.3-59-g8ed1b From d8850c19b589bd364d3c7cd1273193e6dfe83fd9 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 May 2014 10:48:02 -0700 Subject: hwmon: (emc1403) Report external diode fault status Signed-off-by: Guenter Roeck --- drivers/hwmon/emc1403.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 3c9a8a94753f..9acd5bfcfa01 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -188,6 +188,7 @@ static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x19); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0x01); +static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_bit, NULL, 0x36, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, @@ -204,6 +205,7 @@ static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x1A); static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 0x23); +static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_bit, NULL, 0x36, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, @@ -220,6 +222,7 @@ static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x30); static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 0x2A); +static SENSOR_DEVICE_ATTR_2(temp4_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x08); static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO, show_bit, NULL, 0x36, 0x08); static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, @@ -258,6 +261,7 @@ static struct attribute *emc1403_attrs[] = { &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, @@ -266,6 +270,7 @@ static struct attribute *emc1403_attrs[] = { &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_crit.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, @@ -282,6 +287,7 @@ static struct attribute *emc1404_attrs[] = { &sensor_dev_attr_temp4_max.dev_attr.attr, &sensor_dev_attr_temp4_crit.dev_attr.attr, &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_fault.dev_attr.attr, &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, -- cgit v1.2.3-59-g8ed1b From 03f49f641ab70b2ceea674e666f5b933e3bc5d27 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 May 2014 11:03:47 -0700 Subject: hwmon: (emc1403) Add support for alarm and diode fault status on EMC14x2 Alarm and fault status register on EMC1402, EMC1412, and EMC1422 is reported in a different register than with other chips. Add support for it. Signed-off-by: Guenter Roeck --- drivers/hwmon/emc1403.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 9acd5bfcfa01..f76e5503b89a 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -299,6 +299,39 @@ static const struct attribute_group emc1404_group = { .attrs = emc1404_attrs, }; +/* + * EMC14x2 uses a different register and different bits to report alarm and + * fault status. For simplicity, provide a separate attribute group for this + * chip series. + * Since we can not re-use the same attribute names, create a separate attribute + * array. + */ +static struct sensor_device_attribute_2 emc1402_alarms[] = { + SENSOR_ATTR_2(temp1_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x20), + SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x40), + SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x01), + + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x02, 0x04), + SENSOR_ATTR_2(temp2_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x08), + SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x10), + SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x02), +}; + +static struct attribute *emc1402_alarm_attrs[] = { + &emc1402_alarms[0].dev_attr.attr, + &emc1402_alarms[1].dev_attr.attr, + &emc1402_alarms[2].dev_attr.attr, + &emc1402_alarms[3].dev_attr.attr, + &emc1402_alarms[4].dev_attr.attr, + &emc1402_alarms[5].dev_attr.attr, + &emc1402_alarms[6].dev_attr.attr, + NULL, +}; + +static const struct attribute_group emc1402_alarm_group = { + .attrs = emc1402_alarm_attrs, +}; + static int emc1403_detect(struct i2c_client *client, struct i2c_board_info *info) { @@ -395,6 +428,9 @@ static int emc1403_probe(struct i2c_client *client, data->groups[0] = &emc1402_group; } + if (id->driver_data == emc1402) + data->groups[1] = &emc1402_alarm_group; + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, client->name, data, data->groups); -- cgit v1.2.3-59-g8ed1b From 84899d394e755989a1cc080083080f7695c36467 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 May 2014 11:10:56 -0700 Subject: hwmon: (emc1403) Make all hyst attributes except for temp1_crit_hyst read-only All chips in this chip series only support a single hysteresis value. Having multiple writable hysteresis attributes is therefore confusing, since a single write affects all hysteresis temperatures. Make all but one (temp1_crit_hyst) read-only. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/emc1403 | 7 +++++-- drivers/hwmon/emc1403.c | 9 +++------ 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/hwmon') diff --git a/Documentation/hwmon/emc1403 b/Documentation/hwmon/emc1403 index b109e35e2385..a869b0ef6a9d 100644 --- a/Documentation/hwmon/emc1403 +++ b/Documentation/hwmon/emc1403 @@ -51,6 +51,9 @@ This implementation detail implies the following: was 80 degrees C, and the hysteresis was 75 degrees C, and you change the critical limit to 90 degrees C, then the hysteresis will automatically change to 85 degrees C. -* While hysteresis limits can be set for all critical limits, setting a single - hysteresis value affects the hysteresis values for all limits on all sensors. +* The hysteresis values can't be set independently. We decided to make + only temp1_crit_hyst writable, while all other hysteresis attributes + are read-only. Setting temp1_crit_hyst writes the difference between + temp1_crit_hyst and temp1_crit into the chip, and the same relative + hysteresis applies automatically to all other limits. * The limits should be set before the hysteresis. diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index f76e5503b89a..46220b131153 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -195,8 +195,7 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x02); -static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO | S_IWUSR, - show_hyst, store_hyst, 0x19); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_hyst, NULL, 0x19); static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x16); @@ -212,8 +211,7 @@ static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x04); -static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO | S_IWUSR, - show_hyst, store_hyst, 0x1A); +static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_hyst, NULL, 0x1A); static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x2D); @@ -229,8 +227,7 @@ static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x08); static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x08); -static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO | S_IWUSR, - show_hyst, store_hyst, 0x30); +static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO, show_hyst, NULL, 0x30); static SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR, show_bit, store_bit, 0x03, 0x40); -- cgit v1.2.3-59-g8ed1b From ceeaa70c0fa7fbf30a0c7a2b07dc895de22583c9 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 May 2014 11:20:24 -0700 Subject: hwmon: (emc1403) Relax hysteresis limit write checks Writing the hysteresis limit returned -ERANGE if the written hysteresis was too high or too low. Relax error check and adjust the hysteresis value to its valid range. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/emc1403.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 46220b131153..c62bc044a660 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -147,12 +147,7 @@ static ssize_t store_hyst(struct device *dev, goto fail; hyst = limit * 1000 - val; - hyst = DIV_ROUND_CLOSEST(hyst, 1000); - if (hyst < 0 || hyst > 255) { - retval = -ERANGE; - goto fail; - } - + hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255); retval = regmap_write(regmap, 0x21, hyst); if (retval == 0) retval = count; -- cgit v1.2.3-59-g8ed1b From a9a74006867e23ad310c6a0dd5cb8fdec5ae3520 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 May 2014 11:25:47 -0700 Subject: hwmon: (emc1403) Add support for max_hyst attributes The hysteresis value applies to all limits, so add support for tempX_max_hyst. Signed-off-by: Guenter Roeck --- drivers/hwmon/emc1403.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index c62bc044a660..9ee057776f96 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -173,6 +173,7 @@ static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x01); static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x01); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_hyst, NULL, 0x05); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_hyst, store_hyst, 0x20); @@ -190,6 +191,7 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x02); +static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_hyst, NULL, 0x07); static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_hyst, NULL, 0x19); static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR, @@ -206,6 +208,7 @@ static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x04); +static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_hyst, NULL, 0x15); static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_hyst, NULL, 0x1A); static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO | S_IWUSR, @@ -222,6 +225,7 @@ static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x08); static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x08); +static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_hyst, NULL, 0x2C); static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO, show_hyst, NULL, 0x30); static SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR, @@ -232,12 +236,14 @@ static struct attribute *emc1402_attrs[] = { &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, &sensor_dev_attr_power_state.dev_attr.attr, @@ -266,6 +272,7 @@ static struct attribute *emc1403_attrs[] = { &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, NULL }; @@ -283,6 +290,7 @@ static struct attribute *emc1404_attrs[] = { &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, &sensor_dev_attr_temp4_crit_hyst.dev_attr.attr, NULL }; -- cgit v1.2.3-59-g8ed1b From 54392ce4446e31b4f8a98961ef30bf6397c15266 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 May 2014 11:35:06 -0700 Subject: hwmon: (emc1403) Add support for min_hyst attributes The hysteresis value applies to all limits, so add support for tempX_min_hyst. Signed-off-by: Guenter Roeck --- drivers/hwmon/emc1403.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 9ee057776f96..bc96eefe2894 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -106,8 +106,9 @@ static ssize_t store_bit(struct device *dev, return count; } -static ssize_t show_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_hyst_common(struct device *dev, + struct device_attribute *attr, char *buf, + bool is_min) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); struct thermal_data *data = dev_get_drvdata(dev); @@ -124,7 +125,19 @@ static ssize_t show_hyst(struct device *dev, if (retval < 0) return retval; - return sprintf(buf, "%d000\n", limit - hyst); + return sprintf(buf, "%d000\n", is_min ? limit + hyst : limit - hyst); +} + +static ssize_t show_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return show_hyst_common(dev, attr, buf, false); +} + +static ssize_t show_min_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return show_hyst_common(dev, attr, buf, true); } static ssize_t store_hyst(struct device *dev, @@ -173,6 +186,7 @@ static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x01); static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x01); +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x06); static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_hyst, NULL, 0x05); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_hyst, store_hyst, 0x20); @@ -191,6 +205,7 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x02); +static SENSOR_DEVICE_ATTR(temp2_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x08); static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_hyst, NULL, 0x07); static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_hyst, NULL, 0x19); @@ -208,6 +223,7 @@ static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x04); +static SENSOR_DEVICE_ATTR(temp3_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x16); static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_hyst, NULL, 0x15); static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_hyst, NULL, 0x1A); @@ -225,6 +241,7 @@ static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x08); static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x08); +static SENSOR_DEVICE_ATTR(temp4_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x2D); static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_hyst, NULL, 0x2C); static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO, show_hyst, NULL, 0x30); @@ -236,6 +253,7 @@ static struct attribute *emc1402_attrs[] = { &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, @@ -243,6 +261,7 @@ static struct attribute *emc1402_attrs[] = { &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min_hyst.dev_attr.attr, &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, @@ -272,6 +291,7 @@ static struct attribute *emc1403_attrs[] = { &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_min_hyst.dev_attr.attr, &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, NULL @@ -290,6 +310,7 @@ static struct attribute *emc1404_attrs[] = { &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_min_hyst.dev_attr.attr, &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, &sensor_dev_attr_temp4_crit_hyst.dev_attr.attr, NULL -- cgit v1.2.3-59-g8ed1b From 51585befb4c3c629980b5b252a0caaeeac3b7d73 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 May 2014 11:46:12 -0700 Subject: hwmon: (emc1403) Add device IDs for EMC1412, EMC1413, and EMC1414 EMC1412, EMC1413, and EMC1414 are fully compatible to EMC1402, EMC1403, and EMC1404, and even report the same chip ID. Add to device ID table to enable instantiation with correct chip names. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/emc1403.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index bc96eefe2894..a37b2204a418 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -471,6 +471,9 @@ static const struct i2c_device_id emc1403_idtable[] = { { "emc1402", emc1402 }, { "emc1403", emc1403 }, { "emc1404", emc1404 }, + { "emc1412", emc1402 }, + { "emc1413", emc1403 }, + { "emc1414", emc1404 }, { "emc1422", emc1402 }, { "emc1423", emc1403 }, { "emc1424", emc1404 }, -- cgit v1.2.3-59-g8ed1b From d397276b0c833b0089cb19d94fbc35a43ada58a7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 15 Apr 2014 21:28:15 -0700 Subject: hwmon: (jc42) Rearrange code to avoid forward declarations Signed-off-by: Guenter Roeck --- drivers/hwmon/jc42.c | 186 ++++++++++++++++++++++++--------------------------- 1 file changed, 89 insertions(+), 97 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 6013611e4f21..ba1a3f781fde 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -176,65 +176,6 @@ struct jc42_data { u16 temp_max; }; -static int jc42_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info); -static int jc42_remove(struct i2c_client *client); - -static struct jc42_data *jc42_update_device(struct device *dev); - -static const struct i2c_device_id jc42_id[] = { - { "jc42", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, jc42_id); - -#ifdef CONFIG_PM - -static int jc42_suspend(struct device *dev) -{ - struct jc42_data *data = dev_get_drvdata(dev); - - data->config |= JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, - data->config); - return 0; -} - -static int jc42_resume(struct device *dev) -{ - struct jc42_data *data = dev_get_drvdata(dev); - - data->config &= ~JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, - data->config); - return 0; -} - -static const struct dev_pm_ops jc42_dev_pm_ops = { - .suspend = jc42_suspend, - .resume = jc42_resume, -}; - -#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops) -#else -#define JC42_DEV_PM_OPS NULL -#endif /* CONFIG_PM */ - -/* This is the driver that will be inserted */ -static struct i2c_driver jc42_driver = { - .class = I2C_CLASS_SPD, - .driver = { - .name = "jc42", - .pm = JC42_DEV_PM_OPS, - }, - .probe = jc42_probe, - .remove = jc42_remove, - .id_table = jc42_id, - .detect = jc42_detect, - .address_list = normal_i2c, -}; - #define JC42_TEMP_MIN_EXTENDED (-40000) #define JC42_TEMP_MIN 0 #define JC42_TEMP_MAX 125000 @@ -261,6 +202,53 @@ static int jc42_temp_from_reg(s16 reg) return reg * 125 / 2; } +static struct jc42_data *jc42_update_device(struct device *dev) +{ + struct jc42_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct jc42_data *ret = data; + int val; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->temp_input = val; + + val = i2c_smbus_read_word_swapped(client, + JC42_REG_TEMP_CRITICAL); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->temp_crit = val; + + val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_LOWER); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->temp_min = val; + + val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_UPPER); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->temp_max = val; + + data->last_updated = jiffies; + data->valid = true; + } +abort: + mutex_unlock(&data->update_lock); + return ret; +} + /* sysfs stuff */ /* read routines for temperature limits */ @@ -537,52 +525,56 @@ static int jc42_remove(struct i2c_client *client) return 0; } -static struct jc42_data *jc42_update_device(struct device *dev) +#ifdef CONFIG_PM + +static int jc42_suspend(struct device *dev) { struct jc42_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - struct jc42_data *ret = data; - int val; - mutex_lock(&data->update_lock); + data->config |= JC42_CFG_SHUTDOWN; + i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, + data->config); + return 0; +} - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_input = val; +static int jc42_resume(struct device *dev) +{ + struct jc42_data *data = dev_get_drvdata(dev); - val = i2c_smbus_read_word_swapped(client, - JC42_REG_TEMP_CRITICAL); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_crit = val; + data->config &= ~JC42_CFG_SHUTDOWN; + i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, + data->config); + return 0; +} - val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_LOWER); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_min = val; +static const struct dev_pm_ops jc42_dev_pm_ops = { + .suspend = jc42_suspend, + .resume = jc42_resume, +}; - val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_UPPER); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_max = val; +#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops) +#else +#define JC42_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ - data->last_updated = jiffies; - data->valid = true; - } -abort: - mutex_unlock(&data->update_lock); - return ret; -} +static const struct i2c_device_id jc42_id[] = { + { "jc42", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, jc42_id); + +static struct i2c_driver jc42_driver = { + .class = I2C_CLASS_SPD, + .driver = { + .name = "jc42", + .pm = JC42_DEV_PM_OPS, + }, + .probe = jc42_probe, + .remove = jc42_remove, + .id_table = jc42_id, + .detect = jc42_detect, + .address_list = normal_i2c, +}; module_i2c_driver(jc42_driver); -- cgit v1.2.3-59-g8ed1b From 10192bc654bdfd76ece980f2f6b9056c5919e8a8 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 15 Apr 2014 21:44:20 -0700 Subject: hwmon: (jc42) Convert function macros into functions Convert function macros into functions to make the code easier to read and reduce code size. Signed-off-by: Guenter Roeck --- drivers/hwmon/jc42.c | 182 ++++++++++++++++++++------------------------------- 1 file changed, 72 insertions(+), 110 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index ba1a3f781fde..baa912a3ba75 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -161,6 +161,21 @@ static struct jc42_chips jc42_chips[] = { { STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK }, }; +enum temp_index { + t_input = 0, + t_crit, + t_min, + t_max, + t_num_temp +}; + +static const u8 temp_regs[t_num_temp] = { + [t_input] = JC42_REG_TEMP, + [t_crit] = JC42_REG_TEMP_CRITICAL, + [t_min] = JC42_REG_TEMP_LOWER, + [t_max] = JC42_REG_TEMP_UPPER, +}; + /* Each client has this additional data */ struct jc42_data { struct i2c_client *client; @@ -170,10 +185,7 @@ struct jc42_data { unsigned long last_updated; /* In jiffies */ u16 orig_config; /* original configuration */ u16 config; /* current configuration */ - u16 temp_input; /* Temperatures */ - u16 temp_crit; - u16 temp_min; - u16 temp_max; + u16 temp[t_num_temp];/* Temperatures */ }; #define JC42_TEMP_MIN_EXTENDED (-40000) @@ -207,40 +219,19 @@ static struct jc42_data *jc42_update_device(struct device *dev) struct jc42_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; struct jc42_data *ret = data; - int val; + int i, val; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_input = val; - - val = i2c_smbus_read_word_swapped(client, - JC42_REG_TEMP_CRITICAL); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_crit = val; - - val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_LOWER); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; + for (i = 0; i < t_num_temp; i++) { + val = i2c_smbus_read_word_swapped(client, temp_regs[i]); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->temp[i] = val; } - data->temp_min = val; - - val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_UPPER); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp_max = val; - data->last_updated = jiffies; data->valid = true; } @@ -249,79 +240,55 @@ abort: return ret; } -/* sysfs stuff */ - -/* read routines for temperature limits */ -#define show(value) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct jc42_data *data = jc42_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", jc42_temp_from_reg(data->value)); \ -} +/* sysfs functions */ -show(temp_input); -show(temp_crit); -show(temp_min); -show(temp_max); - -/* read routines for hysteresis values */ -static ssize_t show_temp_crit_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct jc42_data *data = jc42_update_device(dev); - int temp, hyst; - if (IS_ERR(data)) return PTR_ERR(data); - - temp = jc42_temp_from_reg(data->temp_crit); - hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) - >> JC42_CFG_HYST_SHIFT]; - return sprintf(buf, "%d\n", temp - hyst); + return sprintf(buf, "%d\n", + jc42_temp_from_reg(data->temp[attr->index])); } -static ssize_t show_temp_max_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct jc42_data *data = jc42_update_device(dev); int temp, hyst; if (IS_ERR(data)) return PTR_ERR(data); - temp = jc42_temp_from_reg(data->temp_max); + temp = jc42_temp_from_reg(data->temp[attr->index]); hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) >> JC42_CFG_HYST_SHIFT]; return sprintf(buf, "%d\n", temp - hyst); } -/* write routines */ -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct jc42_data *data = dev_get_drvdata(dev); \ - int err, ret = count; \ - long val; \ - if (kstrtol(buf, 10, &val) < 0) \ - return -EINVAL; \ - mutex_lock(&data->update_lock); \ - data->value = jc42_temp_to_reg(val, data->extended); \ - err = i2c_smbus_write_word_swapped(data->client, reg, data->value); \ - if (err < 0) \ - ret = err; \ - mutex_unlock(&data->update_lock); \ - return ret; \ -} +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct jc42_data *data = dev_get_drvdata(dev); + int err, ret = count; + int nr = attr->index; + long val; -set(temp_min, JC42_REG_TEMP_LOWER); -set(temp_max, JC42_REG_TEMP_UPPER); -set(temp_crit, JC42_REG_TEMP_CRITICAL); + if (kstrtol(buf, 10, &val) < 0) + return -EINVAL; + mutex_lock(&data->update_lock); + data->temp[nr] = jc42_temp_to_reg(val, data->extended); + err = i2c_smbus_write_word_swapped(data->client, temp_regs[nr], + data->temp[nr]); + if (err < 0) + ret = err; + mutex_unlock(&data->update_lock); + return ret; +} /* * JC42.4 compliant chips only support four hysteresis values. @@ -340,7 +307,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev, if (kstrtoul(buf, 10, &val) < 0) return -EINVAL; - diff = jc42_temp_from_reg(data->temp_crit) - val; + diff = jc42_temp_from_reg(data->temp[t_crit]) - val; hyst = 0; if (diff > 0) { if (diff < 2250) @@ -372,25 +339,20 @@ static ssize_t show_alarm(struct device *dev, if (IS_ERR(data)) return PTR_ERR(data); - val = data->temp_input; + val = data->temp[t_input]; if (bit != JC42_ALARM_CRIT_BIT && (data->config & JC42_CFG_CRIT_ONLY)) val = 0; return sprintf(buf, "%u\n", (val >> bit) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, - show_temp_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IRUGO, - show_temp_crit, set_temp_crit); -static DEVICE_ATTR(temp1_min, S_IRUGO, - show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IRUGO, - show_temp_max, set_temp_max); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, set_temp, t_crit); +static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, set_temp, t_min); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, set_temp, t_max); -static DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, - show_temp_crit_hyst, set_temp_crit_hyst); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, - show_temp_max_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_hyst, + set_temp_crit_hyst, t_crit); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, JC42_ALARM_CRIT_BIT); @@ -400,12 +362,12 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, JC42_ALARM_MAX_BIT); static struct attribute *jc42_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_crit_hyst.attr, - &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, @@ -420,12 +382,12 @@ static umode_t jc42_attribute_mode(struct kobject *kobj, unsigned int config = data->config; bool readonly; - if (attr == &dev_attr_temp1_crit.attr) + if (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr) readonly = config & JC42_CFG_TCRIT_LOCK; - else if (attr == &dev_attr_temp1_min.attr || - attr == &dev_attr_temp1_max.attr) + else if (attr == &sensor_dev_attr_temp1_min.dev_attr.attr || + attr == &sensor_dev_attr_temp1_max.dev_attr.attr) readonly = config & JC42_CFG_EVENT_LOCK; - else if (attr == &dev_attr_temp1_crit_hyst.attr) + else if (attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr) readonly = config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK); else readonly = true; -- cgit v1.2.3-59-g8ed1b From 175c490c9e7f75dbe6addd937c41939c137c6847 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 15 Apr 2014 22:07:30 -0700 Subject: hwmon: (jc42) Add support for STTS2004 and AT30TSE004 Also fix links to datasheets for other supported sensors from ST Microelectronics, and add links to several Atmel datasheets. Signed-off-by: Guenter Roeck --- Documentation/hwmon/jc42 | 16 ++++++++++------ drivers/hwmon/jc42.c | 9 +++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers/hwmon') diff --git a/Documentation/hwmon/jc42 b/Documentation/hwmon/jc42 index 868d74d6b773..f3893f7440de 100644 --- a/Documentation/hwmon/jc42 +++ b/Documentation/hwmon/jc42 @@ -5,9 +5,12 @@ Supported chips: * Analog Devices ADT7408 Datasheets: http://www.analog.com/static/imported-files/data_sheets/ADT7408.pdf - * Atmel AT30TS00 + * Atmel AT30TS00, AT30TS002A/B, AT30TSE004A Datasheets: http://www.atmel.com/Images/doc8585.pdf + http://www.atmel.com/Images/doc8711.pdf + http://www.atmel.com/Images/Atmel-8852-SEEPROM-AT30TSE002A-Datasheet.pdf + http://www.atmel.com/Images/Atmel-8868-DTS-AT30TSE004A-Datasheet.pdf * IDT TSE2002B3, TSE2002GB2, TS3000B3, TS3000GB2 Datasheets: http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf @@ -34,12 +37,13 @@ Supported chips: Datasheet: http://www.onsemi.com/pub_link/Collateral/CAT34TS02-D.PDF http://www.onsemi.com/pub/Collateral/CAT6095-D.PDF - * ST Microelectronics STTS424, STTS424E02, STTS2002, STTS3000 + * ST Microelectronics STTS424, STTS424E02, STTS2002, STTS2004, STTS3000 Datasheets: - http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157556.pdf - http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157558.pdf - http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00225278.pdf - http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/CD00270920.pdf + http://www.st.com/web/en/resource/technical/document/datasheet/CD00157556.pdf + http://www.st.com/web/en/resource/technical/document/datasheet/CD00157558.pdf + http://www.st.com/web/en/resource/technical/document/datasheet/CD00266638.pdf + http://www.st.com/web/en/resource/technical/document/datasheet/CD00225278.pdf + http://www.st.com/web/en/resource/technical/document/datasheet/DM00076709.pdf * JEDEC JC 42.4 compliant temperature sensor chips Datasheet: http://www.jedec.org/sites/default/files/docs/4_01_04R19.pdf diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index baa912a3ba75..388f8bcd898e 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -65,6 +65,7 @@ static const unsigned short normal_i2c[] = { /* Manufacturer IDs */ #define ADT_MANID 0x11d4 /* Analog Devices */ #define ATMEL_MANID 0x001f /* Atmel */ +#define ATMEL_MANID2 0x1114 /* Atmel */ #define MAX_MANID 0x004d /* Maxim */ #define IDT_MANID 0x00b3 /* IDT */ #define MCP_MANID 0x0054 /* Microchip */ @@ -82,6 +83,9 @@ static const unsigned short normal_i2c[] = { #define AT30TS00_DEVID 0x8201 #define AT30TS00_DEVID_MASK 0xffff +#define AT30TSE004_DEVID 0x2200 +#define AT30TSE004_DEVID_MASK 0xffff + /* IDT */ #define TS3000B3_DEVID 0x2903 /* Also matches TSE2002B3 */ #define TS3000B3_DEVID_MASK 0xffff @@ -130,6 +134,9 @@ static const unsigned short normal_i2c[] = { #define STTS2002_DEVID 0x0300 #define STTS2002_DEVID_MASK 0xffff +#define STTS2004_DEVID 0x2201 +#define STTS2004_DEVID_MASK 0xffff + #define STTS3000_DEVID 0x0200 #define STTS3000_DEVID_MASK 0xffff @@ -144,6 +151,7 @@ struct jc42_chips { static struct jc42_chips jc42_chips[] = { { ADT_MANID, ADT7408_DEVID, ADT7408_DEVID_MASK }, { ATMEL_MANID, AT30TS00_DEVID, AT30TS00_DEVID_MASK }, + { ATMEL_MANID2, AT30TSE004_DEVID, AT30TSE004_DEVID_MASK }, { IDT_MANID, TS3000B3_DEVID, TS3000B3_DEVID_MASK }, { IDT_MANID, TS3000GB2_DEVID, TS3000GB2_DEVID_MASK }, { MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK }, @@ -158,6 +166,7 @@ static struct jc42_chips jc42_chips[] = { { STM_MANID, STTS424_DEVID, STTS424_DEVID_MASK }, { STM_MANID, STTS424E_DEVID, STTS424E_DEVID_MASK }, { STM_MANID, STTS2002_DEVID, STTS2002_DEVID_MASK }, + { STM_MANID, STTS2004_DEVID, STTS2004_DEVID_MASK }, { STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK }, }; -- cgit v1.2.3-59-g8ed1b From 628c6d27c0f41657362262000d01861e8cb36c3a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 19 Apr 2014 09:15:38 -0700 Subject: hwmon: (max1619) Fix critical alarm display The overtemperature status bit, which is used to display critical alarm status, matches the output of the OVERT signal 1:1. If that signal is active-low, the bit will read 1 if there is no alarm. It is therefore necessary to reverse the bit in this case. Signed-off-by: Guenter Roeck --- drivers/hwmon/max1619.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 4c23afe113e2..0927902ceba3 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -325,6 +325,7 @@ static struct max1619_data *max1619_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct max1619_data *data = i2c_get_clientdata(client); + int config; mutex_lock(&data->update_lock); @@ -344,6 +345,10 @@ static struct max1619_data *max1619_update_device(struct device *dev) MAX1619_REG_R_TCRIT_HYST); data->alarms = i2c_smbus_read_byte_data(client, MAX1619_REG_R_STATUS); + /* If OVERT polarity is low, reverse alarm bit */ + config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); + if (!(config & 0x20)) + data->alarms ^= 0x02; data->last_updated = jiffies; data->valid = 1; -- cgit v1.2.3-59-g8ed1b From b09489ecce58d4ac9362124a5a5590cb92c58c49 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 10:10:54 -0700 Subject: hwmon: (max1619) Drop FSF address The FSF address may chance over time, so drop it. Signed-off-by: Guenter Roeck --- drivers/hwmon/max1619.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 0927902ceba3..9a8d7ca9b389 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -19,13 +19,8 @@ * 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 #include #include -- cgit v1.2.3-59-g8ed1b From 40089a9fe265cae0669e84c5ee6fafa59949c215 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 10:14:33 -0700 Subject: hwmon: (max1619) Rearrange code to avoid forward declarations Forward declarations are unnecessary and easy to avoid, so rearrange code and drop them. No functional change. Signed-off-by: Guenter Roeck --- drivers/hwmon/max1619.c | 158 +++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 89 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 9a8d7ca9b389..c8a729734df5 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -71,40 +71,6 @@ static int temp_to_reg(int val) return (val < 0 ? val+0x100*1000 : val) / 1000; } -/* - * Functions declaration - */ - -static int max1619_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int max1619_detect(struct i2c_client *client, - struct i2c_board_info *info); -static void max1619_init_client(struct i2c_client *client); -static int max1619_remove(struct i2c_client *client); -static struct max1619_data *max1619_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static const struct i2c_device_id max1619_id[] = { - { "max1619", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max1619_id); - -static struct i2c_driver max1619_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "max1619", - }, - .probe = max1619_probe, - .remove = max1619_remove, - .id_table = max1619_id, - .detect = max1619_detect, - .address_list = normal_i2c, -}; - /* * Client data (each client gets its own) */ @@ -123,6 +89,44 @@ struct max1619_data { u8 alarms; }; +static struct max1619_data *max1619_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max1619_data *data = i2c_get_clientdata(client); + int config; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + dev_dbg(&client->dev, "Updating max1619 data.\n"); + data->temp_input1 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_LOCAL_TEMP); + data->temp_input2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_TEMP); + data->temp_high2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_HIGH); + data->temp_low2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_LOW); + data->temp_crit2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_CRIT); + data->temp_hyst2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_TCRIT_HYST); + data->alarms = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_STATUS); + /* If OVERT polarity is low, reverse alarm bit */ + config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); + if (!(config & 0x20)) + data->alarms ^= 0x02; + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + /* * Sysfs stuff */ @@ -216,10 +220,6 @@ static const struct attribute_group max1619_group = { .attrs = max1619_attributes, }; -/* - * Real code - */ - /* Return 0 if detection is successful, -ENODEV otherwise */ static int max1619_detect(struct i2c_client *client, struct i2c_board_info *info) @@ -256,6 +256,21 @@ static int max1619_detect(struct i2c_client *client, return 0; } +static void max1619_init_client(struct i2c_client *client) +{ + u8 config; + + /* + * Start the conversions. + */ + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, + 5); /* 2 Hz */ + config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); + if (config & 0x40) + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, + config & 0xBF); /* run */ +} + static int max1619_probe(struct i2c_client *new_client, const struct i2c_device_id *id) { @@ -291,21 +306,6 @@ exit_remove_files: return err; } -static void max1619_init_client(struct i2c_client *client) -{ - u8 config; - - /* - * Start the conversions. - */ - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, - 5); /* 2 Hz */ - config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); - if (config & 0x40) - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, - config & 0xBF); /* run */ -} - static int max1619_remove(struct i2c_client *client) { struct max1619_data *data = i2c_get_clientdata(client); @@ -316,43 +316,23 @@ static int max1619_remove(struct i2c_client *client) return 0; } -static struct max1619_data *max1619_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct max1619_data *data = i2c_get_clientdata(client); - int config; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - dev_dbg(&client->dev, "Updating max1619 data.\n"); - data->temp_input1 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_LOCAL_TEMP); - data->temp_input2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TEMP); - data->temp_high2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_HIGH); - data->temp_low2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_LOW); - data->temp_crit2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_CRIT); - data->temp_hyst2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_TCRIT_HYST); - data->alarms = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_STATUS); - /* If OVERT polarity is low, reverse alarm bit */ - config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); - if (!(config & 0x20)) - data->alarms ^= 0x02; - - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); +static const struct i2c_device_id max1619_id[] = { + { "max1619", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max1619_id); - return data; -} +static struct i2c_driver max1619_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "max1619", + }, + .probe = max1619_probe, + .remove = max1619_remove, + .id_table = max1619_id, + .detect = max1619_detect, + .address_list = normal_i2c, +}; module_i2c_driver(max1619_driver); -- cgit v1.2.3-59-g8ed1b From f83111964ed74c3b2cd0a7d6363afb17efd87623 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 10:28:50 -0700 Subject: hwmon: (max1619) Drop function macros Function macros make the code larger and difficult ro read. Drop them and reduce code size (on x86_64) by ~1800 bytes. Signed-off-by: Guenter Roeck --- drivers/hwmon/max1619.c | 141 +++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 68 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index c8a729734df5..4125128898af 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -71,6 +71,16 @@ static int temp_to_reg(int val) return (val < 0 ? val+0x100*1000 : val) / 1000; } +enum temp_index { + t_input1 = 0, + t_input2, + t_low2, + t_high2, + t_crit2, + t_hyst2, + t_num_regs +}; + /* * Client data (each client gets its own) */ @@ -82,35 +92,39 @@ struct max1619_data { unsigned long last_updated; /* in jiffies */ /* registers values */ - u8 temp_input1; /* local */ - u8 temp_input2, temp_low2, temp_high2; /* remote */ - u8 temp_crit2; - u8 temp_hyst2; + u8 temp[t_num_regs]; /* index with enum temp_index */ u8 alarms; }; +static const u8 regs_read[t_num_regs] = { + [t_input1] = MAX1619_REG_R_LOCAL_TEMP, + [t_input2] = MAX1619_REG_R_REMOTE_TEMP, + [t_low2] = MAX1619_REG_R_REMOTE_LOW, + [t_high2] = MAX1619_REG_R_REMOTE_HIGH, + [t_crit2] = MAX1619_REG_R_REMOTE_CRIT, + [t_hyst2] = MAX1619_REG_R_TCRIT_HYST, +}; + +static const u8 regs_write[t_num_regs] = { + [t_low2] = MAX1619_REG_W_REMOTE_LOW, + [t_high2] = MAX1619_REG_W_REMOTE_HIGH, + [t_crit2] = MAX1619_REG_W_REMOTE_CRIT, + [t_hyst2] = MAX1619_REG_W_TCRIT_HYST, +}; + static struct max1619_data *max1619_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct max1619_data *data = i2c_get_clientdata(client); - int config; + int config, i; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { dev_dbg(&client->dev, "Updating max1619 data.\n"); - data->temp_input1 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_LOCAL_TEMP); - data->temp_input2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TEMP); - data->temp_high2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_HIGH); - data->temp_low2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_LOW); - data->temp_crit2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_CRIT); - data->temp_hyst2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_TCRIT_HYST); + for (i = 0; i < t_num_regs; i++) + data->temp[i] = i2c_smbus_read_byte_data(client, + regs_read[i]); data->alarms = i2c_smbus_read_byte_data(client, MAX1619_REG_R_STATUS); /* If OVERT polarity is low, reverse alarm bit */ @@ -131,43 +145,33 @@ static struct max1619_data *max1619_update_device(struct device *dev) * Sysfs stuff */ -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct max1619_data *data = max1619_update_device(dev); \ - return sprintf(buf, "%d\n", temp_from_reg(data->value)); \ -} -show_temp(temp_input1); -show_temp(temp_input2); -show_temp(temp_low2); -show_temp(temp_high2); -show_temp(temp_crit2); -show_temp(temp_hyst2); - -#define set_temp2(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ - const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct max1619_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err) \ - return err; \ -\ - mutex_lock(&data->update_lock); \ - data->value = temp_to_reg(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct max1619_data *data = max1619_update_device(dev); + + return sprintf(buf, "%d\n", temp_from_reg(data->temp[attr->index])); } -set_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW); -set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); -set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); -set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct max1619_data *data = i2c_get_clientdata(client); + long val; + int err = kstrtol(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->temp[attr->index] = temp_to_reg(val); + i2c_smbus_write_byte_data(client, regs_write[attr->index], + data->temp[attr->index]); + mutex_unlock(&data->update_lock); + return count; +} static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) @@ -184,16 +188,17 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, - set_temp_low2); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, - set_temp_high2); -static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, - set_temp_crit2); -static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2, - set_temp_hyst2); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input1); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, t_input2); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_low2); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_high2); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, + t_crit2); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_hyst2); + static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); @@ -201,12 +206,12 @@ static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); static struct attribute *max1619_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_crit.attr, - &dev_attr_temp2_crit_hyst.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, &dev_attr_alarms.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, -- cgit v1.2.3-59-g8ed1b From 9f1513bd55de0a8b4cc8c01a98aa9fb1bacd55e7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 10:35:29 -0700 Subject: hwmon: (max1619) Convert to use devm_hwmon_device_register_with_groups Use devm_hwmon_device_register_with_groups API to attach attributes to hwmon device, simplify code, and reduce code size. Signed-off-by: Guenter Roeck --- drivers/hwmon/max1619.c | 53 +++++++++++++------------------------------------ 1 file changed, 14 insertions(+), 39 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 4125128898af..eda9cf599685 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -86,7 +86,7 @@ enum temp_index { */ struct max1619_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -114,8 +114,8 @@ static const u8 regs_write[t_num_regs] = { static struct max1619_data *max1619_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct max1619_data *data = i2c_get_clientdata(client); + struct max1619_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int config, i; mutex_lock(&data->update_lock); @@ -158,8 +158,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct max1619_data *data = i2c_get_clientdata(client); + struct max1619_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; int err = kstrtol(buf, 10, &val); if (err) @@ -205,7 +205,7 @@ static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); -static struct attribute *max1619_attributes[] = { +static struct attribute *max1619_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, @@ -220,10 +220,7 @@ static struct attribute *max1619_attributes[] = { &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group max1619_group = { - .attrs = max1619_attributes, -}; +ATTRIBUTE_GROUPS(max1619); /* Return 0 if detection is successful, -ENODEV otherwise */ static int max1619_detect(struct i2c_client *client, @@ -280,45 +277,24 @@ static int max1619_probe(struct i2c_client *new_client, const struct i2c_device_id *id) { struct max1619_data *data; - int err; + struct device *hwmon_dev; data = devm_kzalloc(&new_client->dev, sizeof(struct max1619_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); + data->client = new_client; mutex_init(&data->update_lock); /* Initialize the MAX1619 chip */ max1619_init_client(new_client); - /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &max1619_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - -exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &max1619_group); - return err; -} - -static int max1619_remove(struct i2c_client *client) -{ - struct max1619_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &max1619_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, + new_client->name, + data, + max1619_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id max1619_id[] = { @@ -333,7 +309,6 @@ static struct i2c_driver max1619_driver = { .name = "max1619", }, .probe = max1619_probe, - .remove = max1619_remove, .id_table = max1619_id, .detect = max1619_detect, .address_list = normal_i2c, -- cgit v1.2.3-59-g8ed1b From 0968deb4c88e3b3bc589ab11e7ac1bb0a9a38654 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 12:37:01 -0700 Subject: hwmon: (lm83) Drop FSF address The FSF address changes over time, so drop it. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm83.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index be02155788c3..90cba322e840 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -25,10 +25,6 @@ * 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 -- cgit v1.2.3-59-g8ed1b From 41936370f13046b757e4f1051d11007e3b151e8e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 12:39:41 -0700 Subject: hwmon: (lm83) Rearange code to avoid forward declarations Avoid forward declarations by rearranging code. No functional change. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm83.c | 111 +++++++++++++++++++++++---------------------------- 1 file changed, 50 insertions(+), 61 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 90cba322e840..f9fcc91d02ca 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -106,40 +106,6 @@ static const u8 LM83_REG_W_HIGH[] = { LM83_REG_W_TCRIT, }; -/* - * Functions declaration - */ - -static int lm83_detect(struct i2c_client *new_client, - struct i2c_board_info *info); -static int lm83_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm83_remove(struct i2c_client *client); -static struct lm83_data *lm83_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static const struct i2c_device_id lm83_id[] = { - { "lm83", lm83 }, - { "lm82", lm82 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm83_id); - -static struct i2c_driver lm83_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm83", - }, - .probe = lm83_probe, - .remove = lm83_remove, - .id_table = lm83_id, - .detect = lm83_detect, - .address_list = normal_i2c, -}; - /* * Client data (each client gets its own) */ @@ -157,6 +123,36 @@ struct lm83_data { u16 alarms; /* bitvector, combined */ }; +static struct lm83_data *lm83_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm83_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + int nr; + + dev_dbg(&client->dev, "Updating lm83 data.\n"); + for (nr = 0; nr < 9; nr++) { + data->temp[nr] = + i2c_smbus_read_byte_data(client, + LM83_REG_R_TEMP[nr]); + } + data->alarms = + i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) + + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) + << 8); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + /* * Sysfs stuff */ @@ -390,35 +386,28 @@ static int lm83_remove(struct i2c_client *client) return 0; } -static struct lm83_data *lm83_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm83_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - int nr; - - dev_dbg(&client->dev, "Updating lm83 data.\n"); - for (nr = 0; nr < 9; nr++) { - data->temp[nr] = - i2c_smbus_read_byte_data(client, - LM83_REG_R_TEMP[nr]); - } - data->alarms = - i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) - + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) - << 8); - - data->last_updated = jiffies; - data->valid = 1; - } +/* + * Driver data (common to all clients) + */ - mutex_unlock(&data->update_lock); +static const struct i2c_device_id lm83_id[] = { + { "lm83", lm83 }, + { "lm82", lm82 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm83_id); - return data; -} +static struct i2c_driver lm83_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm83", + }, + .probe = lm83_probe, + .remove = lm83_remove, + .id_table = lm83_id, + .detect = lm83_detect, + .address_list = normal_i2c, +}; module_i2c_driver(lm83_driver); -- cgit v1.2.3-59-g8ed1b From a0ac840d99fa7c2ebf5a3df0367992722a92ca65 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 12 Apr 2014 12:46:34 -0700 Subject: hwmon: (lm83) Convert to use devm_hwmon_device_register_with_groups Use devm_hwmon_device_register_with_groups API to attach attributes to hwmon device, simplify code, and reduce code size. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm83.c | 59 ++++++++++++++-------------------------------------- 1 file changed, 16 insertions(+), 43 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index f9fcc91d02ca..9e4d0e1d3c4b 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -111,7 +111,8 @@ static const u8 LM83_REG_W_HIGH[] = { */ struct lm83_data { - struct device *hwmon_dev; + struct i2c_client *client; + const struct attribute_group *groups[3]; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -125,8 +126,8 @@ struct lm83_data { static struct lm83_data *lm83_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm83_data *data = i2c_get_clientdata(client); + struct lm83_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; mutex_lock(&data->update_lock); @@ -169,8 +170,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm83_data *data = i2c_get_clientdata(client); + struct lm83_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; int nr = attr->index; int err; @@ -332,15 +333,15 @@ static int lm83_detect(struct i2c_client *new_client, static int lm83_probe(struct i2c_client *new_client, const struct i2c_device_id *id) { + struct device *hwmon_dev; struct lm83_data *data; - int err; data = devm_kzalloc(&new_client->dev, sizeof(struct lm83_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); + data->client = new_client; mutex_init(&data->update_lock); /* @@ -349,41 +350,14 @@ static int lm83_probe(struct i2c_client *new_client, * at the same register as the LM83 temp3 entry - so we * declare 1 and 3 common, and then 2 and 4 only for the LM83. */ - - err = sysfs_create_group(&new_client->dev.kobj, &lm83_group); - if (err) - return err; - - if (id->driver_data == lm83) { - err = sysfs_create_group(&new_client->dev.kobj, - &lm83_group_opt); - if (err) - goto exit_remove_files; - } - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - -exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &lm83_group); - sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt); - return err; -} - -static int lm83_remove(struct i2c_client *client) -{ - struct lm83_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm83_group); - sysfs_remove_group(&client->dev.kobj, &lm83_group_opt); - - return 0; + data->groups[0] = &lm83_group; + if (id->driver_data == lm83) + data->groups[1] = &lm83_group_opt; + + hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, + new_client->name, + data, data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } /* @@ -403,7 +377,6 @@ static struct i2c_driver lm83_driver = { .name = "lm83", }, .probe = lm83_probe, - .remove = lm83_remove, .id_table = lm83_id, .detect = lm83_detect, .address_list = normal_i2c, -- cgit v1.2.3-59-g8ed1b From 9028ff8e3dd207375d2459079f728322671069ac Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 13 Apr 2014 09:15:09 -0700 Subject: hwmon: (lm80) Simplify TEMP_FROM_REG TEMP_FROM_REG gets 12 bits of temperature data in the upper 12 bit of a signed 16 bit parameter, with the integer part (including sign) in the upper 8 bit and the remainder in bit 4..7. The lower 4 bit of the 16 bit data is always 0. We can use that information to convert the temperature directly into display data (1/1000th of degree C). Note that the stored temperature data is not shifted right as the comment claimed, so remove that misleading comment. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm80.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index bd0a1ebbf867..8e9a0b1dc437 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -86,18 +86,7 @@ static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ (val) == 255 ? 0 : 1350000/((div) * (val))) -static inline long TEMP_FROM_REG(u16 temp) -{ - long res; - - temp >>= 4; - if (temp < 0x0800) - res = 625 * (long) temp; - else - res = ((long) temp - 0x01000) * 625; - - return res / 10; -} +#define TEMP_FROM_REG(temp) ((temp) * 125 / 32) #define TEMP_LIMIT_FROM_REG(val) (((val) > 0x80 ? \ (val) - 0x100 : (val)) * 1000) @@ -124,7 +113,7 @@ struct lm80_data { u8 fan[2]; /* Register value */ u8 fan_min[2]; /* Register value */ u8 fan_div[2]; /* Register encoding, shifted right */ - u16 temp; /* Register values, shifted right */ + s16 temp; /* Register values */ u8 temp_hot_max; /* Register value */ u8 temp_hot_hyst; /* Register value */ u8 temp_os_max; /* Register value */ @@ -309,7 +298,7 @@ static ssize_t show_temp_input1(struct device *dev, struct lm80_data *data = lm80_update_device(dev); if (IS_ERR(data)) return PTR_ERR(data); - return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); } #define show_temp(suffix, value) \ -- cgit v1.2.3-59-g8ed1b From 688a3174a2a0426a898dc641226249fa0df9e922 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 13 Apr 2014 09:30:09 -0700 Subject: hwmon: (lm80) Normalize all temperature values to 16 bit Normalize all stored temperature values to 16 bit to simplify temperature calculations. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm80.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 8e9a0b1dc437..fe980d64dc05 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -86,13 +86,9 @@ static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ (val) == 255 ? 0 : 1350000/((div) * (val))) -#define TEMP_FROM_REG(temp) ((temp) * 125 / 32) - -#define TEMP_LIMIT_FROM_REG(val) (((val) > 0x80 ? \ - (val) - 0x100 : (val)) * 1000) - -#define TEMP_LIMIT_TO_REG(val) clamp_val((val) < 0 ? \ - ((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255) +#define TEMP_FROM_REG(reg) ((reg) * 125 / 32) +#define TEMP_TO_REG(temp) (DIV_ROUND_CLOSEST(clamp_val((temp), \ + -128000, 127000), 1000) << 8) #define DIV_FROM_REG(val) (1 << (val)) @@ -114,10 +110,10 @@ struct lm80_data { u8 fan_min[2]; /* Register value */ u8 fan_div[2]; /* Register encoding, shifted right */ s16 temp; /* Register values */ - u8 temp_hot_max; /* Register value */ - u8 temp_hot_hyst; /* Register value */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ + s16 temp_hot_max; /* Register value, left shifted */ + s16 temp_hot_hyst; /* Register value, left shifted */ + s16 temp_os_max; /* Register value, left shifted */ + s16 temp_os_hyst; /* Register value, left shifted */ u16 alarms; /* Register encoding, combined */ }; @@ -308,7 +304,7 @@ static ssize_t show_temp_##suffix(struct device *dev, \ struct lm80_data *data = lm80_update_device(dev); \ if (IS_ERR(data)) \ return PTR_ERR(data); \ - return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ } show_temp(hot_max, temp_hot_max); show_temp(hot_hyst, temp_hot_hyst); @@ -327,8 +323,8 @@ static ssize_t set_temp_##suffix(struct device *dev, \ return err; \ \ mutex_lock(&data->update_lock); \ - data->value = TEMP_LIMIT_TO_REG(val); \ - lm80_write_value(client, reg, data->value); \ + data->value = TEMP_TO_REG(val); \ + lm80_write_value(client, reg, data->value >> 8); \ mutex_unlock(&data->update_lock); \ return count; \ } @@ -639,22 +635,22 @@ static struct lm80_data *lm80_update_device(struct device *dev) rv = lm80_read_value(client, LM80_REG_TEMP_OS_MAX); if (rv < 0) goto abort; - data->temp_os_max = rv; + data->temp_os_max = rv << 8; rv = lm80_read_value(client, LM80_REG_TEMP_OS_HYST); if (rv < 0) goto abort; - data->temp_os_hyst = rv; + data->temp_os_hyst = rv << 8; rv = lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); if (rv < 0) goto abort; - data->temp_hot_max = rv; + data->temp_hot_max = rv << 8; rv = lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); if (rv < 0) goto abort; - data->temp_hot_hyst = rv; + data->temp_hot_hyst = rv << 8; rv = lm80_read_value(client, LM80_REG_FANDIV); if (rv < 0) -- cgit v1.2.3-59-g8ed1b From 9711bcddde206047415b2eb42c545ad2b1ac8b76 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 13 Apr 2014 09:45:15 -0700 Subject: hwmon: (lm80) Convert temperature display function macros into functions Convert temperature display function macros into functions to reduce code size and improve code readability. Code size reduction is about 2k on x86_64. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm80.c | 134 +++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 75 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index fe980d64dc05..df6e07992baf 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -92,6 +92,23 @@ static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) #define DIV_FROM_REG(val) (1 << (val)) +enum temp_index { + t_input = 0, + t_hot_max, + t_hot_hyst, + t_os_max, + t_os_hyst, + t_num_temp +}; + +static const u8 temp_regs[t_num_temp] = { + [t_input] = LM80_REG_TEMP, + [t_hot_max] = LM80_REG_TEMP_HOT_MAX, + [t_hot_hyst] = LM80_REG_TEMP_HOT_HYST, + [t_os_max] = LM80_REG_TEMP_OS_MAX, + [t_os_hyst] = LM80_REG_TEMP_OS_HYST, +}; + /* * Client data (each client gets its own) */ @@ -109,11 +126,7 @@ struct lm80_data { u8 fan[2]; /* Register value */ u8 fan_min[2]; /* Register value */ u8 fan_div[2]; /* Register encoding, shifted right */ - s16 temp; /* Register values */ - s16 temp_hot_max; /* Register value, left shifted */ - s16 temp_hot_hyst; /* Register value, left shifted */ - s16 temp_os_max; /* Register value, left shifted */ - s16 temp_os_hyst; /* Register value, left shifted */ + s16 temp[t_num_temp]; /* Register values, normalized to 16 bit */ u16 alarms; /* Register encoding, combined */ }; @@ -288,50 +301,34 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_temp_input1(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm80_data *data = lm80_update_device(dev); if (IS_ERR(data)) return PTR_ERR(data); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -#define show_temp(suffix, value) \ -static ssize_t show_temp_##suffix(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show_temp(hot_max, temp_hot_max); -show_temp(hot_hyst, temp_hot_hyst); -show_temp(os_max, temp_os_max); -show_temp(os_hyst, temp_os_hyst); +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int nr = attr->index; + long val; + int err = kstrtol(buf, 10, &val); + if (err < 0) + return err; -#define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct lm80_data *data = dev_get_drvdata(dev); \ - struct i2c_client *client = data->client; \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err < 0) \ - return err; \ -\ - mutex_lock(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - lm80_write_value(client, reg, data->value >> 8); \ - mutex_unlock(&data->update_lock); \ - return count; \ + mutex_lock(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + lm80_write_value(client, temp_regs[nr], data->temp[nr] >> 8); + mutex_unlock(&data->update_lock); + return count; } -set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX); -set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); -set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); -set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) @@ -397,15 +394,15 @@ static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, set_fan_div, 0); static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, set_fan_div, 1); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, - set_temp_hot_max); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst, - set_temp_hot_hyst); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, - set_temp_os_max); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, - set_temp_os_hyst); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_hot_max); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_hot_hyst); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_os_max); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_os_hyst); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); @@ -451,11 +448,11 @@ static struct attribute *lm80_attrs[] = { &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_crit_hyst.attr, + &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, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, &dev_attr_alarms.attr, &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in1_alarm.dev_attr.attr, @@ -630,27 +627,14 @@ static struct lm80_data *lm80_update_device(struct device *dev) rv = lm80_read_value(client, LM80_REG_RES); if (rv < 0) goto abort; - data->temp = (prev_rv << 8) | (rv & 0xf0); + data->temp[t_input] = (prev_rv << 8) | (rv & 0xf0); - rv = lm80_read_value(client, LM80_REG_TEMP_OS_MAX); - if (rv < 0) - goto abort; - data->temp_os_max = rv << 8; - - rv = lm80_read_value(client, LM80_REG_TEMP_OS_HYST); - if (rv < 0) - goto abort; - data->temp_os_hyst = rv << 8; - - rv = lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); - if (rv < 0) - goto abort; - data->temp_hot_max = rv << 8; - - rv = lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); - if (rv < 0) - goto abort; - data->temp_hot_hyst = rv << 8; + for (i = t_input + 1; i < t_num_temp; i++) { + rv = lm80_read_value(client, temp_regs[i]); + if (rv < 0) + goto abort; + data->temp[i] = rv << 8; + } rv = lm80_read_value(client, LM80_REG_FANDIV); if (rv < 0) -- cgit v1.2.3-59-g8ed1b From 1adf3a3e1cf2ceb30c32642ff35cb05467dc7a75 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 13 Apr 2014 10:53:50 -0700 Subject: hwmon: (lm80) Convert voltage display function macros into functions Convert voltage display function macros into functions to reduce code size and improve code readability. Code size reduction is about 600 bytes on x86_64. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm80.c | 148 ++++++++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 72 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index df6e07992baf..8a3fa9aa07f8 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -109,6 +109,13 @@ static const u8 temp_regs[t_num_temp] = { [t_os_hyst] = LM80_REG_TEMP_OS_HYST, }; +enum in_index { + i_input = 0, + i_max, + i_min, + i_num_in +}; + /* * Client data (each client gets its own) */ @@ -120,9 +127,7 @@ struct lm80_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ + u8 in[i_num_in][7]; /* Register value, 1st index is enum in_index */ u8 fan[2]; /* Register value */ u8 fan_min[2]; /* Register value */ u8 fan_div[2]; /* Register encoding, shifted right */ @@ -168,40 +173,39 @@ static struct i2c_driver lm80_driver = { * Sysfs stuff */ -#define show_in(suffix, value) \ -static ssize_t show_in_##suffix(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - int nr = to_sensor_dev_attr(attr)->index; \ - struct lm80_data *data = lm80_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \ +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm80_data *data = lm80_update_device(dev); + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr][index])); } -show_in(min, in_min) -show_in(max, in_max) -show_in(input, in) -#define set_in(suffix, value, reg) \ -static ssize_t set_in_##suffix(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - int nr = to_sensor_dev_attr(attr)->index; \ - struct lm80_data *data = dev_get_drvdata(dev); \ - struct i2c_client *client = data->client; \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err < 0) \ - return err; \ -\ - mutex_lock(&data->update_lock);\ - data->value[nr] = IN_TO_REG(val); \ - lm80_write_value(client, reg(nr), data->value[nr]); \ - mutex_unlock(&data->update_lock);\ - return count; \ +static ssize_t set_in(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + long val; + u8 reg; + int err = kstrtol(buf, 10, &val); + if (err < 0) + return err; + + reg = nr == i_min ? LM80_REG_IN_MIN(index) : LM80_REG_IN_MAX(index); + + mutex_lock(&data->update_lock); + data->in[nr][index] = IN_TO_REG(val); + lm80_write_value(client, reg, data->in[nr][index]); + mutex_unlock(&data->update_lock); + return count; } -set_in(min, in_min, LM80_REG_IN_MIN) -set_in(max, in_max, LM80_REG_IN_MAX) #define show_fan(suffix, value) \ static ssize_t show_fan_##suffix(struct device *dev, \ @@ -349,41 +353,41 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } -static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 0); -static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 1); -static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 2); -static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 3); -static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 4); -static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 5); -static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 6); -static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 0); -static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 1); -static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 2); -static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 3); -static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 4); -static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 5); -static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 6); -static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0); -static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1); -static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2); -static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3); -static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4); -static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5); -static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6); +static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 0); +static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 1); +static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 2); +static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 3); +static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 4); +static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 5); +static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 6); +static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 0); +static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 1); +static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 2); +static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 3); +static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 4); +static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 5); +static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 6); +static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, i_input, 0); +static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, i_input, 1); +static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, i_input, 2); +static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, i_input, 3); +static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, i_input, 4); +static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, i_input, 5); +static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, i_input, 6); static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 0); static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, @@ -588,17 +592,17 @@ static struct lm80_data *lm80_update_device(struct device *dev) rv = lm80_read_value(client, LM80_REG_IN(i)); if (rv < 0) goto abort; - data->in[i] = rv; + data->in[i_input][i] = rv; rv = lm80_read_value(client, LM80_REG_IN_MIN(i)); if (rv < 0) goto abort; - data->in_min[i] = rv; + data->in[i_min][i] = rv; rv = lm80_read_value(client, LM80_REG_IN_MAX(i)); if (rv < 0) goto abort; - data->in_max[i] = rv; + data->in[i_max][i] = rv; } rv = lm80_read_value(client, LM80_REG_FAN1); -- cgit v1.2.3-59-g8ed1b From 85b3ee07b986e90d5e9821dcb28bde340dfc7805 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 13 Apr 2014 11:28:29 -0700 Subject: hwmon: (lm80) Convert fan display function macros into functions Convert fan display function macros into functions to reduce code size and improve code readability. Code size reduction is about 200 bytes on x86_64. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm80.c | 75 ++++++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 34 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 8a3fa9aa07f8..420ad7c5ec28 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -116,6 +116,12 @@ enum in_index { i_num_in }; +enum fan_index { + f_input, + f_min, + f_num_fan +}; + /* * Client data (each client gets its own) */ @@ -128,8 +134,7 @@ struct lm80_data { unsigned long last_updated; /* In jiffies */ u8 in[i_num_in][7]; /* Register value, 1st index is enum in_index */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ + u8 fan[f_num_fan][2]; /* Register value, 1st index enum fan_index */ u8 fan_div[2]; /* Register encoding, shifted right */ s16 temp[t_num_temp]; /* Register values, normalized to 16 bit */ u16 alarms; /* Register encoding, combined */ @@ -207,19 +212,17 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr, return count; } -#define show_fan(suffix, value) \ -static ssize_t show_fan_##suffix(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - int nr = to_sensor_dev_attr(attr)->index; \ - struct lm80_data *data = lm80_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \ - DIV_FROM_REG(data->fan_div[nr]))); \ +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + struct lm80_data *data = lm80_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr][index], + DIV_FROM_REG(data->fan_div[index]))); } -show_fan(min, fan_min) -show_fan(input, fan) static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, char *buf) @@ -234,7 +237,8 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int nr = to_sensor_dev_attr(attr)->index; + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; struct lm80_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; unsigned long val; @@ -243,8 +247,10 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, return err; mutex_lock(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + data->fan[nr][index] = FAN_TO_REG(val, + DIV_FROM_REG(data->fan_div[index])); + lm80_write_value(client, LM80_REG_FAN_MIN(index + 1), + data->fan[nr][index]); mutex_unlock(&data->update_lock); return count; } @@ -269,7 +275,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, /* Save fan_min */ mutex_lock(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], + min = FAN_FROM_REG(data->fan[f_min][nr], DIV_FROM_REG(data->fan_div[nr])); switch (val) { @@ -293,13 +299,14 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, return -EINVAL; } - reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) - | (data->fan_div[nr] << (2 * (nr + 1))); + reg = (lm80_read_value(client, LM80_REG_FANDIV) & + ~(3 << (2 * (nr + 1)))) | (data->fan_div[nr] << (2 * (nr + 1))); lm80_write_value(client, LM80_REG_FANDIV, reg); /* Restore fan_min */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + data->fan[f_min][nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), + data->fan[f_min][nr]); mutex_unlock(&data->update_lock); return count; @@ -388,12 +395,12 @@ static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, i_input, 3); static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, i_input, 4); static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, i_input, 5); static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, i_input, 6); -static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, - show_fan_min, set_fan_min, 0); -static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, - show_fan_min, set_fan_min, 1); -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0); -static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1); +static SENSOR_DEVICE_ATTR_2(fan1_min, S_IWUSR | S_IRUGO, + show_fan, set_fan_min, f_min, 0); +static SENSOR_DEVICE_ATTR_2(fan2_min, S_IWUSR | S_IRUGO, + show_fan, set_fan_min, f_min, 1); +static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, f_input, 0); +static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, f_input, 1); static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, set_fan_div, 0); static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, @@ -537,8 +544,8 @@ static int lm80_probe(struct i2c_client *client, lm80_init_client(client); /* A few vars need to be filled upon startup */ - data->fan_min[0] = lm80_read_value(client, LM80_REG_FAN_MIN(1)); - data->fan_min[1] = lm80_read_value(client, LM80_REG_FAN_MIN(2)); + data->fan[f_min][0] = lm80_read_value(client, LM80_REG_FAN_MIN(1)); + data->fan[f_min][1] = lm80_read_value(client, LM80_REG_FAN_MIN(2)); hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, data, lm80_groups); @@ -608,22 +615,22 @@ static struct lm80_data *lm80_update_device(struct device *dev) rv = lm80_read_value(client, LM80_REG_FAN1); if (rv < 0) goto abort; - data->fan[0] = rv; + data->fan[f_input][0] = rv; rv = lm80_read_value(client, LM80_REG_FAN_MIN(1)); if (rv < 0) goto abort; - data->fan_min[0] = rv; + data->fan[f_min][0] = rv; rv = lm80_read_value(client, LM80_REG_FAN2); if (rv < 0) goto abort; - data->fan[1] = rv; + data->fan[f_input][1] = rv; rv = lm80_read_value(client, LM80_REG_FAN_MIN(2)); if (rv < 0) goto abort; - data->fan_min[1] = rv; + data->fan[f_min][1] = rv; prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP); if (rv < 0) -- cgit v1.2.3-59-g8ed1b From c254ffdefc002b57f1e9eedddcb3569c0d80578f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 13 Apr 2014 11:56:15 -0700 Subject: hwmon: (lm80) Rearrange code to avoid forward declarations Avoid need for forward declarations by rearranging code. No functional change. Signed-off-by: Guenter Roeck --- drivers/hwmon/lm80.c | 290 ++++++++++++++++++++++++--------------------------- 1 file changed, 139 insertions(+), 151 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 420ad7c5ec28..4bcd9b882948 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -140,39 +140,130 @@ struct lm80_data { u16 alarms; /* Register encoding, combined */ }; -/* - * Functions declaration - */ +static int lm80_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} -static int lm80_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info); -static void lm80_init_client(struct i2c_client *client); -static struct lm80_data *lm80_update_device(struct device *dev); -static int lm80_read_value(struct i2c_client *client, u8 reg); -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); +static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} -/* - * Driver data (common to all clients) - */ +/* Called when we have found a new LM80 and after read errors */ +static void lm80_init_client(struct i2c_client *client) +{ + /* + * Reset all except Watchdog values and last conversion values + * This sets fan-divs to 2, among others. This makes most other + * initializations unnecessary + */ + lm80_write_value(client, LM80_REG_CONFIG, 0x80); + /* Set 11-bit temperature resolution */ + lm80_write_value(client, LM80_REG_RES, 0x08); -static const struct i2c_device_id lm80_id[] = { - { "lm80", 0 }, - { "lm96080", 1 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm80_id); + /* Start monitoring */ + lm80_write_value(client, LM80_REG_CONFIG, 0x01); +} -static struct i2c_driver lm80_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm80", - }, - .probe = lm80_probe, - .id_table = lm80_id, - .detect = lm80_detect, - .address_list = normal_i2c, -}; +static struct lm80_data *lm80_update_device(struct device *dev) +{ + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int i; + int rv; + int prev_rv; + struct lm80_data *ret = data; + + mutex_lock(&data->update_lock); + + if (data->error) + lm80_init_client(client); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + dev_dbg(dev, "Starting lm80 update\n"); + for (i = 0; i <= 6; i++) { + rv = lm80_read_value(client, LM80_REG_IN(i)); + if (rv < 0) + goto abort; + data->in[i_input][i] = rv; + + rv = lm80_read_value(client, LM80_REG_IN_MIN(i)); + if (rv < 0) + goto abort; + data->in[i_min][i] = rv; + + rv = lm80_read_value(client, LM80_REG_IN_MAX(i)); + if (rv < 0) + goto abort; + data->in[i_max][i] = rv; + } + + rv = lm80_read_value(client, LM80_REG_FAN1); + if (rv < 0) + goto abort; + data->fan[f_input][0] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN_MIN(1)); + if (rv < 0) + goto abort; + data->fan[f_min][0] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN2); + if (rv < 0) + goto abort; + data->fan[f_input][1] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN_MIN(2)); + if (rv < 0) + goto abort; + data->fan[f_min][1] = rv; + + prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP); + if (rv < 0) + goto abort; + rv = lm80_read_value(client, LM80_REG_RES); + if (rv < 0) + goto abort; + data->temp[t_input] = (prev_rv << 8) | (rv & 0xf0); + + for (i = t_input + 1; i < t_num_temp; i++) { + rv = lm80_read_value(client, temp_regs[i]); + if (rv < 0) + goto abort; + data->temp[i] = rv << 8; + } + + rv = lm80_read_value(client, LM80_REG_FANDIV); + if (rv < 0) + goto abort; + data->fan_div[0] = (rv >> 2) & 0x03; + data->fan_div[1] = (rv >> 4) & 0x03; + + prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1); + if (rv < 0) + goto abort; + rv = lm80_read_value(client, LM80_REG_ALARM2); + if (rv < 0) + goto abort; + data->alarms = prev_rv + (rv << 8); + + data->last_updated = jiffies; + data->valid = 1; + data->error = 0; + } + goto done; + +abort: + ret = ERR_PTR(rv); + data->valid = 0; + data->error = 1; + +done: + mutex_unlock(&data->update_lock); + + return ret; +} /* * Sysfs stuff @@ -553,130 +644,27 @@ static int lm80_probe(struct i2c_client *client, return PTR_ERR_OR_ZERO(hwmon_dev); } -static int lm80_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM80. */ -static void lm80_init_client(struct i2c_client *client) -{ - /* - * Reset all except Watchdog values and last conversion values - * This sets fan-divs to 2, among others. This makes most other - * initializations unnecessary - */ - lm80_write_value(client, LM80_REG_CONFIG, 0x80); - /* Set 11-bit temperature resolution */ - lm80_write_value(client, LM80_REG_RES, 0x08); - - /* Start monitoring */ - lm80_write_value(client, LM80_REG_CONFIG, 0x01); -} - -static struct lm80_data *lm80_update_device(struct device *dev) -{ - struct lm80_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - int i; - int rv; - int prev_rv; - struct lm80_data *ret = data; - - mutex_lock(&data->update_lock); - - if (data->error) - lm80_init_client(client); - - if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { - dev_dbg(dev, "Starting lm80 update\n"); - for (i = 0; i <= 6; i++) { - rv = lm80_read_value(client, LM80_REG_IN(i)); - if (rv < 0) - goto abort; - data->in[i_input][i] = rv; - - rv = lm80_read_value(client, LM80_REG_IN_MIN(i)); - if (rv < 0) - goto abort; - data->in[i_min][i] = rv; - - rv = lm80_read_value(client, LM80_REG_IN_MAX(i)); - if (rv < 0) - goto abort; - data->in[i_max][i] = rv; - } - - rv = lm80_read_value(client, LM80_REG_FAN1); - if (rv < 0) - goto abort; - data->fan[f_input][0] = rv; - - rv = lm80_read_value(client, LM80_REG_FAN_MIN(1)); - if (rv < 0) - goto abort; - data->fan[f_min][0] = rv; - - rv = lm80_read_value(client, LM80_REG_FAN2); - if (rv < 0) - goto abort; - data->fan[f_input][1] = rv; - - rv = lm80_read_value(client, LM80_REG_FAN_MIN(2)); - if (rv < 0) - goto abort; - data->fan[f_min][1] = rv; - - prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP); - if (rv < 0) - goto abort; - rv = lm80_read_value(client, LM80_REG_RES); - if (rv < 0) - goto abort; - data->temp[t_input] = (prev_rv << 8) | (rv & 0xf0); - - for (i = t_input + 1; i < t_num_temp; i++) { - rv = lm80_read_value(client, temp_regs[i]); - if (rv < 0) - goto abort; - data->temp[i] = rv << 8; - } - - rv = lm80_read_value(client, LM80_REG_FANDIV); - if (rv < 0) - goto abort; - data->fan_div[0] = (rv >> 2) & 0x03; - data->fan_div[1] = (rv >> 4) & 0x03; - - prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1); - if (rv < 0) - goto abort; - rv = lm80_read_value(client, LM80_REG_ALARM2); - if (rv < 0) - goto abort; - data->alarms = prev_rv + (rv << 8); - - data->last_updated = jiffies; - data->valid = 1; - data->error = 0; - } - goto done; - -abort: - ret = ERR_PTR(rv); - data->valid = 0; - data->error = 1; +/* + * Driver data (common to all clients) + */ -done: - mutex_unlock(&data->update_lock); +static const struct i2c_device_id lm80_id[] = { + { "lm80", 0 }, + { "lm96080", 1 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm80_id); - return ret; -} +static struct i2c_driver lm80_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm80", + }, + .probe = lm80_probe, + .id_table = lm80_id, + .detect = lm80_detect, + .address_list = normal_i2c, +}; module_i2c_driver(lm80_driver); -- cgit v1.2.3-59-g8ed1b From 41082d66bfd6fafe001c0902bb4622d7aee6f128 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 6 Apr 2014 08:57:20 -0700 Subject: hwmon: Driver for NCT6683D Nuvoton NCT6683D is an eSIO with hardware monitoring capabilities. Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct6683 | 57 ++ drivers/hwmon/Kconfig | 10 + drivers/hwmon/Makefile | 1 + drivers/hwmon/nct6683.c | 1455 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1523 insertions(+) create mode 100644 Documentation/hwmon/nct6683 create mode 100644 drivers/hwmon/nct6683.c (limited to 'drivers/hwmon') diff --git a/Documentation/hwmon/nct6683 b/Documentation/hwmon/nct6683 new file mode 100644 index 000000000000..c1301d4300cd --- /dev/null +++ b/Documentation/hwmon/nct6683 @@ -0,0 +1,57 @@ +Kernel driver nct6683 +===================== + +Supported chips: + * Nuvoton NCT6683D + Prefix: 'nct6683' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: Available from Nuvoton upon request + +Authors: + Guenter Roeck + +Description +----------- + +This driver implements support for the Nuvoton NCT6683D eSIO chip. + +The chips implement up to shared 32 temperature and voltage sensors. +It supports up to 16 fan rotation sensors and up to 8 fan control engines. + +Temperatures are measured in degrees Celsius. Measurement resolution is +0.5 degrees C. + +Voltage sensors (also known as IN sensors) report their values in millivolts. + +Fan rotation speeds are reported in RPM (rotations per minute). + +Usage Note +---------- + +Limit register locations on Intel boards with EC firmware version 1.0 +build date 04/03/13 do not match the register locations in the Nuvoton +datasheet. Nuvoton confirms that Intel uses a special firmware version +with different register addresses. The specification describing the Intel +firmware is held under NDA by Nuvoton and Intel and not available +to the public. + +Some of the register locations can be reverse engineered; others are too +well hidden. Given this, writing any values from the operating system is +considered too risky with this firmware and has been disabled. All limits +must all be written from the BIOS. + +The driver has only been tested with the Intel firmware, and by default +only instantiates on Intel boards. To enable it on non-Intel boards, +set the 'force' module parameter to 1. + +Tested Boards and Firmware Versions +----------------------------------- + +The driver has been reported to work with the following boards and +firmware versions. + +Board Firmware version +--------------------------------------------------------------- +Intel DH87RL NCT6683D EC firmware version 1.0 build 04/03/13 +Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13 +Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13 diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index bc196f49ec53..b7c0b830d9e4 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1065,6 +1065,16 @@ config SENSORS_NTC_THERMISTOR This driver can also be built as a module. If so, the module will be called ntc-thermistor. +config SENSORS_NCT6683 + tristate "Nuvoton NCT6683D" + depends on !PPC + help + If you say yes here you get support for the hardware monitoring + functionality of the Nuvoton NCT6683D eSIO chip. + + This driver can also be built as a module. If so, the module + will be called nct6683. + config SENSORS_NCT6775 tristate "Nuvoton NCT6775F and compatibles" depends on !PPC diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index c48f9873ac73..11798ad7e801 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -114,6 +114,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_MAX6697) += max6697.o obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o +obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c new file mode 100644 index 000000000000..540c81c52344 --- /dev/null +++ b/drivers/hwmon/nct6683.c @@ -0,0 +1,1455 @@ +/* + * nct6683 - Driver for the hardware monitoring functionality of + * Nuvoton NCT6683D eSIO + * + * Copyright (C) 2013 Guenter Roeck + * + * Derived from nct6775 driver + * Copyright (C) 2012, 2013 Guenter Roeck + * + * 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. + * + * Supports the following chips: + * + * Chip #vin #fan #pwm #temp chip ID + * nct6683d 21(1) 16 8 32(1) 0xc730 + * + * Notes: + * (1) Total number of vin and temp inputs is 32. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum kinds { nct6683 }; + +static bool force; +module_param(force, bool, 0); +MODULE_PARM_DESC(force, "Set to one to enable detection on non-Intel boards"); + +static const char * const nct6683_device_names[] = { + "nct6683", +}; + +static const char * const nct6683_chip_names[] = { + "NCT6683D", +}; + +#define DRVNAME "nct6683" + +/* + * Super-I/O constants and functions + */ + +#define NCT6683_LD_ACPI 0x0a +#define NCT6683_LD_HWM 0x0b +#define NCT6683_LD_VID 0x0d + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ + +#define SIO_NCT6681_ID 0xb270 /* for later */ +#define SIO_NCT6683_ID 0xc730 +#define SIO_ID_MASK 0xFFF0 + +static inline void +superio_outb(int ioreg, int reg, int val) +{ + outb(reg, ioreg); + outb(val, ioreg + 1); +} + +static inline int +superio_inb(int ioreg, int reg) +{ + outb(reg, ioreg); + return inb(ioreg + 1); +} + +static inline void +superio_select(int ioreg, int ld) +{ + outb(SIO_REG_LDSEL, ioreg); + outb(ld, ioreg + 1); +} + +static inline int +superio_enter(int ioreg) +{ + /* + * Try to reserve and for exclusive access. + */ + if (!request_muxed_region(ioreg, 2, DRVNAME)) + return -EBUSY; + + outb(0x87, ioreg); + outb(0x87, ioreg); + + return 0; +} + +static inline void +superio_exit(int ioreg) +{ + outb(0xaa, ioreg); + outb(0x02, ioreg); + outb(0x02, ioreg + 1); + release_region(ioreg, 2); +} + +/* + * ISA constants + */ + +#define IOREGION_ALIGNMENT (~7) +#define IOREGION_OFFSET 4 /* Use EC port 1 */ +#define IOREGION_LENGTH 4 + +#define EC_PAGE_REG 0 +#define EC_INDEX_REG 1 +#define EC_DATA_REG 2 +#define EC_EVENT_REG 3 + +/* Common and NCT6683 specific data */ + +#define NCT6683_NUM_REG_MON 32 +#define NCT6683_NUM_REG_FAN 16 +#define NCT6683_NUM_REG_PWM 8 + +#define NCT6683_REG_MON(x) (0x100 + (x) * 2) +#define NCT6683_REG_FAN_RPM(x) (0x140 + (x) * 2) +#define NCT6683_REG_PWM(x) (0x160 + (x)) + +#define NCT6683_REG_MON_STS(x) (0x174 + (x)) +#define NCT6683_REG_IDLE(x) (0x178 + (x)) + +#define NCT6683_REG_FAN_STS(x) (0x17c + (x)) +#define NCT6683_REG_FAN_ERRSTS 0x17e +#define NCT6683_REG_FAN_INITSTS 0x17f + +#define NCT6683_HWM_CFG 0x180 + +#define NCT6683_REG_MON_CFG(x) (0x1a0 + (x)) +#define NCT6683_REG_FANIN_CFG(x) (0x1c0 + (x)) +#define NCT6683_REG_FANOUT_CFG(x) (0x1d0 + (x)) + +#define NCT6683_REG_INTEL_TEMP_MAX(x) (0x901 + (x) * 16) +#define NCT6683_REG_INTEL_TEMP_CRIT(x) (0x90d + (x) * 16) + +#define NCT6683_REG_TEMP_HYST(x) (0x330 + (x)) /* 8 bit */ +#define NCT6683_REG_TEMP_MAX(x) (0x350 + (x)) /* 8 bit */ +#define NCT6683_REG_MON_HIGH(x) (0x370 + (x) * 2) /* 8 bit */ +#define NCT6683_REG_MON_LOW(x) (0x371 + (x) * 2) /* 8 bit */ + +#define NCT6683_REG_FAN_MIN(x) (0x3b8 + (x) * 2) /* 16 bit */ + +#define NCT6683_REG_CUSTOMER_ID 0x602 +#define NCT6683_CUSTOMER_ID_INTEL 0x805 + +#define NCT6683_REG_BUILD_YEAR 0x604 +#define NCT6683_REG_BUILD_MONTH 0x605 +#define NCT6683_REG_BUILD_DAY 0x606 +#define NCT6683_REG_SERIAL 0x607 +#define NCT6683_REG_VERSION_HI 0x608 +#define NCT6683_REG_VERSION_LO 0x609 + +#define NCT6683_REG_CR_CASEOPEN 0xe8 +#define NCT6683_CR_CASEOPEN_MASK (1 << 7) + +#define NCT6683_REG_CR_BEEP 0xe0 +#define NCT6683_CR_BEEP_MASK (1 << 6) + +static const char *const nct6683_mon_label[] = { + NULL, /* disabled */ + "Local", + "Diode 0 (curr)", + "Diode 1 (curr)", + "Diode 2 (curr)", + "Diode 0 (volt)", + "Diode 1 (volt)", + "Diode 2 (volt)", + "Thermistor 14", + "Thermistor 15", + "Thermistor 16", + "Thermistor 0", + "Thermistor 1", + "Thermistor 2", + "Thermistor 3", + "Thermistor 4", + "Thermistor 5", /* 0x10 */ + "Thermistor 6", + "Thermistor 7", + "Thermistor 8", + "Thermistor 9", + "Thermistor 10", + "Thermistor 11", + "Thermistor 12", + "Thermistor 13", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "PECI 0.0", /* 0x20 */ + "PECI 1.0", + "PECI 2.0", + "PECI 3.0", + "PECI 0.1", + "PECI 1.1", + "PECI 2.1", + "PECI 3.1", + "PECI DIMM 0", + "PECI DIMM 1", + "PECI DIMM 2", + "PECI DIMM 3", + NULL, NULL, NULL, NULL, + "PCH CPU", /* 0x30 */ + "PCH CHIP", + "PCH CHIP CPU MAX", + "PCH MCH", + "PCH DIMM 0", + "PCH DIMM 1", + "PCH DIMM 2", + "PCH DIMM 3", + "SMBus 0", + "SMBus 1", + "SMBus 2", + "SMBus 3", + "SMBus 4", + "SMBus 5", + "DIMM 0", + "DIMM 1", + "DIMM 2", /* 0x40 */ + "DIMM 3", + "AMD TSI Addr 90h", + "AMD TSI Addr 92h", + "AMD TSI Addr 94h", + "AMD TSI Addr 96h", + "AMD TSI Addr 98h", + "AMD TSI Addr 9ah", + "AMD TSI Addr 9ch", + "AMD TSI Addr 9dh", + NULL, NULL, NULL, NULL, NULL, NULL, + "Virtual 0", /* 0x50 */ + "Virtual 1", + "Virtual 2", + "Virtual 3", + "Virtual 4", + "Virtual 5", + "Virtual 6", + "Virtual 7", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "VCC", /* 0x60 voltage sensors */ + "VSB", + "AVSB", + "VTT", + "VBAT", + "VREF", + "VIN0", + "VIN1", + "VIN2", + "VIN3", + "VIN4", + "VIN5", + "VIN6", + "VIN7", + "VIN8", + "VIN9", + "VIN10", + "VIN11", + "VIN12", + "VIN13", + "VIN14", + "VIN15", + "VIN16", +}; + +#define NUM_MON_LABELS ARRAY_SIZE(nct6683_mon_label) +#define MON_VOLTAGE_START 0x60 + +/* ------------------------------------------------------- */ + +struct nct6683_data { + int addr; /* IO base of EC space */ + int sioreg; /* SIO register */ + enum kinds kind; + u16 customer_id; + + struct device *hwmon_dev; + const struct attribute_group *groups[6]; + + int temp_num; /* number of temperature attributes */ + u8 temp_index[NCT6683_NUM_REG_MON]; + u8 temp_src[NCT6683_NUM_REG_MON]; + + u8 in_num; /* number of voltage attributes */ + u8 in_index[NCT6683_NUM_REG_MON]; + u8 in_src[NCT6683_NUM_REG_MON]; + + struct mutex update_lock; /* used to protect sensor updates */ + bool valid; /* true if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* Voltage attribute values */ + u8 in[3][NCT6683_NUM_REG_MON]; /* [0]=in, [1]=in_max, [2]=in_min */ + + /* Temperature attribute values */ + s16 temp_in[NCT6683_NUM_REG_MON]; + s8 temp[4][NCT6683_NUM_REG_MON];/* [0]=min, [1]=max, [2]=hyst, + * [3]=crit + */ + + /* Fan attribute values */ + unsigned int rpm[NCT6683_NUM_REG_FAN]; + u16 fan_min[NCT6683_NUM_REG_FAN]; + u8 fanin_cfg[NCT6683_NUM_REG_FAN]; + u8 fanout_cfg[NCT6683_NUM_REG_FAN]; + u16 have_fan; /* some fan inputs can be disabled */ + + u8 have_pwm; + u8 pwm[NCT6683_NUM_REG_PWM]; + +#ifdef CONFIG_PM + /* Remember extra register values over suspend/resume */ + u8 hwm_cfg; +#endif +}; + +struct nct6683_sio_data { + int sioreg; + enum kinds kind; +}; + +struct sensor_device_template { + struct device_attribute dev_attr; + union { + struct { + u8 nr; + u8 index; + } s; + int index; + } u; + bool s2; /* true if both index and nr are used */ +}; + +struct sensor_device_attr_u { + union { + struct sensor_device_attribute a1; + struct sensor_device_attribute_2 a2; + } u; + char name[32]; +}; + +#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \ + .attr = {.name = _template, .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +} + +#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \ + { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \ + .u.index = _index, \ + .s2 = false } + +#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \ + _nr, _index) \ + { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \ + .u.s.index = _index, \ + .u.s.nr = _nr, \ + .s2 = true } + +#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \ +static struct sensor_device_template sensor_dev_template_##_name \ + = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \ + _index) + +#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \ + _nr, _index) \ +static struct sensor_device_template sensor_dev_template_##_name \ + = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \ + _nr, _index) + +struct sensor_template_group { + struct sensor_device_template **templates; + umode_t (*is_visible)(struct kobject *, struct attribute *, int); + int base; +}; + +static struct attribute_group * +nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg, + int repeat) +{ + struct sensor_device_attribute_2 *a2; + struct sensor_device_attribute *a; + struct sensor_device_template **t; + struct sensor_device_attr_u *su; + struct attribute_group *group; + struct attribute **attrs; + int i, j, count; + + if (repeat <= 0) + return ERR_PTR(-EINVAL); + + t = tg->templates; + for (count = 0; *t; t++, count++) + ; + + if (count == 0) + return ERR_PTR(-EINVAL); + + group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL); + if (group == NULL) + return ERR_PTR(-ENOMEM); + + attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1), + GFP_KERNEL); + if (attrs == NULL) + return ERR_PTR(-ENOMEM); + + su = devm_kzalloc(dev, sizeof(*su) * repeat * count, + GFP_KERNEL); + if (su == NULL) + return ERR_PTR(-ENOMEM); + + group->attrs = attrs; + group->is_visible = tg->is_visible; + + for (i = 0; i < repeat; i++) { + t = tg->templates; + for (j = 0; *t != NULL; j++) { + snprintf(su->name, sizeof(su->name), + (*t)->dev_attr.attr.name, tg->base + i); + if ((*t)->s2) { + a2 = &su->u.a2; + a2->dev_attr.attr.name = su->name; + a2->nr = (*t)->u.s.nr + i; + a2->index = (*t)->u.s.index; + a2->dev_attr.attr.mode = + (*t)->dev_attr.attr.mode; + a2->dev_attr.show = (*t)->dev_attr.show; + a2->dev_attr.store = (*t)->dev_attr.store; + *attrs = &a2->dev_attr.attr; + } else { + a = &su->u.a1; + a->dev_attr.attr.name = su->name; + a->index = (*t)->u.index + i; + a->dev_attr.attr.mode = + (*t)->dev_attr.attr.mode; + a->dev_attr.show = (*t)->dev_attr.show; + a->dev_attr.store = (*t)->dev_attr.store; + *attrs = &a->dev_attr.attr; + } + attrs++; + su++; + t++; + } + } + + return group; +} + +/* LSB is 16 mV, except for the following sources, where it is 32 mV */ +#define MON_SRC_VCC 0x60 +#define MON_SRC_VSB 0x61 +#define MON_SRC_AVSB 0x62 +#define MON_SRC_VBAT 0x64 + +static inline long in_from_reg(u16 reg, u8 src) +{ + int scale = 16; + + if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB || + src == MON_SRC_VBAT) + scale <<= 1; + return reg * scale; +} + +static inline u16 in_to_reg(u32 val, u8 src) +{ + int scale = 16; + + if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB || + src == MON_SRC_VBAT) + scale <<= 1; + + return clamp_val(DIV_ROUND_CLOSEST(val, scale), 0, 127); +} + +static u16 nct6683_read(struct nct6683_data *data, u16 reg) +{ + int res; + + outb_p(0xff, data->addr + EC_PAGE_REG); /* unlock */ + outb_p(reg >> 8, data->addr + EC_PAGE_REG); + outb_p(reg & 0xff, data->addr + EC_INDEX_REG); + res = inb_p(data->addr + EC_DATA_REG); + return res; +} + +static u16 nct6683_read16(struct nct6683_data *data, u16 reg) +{ + return (nct6683_read(data, reg) << 8) | nct6683_read(data, reg + 1); +} + +static void nct6683_write(struct nct6683_data *data, u16 reg, u16 value) +{ + outb_p(0xff, data->addr + EC_PAGE_REG); /* unlock */ + outb_p(reg >> 8, data->addr + EC_PAGE_REG); + outb_p(reg & 0xff, data->addr + EC_INDEX_REG); + outb_p(value & 0xff, data->addr + EC_DATA_REG); +} + +static int get_in_reg(struct nct6683_data *data, int nr, int index) +{ + int ch = data->in_index[index]; + int reg = -EINVAL; + + switch (nr) { + case 0: + reg = NCT6683_REG_MON(ch); + break; + case 1: + if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL) + reg = NCT6683_REG_MON_LOW(ch); + break; + case 2: + if (data->customer_id != NCT6683_CUSTOMER_ID_INTEL) + reg = NCT6683_REG_MON_HIGH(ch); + break; + default: + break; + } + return reg; +} + +static int get_temp_reg(struct nct6683_data *data, int nr, int index) +{ + int ch = data->temp_index[index]; + int reg = -EINVAL; + + switch (data->customer_id) { + case NCT6683_CUSTOMER_ID_INTEL: + switch (nr) { + default: + case 1: /* max */ + reg = NCT6683_REG_INTEL_TEMP_MAX(ch); + break; + case 3: /* crit */ + reg = NCT6683_REG_INTEL_TEMP_CRIT(ch); + break; + } + break; + default: + switch (nr) { + default: + case 0: /* min */ + reg = NCT6683_REG_MON_LOW(ch); + break; + case 1: /* max */ + reg = NCT6683_REG_TEMP_MAX(ch); + break; + case 2: /* hyst */ + reg = NCT6683_REG_TEMP_HYST(ch); + break; + case 3: /* crit */ + reg = NCT6683_REG_MON_HIGH(ch); + break; + } + break; + } + return reg; +} + +static void nct6683_update_pwm(struct device *dev) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + int i; + + for (i = 0; i < NCT6683_NUM_REG_PWM; i++) { + if (!(data->have_pwm & (1 << i))) + continue; + data->pwm[i] = nct6683_read(data, NCT6683_REG_PWM(i)); + } +} + +static struct nct6683_data *nct6683_update_device(struct device *dev) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + int i, j; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + /* Measured voltages and limits */ + for (i = 0; i < data->in_num; i++) { + for (j = 0; j < 3; j++) { + int reg = get_in_reg(data, j, i); + + if (reg >= 0) + data->in[j][i] = + nct6683_read(data, reg); + } + } + + /* Measured temperatures and limits */ + for (i = 0; i < data->temp_num; i++) { + u8 ch = data->temp_index[i]; + + data->temp_in[i] = nct6683_read16(data, + NCT6683_REG_MON(ch)); + for (j = 0; j < 4; j++) { + int reg = get_temp_reg(data, j, i); + + if (reg >= 0) + data->temp[j][i] = + nct6683_read(data, reg); + } + } + + /* Measured fan speeds and limits */ + for (i = 0; i < ARRAY_SIZE(data->rpm); i++) { + if (!(data->have_fan & (1 << i))) + continue; + + data->rpm[i] = nct6683_read16(data, + NCT6683_REG_FAN_RPM(i)); + data->fan_min[i] = nct6683_read16(data, + NCT6683_REG_FAN_MIN(i)); + } + + nct6683_update_pwm(dev); + + data->last_updated = jiffies; + data->valid = true; + } + + mutex_unlock(&data->update_lock); + return data; +} + +/* + * Sysfs callback functions + */ +static ssize_t +show_in_label(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int nr = sattr->index; + + return sprintf(buf, "%s\n", nct6683_mon_label[data->in_src[nr]]); +} + +static ssize_t +show_in_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int index = sattr->index; + int nr = sattr->nr; + + return sprintf(buf, "%ld\n", + in_from_reg(data->in[index][nr], data->in_index[index])); +} + +static umode_t nct6683_in_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct6683_data *data = dev_get_drvdata(dev); + int nr = index % 4; /* attribute */ + + /* + * Voltage limits exist for Intel boards, + * but register location and encoding is unknown + */ + if ((nr == 2 || nr == 3) && + data->customer_id == NCT6683_CUSTOMER_ID_INTEL) + return 0; + + return attr->mode; +} + +SENSOR_TEMPLATE(in_label, "in%d_label", S_IRUGO, show_in_label, NULL, 0); +SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0); +SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IRUGO, show_in_reg, NULL, 0, 1); +SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IRUGO, show_in_reg, NULL, 0, 2); + +static struct sensor_device_template *nct6683_attributes_in_template[] = { + &sensor_dev_template_in_label, + &sensor_dev_template_in_input, + &sensor_dev_template_in_min, + &sensor_dev_template_in_max, + NULL +}; + +static struct sensor_template_group nct6683_in_template_group = { + .templates = nct6683_attributes_in_template, + .is_visible = nct6683_in_is_visible, +}; + +static ssize_t +show_fan(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + + return sprintf(buf, "%d\n", data->rpm[sattr->index]); +} + +static ssize_t +show_fan_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = nct6683_update_device(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + int nr = sattr->index; + + return sprintf(buf, "%d\n", data->fan_min[nr]); +} + +static ssize_t +show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + + return sprintf(buf, "%d\n", + ((data->fanin_cfg[sattr->index] >> 5) & 0x03) + 1); +} + +static umode_t nct6683_fan_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct6683_data *data = dev_get_drvdata(dev); + int fan = index / 3; /* fan index */ + int nr = index % 3; /* attribute index */ + + if (!(data->have_fan & (1 << fan))) + return 0; + + /* + * Intel may have minimum fan speed limits, + * but register location and encoding are unknown. + */ + if (nr == 2 && data->customer_id == NCT6683_CUSTOMER_ID_INTEL) + return 0; + + return attr->mode; +} + +SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0); +SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IRUGO, show_fan_pulses, NULL, 0); +SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IRUGO, show_fan_min, NULL, 0); + +/* + * nct6683_fan_is_visible uses the index into the following array + * to determine if attributes should be created or not. + * Any change in order or content must be matched. + */ +static struct sensor_device_template *nct6683_attributes_fan_template[] = { + &sensor_dev_template_fan_input, + &sensor_dev_template_fan_pulses, + &sensor_dev_template_fan_min, + NULL +}; + +static struct sensor_template_group nct6683_fan_template_group = { + .templates = nct6683_attributes_fan_template, + .is_visible = nct6683_fan_is_visible, + .base = 1, +}; + +static ssize_t +show_temp_label(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int nr = sattr->index; + + return sprintf(buf, "%s\n", nct6683_mon_label[data->temp_src[nr]]); +} + +static ssize_t +show_temp8(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int index = sattr->index; + int nr = sattr->nr; + + return sprintf(buf, "%d\n", data->temp[index][nr] * 1000); +} + +static ssize_t +show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int nr = sattr->index; + int temp = data->temp[1][nr] - data->temp[2][nr]; + + return sprintf(buf, "%d\n", temp * 1000); +} + +static ssize_t +show_temp16(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct6683_data *data = nct6683_update_device(dev); + int index = sattr->index; + + return sprintf(buf, "%d\n", (data->temp_in[index] / 128) * 500); +} + +/* + * Temperature sensor type is determined by temperature source + * and can not be modified. + * 0x02..0x07: Thermal diode + * 0x08..0x18: Thermistor + * 0x20..0x2b: Intel PECI + * 0x42..0x49: AMD TSI + * Others are unspecified (not visible) + */ + +static int get_temp_type(u8 src) +{ + if (src >= 0x02 && src <= 0x07) + return 3; /* thermal diode */ + else if (src >= 0x08 && src <= 0x18) + return 4; /* thermistor */ + else if (src >= 0x20 && src <= 0x2b) + return 6; /* PECI */ + else if (src >= 0x42 && src <= 0x49) + return 5; + + return 0; +} + +static ssize_t +show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = nct6683_update_device(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + int nr = sattr->index; + return sprintf(buf, "%d\n", get_temp_type(data->temp_src[nr])); +} + +static umode_t nct6683_temp_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct6683_data *data = dev_get_drvdata(dev); + int temp = index / 7; /* temp index */ + int nr = index % 7; /* attribute index */ + + /* + * Intel does not have low temperature limits or temperature hysteresis + * registers, or at least register location and encoding is unknown. + */ + if ((nr == 2 || nr == 4) && + data->customer_id == NCT6683_CUSTOMER_ID_INTEL) + return 0; + + if (nr == 6 && get_temp_type(data->temp_src[temp]) == 0) + return 0; /* type */ + + return attr->mode; +} + +SENSOR_TEMPLATE(temp_input, "temp%d_input", S_IRUGO, show_temp16, NULL, 0); +SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0); +SENSOR_TEMPLATE_2(temp_min, "temp%d_min", S_IRUGO, show_temp8, NULL, 0, 0); +SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO, show_temp8, NULL, 0, 1); +SENSOR_TEMPLATE(temp_max_hyst, "temp%d_max_hyst", S_IRUGO, show_temp_hyst, NULL, + 0); +SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO, show_temp8, NULL, 0, 3); +SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO, show_temp_type, NULL, 0); + +/* + * nct6683_temp_is_visible uses the index into the following array + * to determine if attributes should be created or not. + * Any change in order or content must be matched. + */ +static struct sensor_device_template *nct6683_attributes_temp_template[] = { + &sensor_dev_template_temp_input, + &sensor_dev_template_temp_label, + &sensor_dev_template_temp_min, /* 2 */ + &sensor_dev_template_temp_max, /* 3 */ + &sensor_dev_template_temp_max_hyst, /* 4 */ + &sensor_dev_template_temp_crit, /* 5 */ + &sensor_dev_template_temp_type, /* 6 */ + NULL +}; + +static struct sensor_template_group nct6683_temp_template_group = { + .templates = nct6683_attributes_temp_template, + .is_visible = nct6683_temp_is_visible, + .base = 1, +}; + +static ssize_t +show_pwm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = nct6683_update_device(dev); + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int index = sattr->index; + + return sprintf(buf, "%d\n", data->pwm[index]); +} + +SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, NULL, 0); + +static umode_t nct6683_pwm_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nct6683_data *data = dev_get_drvdata(dev); + int pwm = index; /* pwm index */ + + if (!(data->have_pwm & (1 << pwm))) + return 0; + + return attr->mode; +} + +static struct sensor_device_template *nct6683_attributes_pwm_template[] = { + &sensor_dev_template_pwm, + NULL +}; + +static struct sensor_template_group nct6683_pwm_template_group = { + .templates = nct6683_attributes_pwm_template, + .is_visible = nct6683_pwm_is_visible, + .base = 1, +}; + +static ssize_t +show_global_beep(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + int ret; + u8 reg; + + mutex_lock(&data->update_lock); + + ret = superio_enter(data->sioreg); + if (ret) + goto error; + superio_select(data->sioreg, NCT6683_LD_HWM); + reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP); + superio_exit(data->sioreg); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%u\n", !!(reg & NCT6683_CR_BEEP_MASK)); + +error: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t +store_global_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + unsigned long val; + u8 reg; + int ret; + + if (kstrtoul(buf, 10, &val) || (val != 0 && val != 1)) + return -EINVAL; + + mutex_lock(&data->update_lock); + + ret = superio_enter(data->sioreg); + if (ret) { + count = ret; + goto error; + } + + superio_select(data->sioreg, NCT6683_LD_HWM); + reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP); + if (val) + reg |= NCT6683_CR_BEEP_MASK; + else + reg &= ~NCT6683_CR_BEEP_MASK; + superio_outb(data->sioreg, NCT6683_REG_CR_BEEP, reg); + superio_exit(data->sioreg); +error: + mutex_unlock(&data->update_lock); + return count; +} + +/* Case open detection */ + +static ssize_t +show_caseopen(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + int ret; + u8 reg; + + mutex_lock(&data->update_lock); + + ret = superio_enter(data->sioreg); + if (ret) + goto error; + superio_select(data->sioreg, NCT6683_LD_ACPI); + reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN); + superio_exit(data->sioreg); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%u\n", !(reg & NCT6683_CR_CASEOPEN_MASK)); + +error: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t +clear_caseopen(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + unsigned long val; + u8 reg; + int ret; + + if (kstrtoul(buf, 10, &val) || val != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + + /* + * Use CR registers to clear caseopen status. + * Caseopen is activ low, clear by writing 1 into the register. + */ + + ret = superio_enter(data->sioreg); + if (ret) { + count = ret; + goto error; + } + + superio_select(data->sioreg, NCT6683_LD_ACPI); + reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN); + reg |= NCT6683_CR_CASEOPEN_MASK; + superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg); + reg &= ~NCT6683_CR_CASEOPEN_MASK; + superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg); + superio_exit(data->sioreg); + + data->valid = false; /* Force cache refresh */ +error: + mutex_unlock(&data->update_lock); + return count; +} + +static DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_caseopen, + clear_caseopen); +static DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_global_beep, + store_global_beep); + +static struct attribute *nct6683_attributes_other[] = { + &dev_attr_intrusion0_alarm.attr, + &dev_attr_beep_enable.attr, + NULL +}; + +static const struct attribute_group nct6683_group_other = { + .attrs = nct6683_attributes_other, +}; + +/* Get the monitoring functions started */ +static inline void nct6683_init_device(struct nct6683_data *data) +{ + u8 tmp; + + /* Start hardware monitoring if needed */ + tmp = nct6683_read(data, NCT6683_HWM_CFG); + if (!(tmp & 0x80)) + nct6683_write(data, NCT6683_HWM_CFG, tmp | 0x80); +} + +/* + * There are a total of 24 fan inputs. Each can be configured as input + * or as output. A maximum of 16 inputs and 8 outputs is configurable. + */ +static void +nct6683_setup_fans(struct nct6683_data *data) +{ + int i; + u8 reg; + + for (i = 0; i < NCT6683_NUM_REG_FAN; i++) { + reg = nct6683_read(data, NCT6683_REG_FANIN_CFG(i)); + if (reg & 0x80) + data->have_fan |= 1 << i; + data->fanin_cfg[i] = reg; + } + for (i = 0; i < NCT6683_NUM_REG_PWM; i++) { + reg = nct6683_read(data, NCT6683_REG_FANOUT_CFG(i)); + if (reg & 0x80) + data->have_pwm |= 1 << i; + data->fanout_cfg[i] = reg; + } +} + +/* + * Translation from monitoring register to temperature and voltage attributes + * ========================================================================== + * + * There are a total of 32 monitoring registers. Each can be assigned to either + * a temperature or voltage monitoring source. + * NCT6683_REG_MON_CFG(x) defines assignment for each monitoring source. + * + * Temperature and voltage attribute mapping is determined by walking through + * the NCT6683_REG_MON_CFG registers. If the assigned source is + * a temperature, temp_index[n] is set to the monitor register index, and + * temp_src[n] is set to the temperature source. If the assigned source is + * a voltage, the respective values are stored in in_index[] and in_src[], + * respectively. + */ + +static void nct6683_setup_sensors(struct nct6683_data *data) +{ + u8 reg; + int i; + + data->temp_num = 0; + data->in_num = 0; + for (i = 0; i < NCT6683_NUM_REG_MON; i++) { + reg = nct6683_read(data, NCT6683_REG_MON_CFG(i)) & 0x7f; + /* Ignore invalid assignments */ + if (reg >= NUM_MON_LABELS) + continue; + /* Skip if disabled or reserved */ + if (nct6683_mon_label[reg] == NULL) + continue; + if (reg < MON_VOLTAGE_START) { + data->temp_index[data->temp_num] = i; + data->temp_src[data->temp_num] = reg; + data->temp_num++; + } else { + data->in_index[data->in_num] = i; + data->in_src[data->in_num] = reg; + data->in_num++; + } + } +} + +static int nct6683_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct nct6683_sio_data *sio_data = dev->platform_data; + struct attribute_group *group; + struct nct6683_data *data; + struct device *hwmon_dev; + struct resource *res; + int groups = 0; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME)) + return -EBUSY; + + data = devm_kzalloc(dev, sizeof(struct nct6683_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->kind = sio_data->kind; + data->sioreg = sio_data->sioreg; + data->addr = res->start; + mutex_init(&data->update_lock); + platform_set_drvdata(pdev, data); + + data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID); + + nct6683_init_device(data); + nct6683_setup_fans(data); + nct6683_setup_sensors(data); + + /* Register sysfs hooks */ + + if (data->have_pwm) { + group = nct6683_create_attr_group(dev, + &nct6683_pwm_template_group, + fls(data->have_pwm)); + if (IS_ERR(group)) + return PTR_ERR(group); + data->groups[groups++] = group; + } + + if (data->in_num) { + group = nct6683_create_attr_group(dev, + &nct6683_in_template_group, + data->in_num); + if (IS_ERR(group)) + return PTR_ERR(group); + data->groups[groups++] = group; + } + + if (data->have_fan) { + group = nct6683_create_attr_group(dev, + &nct6683_fan_template_group, + fls(data->have_fan)); + if (IS_ERR(group)) + return PTR_ERR(group); + data->groups[groups++] = group; + } + + if (data->temp_num) { + group = nct6683_create_attr_group(dev, + &nct6683_temp_template_group, + data->temp_num); + if (IS_ERR(group)) + return PTR_ERR(group); + data->groups[groups++] = group; + } + data->groups[groups++] = &nct6683_group_other; + + dev_info(dev, "%s EC firmware version %d.%d build %02x/%02x/%02x\n", + nct6683_chip_names[data->kind], + nct6683_read(data, NCT6683_REG_VERSION_HI), + nct6683_read(data, NCT6683_REG_VERSION_LO), + nct6683_read(data, NCT6683_REG_BUILD_MONTH), + nct6683_read(data, NCT6683_REG_BUILD_DAY), + nct6683_read(data, NCT6683_REG_BUILD_YEAR)); + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, + nct6683_device_names[data->kind], data, data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +#ifdef CONFIG_PM +static int nct6683_suspend(struct device *dev) +{ + struct nct6683_data *data = nct6683_update_device(dev); + + mutex_lock(&data->update_lock); + data->hwm_cfg = nct6683_read(data, NCT6683_HWM_CFG); + mutex_unlock(&data->update_lock); + + return 0; +} + +static int nct6683_resume(struct device *dev) +{ + struct nct6683_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->update_lock); + + nct6683_write(data, NCT6683_HWM_CFG, data->hwm_cfg); + + /* Force re-reading all values */ + data->valid = false; + mutex_unlock(&data->update_lock); + + return 0; +} + +static const struct dev_pm_ops nct6683_dev_pm_ops = { + .suspend = nct6683_suspend, + .resume = nct6683_resume, + .freeze = nct6683_suspend, + .restore = nct6683_resume, +}; + +#define NCT6683_DEV_PM_OPS (&nct6683_dev_pm_ops) +#else +#define NCT6683_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + +static struct platform_driver nct6683_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + .pm = NCT6683_DEV_PM_OPS, + }, + .probe = nct6683_probe, +}; + +static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data) +{ + const char *board_vendor; + int addr; + u16 val; + int err; + + /* + * Only run on Intel boards unless the 'force' module parameter is set + */ + if (!force) { + board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); + if (!board_vendor || strcmp(board_vendor, "Intel Corporation")) + return -ENODEV; + } + + err = superio_enter(sioaddr); + if (err) + return err; + + val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) + | superio_inb(sioaddr, SIO_REG_DEVID + 1); + + switch (val & SIO_ID_MASK) { + case SIO_NCT6683_ID: + sio_data->kind = nct6683; + break; + default: + if (val != 0xffff) + pr_debug("unsupported chip ID: 0x%04x\n", val); + goto fail; + } + + /* We have a known chip, find the HWM I/O address */ + superio_select(sioaddr, NCT6683_LD_HWM); + val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8) + | superio_inb(sioaddr, SIO_REG_ADDR + 1); + addr = val & IOREGION_ALIGNMENT; + if (addr == 0) { + pr_err("EC base I/O port unconfigured\n"); + goto fail; + } + + /* Activate logical device if needed */ + val = superio_inb(sioaddr, SIO_REG_ENABLE); + if (!(val & 0x01)) { + pr_err("EC is disabled\n"); + goto fail; + } + + superio_exit(sioaddr); + pr_info("Found %s or compatible chip at %#x:%#x\n", + nct6683_chip_names[sio_data->kind], sioaddr, addr); + sio_data->sioreg = sioaddr; + + return addr; + +fail: + superio_exit(sioaddr); + return -ENODEV; +} + +/* + * when Super-I/O functions move to a separate file, the Super-I/O + * bus will manage the lifetime of the device and this module will only keep + * track of the nct6683 driver. But since we use platform_device_alloc(), we + * must keep track of the device + */ +static struct platform_device *pdev[2]; + +static int __init sensors_nct6683_init(void) +{ + struct nct6683_sio_data sio_data; + int sioaddr[2] = { 0x2e, 0x4e }; + struct resource res; + bool found = false; + int address; + int i, err; + + err = platform_driver_register(&nct6683_driver); + if (err) + return err; + + /* + * initialize sio_data->kind and sio_data->sioreg. + * + * when Super-I/O functions move to a separate file, the Super-I/O + * driver will probe 0x2e and 0x4e and auto-detect the presence of a + * nct6683 hardware monitor, and call probe() + */ + for (i = 0; i < ARRAY_SIZE(pdev); i++) { + address = nct6683_find(sioaddr[i], &sio_data); + if (address <= 0) + continue; + + found = true; + + pdev[i] = platform_device_alloc(DRVNAME, address); + if (!pdev[i]) { + err = -ENOMEM; + goto exit_device_put; + } + + err = platform_device_add_data(pdev[i], &sio_data, + sizeof(struct nct6683_sio_data)); + if (err) + goto exit_device_put; + + memset(&res, 0, sizeof(res)); + res.name = DRVNAME; + res.start = address + IOREGION_OFFSET; + res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; + res.flags = IORESOURCE_IO; + + err = acpi_check_resource_conflict(&res); + if (err) { + platform_device_put(pdev[i]); + pdev[i] = NULL; + continue; + } + + err = platform_device_add_resources(pdev[i], &res, 1); + if (err) + goto exit_device_put; + + /* platform_device_add calls probe() */ + err = platform_device_add(pdev[i]); + if (err) + goto exit_device_put; + } + if (!found) { + err = -ENODEV; + goto exit_unregister; + } + + return 0; + +exit_device_put: + for (i = 0; i < ARRAY_SIZE(pdev); i++) { + if (pdev[i]) + platform_device_put(pdev[i]); + } +exit_unregister: + platform_driver_unregister(&nct6683_driver); + return err; +} + +static void __exit sensors_nct6683_exit(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pdev); i++) { + if (pdev[i]) + platform_device_unregister(pdev[i]); + } + platform_driver_unregister(&nct6683_driver); +} + +MODULE_AUTHOR("Guenter Roeck "); +MODULE_DESCRIPTION("NCT6683D driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_nct6683_init); +module_exit(sensors_nct6683_exit); -- cgit v1.2.3-59-g8ed1b From e8cba3cda44e1b042a64ab43d15d4d77c2038235 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Tue, 20 May 2014 23:45:37 +0530 Subject: hwmon: (ultra45_env) Introduce managed version of kzalloc This patch moves data allocated using kzalloc to managed data allocated using devm_kzalloc and cleans now unnecessary kfrees in probe and remove functions. Also, the unnecessary label out_free is removed. The following Coccinelle semantic patch was used for making the change: @platform@ identifier p, probefn, removefn; @@ struct platform_driver p = { .probe = probefn, .remove = removefn, }; @prb@ identifier platform.probefn, pdev; expression e, e1, e2; @@ probefn(struct platform_device *pdev, ...) { <+... - e = kzalloc(e1, e2) + e = devm_kzalloc(&pdev->dev, e1, e2) ... ?-kfree(e); ...+> } @rem depends on prb@ identifier platform.removefn; expression e; @@ removefn(...) { <... - kfree(e); ...> } Signed-off-by: Himangi Saraogi Signed-off-by: Guenter Roeck --- drivers/hwmon/ultra45_env.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index fb3e69341c1b..7d4658636064 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -252,7 +252,7 @@ static const struct attribute_group env_group = { static int env_probe(struct platform_device *op) { - struct env *p = kzalloc(sizeof(*p), GFP_KERNEL); + struct env *p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL); int err = -ENOMEM; if (!p) @@ -262,7 +262,7 @@ static int env_probe(struct platform_device *op) p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747"); if (!p->regs) - goto out_free; + goto out; err = sysfs_create_group(&op->dev.kobj, &env_group); if (err) @@ -286,8 +286,6 @@ out_sysfs_remove_group: out_iounmap: of_iounmap(&op->resource[0], p->regs, REG_SIZE); -out_free: - kfree(p); goto out; } @@ -299,7 +297,6 @@ static int env_remove(struct platform_device *op) sysfs_remove_group(&op->dev.kobj, &env_group); hwmon_device_unregister(p->hwmon_dev); of_iounmap(&op->resource[0], p->regs, REG_SIZE); - kfree(p); } return 0; -- cgit v1.2.3-59-g8ed1b From 30190c3c6181470203e6f635166496aa640ffe06 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 24 May 2014 23:04:22 +0800 Subject: hwmon: (nct6683) Fix probe unwind paths to properly unregister platform devices Call platform_device_unregister() rather than platform_device_put() to unregister successfully registered platform devices. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6683.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index 540c81c52344..7710f4694ba1 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -1389,7 +1389,7 @@ static int __init sensors_nct6683_init(void) pdev[i] = platform_device_alloc(DRVNAME, address); if (!pdev[i]) { err = -ENOMEM; - goto exit_device_put; + goto exit_device_unregister; } err = platform_device_add_data(pdev[i], &sio_data, @@ -1427,9 +1427,11 @@ static int __init sensors_nct6683_init(void) return 0; exit_device_put: - for (i = 0; i < ARRAY_SIZE(pdev); i++) { + platform_device_put(pdev[i]); +exit_device_unregister: + while (--i >= 0) { if (pdev[i]) - platform_device_put(pdev[i]); + platform_device_unregister(pdev[i]); } exit_unregister: platform_driver_unregister(&nct6683_driver); -- cgit v1.2.3-59-g8ed1b From 9d311eddf3565ed0e05b3cb5a22db41fa74d9d86 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 24 May 2014 23:21:23 +0800 Subject: hwmon: (nct6775) Fix probe unwind paths to properly unregister platform devices Call platform_device_unregister() rather than platform_device_put() to unregister successfully registered platform devices. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6775.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 38d5a6334053..59d9a3fc96b7 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -4160,7 +4160,7 @@ static int __init sensors_nct6775_init(void) pdev[i] = platform_device_alloc(DRVNAME, address); if (!pdev[i]) { err = -ENOMEM; - goto exit_device_put; + goto exit_device_unregister; } err = platform_device_add_data(pdev[i], &sio_data, @@ -4198,9 +4198,11 @@ static int __init sensors_nct6775_init(void) return 0; exit_device_put: - for (i = 0; i < ARRAY_SIZE(pdev); i++) { + platform_device_put(pdev[i]); +exit_device_unregister: + while (--i >= 0) { if (pdev[i]) - platform_device_put(pdev[i]); + platform_device_unregister(pdev[i]); } exit_unregister: platform_driver_unregister(&nct6775_driver); -- cgit v1.2.3-59-g8ed1b