Commit cff37c9e authored by Jean Delvare's avatar Jean Delvare

hwmon: (tmp102) Various fixes

Fixes from my driver review:
http://lists.lm-sensors.org/pipermail/lm-sensors/2010-March/028051.html

Only the small changes are in there, more important changes will come
later separately as time permits.

* Drop the remnants of the now gone detect function
* The TMP102 has no known compatible chip
* Include the right header files
* Clarify why byte swapping of register values is needed
* Strip resolution info bit from temperature register value
* Set cache lifetime to 1/3 second
* Don't arbitrarily reject limit values; clamp as needed
* Make limit writing unconditional
* Don't check for transaction types the driver doesn't use
* Properly check for error when setting configuration
* Report error on failed probe
* Make the driver load automatically where needed
* Various other minor fixes
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Cc: Steven King <sfking@fdwdc.com>
parent beb1b6bb
...@@ -4,7 +4,7 @@ Kernel driver tmp102 ...@@ -4,7 +4,7 @@ Kernel driver tmp102
Supported chips: Supported chips:
* Texas Instruments TMP102 * Texas Instruments TMP102
Prefix: 'tmp102' Prefix: 'tmp102'
Addresses scanned: I2C 0x48 0x49 0x4a 0x4b Addresses scanned: none
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp102.html Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp102.html
Author: Author:
...@@ -15,13 +15,12 @@ Description ...@@ -15,13 +15,12 @@ Description
The Texas Instruments TMP102 implements one temperature sensor. Limits can be The Texas Instruments TMP102 implements one temperature sensor. Limits can be
set through the Overtemperature Shutdown register and Hysteresis register. The set through the Overtemperature Shutdown register and Hysteresis register. The
sensor is accurate to 0.5 degrees over the range of -25 to +85 C, and to 1.0 sensor is accurate to 0.5 degree over the range of -25 to +85 C, and to 1.0
degrees from -40 to +125 C. Resolution of the sensor is 0.0625 degree. The degree from -40 to +125 C. Resolution of the sensor is 0.0625 degree. The
operating temperature has a minimum of -55 C and a maximum of +150 C. operating temperature has a minimum of -55 C and a maximum of +150 C.
The TMP102 has a programmable update rate that can select between 8, 4, 1, and The TMP102 has a programmable update rate that can select between 8, 4, 1, and
0.5 Hz. (Currently the driver only supports the default of 4 Hz). 0.5 Hz. (Currently the driver only supports the default of 4 Hz).
The driver provides the common sysfs-interface for temperatures (see The driver provides the common sysfs-interface for temperatures (see
/Documentation/hwmon/sysfs-interface under Temperatures). Documentation/hwmon/sysfs-interface under Temperatures).
...@@ -843,7 +843,7 @@ config SENSORS_THMC50 ...@@ -843,7 +843,7 @@ config SENSORS_THMC50
will be called thmc50. will be called thmc50.
config SENSORS_TMP102 config SENSORS_TMP102
tristate "Texas Instruments TMP102 and compatibles" tristate "Texas Instruments TMP102"
depends on I2C && EXPERIMENTAL depends on I2C && EXPERIMENTAL
help help
If you say yes here you get support for Texas Instruments TMP102 If you say yes here you get support for Texas Instruments TMP102
......
/* Texas Instruments TMP102 SMBUS temperature sensor driver /* Texas Instruments TMP102 SMBus temperature sensor driver
* *
* Copyright 2010 Steven King <sfking@fdwdc.com> * Copyright (C) 2010 Steven King <sfking@fdwdc.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -17,8 +17,6 @@ ...@@ -17,8 +17,6 @@
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -27,7 +25,7 @@ ...@@ -27,7 +25,7 @@
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/delay.h> #include <linux/device.h>
#define DRIVER_NAME "tmp102" #define DRIVER_NAME "tmp102"
...@@ -56,26 +54,27 @@ struct tmp102 { ...@@ -56,26 +54,27 @@ struct tmp102 {
int temp[3]; int temp[3];
}; };
/* the TMP102 registers are big endian so we have to swab16 the values */ /* SMBus specifies low byte first, but the TMP102 returns high byte first,
static int tmp102_read_reg(struct i2c_client *client, u8 reg) * so we have to swab16 the values */
static inline int tmp102_read_reg(struct i2c_client *client, u8 reg)
{ {
int result = i2c_smbus_read_word_data(client, reg); int result = i2c_smbus_read_word_data(client, reg);
return result < 0 ? result : swab16(result); return result < 0 ? result : swab16(result);
} }
static int tmp102_write_reg(struct i2c_client *client, u8 reg, u16 val) static inline int tmp102_write_reg(struct i2c_client *client, u8 reg, u16 val)
{ {
return i2c_smbus_write_word_data(client, reg, swab16(val)); return i2c_smbus_write_word_data(client, reg, swab16(val));
} }
/* convert left adjusted 13bit TMP102 register value to miliCelsius */ /* convert left adjusted 13-bit TMP102 register value to milliCelsius */
static int tmp102_reg_to_mC(s16 val) static inline int tmp102_reg_to_mC(s16 val)
{ {
return (val * 1000) / 128; return ((val & ~0x01) * 1000) / 128;
} }
/* convert miliCelsius to left adjusted 13bit TMP102 register value */ /* convert milliCelsius to left adjusted 13-bit TMP102 register value */
static u16 tmp102_mC_to_reg(int val) static inline u16 tmp102_mC_to_reg(int val)
{ {
return (val * 128) / 1000; return (val * 128) / 1000;
} }
...@@ -91,7 +90,7 @@ static struct tmp102 *tmp102_update_device(struct i2c_client *client) ...@@ -91,7 +90,7 @@ static struct tmp102 *tmp102_update_device(struct i2c_client *client)
struct tmp102 *tmp102 = i2c_get_clientdata(client); struct tmp102 *tmp102 = i2c_get_clientdata(client);
mutex_lock(&tmp102->lock); mutex_lock(&tmp102->lock);
if (time_after(jiffies, tmp102->last_update + HZ / 4)) { if (time_after(jiffies, tmp102->last_update + HZ / 3)) {
int i; int i;
for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) { for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) {
int status = tmp102_read_reg(client, tmp102_reg[i]); int status = tmp102_read_reg(client, tmp102_reg[i]);
...@@ -122,16 +121,16 @@ static ssize_t tmp102_set_temp(struct device *dev, ...@@ -122,16 +121,16 @@ static ssize_t tmp102_set_temp(struct device *dev,
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct tmp102 *tmp102 = i2c_get_clientdata(client); struct tmp102 *tmp102 = i2c_get_clientdata(client);
long val; long val;
int status = 0; int status;
if ((strict_strtol(buf, 10, &val) < 0) || (abs(val) > 150000)) if (strict_strtol(buf, 10, &val) < 0)
return -EINVAL; return -EINVAL;
val = SENSORS_LIMIT(val, -256000, 255000);
mutex_lock(&tmp102->lock); mutex_lock(&tmp102->lock);
if (tmp102->temp[sda->index] != val) {
tmp102->temp[sda->index] = val; tmp102->temp[sda->index] = val;
status = tmp102_write_reg(client, tmp102_reg[sda->index], status = tmp102_write_reg(client, tmp102_reg[sda->index],
tmp102_mC_to_reg(val)); tmp102_mC_to_reg(val));
}
mutex_unlock(&tmp102->lock); mutex_unlock(&tmp102->lock);
return status ? : count; return status ? : count;
} }
...@@ -164,9 +163,10 @@ static int __devinit tmp102_probe(struct i2c_client *client, ...@@ -164,9 +163,10 @@ static int __devinit tmp102_probe(struct i2c_client *client,
struct tmp102 *tmp102; struct tmp102 *tmp102;
int status; int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) { I2C_FUNC_SMBUS_WORD_DATA)) {
dev_dbg(&client->dev, "adapter doesnt support SMBUS\n"); dev_err(&client->dev, "adapter doesnt support SMBus word "
"transactions\n");
return -ENODEV; return -ENODEV;
} }
...@@ -177,16 +177,20 @@ static int __devinit tmp102_probe(struct i2c_client *client, ...@@ -177,16 +177,20 @@ static int __devinit tmp102_probe(struct i2c_client *client,
} }
i2c_set_clientdata(client, tmp102); i2c_set_clientdata(client, tmp102);
tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG); status = tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG);
if (status < 0) {
dev_err(&client->dev, "error writing config register\n");
goto fail0;
}
status = tmp102_read_reg(client, TMP102_CONF_REG); status = tmp102_read_reg(client, TMP102_CONF_REG);
if (status < 0) { if (status < 0) {
dev_dbg(&client->dev, "error reading config register\n"); dev_err(&client->dev, "error reading config register\n");
goto fail0; goto fail0;
} }
status &= ~TMP102_CONFIG_RD_ONLY; status &= ~TMP102_CONFIG_RD_ONLY;
if (status != TMP102_CONFIG) { if (status != TMP102_CONFIG) {
dev_dbg(&client->dev, "could not verify config settings\n"); dev_err(&client->dev, "config settings did not stick\n");
status = -EIO; status = -ENODEV;
goto fail0; goto fail0;
} }
tmp102->last_update = jiffies - HZ; tmp102->last_update = jiffies - HZ;
...@@ -213,7 +217,7 @@ static int __devinit tmp102_probe(struct i2c_client *client, ...@@ -213,7 +217,7 @@ static int __devinit tmp102_probe(struct i2c_client *client,
i2c_set_clientdata(client, NULL); i2c_set_clientdata(client, NULL);
kfree(tmp102); kfree(tmp102);
return 0; return status;
} }
static int __devexit tmp102_remove(struct i2c_client *client) static int __devexit tmp102_remove(struct i2c_client *client)
...@@ -260,23 +264,18 @@ static const struct dev_pm_ops tmp102_dev_pm_ops = { ...@@ -260,23 +264,18 @@ static const struct dev_pm_ops tmp102_dev_pm_ops = {
#define TMP102_DEV_PM_OPS NULL #define TMP102_DEV_PM_OPS NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static const unsigned short normal_i2c[] = {
0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END
};
static const struct i2c_device_id tmp102_id[] = { static const struct i2c_device_id tmp102_id[] = {
{ DRIVER_NAME, 0 }, { "tmp102", 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, tmp102_id);
static struct i2c_driver tmp102_driver = { static struct i2c_driver tmp102_driver = {
.driver.name = DRIVER_NAME, .driver.name = DRIVER_NAME,
.driver.pm = TMP102_DEV_PM_OPS, .driver.pm = TMP102_DEV_PM_OPS,
.class = I2C_CLASS_HWMON,
.probe = tmp102_probe, .probe = tmp102_probe,
.remove = __devexit_p(tmp102_remove), .remove = __devexit_p(tmp102_remove),
.id_table = tmp102_id, .id_table = tmp102_id,
.address_list = normal_i2c,
}; };
static int __init tmp102_init(void) static int __init tmp102_init(void)
...@@ -291,7 +290,6 @@ static void __exit tmp102_exit(void) ...@@ -291,7 +290,6 @@ static void __exit tmp102_exit(void)
} }
module_exit(tmp102_exit); module_exit(tmp102_exit);
MODULE_AUTHOR("Steven King <sfking@fdwdc.com>"); MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
MODULE_DESCRIPTION("Texas Instruments TMP102 temperature sensor driver"); MODULE_DESCRIPTION("Texas Instruments TMP102 temperature sensor driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment