diff options
author | Guenter Roeck <linux@roeck-us.net> | 2013-01-27 12:24:28 -0500 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2013-04-08 00:16:41 -0400 |
commit | fd9175d2f603509e7ddf14e7b60633f6e88fb0e7 (patch) | |
tree | b95554cbce8703c52411323196e62ec755b867b5 /drivers/hwmon | |
parent | 8c770f3a472fa74ad86871f42f6e991951ddeed2 (diff) |
hwmon: (pmbus/ltc2978) Add support for LTC2974 and LTC3883
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/pmbus/Kconfig | 4 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ltc2978.c | 149 |
2 files changed, 132 insertions, 21 deletions
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 4f9eb0af5229..b1adad60d6ad 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig | |||
@@ -48,11 +48,11 @@ config SENSORS_LM25066 | |||
48 | be called lm25066. | 48 | be called lm25066. |
49 | 49 | ||
50 | config SENSORS_LTC2978 | 50 | config SENSORS_LTC2978 |
51 | tristate "Linear Technologies LTC2978 and LTC3880" | 51 | tristate "Linear Technologies LTC2974, LTC2978, LTC3880, and LTC3883" |
52 | default n | 52 | default n |
53 | help | 53 | help |
54 | If you say yes here you get hardware monitoring support for Linear | 54 | If you say yes here you get hardware monitoring support for Linear |
55 | Technology LTC2978 and LTC3880. | 55 | Technology LTC2974, LTC2978, LTC3880, and LTC3883. |
56 | 56 | ||
57 | This driver can also be built as a module. If so, the module will | 57 | This driver can also be built as a module. If so, the module will |
58 | be called ltc2978. | 58 | be called ltc2978. |
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 945f7eced409..586a89ef9e0f 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Hardware monitoring driver for LTC2978 and LTC3880 | 2 | * Hardware monitoring driver for LTC2974, LTC2978, LTC3880, and LTC3883 |
3 | * | 3 | * |
4 | * Copyright (c) 2011 Ericsson AB. | 4 | * Copyright (c) 2011 Ericsson AB. |
5 | * Copyright (c) 2013 Guenter Roeck | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -26,31 +27,43 @@ | |||
26 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
27 | #include "pmbus.h" | 28 | #include "pmbus.h" |
28 | 29 | ||
29 | enum chips { ltc2978, ltc3880 }; | 30 | enum chips { ltc2974, ltc2978, ltc3880, ltc3883 }; |
30 | 31 | ||
31 | /* LTC2978 and LTC3880 */ | 32 | /* Common for all chips */ |
32 | #define LTC2978_MFR_VOUT_PEAK 0xdd | 33 | #define LTC2978_MFR_VOUT_PEAK 0xdd |
33 | #define LTC2978_MFR_VIN_PEAK 0xde | 34 | #define LTC2978_MFR_VIN_PEAK 0xde |
34 | #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf | 35 | #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf |
35 | #define LTC2978_MFR_SPECIAL_ID 0xe7 | 36 | #define LTC2978_MFR_SPECIAL_ID 0xe7 |
36 | 37 | ||
37 | /* LTC2978 only */ | 38 | /* LTC2974 and LTC2978 */ |
38 | #define LTC2978_MFR_VOUT_MIN 0xfb | 39 | #define LTC2978_MFR_VOUT_MIN 0xfb |
39 | #define LTC2978_MFR_VIN_MIN 0xfc | 40 | #define LTC2978_MFR_VIN_MIN 0xfc |
40 | #define LTC2978_MFR_TEMPERATURE_MIN 0xfd | 41 | #define LTC2978_MFR_TEMPERATURE_MIN 0xfd |
41 | 42 | ||
42 | /* LTC3880 only */ | 43 | /* LTC2974 only */ |
44 | #define LTC2974_MFR_IOUT_PEAK 0xd7 | ||
45 | #define LTC2974_MFR_IOUT_MIN 0xd8 | ||
46 | |||
47 | /* LTC3880 and LTC3883 */ | ||
43 | #define LTC3880_MFR_IOUT_PEAK 0xd7 | 48 | #define LTC3880_MFR_IOUT_PEAK 0xd7 |
44 | #define LTC3880_MFR_CLEAR_PEAKS 0xe3 | 49 | #define LTC3880_MFR_CLEAR_PEAKS 0xe3 |
45 | #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 | 50 | #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 |
46 | 51 | ||
52 | /* LTC3883 only */ | ||
53 | #define LTC3883_MFR_IIN_PEAK 0xe1 | ||
54 | |||
55 | #define LTC2974_ID 0x0212 | ||
47 | #define LTC2978_ID_REV1 0x0121 | 56 | #define LTC2978_ID_REV1 0x0121 |
48 | #define LTC2978_ID_REV2 0x0122 | 57 | #define LTC2978_ID_REV2 0x0122 |
49 | #define LTC3880_ID 0x4000 | 58 | #define LTC3880_ID 0x4000 |
50 | #define LTC3880_ID_MASK 0xff00 | 59 | #define LTC3880_ID_MASK 0xff00 |
60 | #define LTC3883_ID 0x4300 | ||
61 | #define LTC3883_ID_MASK 0xff00 | ||
51 | 62 | ||
63 | #define LTC2974_NUM_PAGES 4 | ||
52 | #define LTC2978_NUM_PAGES 8 | 64 | #define LTC2978_NUM_PAGES 8 |
53 | #define LTC3880_NUM_PAGES 2 | 65 | #define LTC3880_NUM_PAGES 2 |
66 | #define LTC3883_NUM_PAGES 1 | ||
54 | 67 | ||
55 | /* | 68 | /* |
56 | * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which | 69 | * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which |
@@ -63,9 +76,10 @@ enum chips { ltc2978, ltc3880 }; | |||
63 | struct ltc2978_data { | 76 | struct ltc2978_data { |
64 | enum chips id; | 77 | enum chips id; |
65 | u16 vin_min, vin_max; | 78 | u16 vin_min, vin_max; |
66 | u16 temp_min, temp_max[LTC3880_NUM_PAGES]; | 79 | u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES]; |
67 | u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES]; | 80 | u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES]; |
68 | u16 iout_max[LTC3880_NUM_PAGES]; | 81 | u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES]; |
82 | u16 iin_max; | ||
69 | u16 temp2_max; | 83 | u16 temp2_max; |
70 | struct pmbus_driver_info info; | 84 | struct pmbus_driver_info info; |
71 | }; | 85 | }; |
@@ -171,9 +185,9 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) | |||
171 | LTC2978_MFR_TEMPERATURE_MIN); | 185 | LTC2978_MFR_TEMPERATURE_MIN); |
172 | if (ret >= 0) { | 186 | if (ret >= 0) { |
173 | if (lin11_to_val(ret) | 187 | if (lin11_to_val(ret) |
174 | < lin11_to_val(data->temp_min)) | 188 | < lin11_to_val(data->temp_min[page])) |
175 | data->temp_min = ret; | 189 | data->temp_min[page] = ret; |
176 | ret = data->temp_min; | 190 | ret = data->temp_min[page]; |
177 | } | 191 | } |
178 | break; | 192 | break; |
179 | case PMBUS_VIRT_READ_IOUT_MAX: | 193 | case PMBUS_VIRT_READ_IOUT_MAX: |
@@ -189,6 +203,41 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) | |||
189 | return ret; | 203 | return ret; |
190 | } | 204 | } |
191 | 205 | ||
206 | static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg) | ||
207 | { | ||
208 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
209 | struct ltc2978_data *data = to_ltc2978_data(info); | ||
210 | int ret; | ||
211 | |||
212 | switch (reg) { | ||
213 | case PMBUS_VIRT_READ_IOUT_MAX: | ||
214 | ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_PEAK); | ||
215 | if (ret >= 0) { | ||
216 | if (lin11_to_val(ret) | ||
217 | > lin11_to_val(data->iout_max[page])) | ||
218 | data->iout_max[page] = ret; | ||
219 | ret = data->iout_max[page]; | ||
220 | } | ||
221 | break; | ||
222 | case PMBUS_VIRT_READ_IOUT_MIN: | ||
223 | ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_MIN); | ||
224 | if (ret >= 0) { | ||
225 | if (lin11_to_val(ret) | ||
226 | < lin11_to_val(data->iout_min[page])) | ||
227 | data->iout_min[page] = ret; | ||
228 | ret = data->iout_min[page]; | ||
229 | } | ||
230 | break; | ||
231 | case PMBUS_VIRT_RESET_IOUT_HISTORY: | ||
232 | ret = 0; | ||
233 | break; | ||
234 | default: | ||
235 | ret = ltc2978_read_word_data(client, page, reg); | ||
236 | break; | ||
237 | } | ||
238 | return ret; | ||
239 | } | ||
240 | |||
192 | static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) | 241 | static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) |
193 | { | 242 | { |
194 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | 243 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
@@ -230,15 +279,41 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) | |||
230 | return ret; | 279 | return ret; |
231 | } | 280 | } |
232 | 281 | ||
282 | static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg) | ||
283 | { | ||
284 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
285 | struct ltc2978_data *data = to_ltc2978_data(info); | ||
286 | int ret; | ||
287 | |||
288 | switch (reg) { | ||
289 | case PMBUS_VIRT_READ_IIN_MAX: | ||
290 | ret = pmbus_read_word_data(client, page, LTC3883_MFR_IIN_PEAK); | ||
291 | if (ret >= 0) { | ||
292 | if (lin11_to_val(ret) | ||
293 | > lin11_to_val(data->iin_max)) | ||
294 | data->iin_max = ret; | ||
295 | ret = data->iin_max; | ||
296 | } | ||
297 | break; | ||
298 | case PMBUS_VIRT_RESET_IIN_HISTORY: | ||
299 | ret = 0; | ||
300 | break; | ||
301 | default: | ||
302 | ret = ltc3880_read_word_data(client, page, reg); | ||
303 | break; | ||
304 | } | ||
305 | return ret; | ||
306 | } | ||
307 | |||
233 | static int ltc2978_clear_peaks(struct i2c_client *client, int page, | 308 | static int ltc2978_clear_peaks(struct i2c_client *client, int page, |
234 | enum chips id) | 309 | enum chips id) |
235 | { | 310 | { |
236 | int ret; | 311 | int ret; |
237 | 312 | ||
238 | if (id == ltc2978) | 313 | if (id == ltc3880 || id == ltc3883) |
239 | ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); | ||
240 | else | ||
241 | ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); | 314 | ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); |
315 | else | ||
316 | ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); | ||
242 | 317 | ||
243 | return ret; | 318 | return ret; |
244 | } | 319 | } |
@@ -251,8 +326,13 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, | |||
251 | int ret; | 326 | int ret; |
252 | 327 | ||
253 | switch (reg) { | 328 | switch (reg) { |
329 | case PMBUS_VIRT_RESET_IIN_HISTORY: | ||
330 | data->iin_max = 0x7c00; | ||
331 | ret = ltc2978_clear_peaks(client, page, data->id); | ||
332 | break; | ||
254 | case PMBUS_VIRT_RESET_IOUT_HISTORY: | 333 | case PMBUS_VIRT_RESET_IOUT_HISTORY: |
255 | data->iout_max[page] = 0x7c00; | 334 | data->iout_max[page] = 0x7c00; |
335 | data->iout_min[page] = 0xfbff; | ||
256 | ret = ltc2978_clear_peaks(client, page, data->id); | 336 | ret = ltc2978_clear_peaks(client, page, data->id); |
257 | break; | 337 | break; |
258 | case PMBUS_VIRT_RESET_TEMP2_HISTORY: | 338 | case PMBUS_VIRT_RESET_TEMP2_HISTORY: |
@@ -270,7 +350,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, | |||
270 | ret = ltc2978_clear_peaks(client, page, data->id); | 350 | ret = ltc2978_clear_peaks(client, page, data->id); |
271 | break; | 351 | break; |
272 | case PMBUS_VIRT_RESET_TEMP_HISTORY: | 352 | case PMBUS_VIRT_RESET_TEMP_HISTORY: |
273 | data->temp_min = 0x7bff; | 353 | data->temp_min[page] = 0x7bff; |
274 | data->temp_max[page] = 0x7c00; | 354 | data->temp_max[page] = 0x7c00; |
275 | ret = ltc2978_clear_peaks(client, page, data->id); | 355 | ret = ltc2978_clear_peaks(client, page, data->id); |
276 | break; | 356 | break; |
@@ -282,8 +362,10 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, | |||
282 | } | 362 | } |
283 | 363 | ||
284 | static const struct i2c_device_id ltc2978_id[] = { | 364 | static const struct i2c_device_id ltc2978_id[] = { |
365 | {"ltc2974", ltc2974}, | ||
285 | {"ltc2978", ltc2978}, | 366 | {"ltc2978", ltc2978}, |
286 | {"ltc3880", ltc3880}, | 367 | {"ltc3880", ltc3880}, |
368 | {"ltc3883", ltc3883}, | ||
287 | {} | 369 | {} |
288 | }; | 370 | }; |
289 | MODULE_DEVICE_TABLE(i2c, ltc2978_id); | 371 | MODULE_DEVICE_TABLE(i2c, ltc2978_id); |
@@ -308,10 +390,14 @@ static int ltc2978_probe(struct i2c_client *client, | |||
308 | if (chip_id < 0) | 390 | if (chip_id < 0) |
309 | return chip_id; | 391 | return chip_id; |
310 | 392 | ||
311 | if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) { | 393 | if (chip_id == LTC2974_ID) { |
394 | data->id = ltc2974; | ||
395 | } else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) { | ||
312 | data->id = ltc2978; | 396 | data->id = ltc2978; |
313 | } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) { | 397 | } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) { |
314 | data->id = ltc3880; | 398 | data->id = ltc3880; |
399 | } else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) { | ||
400 | data->id = ltc3883; | ||
315 | } else { | 401 | } else { |
316 | dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); | 402 | dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); |
317 | return -ENODEV; | 403 | return -ENODEV; |
@@ -329,12 +415,29 @@ static int ltc2978_probe(struct i2c_client *client, | |||
329 | data->vin_max = 0x7c00; | 415 | data->vin_max = 0x7c00; |
330 | for (i = 0; i < ARRAY_SIZE(data->vout_min); i++) | 416 | for (i = 0; i < ARRAY_SIZE(data->vout_min); i++) |
331 | data->vout_min[i] = 0xffff; | 417 | data->vout_min[i] = 0xffff; |
332 | data->temp_min = 0x7bff; | 418 | for (i = 0; i < ARRAY_SIZE(data->iout_min); i++) |
419 | data->iout_min[i] = 0xfbff; | ||
420 | for (i = 0; i < ARRAY_SIZE(data->iout_max); i++) | ||
421 | data->iout_max[i] = 0x7c00; | ||
422 | for (i = 0; i < ARRAY_SIZE(data->temp_min); i++) | ||
423 | data->temp_min[i] = 0x7bff; | ||
333 | for (i = 0; i < ARRAY_SIZE(data->temp_max); i++) | 424 | for (i = 0; i < ARRAY_SIZE(data->temp_max); i++) |
334 | data->temp_max[i] = 0x7c00; | 425 | data->temp_max[i] = 0x7c00; |
335 | data->temp2_max = 0x7c00; | 426 | data->temp2_max = 0x7c00; |
336 | 427 | ||
337 | switch (data->id) { | 428 | switch (data->id) { |
429 | case ltc2974: | ||
430 | info->read_word_data = ltc2974_read_word_data; | ||
431 | info->pages = LTC2974_NUM_PAGES; | ||
432 | info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | ||
433 | | PMBUS_HAVE_TEMP2; | ||
434 | for (i = 0; i < info->pages; i++) { | ||
435 | info->func[i] |= PMBUS_HAVE_VOUT | ||
436 | | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT | ||
437 | | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | ||
438 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; | ||
439 | } | ||
440 | break; | ||
338 | case ltc2978: | 441 | case ltc2978: |
339 | info->read_word_data = ltc2978_read_word_data; | 442 | info->read_word_data = ltc2978_read_word_data; |
340 | info->pages = LTC2978_NUM_PAGES; | 443 | info->pages = LTC2978_NUM_PAGES; |
@@ -359,8 +462,16 @@ static int ltc2978_probe(struct i2c_client *client, | |||
359 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | 462 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
360 | | PMBUS_HAVE_POUT | 463 | | PMBUS_HAVE_POUT |
361 | | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; | 464 | | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; |
362 | data->iout_max[0] = 0x7c00; | 465 | break; |
363 | data->iout_max[1] = 0x7c00; | 466 | case ltc3883: |
467 | info->read_word_data = ltc3883_read_word_data; | ||
468 | info->pages = LTC3883_NUM_PAGES; | ||
469 | info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | ||
470 | | PMBUS_HAVE_STATUS_INPUT | ||
471 | | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
472 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ||
473 | | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | ||
474 | | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; | ||
364 | break; | 475 | break; |
365 | default: | 476 | default: |
366 | return -ENODEV; | 477 | return -ENODEV; |
@@ -381,5 +492,5 @@ static struct i2c_driver ltc2978_driver = { | |||
381 | module_i2c_driver(ltc2978_driver); | 492 | module_i2c_driver(ltc2978_driver); |
382 | 493 | ||
383 | MODULE_AUTHOR("Guenter Roeck"); | 494 | MODULE_AUTHOR("Guenter Roeck"); |
384 | MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880"); | 495 | MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883"); |
385 | MODULE_LICENSE("GPL"); | 496 | MODULE_LICENSE("GPL"); |