diff options
author | Guenter Roeck <linux@roeck-us.net> | 2012-05-12 14:21:01 -0400 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2012-09-24 00:08:34 -0400 |
commit | 6106db25c27550337a1d701631093cdfc645aa7b (patch) | |
tree | 22797d324f513dd903c702801d70248be24159cf /drivers/hwmon/ina2xx.c | |
parent | 9224c38a312a339f1c9c2115a1f379c9f8f1731e (diff) |
hwmon: (ina2xx) Use structure array to distinguish chip types
Replace per-device initialization and per-device calculation code with
per-device configuration data, which is then used to configure the chip and
perform calculations based on that data.
This patch reduces code size by more than 400 bytes on x86_64.
Cc: Lothar Felten <l-felten@ti.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/ina2xx.c')
-rw-r--r-- | drivers/hwmon/ina2xx.c | 159 |
1 files changed, 56 insertions, 103 deletions
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 602148299f68..de8f2c6c6b66 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c | |||
@@ -57,18 +57,49 @@ | |||
57 | 57 | ||
58 | enum ina2xx_ids { ina219, ina226 }; | 58 | enum ina2xx_ids { ina219, ina226 }; |
59 | 59 | ||
60 | struct ina2xx_config { | ||
61 | u16 config_default; | ||
62 | int calibration_factor; | ||
63 | int registers; | ||
64 | int shunt_div; | ||
65 | int bus_voltage_shift; | ||
66 | int bus_voltage_lsb; /* uV */ | ||
67 | int power_lsb; /* uW */ | ||
68 | }; | ||
69 | |||
60 | struct ina2xx_data { | 70 | struct ina2xx_data { |
61 | struct device *hwmon_dev; | 71 | struct device *hwmon_dev; |
72 | const struct ina2xx_config *config; | ||
62 | 73 | ||
63 | struct mutex update_lock; | 74 | struct mutex update_lock; |
64 | bool valid; | 75 | bool valid; |
65 | unsigned long last_updated; | 76 | unsigned long last_updated; |
66 | 77 | ||
67 | int kind; | 78 | int kind; |
68 | int registers; | ||
69 | u16 regs[INA2XX_MAX_REGISTERS]; | 79 | u16 regs[INA2XX_MAX_REGISTERS]; |
70 | }; | 80 | }; |
71 | 81 | ||
82 | static const struct ina2xx_config ina2xx_config[] = { | ||
83 | [ina219] = { | ||
84 | .config_default = INA219_CONFIG_DEFAULT, | ||
85 | .calibration_factor = 40960000, | ||
86 | .registers = INA219_REGISTERS, | ||
87 | .shunt_div = 100, | ||
88 | .bus_voltage_shift = 3, | ||
89 | .bus_voltage_lsb = 4000, | ||
90 | .power_lsb = 20000, | ||
91 | }, | ||
92 | [ina226] = { | ||
93 | .config_default = INA226_CONFIG_DEFAULT, | ||
94 | .calibration_factor = 5120000, | ||
95 | .registers = INA226_REGISTERS, | ||
96 | .shunt_div = 400, | ||
97 | .bus_voltage_shift = 0, | ||
98 | .bus_voltage_lsb = 1250, | ||
99 | .power_lsb = 25000, | ||
100 | }, | ||
101 | }; | ||
102 | |||
72 | static struct ina2xx_data *ina2xx_update_device(struct device *dev) | 103 | static struct ina2xx_data *ina2xx_update_device(struct device *dev) |
73 | { | 104 | { |
74 | struct i2c_client *client = to_i2c_client(dev); | 105 | struct i2c_client *client = to_i2c_client(dev); |
@@ -85,7 +116,7 @@ static struct ina2xx_data *ina2xx_update_device(struct device *dev) | |||
85 | dev_dbg(&client->dev, "Starting ina2xx update\n"); | 116 | dev_dbg(&client->dev, "Starting ina2xx update\n"); |
86 | 117 | ||
87 | /* Read all registers */ | 118 | /* Read all registers */ |
88 | for (i = 0; i < data->registers; i++) { | 119 | for (i = 0; i < data->config->registers; i++) { |
89 | int rv = i2c_smbus_read_word_swapped(client, i); | 120 | int rv = i2c_smbus_read_word_swapped(client, i); |
90 | if (rv < 0) { | 121 | if (rv < 0) { |
91 | ret = ERR_PTR(rv); | 122 | ret = ERR_PTR(rv); |
@@ -101,73 +132,26 @@ abort: | |||
101 | return ret; | 132 | return ret; |
102 | } | 133 | } |
103 | 134 | ||
104 | static int ina219_get_value(struct ina2xx_data *data, u8 reg) | 135 | static int ina2xx_get_value(struct ina2xx_data *data, u8 reg) |
105 | { | ||
106 | /* | ||
107 | * calculate exact value for the given register | ||
108 | * we assume default power-on reset settings: | ||
109 | * bus voltage range 32V | ||
110 | * gain = /8 | ||
111 | * adc 1 & 2 -> conversion time 532uS | ||
112 | * mode is continuous shunt and bus | ||
113 | * calibration value is INA219_CALIBRATION_VALUE | ||
114 | */ | ||
115 | int val = data->regs[reg]; | ||
116 | |||
117 | switch (reg) { | ||
118 | case INA2XX_SHUNT_VOLTAGE: | ||
119 | /* LSB=10uV. Convert to mV. */ | ||
120 | val = DIV_ROUND_CLOSEST(val, 100); | ||
121 | break; | ||
122 | case INA2XX_BUS_VOLTAGE: | ||
123 | /* LSB=4mV. Register is not right aligned, convert to mV. */ | ||
124 | val = (val >> 3) * 4; | ||
125 | break; | ||
126 | case INA2XX_POWER: | ||
127 | /* LSB=20mW. Convert to uW */ | ||
128 | val = val * 20 * 1000; | ||
129 | break; | ||
130 | case INA2XX_CURRENT: | ||
131 | /* LSB=1mA (selected). Is in mA */ | ||
132 | break; | ||
133 | default: | ||
134 | /* programmer goofed */ | ||
135 | WARN_ON_ONCE(1); | ||
136 | val = 0; | ||
137 | break; | ||
138 | } | ||
139 | |||
140 | return val; | ||
141 | } | ||
142 | |||
143 | static int ina226_get_value(struct ina2xx_data *data, u8 reg) | ||
144 | { | 136 | { |
145 | /* | 137 | int val; |
146 | * calculate exact value for the given register | ||
147 | * we assume default power-on reset settings: | ||
148 | * bus voltage range 32V | ||
149 | * gain = /8 | ||
150 | * adc 1 & 2 -> conversion time 532uS | ||
151 | * mode is continuous shunt and bus | ||
152 | * calibration value is INA226_CALIBRATION_VALUE | ||
153 | */ | ||
154 | int val = data->regs[reg]; | ||
155 | 138 | ||
156 | switch (reg) { | 139 | switch (reg) { |
157 | case INA2XX_SHUNT_VOLTAGE: | 140 | case INA2XX_SHUNT_VOLTAGE: |
158 | /* LSB=2.5uV. Convert to mV. */ | 141 | val = DIV_ROUND_CLOSEST(data->regs[reg], |
159 | val = DIV_ROUND_CLOSEST(val, 400); | 142 | data->config->shunt_div); |
160 | break; | 143 | break; |
161 | case INA2XX_BUS_VOLTAGE: | 144 | case INA2XX_BUS_VOLTAGE: |
162 | /* LSB=1.25mV. Convert to mV. */ | 145 | val = (data->regs[reg] >> data->config->bus_voltage_shift) |
163 | val = val + DIV_ROUND_CLOSEST(val, 4); | 146 | * data->config->bus_voltage_lsb; |
147 | val = DIV_ROUND_CLOSEST(val, 1000); | ||
164 | break; | 148 | break; |
165 | case INA2XX_POWER: | 149 | case INA2XX_POWER: |
166 | /* LSB=25mW. Convert to uW */ | 150 | val = data->regs[reg] * data->config->power_lsb; |
167 | val = val * 25 * 1000; | ||
168 | break; | 151 | break; |
169 | case INA2XX_CURRENT: | 152 | case INA2XX_CURRENT: |
170 | /* LSB=1mA (selected). Is in mA */ | 153 | /* LSB=1mA (selected). Is in mA */ |
154 | val = data->regs[reg]; | ||
171 | break; | 155 | break; |
172 | default: | 156 | default: |
173 | /* programmer goofed */ | 157 | /* programmer goofed */ |
@@ -184,23 +168,12 @@ static ssize_t ina2xx_show_value(struct device *dev, | |||
184 | { | 168 | { |
185 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | 169 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
186 | struct ina2xx_data *data = ina2xx_update_device(dev); | 170 | struct ina2xx_data *data = ina2xx_update_device(dev); |
187 | int value = 0; | ||
188 | 171 | ||
189 | if (IS_ERR(data)) | 172 | if (IS_ERR(data)) |
190 | return PTR_ERR(data); | 173 | return PTR_ERR(data); |
191 | 174 | ||
192 | switch (data->kind) { | 175 | return snprintf(buf, PAGE_SIZE, "%d\n", |
193 | case ina219: | 176 | ina2xx_get_value(data, attr->index)); |
194 | value = ina219_get_value(data, attr->index); | ||
195 | break; | ||
196 | case ina226: | ||
197 | value = ina226_get_value(data, attr->index); | ||
198 | break; | ||
199 | default: | ||
200 | WARN_ON_ONCE(1); | ||
201 | break; | ||
202 | } | ||
203 | return snprintf(buf, PAGE_SIZE, "%d\n", value); | ||
204 | } | 177 | } |
205 | 178 | ||
206 | /* shunt voltage */ | 179 | /* shunt voltage */ |
@@ -238,7 +211,7 @@ static int ina2xx_probe(struct i2c_client *client, | |||
238 | struct i2c_adapter *adapter = client->adapter; | 211 | struct i2c_adapter *adapter = client->adapter; |
239 | struct ina2xx_data *data; | 212 | struct ina2xx_data *data; |
240 | struct ina2xx_platform_data *pdata; | 213 | struct ina2xx_platform_data *pdata; |
241 | int ret = 0; | 214 | int ret; |
242 | long shunt = 10000; /* default shunt value 10mOhms */ | 215 | long shunt = 10000; /* default shunt value 10mOhms */ |
243 | 216 | ||
244 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) | 217 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) |
@@ -259,38 +232,15 @@ static int ina2xx_probe(struct i2c_client *client, | |||
259 | 232 | ||
260 | /* set the device type */ | 233 | /* set the device type */ |
261 | data->kind = id->driver_data; | 234 | data->kind = id->driver_data; |
235 | data->config = &ina2xx_config[data->kind]; | ||
262 | 236 | ||
263 | switch (data->kind) { | 237 | /* device configuration */ |
264 | case ina219: | 238 | i2c_smbus_write_word_swapped(client, INA2XX_CONFIG, |
265 | /* device configuration */ | 239 | data->config->config_default); |
266 | i2c_smbus_write_word_swapped(client, INA2XX_CONFIG, | 240 | /* set current LSB to 1mA, shunt is in uOhms */ |
267 | INA219_CONFIG_DEFAULT); | 241 | /* (equation 13 in datasheet) */ |
268 | 242 | i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION, | |
269 | /* set current LSB to 1mA, shunt is in uOhms */ | 243 | data->config->calibration_factor / shunt); |
270 | /* (equation 13 in datasheet) */ | ||
271 | i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION, | ||
272 | 40960000 / shunt); | ||
273 | dev_info(&client->dev, | ||
274 | "power monitor INA219 (Rshunt = %li uOhm)\n", shunt); | ||
275 | data->registers = INA219_REGISTERS; | ||
276 | break; | ||
277 | case ina226: | ||
278 | /* device configuration */ | ||
279 | i2c_smbus_write_word_swapped(client, INA2XX_CONFIG, | ||
280 | INA226_CONFIG_DEFAULT); | ||
281 | |||
282 | /* set current LSB to 1mA, shunt is in uOhms */ | ||
283 | /* (equation 1 in datasheet)*/ | ||
284 | i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION, | ||
285 | 5120000 / shunt); | ||
286 | dev_info(&client->dev, | ||
287 | "power monitor INA226 (Rshunt = %li uOhm)\n", shunt); | ||
288 | data->registers = INA226_REGISTERS; | ||
289 | break; | ||
290 | default: | ||
291 | /* unknown device id */ | ||
292 | return -ENODEV; | ||
293 | } | ||
294 | 244 | ||
295 | i2c_set_clientdata(client, data); | 245 | i2c_set_clientdata(client, data); |
296 | mutex_init(&data->update_lock); | 246 | mutex_init(&data->update_lock); |
@@ -305,6 +255,9 @@ static int ina2xx_probe(struct i2c_client *client, | |||
305 | goto out_err_hwmon; | 255 | goto out_err_hwmon; |
306 | } | 256 | } |
307 | 257 | ||
258 | dev_info(&client->dev, "power monitor %s (Rshunt = %li uOhm)\n", | ||
259 | id->name, shunt); | ||
260 | |||
308 | return 0; | 261 | return 0; |
309 | 262 | ||
310 | out_err_hwmon: | 263 | out_err_hwmon: |