diff options
| author | Manuel Lauss <mano@roarinelk.homelinux.net> | 2009-01-07 10:37:34 -0500 |
|---|---|---|
| committer | Jean Delvare <khali@linux-fr.org> | 2009-01-07 10:37:34 -0500 |
| commit | c8ac32e4711639c81e5f4d4cd78c8f21675a2bae (patch) | |
| tree | 3ec6572d74cf2fc824a8176aa5f3adeac04002ed | |
| parent | 2b7300513b98e05058a803de3beb8a1c0a0c61d9 (diff) | |
hwmon: (lm70) Add TI TMP121 support
The Texas Instruments TMP121 is a SPI temperature sensor very similar
to the LM70, with slightly higher resolution. This patch extends the
LM70 driver to support the TMP121. The TMP123 differs in pin assign-
ment.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
| -rw-r--r-- | Documentation/hwmon/lm70 | 8 | ||||
| -rw-r--r-- | drivers/hwmon/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/hwmon/lm70.c | 84 |
3 files changed, 84 insertions, 13 deletions
diff --git a/Documentation/hwmon/lm70 b/Documentation/hwmon/lm70 index b8d1a521e689..0d240291e3cc 100644 --- a/Documentation/hwmon/lm70 +++ b/Documentation/hwmon/lm70 | |||
| @@ -1,9 +1,11 @@ | |||
| 1 | Kernel driver lm70 | 1 | Kernel driver lm70 |
| 2 | ================== | 2 | ================== |
| 3 | 3 | ||
| 4 | Supported chip: | 4 | Supported chips: |
| 5 | * National Semiconductor LM70 | 5 | * National Semiconductor LM70 |
| 6 | Datasheet: http://www.national.com/pf/LM/LM70.html | 6 | Datasheet: http://www.national.com/pf/LM/LM70.html |
| 7 | * Texas Instruments TMP121/TMP123 | ||
| 8 | Information: http://focus.ti.com/docs/prod/folders/print/tmp121.html | ||
| 7 | 9 | ||
| 8 | Author: | 10 | Author: |
| 9 | Kaiwan N Billimoria <kaiwan@designergraphix.com> | 11 | Kaiwan N Billimoria <kaiwan@designergraphix.com> |
| @@ -29,6 +31,10 @@ As a real (in-tree) example of this "SPI protocol driver" interfacing | |||
| 29 | with a "SPI master controller driver", see drivers/spi/spi_lm70llp.c | 31 | with a "SPI master controller driver", see drivers/spi/spi_lm70llp.c |
| 30 | and its associated documentation. | 32 | and its associated documentation. |
| 31 | 33 | ||
| 34 | The TMP121/TMP123 are very similar; main differences are 4 wire SPI inter- | ||
| 35 | face (read only) and 13-bit temperature data (0.0625 degrees celsius reso- | ||
| 36 | lution). | ||
| 37 | |||
| 32 | Thanks to | 38 | Thanks to |
| 33 | --------- | 39 | --------- |
| 34 | Jean Delvare <khali@linux-fr.org> for mentoring the hwmon-side driver | 40 | Jean Delvare <khali@linux-fr.org> for mentoring the hwmon-side driver |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 3c34fb5e4194..4b33bc82cc24 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
| @@ -428,11 +428,12 @@ config SENSORS_LM63 | |||
| 428 | will be called lm63. | 428 | will be called lm63. |
| 429 | 429 | ||
| 430 | config SENSORS_LM70 | 430 | config SENSORS_LM70 |
| 431 | tristate "National Semiconductor LM70" | 431 | tristate "National Semiconductor LM70 / Texas Instruments TMP121" |
| 432 | depends on SPI_MASTER && EXPERIMENTAL | 432 | depends on SPI_MASTER && EXPERIMENTAL |
| 433 | help | 433 | help |
| 434 | If you say yes here you get support for the National Semiconductor | 434 | If you say yes here you get support for the National Semiconductor |
| 435 | LM70 digital temperature sensor chip. | 435 | LM70 and Texas Instruments TMP121/TMP123 digital temperature |
| 436 | sensor chips. | ||
| 436 | 437 | ||
| 437 | This driver can also be built as a module. If so, the module | 438 | This driver can also be built as a module. If so, the module |
| 438 | will be called lm70. | 439 | will be called lm70. |
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 9f9741b1d2b5..ae6204f33214 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c | |||
| @@ -37,9 +37,13 @@ | |||
| 37 | 37 | ||
| 38 | #define DRVNAME "lm70" | 38 | #define DRVNAME "lm70" |
| 39 | 39 | ||
| 40 | #define LM70_CHIP_LM70 0 /* original NS LM70 */ | ||
| 41 | #define LM70_CHIP_TMP121 1 /* TI TMP121/TMP123 */ | ||
| 42 | |||
| 40 | struct lm70 { | 43 | struct lm70 { |
| 41 | struct device *hwmon_dev; | 44 | struct device *hwmon_dev; |
| 42 | struct mutex lock; | 45 | struct mutex lock; |
| 46 | unsigned int chip; | ||
| 43 | }; | 47 | }; |
| 44 | 48 | ||
| 45 | /* sysfs hook function */ | 49 | /* sysfs hook function */ |
| @@ -47,7 +51,7 @@ static ssize_t lm70_sense_temp(struct device *dev, | |||
| 47 | struct device_attribute *attr, char *buf) | 51 | struct device_attribute *attr, char *buf) |
| 48 | { | 52 | { |
| 49 | struct spi_device *spi = to_spi_device(dev); | 53 | struct spi_device *spi = to_spi_device(dev); |
| 50 | int status, val; | 54 | int status, val = 0; |
| 51 | u8 rxbuf[2]; | 55 | u8 rxbuf[2]; |
| 52 | s16 raw=0; | 56 | s16 raw=0; |
| 53 | struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); | 57 | struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); |
| @@ -70,6 +74,7 @@ static ssize_t lm70_sense_temp(struct device *dev, | |||
| 70 | rxbuf[0], rxbuf[1], raw); | 74 | rxbuf[0], rxbuf[1], raw); |
| 71 | 75 | ||
| 72 | /* | 76 | /* |
| 77 | * LM70: | ||
| 73 | * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's | 78 | * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's |
| 74 | * complement value. Only the MSB 11 bits (1 sign + 10 temperature | 79 | * complement value. Only the MSB 11 bits (1 sign + 10 temperature |
| 75 | * bits) are meaningful; the LSB 5 bits are to be discarded. | 80 | * bits) are meaningful; the LSB 5 bits are to be discarded. |
| @@ -79,8 +84,21 @@ static ssize_t lm70_sense_temp(struct device *dev, | |||
| 79 | * by 0.25. Also multiply by 1000 to represent in millidegrees | 84 | * by 0.25. Also multiply by 1000 to represent in millidegrees |
| 80 | * Celsius. | 85 | * Celsius. |
| 81 | * So it's equivalent to multiplying by 0.25 * 1000 = 250. | 86 | * So it's equivalent to multiplying by 0.25 * 1000 = 250. |
| 87 | * | ||
| 88 | * TMP121/TMP123: | ||
| 89 | * 13 bits of 2's complement data, discard LSB 3 bits, | ||
| 90 | * resolution 0.0625 degrees celsius. | ||
| 82 | */ | 91 | */ |
| 83 | val = ((int)raw/32) * 250; | 92 | switch (p_lm70->chip) { |
| 93 | case LM70_CHIP_LM70: | ||
| 94 | val = ((int)raw / 32) * 250; | ||
| 95 | break; | ||
| 96 | |||
| 97 | case LM70_CHIP_TMP121: | ||
| 98 | val = ((int)raw / 8) * 625 / 10; | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | |||
| 84 | status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */ | 102 | status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */ |
| 85 | out: | 103 | out: |
| 86 | mutex_unlock(&p_lm70->lock); | 104 | mutex_unlock(&p_lm70->lock); |
| @@ -92,22 +110,31 @@ static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL); | |||
| 92 | static ssize_t lm70_show_name(struct device *dev, struct device_attribute | 110 | static ssize_t lm70_show_name(struct device *dev, struct device_attribute |
| 93 | *devattr, char *buf) | 111 | *devattr, char *buf) |
| 94 | { | 112 | { |
| 95 | return sprintf(buf, "lm70\n"); | 113 | struct lm70 *p_lm70 = dev_get_drvdata(dev); |
| 114 | int ret; | ||
| 115 | |||
| 116 | switch (p_lm70->chip) { | ||
| 117 | case LM70_CHIP_LM70: | ||
| 118 | ret = sprintf(buf, "lm70\n"); | ||
| 119 | break; | ||
| 120 | case LM70_CHIP_TMP121: | ||
| 121 | ret = sprintf(buf, "tmp121\n"); | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | ret = -EINVAL; | ||
| 125 | } | ||
| 126 | return ret; | ||
| 96 | } | 127 | } |
| 97 | 128 | ||
| 98 | static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL); | 129 | static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL); |
| 99 | 130 | ||
| 100 | /*----------------------------------------------------------------------*/ | 131 | /*----------------------------------------------------------------------*/ |
| 101 | 132 | ||
| 102 | static int __devinit lm70_probe(struct spi_device *spi) | 133 | static int __devinit common_probe(struct spi_device *spi, int chip) |
| 103 | { | 134 | { |
| 104 | struct lm70 *p_lm70; | 135 | struct lm70 *p_lm70; |
| 105 | int status; | 136 | int status; |
| 106 | 137 | ||
| 107 | /* signaling is SPI_MODE_0 on a 3-wire link (shared SI/SO) */ | ||
| 108 | if ((spi->mode & (SPI_CPOL|SPI_CPHA)) || !(spi->mode & SPI_3WIRE)) | ||
| 109 | return -EINVAL; | ||
| 110 | |||
| 111 | /* NOTE: we assume 8-bit words, and convert to 16 bits manually */ | 138 | /* NOTE: we assume 8-bit words, and convert to 16 bits manually */ |
| 112 | 139 | ||
| 113 | p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL); | 140 | p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL); |
| @@ -115,6 +142,7 @@ static int __devinit lm70_probe(struct spi_device *spi) | |||
| 115 | return -ENOMEM; | 142 | return -ENOMEM; |
| 116 | 143 | ||
| 117 | mutex_init(&p_lm70->lock); | 144 | mutex_init(&p_lm70->lock); |
| 145 | p_lm70->chip = chip; | ||
| 118 | 146 | ||
| 119 | /* sysfs hook */ | 147 | /* sysfs hook */ |
| 120 | p_lm70->hwmon_dev = hwmon_device_register(&spi->dev); | 148 | p_lm70->hwmon_dev = hwmon_device_register(&spi->dev); |
| @@ -142,6 +170,24 @@ out_dev_reg_failed: | |||
| 142 | return status; | 170 | return status; |
| 143 | } | 171 | } |
| 144 | 172 | ||
| 173 | static int __devinit lm70_probe(struct spi_device *spi) | ||
| 174 | { | ||
| 175 | /* signaling is SPI_MODE_0 on a 3-wire link (shared SI/SO) */ | ||
| 176 | if ((spi->mode & (SPI_CPOL | SPI_CPHA)) || !(spi->mode & SPI_3WIRE)) | ||
| 177 | return -EINVAL; | ||
| 178 | |||
| 179 | return common_probe(spi, LM70_CHIP_LM70); | ||
| 180 | } | ||
| 181 | |||
| 182 | static int __devinit tmp121_probe(struct spi_device *spi) | ||
| 183 | { | ||
| 184 | /* signaling is SPI_MODE_0 with only MISO connected */ | ||
| 185 | if (spi->mode & (SPI_CPOL | SPI_CPHA)) | ||
| 186 | return -EINVAL; | ||
| 187 | |||
| 188 | return common_probe(spi, LM70_CHIP_TMP121); | ||
| 189 | } | ||
| 190 | |||
| 145 | static int __devexit lm70_remove(struct spi_device *spi) | 191 | static int __devexit lm70_remove(struct spi_device *spi) |
| 146 | { | 192 | { |
| 147 | struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); | 193 | struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); |
| @@ -155,6 +201,15 @@ static int __devexit lm70_remove(struct spi_device *spi) | |||
| 155 | return 0; | 201 | return 0; |
| 156 | } | 202 | } |
| 157 | 203 | ||
| 204 | static struct spi_driver tmp121_driver = { | ||
| 205 | .driver = { | ||
| 206 | .name = "tmp121", | ||
| 207 | .owner = THIS_MODULE, | ||
| 208 | }, | ||
| 209 | .probe = tmp121_probe, | ||
| 210 | .remove = __devexit_p(lm70_remove), | ||
| 211 | }; | ||
| 212 | |||
| 158 | static struct spi_driver lm70_driver = { | 213 | static struct spi_driver lm70_driver = { |
| 159 | .driver = { | 214 | .driver = { |
| 160 | .name = "lm70", | 215 | .name = "lm70", |
| @@ -166,17 +221,26 @@ static struct spi_driver lm70_driver = { | |||
| 166 | 221 | ||
| 167 | static int __init init_lm70(void) | 222 | static int __init init_lm70(void) |
| 168 | { | 223 | { |
| 169 | return spi_register_driver(&lm70_driver); | 224 | int ret = spi_register_driver(&lm70_driver); |
| 225 | if (ret) | ||
| 226 | return ret; | ||
| 227 | |||
| 228 | ret = spi_register_driver(&tmp121_driver); | ||
| 229 | if (ret) | ||
| 230 | spi_unregister_driver(&lm70_driver); | ||
| 231 | |||
| 232 | return ret; | ||
| 170 | } | 233 | } |
| 171 | 234 | ||
| 172 | static void __exit cleanup_lm70(void) | 235 | static void __exit cleanup_lm70(void) |
| 173 | { | 236 | { |
| 174 | spi_unregister_driver(&lm70_driver); | 237 | spi_unregister_driver(&lm70_driver); |
| 238 | spi_unregister_driver(&tmp121_driver); | ||
| 175 | } | 239 | } |
| 176 | 240 | ||
| 177 | module_init(init_lm70); | 241 | module_init(init_lm70); |
| 178 | module_exit(cleanup_lm70); | 242 | module_exit(cleanup_lm70); |
| 179 | 243 | ||
| 180 | MODULE_AUTHOR("Kaiwan N Billimoria"); | 244 | MODULE_AUTHOR("Kaiwan N Billimoria"); |
| 181 | MODULE_DESCRIPTION("National Semiconductor LM70 Linux driver"); | 245 | MODULE_DESCRIPTION("NS LM70 / TI TMP121/TMP123 Linux driver"); |
| 182 | MODULE_LICENSE("GPL"); | 246 | MODULE_LICENSE("GPL"); |
