aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2014-01-30 22:51:14 -0500
committerGuenter Roeck <linux@roeck-us.net>2014-02-03 00:21:40 -0500
commitdaa436e67cd2dcac7cbb505bb4425fdfdafaa5a7 (patch)
treee61017bf92b7a4a021d362379ab3504df46b15bd /drivers
parent38dbfb59d1175ef458d006556061adeaa8751b72 (diff)
hwmon: (pmbus) Support per-page exponent in linear mode
Some chips use different exponents for sensors on different pages or rails. Detect and store exponent per page to support this situation. This fixes a problem with wrong voltages seen on UCD90120. Reported-by: Soren Brinkmann <soren.brinkmann@xilinx.com> Tested-by: Soren Brinkmann <soren.brinkmann@xilinx.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c68
1 files changed, 36 insertions, 32 deletions
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 3cbf66e9d861..291d11fe93e7 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -90,7 +90,8 @@ struct pmbus_data {
90 90
91 u32 flags; /* from platform data */ 91 u32 flags; /* from platform data */
92 92
93 int exponent; /* linear mode: exponent for output voltages */ 93 int exponent[PMBUS_PAGES];
94 /* linear mode: exponent for output voltages */
94 95
95 const struct pmbus_driver_info *info; 96 const struct pmbus_driver_info *info;
96 97
@@ -410,7 +411,7 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
410 long val; 411 long val;
411 412
412 if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ 413 if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */
413 exponent = data->exponent; 414 exponent = data->exponent[sensor->page];
414 mantissa = (u16) sensor->data; 415 mantissa = (u16) sensor->data;
415 } else { /* LINEAR11 */ 416 } else { /* LINEAR11 */
416 exponent = ((s16)sensor->data) >> 11; 417 exponent = ((s16)sensor->data) >> 11;
@@ -516,7 +517,7 @@ static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
516#define MIN_MANTISSA (511 * 1000) 517#define MIN_MANTISSA (511 * 1000)
517 518
518static u16 pmbus_data2reg_linear(struct pmbus_data *data, 519static u16 pmbus_data2reg_linear(struct pmbus_data *data,
519 enum pmbus_sensor_classes class, long val) 520 struct pmbus_sensor *sensor, long val)
520{ 521{
521 s16 exponent = 0, mantissa; 522 s16 exponent = 0, mantissa;
522 bool negative = false; 523 bool negative = false;
@@ -525,7 +526,7 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
525 if (val == 0) 526 if (val == 0)
526 return 0; 527 return 0;
527 528
528 if (class == PSC_VOLTAGE_OUT) { 529 if (sensor->class == PSC_VOLTAGE_OUT) {
529 /* LINEAR16 does not support negative voltages */ 530 /* LINEAR16 does not support negative voltages */
530 if (val < 0) 531 if (val < 0)
531 return 0; 532 return 0;
@@ -534,10 +535,10 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
534 * For a static exponents, we don't have a choice 535 * For a static exponents, we don't have a choice
535 * but to adjust the value to it. 536 * but to adjust the value to it.
536 */ 537 */
537 if (data->exponent < 0) 538 if (data->exponent[sensor->page] < 0)
538 val <<= -data->exponent; 539 val <<= -data->exponent[sensor->page];
539 else 540 else
540 val >>= data->exponent; 541 val >>= data->exponent[sensor->page];
541 val = DIV_ROUND_CLOSEST(val, 1000); 542 val = DIV_ROUND_CLOSEST(val, 1000);
542 return val & 0xffff; 543 return val & 0xffff;
543 } 544 }
@@ -548,14 +549,14 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
548 } 549 }
549 550
550 /* Power is in uW. Convert to mW before converting. */ 551 /* Power is in uW. Convert to mW before converting. */
551 if (class == PSC_POWER) 552 if (sensor->class == PSC_POWER)
552 val = DIV_ROUND_CLOSEST(val, 1000L); 553 val = DIV_ROUND_CLOSEST(val, 1000L);
553 554
554 /* 555 /*
555 * For simplicity, convert fan data to milli-units 556 * For simplicity, convert fan data to milli-units
556 * before calculating the exponent. 557 * before calculating the exponent.
557 */ 558 */
558 if (class == PSC_FAN) 559 if (sensor->class == PSC_FAN)
559 val = val * 1000; 560 val = val * 1000;
560 561
561 /* Reduce large mantissa until it fits into 10 bit */ 562 /* Reduce large mantissa until it fits into 10 bit */
@@ -585,22 +586,22 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
585} 586}
586 587
587static u16 pmbus_data2reg_direct(struct pmbus_data *data, 588static u16 pmbus_data2reg_direct(struct pmbus_data *data,
588 enum pmbus_sensor_classes class, long val) 589 struct pmbus_sensor *sensor, long val)
589{ 590{
590 long m, b, R; 591 long m, b, R;
591 592
592 m = data->info->m[class]; 593 m = data->info->m[sensor->class];
593 b = data->info->b[class]; 594 b = data->info->b[sensor->class];
594 R = data->info->R[class]; 595 R = data->info->R[sensor->class];
595 596
596 /* Power is in uW. Adjust R and b. */ 597 /* Power is in uW. Adjust R and b. */
597 if (class == PSC_POWER) { 598 if (sensor->class == PSC_POWER) {
598 R -= 3; 599 R -= 3;
599 b *= 1000; 600 b *= 1000;
600 } 601 }
601 602
602 /* Calculate Y = (m * X + b) * 10^R */ 603 /* Calculate Y = (m * X + b) * 10^R */
603 if (class != PSC_FAN) { 604 if (sensor->class != PSC_FAN) {
604 R -= 3; /* Adjust R and b for data in milli-units */ 605 R -= 3; /* Adjust R and b for data in milli-units */
605 b *= 1000; 606 b *= 1000;
606 } 607 }
@@ -619,7 +620,7 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
619} 620}
620 621
621static u16 pmbus_data2reg_vid(struct pmbus_data *data, 622static u16 pmbus_data2reg_vid(struct pmbus_data *data,
622 enum pmbus_sensor_classes class, long val) 623 struct pmbus_sensor *sensor, long val)
623{ 624{
624 val = clamp_val(val, 500, 1600); 625 val = clamp_val(val, 500, 1600);
625 626
@@ -627,20 +628,20 @@ static u16 pmbus_data2reg_vid(struct pmbus_data *data,
627} 628}
628 629
629static u16 pmbus_data2reg(struct pmbus_data *data, 630static u16 pmbus_data2reg(struct pmbus_data *data,
630 enum pmbus_sensor_classes class, long val) 631 struct pmbus_sensor *sensor, long val)
631{ 632{
632 u16 regval; 633 u16 regval;
633 634
634 switch (data->info->format[class]) { 635 switch (data->info->format[sensor->class]) {
635 case direct: 636 case direct:
636 regval = pmbus_data2reg_direct(data, class, val); 637 regval = pmbus_data2reg_direct(data, sensor, val);
637 break; 638 break;
638 case vid: 639 case vid:
639 regval = pmbus_data2reg_vid(data, class, val); 640 regval = pmbus_data2reg_vid(data, sensor, val);
640 break; 641 break;
641 case linear: 642 case linear:
642 default: 643 default:
643 regval = pmbus_data2reg_linear(data, class, val); 644 regval = pmbus_data2reg_linear(data, sensor, val);
644 break; 645 break;
645 } 646 }
646 return regval; 647 return regval;
@@ -746,7 +747,7 @@ static ssize_t pmbus_set_sensor(struct device *dev,
746 return -EINVAL; 747 return -EINVAL;
747 748
748 mutex_lock(&data->update_lock); 749 mutex_lock(&data->update_lock);
749 regval = pmbus_data2reg(data, sensor->class, val); 750 regval = pmbus_data2reg(data, sensor, val);
750 ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval); 751 ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval);
751 if (ret < 0) 752 if (ret < 0)
752 rv = ret; 753 rv = ret;
@@ -1643,12 +1644,13 @@ static int pmbus_find_attributes(struct i2c_client *client,
1643 * This function is called for all chips. 1644 * This function is called for all chips.
1644 */ 1645 */
1645static int pmbus_identify_common(struct i2c_client *client, 1646static int pmbus_identify_common(struct i2c_client *client,
1646 struct pmbus_data *data) 1647 struct pmbus_data *data, int page)
1647{ 1648{
1648 int vout_mode = -1; 1649 int vout_mode = -1;
1649 1650
1650 if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) 1651 if (pmbus_check_byte_register(client, page, PMBUS_VOUT_MODE))
1651 vout_mode = _pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); 1652 vout_mode = _pmbus_read_byte_data(client, page,
1653 PMBUS_VOUT_MODE);
1652 if (vout_mode >= 0 && vout_mode != 0xff) { 1654 if (vout_mode >= 0 && vout_mode != 0xff) {
1653 /* 1655 /*
1654 * Not all chips support the VOUT_MODE command, 1656 * Not all chips support the VOUT_MODE command,
@@ -1659,7 +1661,7 @@ static int pmbus_identify_common(struct i2c_client *client,
1659 if (data->info->format[PSC_VOLTAGE_OUT] != linear) 1661 if (data->info->format[PSC_VOLTAGE_OUT] != linear)
1660 return -ENODEV; 1662 return -ENODEV;
1661 1663
1662 data->exponent = ((s8)(vout_mode << 3)) >> 3; 1664 data->exponent[page] = ((s8)(vout_mode << 3)) >> 3;
1663 break; 1665 break;
1664 case 1: /* VID mode */ 1666 case 1: /* VID mode */
1665 if (data->info->format[PSC_VOLTAGE_OUT] != vid) 1667 if (data->info->format[PSC_VOLTAGE_OUT] != vid)
@@ -1674,7 +1676,7 @@ static int pmbus_identify_common(struct i2c_client *client,
1674 } 1676 }
1675 } 1677 }
1676 1678
1677 pmbus_clear_fault_page(client, 0); 1679 pmbus_clear_fault_page(client, page);
1678 return 0; 1680 return 0;
1679} 1681}
1680 1682
@@ -1682,7 +1684,7 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
1682 struct pmbus_driver_info *info) 1684 struct pmbus_driver_info *info)
1683{ 1685{
1684 struct device *dev = &client->dev; 1686 struct device *dev = &client->dev;
1685 int ret; 1687 int page, ret;
1686 1688
1687 /* 1689 /*
1688 * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try 1690 * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try
@@ -1715,10 +1717,12 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
1715 return -ENODEV; 1717 return -ENODEV;
1716 } 1718 }
1717 1719
1718 ret = pmbus_identify_common(client, data); 1720 for (page = 0; page < info->pages; page++) {
1719 if (ret < 0) { 1721 ret = pmbus_identify_common(client, data, page);
1720 dev_err(dev, "Failed to identify chip capabilities\n"); 1722 if (ret < 0) {
1721 return ret; 1723 dev_err(dev, "Failed to identify chip capabilities\n");
1724 return ret;
1725 }
1722 } 1726 }
1723 return 0; 1727 return 0;
1724} 1728}