Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

hwmon: (ina238) Rework and simplify temperature calculations

The temperature register is 16 bit wide for all chips. The decimal point
is at the same location (bit 7 = 1 degree C). That means we can use the
resolution to calculate temperatures. Do that to simplify the code.

There is only a single writeable temperature attribute, and it is very
unlikely that the chips supported by this driver will ever require another
one. That means checking for that attribute in the write function is
unnecessary. Drop the check. Rename the write function from
ina238_write_temp() to ina238_write_temp_max() to reflect that a single
attribute is written.

Also extend the accepted temperature value range to the range supported by
the chip registers. Limiting the accepted value range to the temperature
range supported by the chip would make it impossible to read an
out-of-range limit from the chip and to write the same value back into it.
This is undesirable, especially since the maximum temperature register does
contain the maximum register value after a chip reset, not the temperature
limit supported by the chip.

Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Tested-by: Chris Packham <chris.packham@alliedtelesis.co.nz> # INA780
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

+24 -28
+24 -28
drivers/hwmon/ina238.c
··· 103 103 104 104 #define INA238_SHUNT_VOLTAGE_LSB 5 /* 5 uV/lsb */ 105 105 #define INA238_BUS_VOLTAGE_LSB 3125 /* 3.125 mV/lsb */ 106 - #define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */ 107 106 #define SQ52206_BUS_VOLTAGE_LSB 3750 /* 3.75 mV/lsb */ 108 - #define SQ52206_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */ 109 - #define INA228_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */ 110 107 111 108 static const struct regmap_config ina238_regmap_config = { 112 109 .max_register = INA238_REGISTERS, ··· 117 120 bool has_20bit_voltage_current; /* vshunt, vbus and current are 20-bit fields */ 118 121 bool has_power_highest; /* chip detection power peak */ 119 122 bool has_energy; /* chip detection energy */ 120 - u8 temp_shift; /* fixed parameters for temp calculate */ 123 + u8 temp_resolution; /* temperature register resolution in bit */ 121 124 u32 power_calculate_factor; /* fixed parameters for power calculate */ 122 125 u16 config_default; /* Power-on default state */ 123 126 int bus_voltage_lsb; /* use for temperature calculate, uV/lsb */ 124 - int temp_lsb; /* use for temperature calculate */ 125 127 }; 126 128 127 129 struct ina238_data { ··· 137 141 .has_20bit_voltage_current = false, 138 142 .has_energy = false, 139 143 .has_power_highest = false, 140 - .temp_shift = 4, 141 144 .power_calculate_factor = 20, 142 145 .config_default = INA238_CONFIG_DEFAULT, 143 146 .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, 144 - .temp_lsb = INA238_DIE_TEMP_LSB, 147 + .temp_resolution = 12, 145 148 }, 146 149 [ina237] = { 147 150 .has_20bit_voltage_current = false, 148 151 .has_energy = false, 149 152 .has_power_highest = false, 150 - .temp_shift = 4, 151 153 .power_calculate_factor = 20, 152 154 .config_default = INA238_CONFIG_DEFAULT, 153 155 .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, 154 - .temp_lsb = INA238_DIE_TEMP_LSB, 156 + .temp_resolution = 12, 155 157 }, 156 158 [sq52206] = { 157 159 .has_20bit_voltage_current = false, 158 160 .has_energy = true, 159 161 .has_power_highest = true, 160 - .temp_shift = 0, 161 162 .power_calculate_factor = 24, 162 163 .config_default = SQ52206_CONFIG_DEFAULT, 163 164 .bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB, 164 - .temp_lsb = SQ52206_DIE_TEMP_LSB, 165 + .temp_resolution = 16, 165 166 }, 166 167 [ina228] = { 167 168 .has_20bit_voltage_current = true, 168 169 .has_energy = true, 169 170 .has_power_highest = false, 170 - .temp_shift = 0, 171 171 .power_calculate_factor = 20, 172 172 .config_default = INA238_CONFIG_DEFAULT, 173 173 .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, 174 - .temp_lsb = INA228_DIE_TEMP_LSB, 174 + .temp_resolution = 16, 175 175 }, 176 176 }; 177 177 ··· 514 522 return regmap_write(data->regmap, INA238_POWER_LIMIT, regval); 515 523 } 516 524 525 + static int ina238_temp_from_reg(s16 regval, u8 resolution) 526 + { 527 + return ((regval >> (16 - resolution)) * 1000) >> (resolution - 9); 528 + } 529 + 517 530 static int ina238_read_temp(struct device *dev, u32 attr, long *val) 518 531 { 519 532 struct ina238_data *data = dev_get_drvdata(dev); ··· 530 533 err = regmap_read(data->regmap, INA238_DIE_TEMP, &regval); 531 534 if (err) 532 535 return err; 533 - /* Signed, result in mC */ 534 - *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) * 535 - (s64)data->config->temp_lsb, 10000); 536 + *val = ina238_temp_from_reg(regval, data->config->temp_resolution); 536 537 break; 537 538 case hwmon_temp_max: 538 539 err = regmap_read(data->regmap, INA238_TEMP_LIMIT, &regval); 539 540 if (err) 540 541 return err; 541 542 /* Signed, result in mC */ 542 - *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) * 543 - (s64)data->config->temp_lsb, 10000); 543 + *val = ina238_temp_from_reg(regval, data->config->temp_resolution); 544 544 break; 545 545 case hwmon_temp_max_alarm: 546 546 err = regmap_read(data->regmap, INA238_DIAG_ALERT, &regval); ··· 553 559 return 0; 554 560 } 555 561 556 - static int ina238_write_temp(struct device *dev, u32 attr, long val) 562 + static u16 ina238_temp_to_reg(long val, u8 resolution) 563 + { 564 + int fraction = 1000 - DIV_ROUND_CLOSEST(1000, BIT(resolution - 9)); 565 + 566 + val = clamp_val(val, -255000 - fraction, 255000 + fraction); 567 + 568 + return (DIV_ROUND_CLOSEST(val << (resolution - 9), 1000) << (16 - resolution)) & 0xffff; 569 + } 570 + 571 + static int ina238_write_temp_max(struct device *dev, long val) 557 572 { 558 573 struct ina238_data *data = dev_get_drvdata(dev); 559 574 int regval; 560 575 561 - if (attr != hwmon_temp_max) 562 - return -EOPNOTSUPP; 563 - 564 - /* Signed */ 565 - val = clamp_val(val, -40000, 125000); 566 - regval = div_s64(val * 10000, data->config->temp_lsb) << data->config->temp_shift; 567 - regval = clamp_val(regval, S16_MIN, S16_MAX) & (0xffff << data->config->temp_shift); 568 - 576 + regval = ina238_temp_to_reg(val, data->config->temp_resolution); 569 577 return regmap_write(data->regmap, INA238_TEMP_LIMIT, regval); 570 578 } 571 579 ··· 624 628 err = ina238_write_power_max(dev, val); 625 629 break; 626 630 case hwmon_temp: 627 - err = ina238_write_temp(dev, attr, val); 631 + err = ina238_write_temp_max(dev, val); 628 632 break; 629 633 default: 630 634 err = -EOPNOTSUPP;