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 | |
| 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>
| -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: |
