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

hwmon: (mcp3021) Fix broken output scaling

The mcp3021 scaling code is dividing the VDD (full-scale) value in
millivolts by the A2D resolution to obtain the scaling factor. When VDD
is 3300mV (the standard value) and the resolution is 12-bit (4096
divisions), the result is a scale factor of 3300/4096, which is always
one. Effectively, the raw A2D reading is always being returned because
no scaling is applied.

This patch fixes the issue and simplifies the register-to-volts
calculation, removing the unneeded "output_scale" struct member.

Signed-off-by: Nick Stevens <Nick.Stevens@digi.com>
Cc: stable@vger.kernel.org # v3.10+
[Guenter Roeck: Dropped unnecessary value check]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Stevens, Nick and committed by
Guenter Roeck
347d7e45 56172d81

+1 -13
+1 -13
drivers/hwmon/mcp3021.c
··· 31 31 /* output format */ 32 32 #define MCP3021_SAR_SHIFT 2 33 33 #define MCP3021_SAR_MASK 0x3ff 34 - 35 34 #define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */ 36 - #define MCP3021_OUTPUT_SCALE 4 37 35 38 36 #define MCP3221_SAR_SHIFT 0 39 37 #define MCP3221_SAR_MASK 0xfff 40 38 #define MCP3221_OUTPUT_RES 12 /* 12-bit resolution */ 41 - #define MCP3221_OUTPUT_SCALE 1 42 39 43 40 enum chips { 44 41 mcp3021, ··· 51 54 u16 sar_shift; 52 55 u16 sar_mask; 53 56 u8 output_res; 54 - u8 output_scale; 55 57 }; 56 58 57 59 static int mcp3021_read16(struct i2c_client *client) ··· 80 84 81 85 static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val) 82 86 { 83 - if (val == 0) 84 - return 0; 85 - 86 - val = val * data->output_scale - data->output_scale / 2; 87 - 88 - return val * DIV_ROUND_CLOSEST(data->vdd, 89 - (1 << data->output_res) * data->output_scale); 87 + return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res); 90 88 } 91 89 92 90 static ssize_t show_in_input(struct device *dev, struct device_attribute *attr, ··· 122 132 data->sar_shift = MCP3021_SAR_SHIFT; 123 133 data->sar_mask = MCP3021_SAR_MASK; 124 134 data->output_res = MCP3021_OUTPUT_RES; 125 - data->output_scale = MCP3021_OUTPUT_SCALE; 126 135 break; 127 136 128 137 case mcp3221: 129 138 data->sar_shift = MCP3221_SAR_SHIFT; 130 139 data->sar_mask = MCP3221_SAR_MASK; 131 140 data->output_res = MCP3221_OUTPUT_RES; 132 - data->output_scale = MCP3221_OUTPUT_SCALE; 133 141 break; 134 142 } 135 143