OSDN Git Service

hwmon: (ina2xx) Use structure array to distinguish chip types
authorGuenter Roeck <linux@roeck-us.net>
Sat, 12 May 2012 18:21:01 +0000 (11:21 -0700)
committerGuenter Roeck <linux@roeck-us.net>
Mon, 24 Sep 2012 04:08:34 +0000 (21:08 -0700)
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>
drivers/hwmon/ina2xx.c

index 6021482..de8f2c6 100644 (file)
 
 enum ina2xx_ids { ina219, ina226 };
 
+struct ina2xx_config {
+       u16 config_default;
+       int calibration_factor;
+       int registers;
+       int shunt_div;
+       int bus_voltage_shift;
+       int bus_voltage_lsb;    /* uV */
+       int power_lsb;          /* uW */
+};
+
 struct ina2xx_data {
        struct device *hwmon_dev;
+       const struct ina2xx_config *config;
 
        struct mutex update_lock;
        bool valid;
        unsigned long last_updated;
 
        int kind;
-       int registers;
        u16 regs[INA2XX_MAX_REGISTERS];
 };
 
+static const struct ina2xx_config ina2xx_config[] = {
+       [ina219] = {
+               .config_default = INA219_CONFIG_DEFAULT,
+               .calibration_factor = 40960000,
+               .registers = INA219_REGISTERS,
+               .shunt_div = 100,
+               .bus_voltage_shift = 3,
+               .bus_voltage_lsb = 4000,
+               .power_lsb = 20000,
+       },
+       [ina226] = {
+               .config_default = INA226_CONFIG_DEFAULT,
+               .calibration_factor = 5120000,
+               .registers = INA226_REGISTERS,
+               .shunt_div = 400,
+               .bus_voltage_shift = 0,
+               .bus_voltage_lsb = 1250,
+               .power_lsb = 25000,
+       },
+};
+
 static struct ina2xx_data *ina2xx_update_device(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -85,7 +116,7 @@ static struct ina2xx_data *ina2xx_update_device(struct device *dev)
                dev_dbg(&client->dev, "Starting ina2xx update\n");
 
                /* Read all registers */
-               for (i = 0; i < data->registers; i++) {
+               for (i = 0; i < data->config->registers; i++) {
                        int rv = i2c_smbus_read_word_swapped(client, i);
                        if (rv < 0) {
                                ret = ERR_PTR(rv);
@@ -101,73 +132,26 @@ abort:
        return ret;
 }
 
-static int ina219_get_value(struct ina2xx_data *data, u8 reg)
-{
-       /*
-        * calculate exact value for the given register
-        * we assume default power-on reset settings:
-        * bus voltage range 32V
-        * gain = /8
-        * adc 1 & 2 -> conversion time 532uS
-        * mode is continuous shunt and bus
-        * calibration value is INA219_CALIBRATION_VALUE
-        */
-       int val = data->regs[reg];
-
-       switch (reg) {
-       case INA2XX_SHUNT_VOLTAGE:
-               /* LSB=10uV. Convert to mV. */
-               val = DIV_ROUND_CLOSEST(val, 100);
-               break;
-       case INA2XX_BUS_VOLTAGE:
-               /* LSB=4mV. Register is not right aligned, convert to mV. */
-               val = (val >> 3) * 4;
-               break;
-       case INA2XX_POWER:
-               /* LSB=20mW. Convert to uW */
-               val = val * 20 * 1000;
-               break;
-       case INA2XX_CURRENT:
-               /* LSB=1mA (selected). Is in mA */
-               break;
-       default:
-               /* programmer goofed */
-               WARN_ON_ONCE(1);
-               val = 0;
-               break;
-       }
-
-       return val;
-}
-
-static int ina226_get_value(struct ina2xx_data *data, u8 reg)
+static int ina2xx_get_value(struct ina2xx_data *data, u8 reg)
 {
-       /*
-        * calculate exact value for the given register
-        * we assume default power-on reset settings:
-        * bus voltage range 32V
-        * gain = /8
-        * adc 1 & 2 -> conversion time 532uS
-        * mode is continuous shunt and bus
-        * calibration value is INA226_CALIBRATION_VALUE
-        */
-       int val = data->regs[reg];
+       int val;
 
        switch (reg) {
        case INA2XX_SHUNT_VOLTAGE:
-               /* LSB=2.5uV. Convert to mV. */
-               val = DIV_ROUND_CLOSEST(val, 400);
+               val = DIV_ROUND_CLOSEST(data->regs[reg],
+                                       data->config->shunt_div);
                break;
        case INA2XX_BUS_VOLTAGE:
-               /* LSB=1.25mV. Convert to mV. */
-               val = val + DIV_ROUND_CLOSEST(val, 4);
+               val = (data->regs[reg] >> data->config->bus_voltage_shift)
+                 * data->config->bus_voltage_lsb;
+               val = DIV_ROUND_CLOSEST(val, 1000);
                break;
        case INA2XX_POWER:
-               /* LSB=25mW. Convert to uW */
-               val = val * 25 * 1000;
+               val = data->regs[reg] * data->config->power_lsb;
                break;
        case INA2XX_CURRENT:
                /* LSB=1mA (selected). Is in mA */
+               val = data->regs[reg];
                break;
        default:
                /* programmer goofed */
@@ -184,23 +168,12 @@ static ssize_t ina2xx_show_value(struct device *dev,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
        struct ina2xx_data *data = ina2xx_update_device(dev);
-       int value = 0;
 
        if (IS_ERR(data))
                return PTR_ERR(data);
 
-       switch (data->kind) {
-       case ina219:
-               value = ina219_get_value(data, attr->index);
-               break;
-       case ina226:
-               value = ina226_get_value(data, attr->index);
-               break;
-       default:
-               WARN_ON_ONCE(1);
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%d\n", value);
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       ina2xx_get_value(data, attr->index));
 }
 
 /* shunt voltage */
@@ -238,7 +211,7 @@ static int ina2xx_probe(struct i2c_client *client,
        struct i2c_adapter *adapter = client->adapter;
        struct ina2xx_data *data;
        struct ina2xx_platform_data *pdata;
-       int ret = 0;
+       int ret;
        long shunt = 10000; /* default shunt value 10mOhms */
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
@@ -259,38 +232,15 @@ static int ina2xx_probe(struct i2c_client *client,
 
        /* set the device type */
        data->kind = id->driver_data;
+       data->config = &ina2xx_config[data->kind];
 
-       switch (data->kind) {
-       case ina219:
-               /* device configuration */
-               i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
-                                            INA219_CONFIG_DEFAULT);
-
-               /* set current LSB to 1mA, shunt is in uOhms */
-               /* (equation 13 in datasheet) */
-               i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
-                                            40960000 / shunt);
-               dev_info(&client->dev,
-                        "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
-               data->registers = INA219_REGISTERS;
-               break;
-       case ina226:
-               /* device configuration */
-               i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
-                                            INA226_CONFIG_DEFAULT);
-
-               /* set current LSB to 1mA, shunt is in uOhms */
-               /* (equation 1 in datasheet)*/
-               i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
-                                            5120000 / shunt);
-               dev_info(&client->dev,
-                        "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
-               data->registers = INA226_REGISTERS;
-               break;
-       default:
-               /* unknown device id */
-               return -ENODEV;
-       }
+       /* device configuration */
+       i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
+                                    data->config->config_default);
+       /* set current LSB to 1mA, shunt is in uOhms */
+       /* (equation 13 in datasheet) */
+       i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
+                                    data->config->calibration_factor / shunt);
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -305,6 +255,9 @@ static int ina2xx_probe(struct i2c_client *client,
                goto out_err_hwmon;
        }
 
+       dev_info(&client->dev, "power monitor %s (Rshunt = %li uOhm)\n",
+                id->name, shunt);
+
        return 0;
 
 out_err_hwmon: