diff options
-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"); |