aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/pmbus/ltc2978.c
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2015-06-08 12:56:20 -0400
committerGuenter Roeck <linux@roeck-us.net>2015-08-17 14:55:55 -0400
commit649ca820dab3d76e12408b74af3e8e97abb07ae0 (patch)
tree20d6e9797f112f6af616b532b809fd3dd1fd4d2d /drivers/hwmon/pmbus/ltc2978.c
parent15398566f0ea95c66d202b8705dba4f59b9ba01c (diff)
hwmon: (ltc2978) Add support for LTC2975
LTC2975 is mostly compatible to LTC2974, but supports input current and power measurement. Tested-by: Michael Jones <mike@proclivis.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon/pmbus/ltc2978.c')
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c104
1 files changed, 94 insertions, 10 deletions
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index 0756d8ae9dad..e153ffd59ab0 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -1,9 +1,8 @@
1/* 1/*
2 * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880, 2 * Hardware monitoring driver for LTC2978 and compatible chips.
3 * LTC3883, LTC3887. and LTM4676
4 * 3 *
5 * Copyright (c) 2011 Ericsson AB. 4 * Copyright (c) 2011 Ericsson AB.
6 * Copyright (c) 2013, 2014 Guenter Roeck 5 * Copyright (c) 2013, 2014, 2015 Guenter Roeck
7 * 6 *
8 * 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
9 * 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
@@ -25,8 +24,8 @@
25#include <linux/regulator/driver.h> 24#include <linux/regulator/driver.h>
26#include "pmbus.h" 25#include "pmbus.h"
27 26
28enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887, 27enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883,
29 ltm4676 }; 28 ltc3887, ltm4676 };
30 29
31/* Common for all chips */ 30/* Common for all chips */
32#define LTC2978_MFR_VOUT_PEAK 0xdd 31#define LTC2978_MFR_VOUT_PEAK 0xdd
@@ -34,12 +33,12 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887,
34#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf 33#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
35#define LTC2978_MFR_SPECIAL_ID 0xe7 /* Not on LTC3882 */ 34#define LTC2978_MFR_SPECIAL_ID 0xe7 /* Not on LTC3882 */
36 35
37/* LTC2974, LCT2977, and LTC2978 */ 36/* LTC2974, LTC2975, LCT2977, and LTC2978 */
38#define LTC2978_MFR_VOUT_MIN 0xfb 37#define LTC2978_MFR_VOUT_MIN 0xfb
39#define LTC2978_MFR_VIN_MIN 0xfc 38#define LTC2978_MFR_VIN_MIN 0xfc
40#define LTC2978_MFR_TEMPERATURE_MIN 0xfd 39#define LTC2978_MFR_TEMPERATURE_MIN 0xfd
41 40
42/* LTC2974 only */ 41/* LTC2974, LTC2975 */
43#define LTC2974_MFR_IOUT_PEAK 0xd7 42#define LTC2974_MFR_IOUT_PEAK 0xd7
44#define LTC2974_MFR_IOUT_MIN 0xd8 43#define LTC2974_MFR_IOUT_MIN 0xd8
45 44
@@ -51,8 +50,15 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887,
51/* LTC3883 only */ 50/* LTC3883 only */
52#define LTC3883_MFR_IIN_PEAK 0xe1 51#define LTC3883_MFR_IIN_PEAK 0xe1
53 52
53/* LTC2975 only */
54#define LTC2975_MFR_IIN_PEAK 0xc4
55#define LTC2975_MFR_IIN_MIN 0xc5
56#define LTC2975_MFR_PIN_PEAK 0xc6
57#define LTC2975_MFR_PIN_MIN 0xc7
58
54#define LTC2974_ID_REV1 0x0212 59#define LTC2974_ID_REV1 0x0212
55#define LTC2974_ID_REV2 0x0213 60#define LTC2974_ID_REV2 0x0213
61#define LTC2975_ID 0x0223
56#define LTC2977_ID 0x0130 62#define LTC2977_ID 0x0130
57#define LTC2978_ID_REV1 0x0121 63#define LTC2978_ID_REV1 0x0121
58#define LTC2978_ID_REV2 0x0122 64#define LTC2978_ID_REV2 0x0122
@@ -87,7 +93,8 @@ struct ltc2978_data {
87 u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES]; 93 u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES];
88 u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES]; 94 u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES];
89 u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES]; 95 u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES];
90 u16 iin_max; 96 u16 iin_min, iin_max;
97 u16 pin_min, pin_max;
91 u16 temp2_max; 98 u16 temp2_max;
92 struct pmbus_driver_info info; 99 struct pmbus_driver_info info;
93}; 100};
@@ -246,6 +253,60 @@ static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
246 return ret; 253 return ret;
247} 254}
248 255
256static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg)
257{
258 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
259 struct ltc2978_data *data = to_ltc2978_data(info);
260 int ret;
261
262 switch (reg) {
263 case PMBUS_VIRT_READ_IIN_MAX:
264 ret = pmbus_read_word_data(client, page, LTC2975_MFR_IIN_PEAK);
265 if (ret >= 0) {
266 if (lin11_to_val(ret)
267 > lin11_to_val(data->iin_max))
268 data->iin_max = ret;
269 ret = data->iin_max;
270 }
271 break;
272 case PMBUS_VIRT_READ_IIN_MIN:
273 ret = pmbus_read_word_data(client, page, LTC2975_MFR_IIN_MIN);
274 if (ret >= 0) {
275 if (lin11_to_val(ret)
276 < lin11_to_val(data->iin_min))
277 data->iin_min = ret;
278 ret = data->iin_min;
279 }
280 break;
281 case PMBUS_VIRT_READ_PIN_MAX:
282 ret = pmbus_read_word_data(client, page, LTC2975_MFR_PIN_PEAK);
283 if (ret >= 0) {
284 if (lin11_to_val(ret)
285 > lin11_to_val(data->pin_max))
286 data->pin_max = ret;
287 ret = data->pin_max;
288 }
289 break;
290 case PMBUS_VIRT_READ_PIN_MIN:
291 ret = pmbus_read_word_data(client, page, LTC2975_MFR_PIN_MIN);
292 if (ret >= 0) {
293 if (lin11_to_val(ret)
294 < lin11_to_val(data->pin_min))
295 data->pin_min = ret;
296 ret = data->pin_min;
297 }
298 break;
299 case PMBUS_VIRT_RESET_IIN_HISTORY:
300 case PMBUS_VIRT_RESET_PIN_HISTORY:
301 ret = 0;
302 break;
303 default:
304 ret = ltc2978_read_word_data(client, page, reg);
305 break;
306 }
307 return ret;
308}
309
249static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) 310static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
250{ 311{
251 const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 312 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
@@ -337,7 +398,13 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
337 switch (reg) { 398 switch (reg) {
338 case PMBUS_VIRT_RESET_IIN_HISTORY: 399 case PMBUS_VIRT_RESET_IIN_HISTORY:
339 data->iin_max = 0x7c00; 400 data->iin_max = 0x7c00;
340 ret = ltc2978_clear_peaks(client, page, data->id); 401 data->iin_min = 0x7bff;
402 ret = ltc2978_clear_peaks(client, 0, data->id);
403 break;
404 case PMBUS_VIRT_RESET_PIN_HISTORY:
405 data->pin_max = 0x7c00;
406 data->pin_min = 0x7bff;
407 ret = ltc2978_clear_peaks(client, 0, data->id);
341 break; 408 break;
342 case PMBUS_VIRT_RESET_IOUT_HISTORY: 409 case PMBUS_VIRT_RESET_IOUT_HISTORY:
343 data->iout_max[page] = 0x7c00; 410 data->iout_max[page] = 0x7c00;
@@ -372,6 +439,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
372 439
373static const struct i2c_device_id ltc2978_id[] = { 440static const struct i2c_device_id ltc2978_id[] = {
374 {"ltc2974", ltc2974}, 441 {"ltc2974", ltc2974},
442 {"ltc2975", ltc2975},
375 {"ltc2977", ltc2977}, 443 {"ltc2977", ltc2977},
376 {"ltc2978", ltc2978}, 444 {"ltc2978", ltc2978},
377 {"ltc3880", ltc3880}, 445 {"ltc3880", ltc3880},
@@ -428,6 +496,8 @@ static int ltc2978_get_id(struct i2c_client *client)
428 496
429 if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) 497 if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2)
430 return ltc2974; 498 return ltc2974;
499 else if (chip_id == LTC2975_ID)
500 return ltc2975;
431 else if (chip_id == LTC2977_ID) 501 else if (chip_id == LTC2977_ID)
432 return ltc2977; 502 return ltc2977;
433 else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 || 503 else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 ||
@@ -505,6 +575,19 @@ static int ltc2978_probe(struct i2c_client *client,
505 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; 575 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
506 } 576 }
507 break; 577 break;
578 case ltc2975:
579 info->read_word_data = ltc2975_read_word_data;
580 info->pages = LTC2974_NUM_PAGES;
581 info->func[0] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN
582 | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
583 | PMBUS_HAVE_TEMP2;
584 for (i = 0; i < info->pages; i++) {
585 info->func[i] |= PMBUS_HAVE_VOUT
586 | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
587 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
588 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
589 }
590 break;
508 case ltc2977: 591 case ltc2977:
509 case ltc2978: 592 case ltc2978:
510 info->read_word_data = ltc2978_read_word_data; 593 info->read_word_data = ltc2978_read_word_data;
@@ -576,6 +659,7 @@ static int ltc2978_probe(struct i2c_client *client,
576#ifdef CONFIG_OF 659#ifdef CONFIG_OF
577static const struct of_device_id ltc2978_of_match[] = { 660static const struct of_device_id ltc2978_of_match[] = {
578 { .compatible = "lltc,ltc2974" }, 661 { .compatible = "lltc,ltc2974" },
662 { .compatible = "lltc,ltc2975" },
579 { .compatible = "lltc,ltc2977" }, 663 { .compatible = "lltc,ltc2977" },
580 { .compatible = "lltc,ltc2978" }, 664 { .compatible = "lltc,ltc2978" },
581 { .compatible = "lltc,ltc3880" }, 665 { .compatible = "lltc,ltc3880" },
@@ -601,5 +685,5 @@ static struct i2c_driver ltc2978_driver = {
601module_i2c_driver(ltc2978_driver); 685module_i2c_driver(ltc2978_driver);
602 686
603MODULE_AUTHOR("Guenter Roeck"); 687MODULE_AUTHOR("Guenter Roeck");
604MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676"); 688MODULE_DESCRIPTION("PMBus driver for LTC2978 and comppatible chips");
605MODULE_LICENSE("GPL"); 689MODULE_LICENSE("GPL");