aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorGuenter Roeck <guenter.roeck@ericsson.com>2011-06-25 14:21:49 -0400
committerGuenter Roeck <guenter.roeck@ericsson.com>2011-07-28 18:31:11 -0400
commit1061d8518f8bde548a03a5ff77dbe9a4202ad826 (patch)
treee5bd62c9c7d065c4acb249bc60e057b64023c32c /drivers/hwmon
parent9d2ecfb768bd2f8b41816a23b0f1dda026fef41d (diff)
hwmon: (pmbus) Add support for VID output voltage mode
In VID mode, output voltages are measured and reported as VID values, and have to be converted to voltages using VID conversion tables or functions. Support is added for VR11 only at this time. This patch enables support for PMBus devices supporting VID VR11 based output voltage selection such as NCP4200 and NCP4208. Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com> Reviewed-by: Robert Coulson <robert.coulson@ericsson.com>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/pmbus/adm1275.c6
-rw-r--r--drivers/hwmon/pmbus/max16064.c6
-rw-r--r--drivers/hwmon/pmbus/max34440.c18
-rw-r--r--drivers/hwmon/pmbus/max8688.c8
-rw-r--r--drivers/hwmon/pmbus/pmbus.c34
-rw-r--r--drivers/hwmon/pmbus/pmbus.h7
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c60
7 files changed, 105 insertions, 34 deletions
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
index 8bc1bd66372..71770ffbdaf 100644
--- a/drivers/hwmon/pmbus/adm1275.c
+++ b/drivers/hwmon/pmbus/adm1275.c
@@ -50,9 +50,9 @@ static int adm1275_probe(struct i2c_client *client,
50 } 50 }
51 51
52 info->pages = 1; 52 info->pages = 1;
53 info->direct[PSC_VOLTAGE_IN] = true; 53 info->format[PSC_VOLTAGE_IN] = direct;
54 info->direct[PSC_VOLTAGE_OUT] = true; 54 info->format[PSC_VOLTAGE_OUT] = direct;
55 info->direct[PSC_CURRENT_OUT] = true; 55 info->format[PSC_CURRENT_OUT] = direct;
56 info->m[PSC_CURRENT_OUT] = 807; 56 info->m[PSC_CURRENT_OUT] = 807;
57 info->b[PSC_CURRENT_OUT] = 20475; 57 info->b[PSC_CURRENT_OUT] = 20475;
58 info->R[PSC_CURRENT_OUT] = -1; 58 info->R[PSC_CURRENT_OUT] = -1;
diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c
index 1d6d717060d..78e20bca53a 100644
--- a/drivers/hwmon/pmbus/max16064.c
+++ b/drivers/hwmon/pmbus/max16064.c
@@ -27,9 +27,9 @@
27 27
28static struct pmbus_driver_info max16064_info = { 28static struct pmbus_driver_info max16064_info = {
29 .pages = 4, 29 .pages = 4,
30 .direct[PSC_VOLTAGE_IN] = true, 30 .format[PSC_VOLTAGE_IN] = direct,
31 .direct[PSC_VOLTAGE_OUT] = true, 31 .format[PSC_VOLTAGE_OUT] = direct,
32 .direct[PSC_TEMPERATURE] = true, 32 .format[PSC_TEMPERATURE] = direct,
33 .m[PSC_VOLTAGE_IN] = 19995, 33 .m[PSC_VOLTAGE_IN] = 19995,
34 .b[PSC_VOLTAGE_IN] = 0, 34 .b[PSC_VOLTAGE_IN] = 0,
35 .R[PSC_VOLTAGE_IN] = -1, 35 .R[PSC_VOLTAGE_IN] = -1,
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
index db11e1a175b..2e30046a116 100644
--- a/drivers/hwmon/pmbus/max34440.c
+++ b/drivers/hwmon/pmbus/max34440.c
@@ -72,10 +72,10 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
72static struct pmbus_driver_info max34440_info[] = { 72static struct pmbus_driver_info max34440_info[] = {
73 [max34440] = { 73 [max34440] = {
74 .pages = 14, 74 .pages = 14,
75 .direct[PSC_VOLTAGE_IN] = true, 75 .format[PSC_VOLTAGE_IN] = direct,
76 .direct[PSC_VOLTAGE_OUT] = true, 76 .format[PSC_VOLTAGE_OUT] = direct,
77 .direct[PSC_TEMPERATURE] = true, 77 .format[PSC_TEMPERATURE] = direct,
78 .direct[PSC_CURRENT_OUT] = true, 78 .format[PSC_CURRENT_OUT] = direct,
79 .m[PSC_VOLTAGE_IN] = 1, 79 .m[PSC_VOLTAGE_IN] = 1,
80 .b[PSC_VOLTAGE_IN] = 0, 80 .b[PSC_VOLTAGE_IN] = 0,
81 .R[PSC_VOLTAGE_IN] = 3, /* R = 0 in datasheet reflects mV */ 81 .R[PSC_VOLTAGE_IN] = 3, /* R = 0 in datasheet reflects mV */
@@ -112,11 +112,11 @@ static struct pmbus_driver_info max34440_info[] = {
112 }, 112 },
113 [max34441] = { 113 [max34441] = {
114 .pages = 12, 114 .pages = 12,
115 .direct[PSC_VOLTAGE_IN] = true, 115 .format[PSC_VOLTAGE_IN] = direct,
116 .direct[PSC_VOLTAGE_OUT] = true, 116 .format[PSC_VOLTAGE_OUT] = direct,
117 .direct[PSC_TEMPERATURE] = true, 117 .format[PSC_TEMPERATURE] = direct,
118 .direct[PSC_CURRENT_OUT] = true, 118 .format[PSC_CURRENT_OUT] = direct,
119 .direct[PSC_FAN] = true, 119 .format[PSC_FAN] = direct,
120 .m[PSC_VOLTAGE_IN] = 1, 120 .m[PSC_VOLTAGE_IN] = 1,
121 .b[PSC_VOLTAGE_IN] = 0, 121 .b[PSC_VOLTAGE_IN] = 0,
122 .R[PSC_VOLTAGE_IN] = 3, 122 .R[PSC_VOLTAGE_IN] = 3,
diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c
index 7fb93f4e9f2..ddc8a64c2ba 100644
--- a/drivers/hwmon/pmbus/max8688.c
+++ b/drivers/hwmon/pmbus/max8688.c
@@ -91,10 +91,10 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
91 91
92static struct pmbus_driver_info max8688_info = { 92static struct pmbus_driver_info max8688_info = {
93 .pages = 1, 93 .pages = 1,
94 .direct[PSC_VOLTAGE_IN] = true, 94 .format[PSC_VOLTAGE_IN] = direct,
95 .direct[PSC_VOLTAGE_OUT] = true, 95 .format[PSC_VOLTAGE_OUT] = direct,
96 .direct[PSC_TEMPERATURE] = true, 96 .format[PSC_TEMPERATURE] = direct,
97 .direct[PSC_CURRENT_OUT] = true, 97 .format[PSC_CURRENT_OUT] = direct,
98 .m[PSC_VOLTAGE_IN] = 19995, 98 .m[PSC_VOLTAGE_IN] = 19995,
99 .b[PSC_VOLTAGE_IN] = 0, 99 .b[PSC_VOLTAGE_IN] = 0,
100 .R[PSC_VOLTAGE_IN] = -1, 100 .R[PSC_VOLTAGE_IN] = -1,
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
index 9b1f0c37ef7..4d8e31bcd7a 100644
--- a/drivers/hwmon/pmbus/pmbus.c
+++ b/drivers/hwmon/pmbus/pmbus.c
@@ -96,6 +96,8 @@ static void pmbus_find_sensor_groups(struct i2c_client *client,
96static int pmbus_identify(struct i2c_client *client, 96static int pmbus_identify(struct i2c_client *client,
97 struct pmbus_driver_info *info) 97 struct pmbus_driver_info *info)
98{ 98{
99 int ret = 0;
100
99 if (!info->pages) { 101 if (!info->pages) {
100 /* 102 /*
101 * Check if the PAGE command is supported. If it is, 103 * Check if the PAGE command is supported. If it is,
@@ -117,6 +119,27 @@ static int pmbus_identify(struct i2c_client *client,
117 } 119 }
118 } 120 }
119 121
122 if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
123 int vout_mode;
124
125 vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
126 if (vout_mode >= 0 && vout_mode != 0xff) {
127 switch (vout_mode >> 5) {
128 case 0:
129 break;
130 case 1:
131 info->format[PSC_VOLTAGE_OUT] = vid;
132 break;
133 case 2:
134 info->format[PSC_VOLTAGE_OUT] = direct;
135 break;
136 default:
137 ret = -ENODEV;
138 goto abort;
139 }
140 }
141 }
142
120 /* 143 /*
121 * We should check if the COEFFICIENTS register is supported. 144 * We should check if the COEFFICIENTS register is supported.
122 * If it is, and the chip is configured for direct mode, we can read 145 * If it is, and the chip is configured for direct mode, we can read
@@ -125,13 +148,18 @@ static int pmbus_identify(struct i2c_client *client,
125 * 148 *
126 * To do this, we will need access to a chip which actually supports the 149 * To do this, we will need access to a chip which actually supports the
127 * COEFFICIENTS command, since the command is too complex to implement 150 * COEFFICIENTS command, since the command is too complex to implement
128 * without testing it. 151 * without testing it. Until then, abort if a chip configured for direct
152 * mode was detected.
129 */ 153 */
154 if (info->format[PSC_VOLTAGE_OUT] == direct) {
155 ret = -ENODEV;
156 goto abort;
157 }
130 158
131 /* Try to find sensor groups */ 159 /* Try to find sensor groups */
132 pmbus_find_sensor_groups(client, info); 160 pmbus_find_sensor_groups(client, info);
133 161abort:
134 return 0; 162 return ret;
135} 163}
136 164
137static int pmbus_probe(struct i2c_client *client, 165static int pmbus_probe(struct i2c_client *client,
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 50647ab7235..cc5b6a23260 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -266,11 +266,11 @@ enum pmbus_sensor_classes {
266#define PMBUS_HAVE_STATUS_FAN12 (1 << 16) 266#define PMBUS_HAVE_STATUS_FAN12 (1 << 16)
267#define PMBUS_HAVE_STATUS_FAN34 (1 << 17) 267#define PMBUS_HAVE_STATUS_FAN34 (1 << 17)
268 268
269enum pmbus_data_format { linear = 0, direct, vid };
270
269struct pmbus_driver_info { 271struct pmbus_driver_info {
270 int pages; /* Total number of pages */ 272 int pages; /* Total number of pages */
271 bool direct[PSC_NUM_CLASSES]; 273 enum pmbus_data_format format[PSC_NUM_CLASSES];
272 /* true if device uses direct data format
273 for the given sensor class */
274 /* 274 /*
275 * Support one set of coefficients for each sensor type 275 * Support one set of coefficients for each sensor type
276 * Used for chips providing data in direct mode. 276 * Used for chips providing data in direct mode.
@@ -299,6 +299,7 @@ struct pmbus_driver_info {
299 299
300int pmbus_set_page(struct i2c_client *client, u8 page); 300int pmbus_set_page(struct i2c_client *client, u8 page);
301int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg); 301int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
302int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg);
302void pmbus_clear_faults(struct i2c_client *client); 303void pmbus_clear_faults(struct i2c_client *client);
303bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); 304bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
304bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); 305bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 8e31a8e2c74..cef763c7da3 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -197,7 +197,7 @@ int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg)
197} 197}
198EXPORT_SYMBOL_GPL(pmbus_read_word_data); 198EXPORT_SYMBOL_GPL(pmbus_read_word_data);
199 199
200static int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg) 200int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg)
201{ 201{
202 int rv; 202 int rv;
203 203
@@ -207,6 +207,7 @@ static int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg)
207 207
208 return i2c_smbus_read_byte_data(client, reg); 208 return i2c_smbus_read_byte_data(client, reg);
209} 209}
210EXPORT_SYMBOL_GPL(pmbus_read_byte_data);
210 211
211static void pmbus_clear_fault_page(struct i2c_client *client, int page) 212static void pmbus_clear_fault_page(struct i2c_client *client, int page)
212{ 213{
@@ -443,15 +444,37 @@ static long pmbus_reg2data_direct(struct pmbus_data *data,
443 return (val - b) / m; 444 return (val - b) / m;
444} 445}
445 446
447/*
448 * Convert VID sensor values to milli- or micro-units
449 * depending on sensor type.
450 * We currently only support VR11.
451 */
452static long pmbus_reg2data_vid(struct pmbus_data *data,
453 struct pmbus_sensor *sensor)
454{
455 long val = sensor->data;
456
457 if (val < 0x02 || val > 0xb2)
458 return 0;
459 return DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100);
460}
461
446static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) 462static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
447{ 463{
448 long val; 464 long val;
449 465
450 if (data->info->direct[sensor->class]) 466 switch (data->info->format[sensor->class]) {
467 case direct:
451 val = pmbus_reg2data_direct(data, sensor); 468 val = pmbus_reg2data_direct(data, sensor);
452 else 469 break;
470 case vid:
471 val = pmbus_reg2data_vid(data, sensor);
472 break;
473 case linear:
474 default:
453 val = pmbus_reg2data_linear(data, sensor); 475 val = pmbus_reg2data_linear(data, sensor);
454 476 break;
477 }
455 return val; 478 return val;
456} 479}
457 480
@@ -561,16 +584,31 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
561 return val; 584 return val;
562} 585}
563 586
587static u16 pmbus_data2reg_vid(struct pmbus_data *data,
588 enum pmbus_sensor_classes class, long val)
589{
590 val = SENSORS_LIMIT(val, 500, 1600);
591
592 return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625);
593}
594
564static u16 pmbus_data2reg(struct pmbus_data *data, 595static u16 pmbus_data2reg(struct pmbus_data *data,
565 enum pmbus_sensor_classes class, long val) 596 enum pmbus_sensor_classes class, long val)
566{ 597{
567 u16 regval; 598 u16 regval;
568 599
569 if (data->info->direct[class]) 600 switch (data->info->format[class]) {
601 case direct:
570 regval = pmbus_data2reg_direct(data, class, val); 602 regval = pmbus_data2reg_direct(data, class, val);
571 else 603 break;
604 case vid:
605 regval = pmbus_data2reg_vid(data, class, val);
606 break;
607 case linear:
608 default:
572 regval = pmbus_data2reg_linear(data, class, val); 609 regval = pmbus_data2reg_linear(data, class, val);
573 610 break;
611 }
574 return regval; 612 return regval;
575} 613}
576 614
@@ -1380,7 +1418,7 @@ static int pmbus_identify_common(struct i2c_client *client,
1380 */ 1418 */
1381 switch (vout_mode >> 5) { 1419 switch (vout_mode >> 5) {
1382 case 0: /* linear mode */ 1420 case 0: /* linear mode */
1383 if (data->info->direct[PSC_VOLTAGE_OUT]) 1421 if (data->info->format[PSC_VOLTAGE_OUT] != linear)
1384 return -ENODEV; 1422 return -ENODEV;
1385 1423
1386 exponent = vout_mode & 0x1f; 1424 exponent = vout_mode & 0x1f;
@@ -1389,8 +1427,12 @@ static int pmbus_identify_common(struct i2c_client *client,
1389 exponent |= ~0x1f; 1427 exponent |= ~0x1f;
1390 data->exponent = exponent; 1428 data->exponent = exponent;
1391 break; 1429 break;
1430 case 1: /* VID mode */
1431 if (data->info->format[PSC_VOLTAGE_OUT] != vid)
1432 return -ENODEV;
1433 break;
1392 case 2: /* direct mode */ 1434 case 2: /* direct mode */
1393 if (!data->info->direct[PSC_VOLTAGE_OUT]) 1435 if (data->info->format[PSC_VOLTAGE_OUT] != direct)
1394 return -ENODEV; 1436 return -ENODEV;
1395 break; 1437 break;
1396 default: 1438 default: