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: Jean Delvare <khali@linux-fr.org> Cc: Steven King <sfking@fdwdc.com>
This commit is contained in:
@@ -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
|
|||||||
|
|
||||||
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
|
|||||||
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
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/* 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 @@
|
|||||||
* 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 @@
|
|||||||
#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 {
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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 @@ fail0:
|
|||||||
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 = {
|
|||||||
#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)
|
|||||||
}
|
}
|
||||||
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");
|
||||||
|
Reference in New Issue
Block a user