// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Texas Instruments INA219, INA226 power monitor chips * * INA219: * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface * Datasheet: https://www.ti.com/product/ina219 * * INA220: * Bi-Directional Current/Power Monitor with I2C Interface * Datasheet: https://www.ti.com/product/ina220 * * INA226: * Bi-Directional Current/Power Monitor with I2C Interface * Datasheet: https://www.ti.com/product/ina226 * * INA230: * Bi-directional Current/Power Monitor with I2C Interface * Datasheet: https://www.ti.com/product/ina230 * * Copyright (C) 2012 Lothar Felten * Thanks to Jan Volkering */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* common register definitions */ #define INA2XX_CONFIG 0x00 #define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */ #define INA2XX_BUS_VOLTAGE 0x02 /* readonly */ #define INA2XX_POWER 0x03 /* readonly */ #define INA2XX_CURRENT 0x04 /* readonly */ #define INA2XX_CALIBRATION 0x05 /* INA226 register definitions */ #define INA226_MASK_ENABLE 0x06 #define INA226_ALERT_LIMIT 0x07 #define INA226_DIE_ID 0xFF #define INA2XX_MAX_REGISTERS 8 /* settings - depend on use case */ #define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */ #define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */ /* worst case is 68.10 ms (~14.6Hz, ina219) */ #define INA2XX_CONVERSION_RATE 15 #define INA2XX_MAX_DELAY 69 /* worst case delay in ms */ #define INA2XX_RSHUNT_DEFAULT 10000 /* bit mask for reading the averaging setting in the configuration register */ #define INA226_AVG_RD_MASK GENMASK(11, 9) #define INA226_READ_AVG(reg) FIELD_GET(INA226_AVG_RD_MASK, reg) #define INA226_ALERT_LATCH_ENABLE BIT(0) #define INA226_ALERT_POLARITY BIT(1) /* bit number of alert functions in Mask/Enable Register */ #define INA226_SHUNT_OVER_VOLTAGE_MASK BIT(15) #define INA226_SHUNT_UNDER_VOLTAGE_MASK BIT(14) #define INA226_BUS_OVER_VOLTAGE_MASK BIT(13) #define INA226_BUS_UNDER_VOLTAGE_MASK BIT(12) #define INA226_POWER_OVER_LIMIT_MASK BIT(11) /* bit mask for alert config bits of Mask/Enable Register */ #define INA226_ALERT_CONFIG_MASK GENMASK(15, 10) #define INA226_ALERT_FUNCTION_FLAG BIT(4) /* * Both bus voltage and shunt voltage conversion times for ina226 are set * to 0b0100 on POR, which translates to 2200 microseconds in total. */ #define INA226_TOTAL_CONV_TIME_DEFAULT 2200 static bool ina2xx_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { case INA2XX_CONFIG: case INA2XX_CALIBRATION: case INA226_MASK_ENABLE: case INA226_ALERT_LIMIT: return true; default: return false; } } static bool ina2xx_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case INA2XX_SHUNT_VOLTAGE: case INA2XX_BUS_VOLTAGE: case INA2XX_POWER: case INA2XX_CURRENT: return true; default: return false; } } static const struct regmap_config ina2xx_regmap_config = { .reg_bits = 8, .val_bits = 16, .use_single_write = true, .use_single_read = true, .max_register = INA2XX_MAX_REGISTERS, .cache_type = REGCACHE_MAPLE, .volatile_reg = ina2xx_volatile_reg, .writeable_reg = ina2xx_writeable_reg, }; enum ina2xx_ids { ina219, ina226 }; struct ina2xx_config { u16 config_default; int calibration_value; int shunt_div; int bus_voltage_shift; int bus_voltage_lsb; /* uV */ int power_lsb_factor; }; struct ina2xx_data { const struct ina2xx_config *config; enum ina2xx_ids chip; long rshunt; long current_lsb_uA; long power_lsb_uW; struct mutex config_lock; struct regmap *regmap; }; static const struct ina2xx_config ina2xx_config[] = { [ina219] = { .config_default = INA219_CONFIG_DEFAULT, .calibration_value = 4096, .shunt_div = 100, .bus_voltage_shift = 3, .bus_voltage_lsb = 4000, .power_lsb_factor = 20, }, [ina226] = { .config_default = INA226_CONFIG_DEFAULT, .calibration_value = 2048, .shunt_div = 400, .bus_voltage_shift = 0, .bus_voltage_lsb = 1250, .power_lsb_factor = 25, }, }; /* * Available averaging rates for ina226. The indices correspond with * the bit values expected by the chip (according to the ina226 datasheet, * table 3 AVG bit settings, found at * https://www.ti.com/lit/ds/symlink/ina226.pdf. */ static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 }; static int ina226_reg_to_interval(u16 config) { int avg = ina226_avg_tab[INA226_READ_AVG(config)]; /* * Multiply the total conversion time by the number of averages. * Return the result in milliseconds. */ return DIV_ROUND_CLOSEST(avg * INA226_TOTAL_CONV_TIME_DEFAULT, 1000); } /* * Return the new, shifted AVG field value of CONFIG register, * to use with regmap_update_bits */ static u16 ina226_interval_to_reg(long interval) { int avg, avg_bits; /* * The maximum supported interval is 1,024 * (2 * 8.244ms) ~= 16.8s. * Clamp to 32 seconds before calculations to avoid overflows. */ interval = clamp_val(interval, 0, 32000); avg = DIV_ROUND_CLOSEST(interval * 1000, INA226_TOTAL_CONV_TIME_DEFAULT); avg_bits = find_closest(avg, ina226_avg_tab, ARRAY_SIZE(ina226_avg_tab)); return FIELD_PREP(INA226_AVG_RD_MASK, avg_bits); } static int ina2xx_get_value(struct ina2xx_data *data, u8 reg, unsigned int regval) { int val; switch (reg) { case INA2XX_SHUNT_VOLTAGE: /* signed register */ val = DIV_ROUND_CLOSEST((s16)regval, data->config->shunt_div); break; case INA2XX_BUS_VOLTAGE: val = (regval >> data->config->bus_voltage_shift) * data->config->bus_voltage_lsb; val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_POWER: val = regval * data->power_lsb_uW; break; case INA2XX_CURRENT: /* signed register, result in mA */ val = (s16)regval * data->current_lsb_uA; val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_CALIBRATION: val = regval; break; default: /* programmer goofed */ WARN_ON_ONCE(1); val = 0; break; } return val; } /* * Read and convert register value from chip. If the register value is 0, * check if the chip has been power cycled or reset. If so, re-initialize it. */ static int ina2xx_read_init(struct device *dev, int reg, long *val) { struct ina2xx_data *data = dev_get_drvdata(dev); struct regmap *regmap = data->regmap; unsigned int regval; int ret, retry; for (retry = 5; retry; retry--) { ret = regmap_read(regmap, reg, ®val); if (ret < 0) return ret; /* * If the current value in the calibration register is 0, the * power and current registers will also remain at 0. In case * the chip has been reset let's check the calibration * register and reinitialize if needed. * We do that extra read of the calibration register if there * is some hint of a chip reset. */ if (regval == 0) { unsigned int cal; ret = regmap_read_bypassed(regmap, INA2XX_CALIBRATION, &cal); if (ret < 0) return ret; if (cal == 0) { dev_warn(dev, "chip not calibrated, reinitializing\n"); regcache_mark_dirty(regmap); regcache_sync(regmap); /* * Let's make sure the power and current * registers have been updated before trying * again. */ msleep(INA2XX_MAX_DELAY); continue; } } *val = ina2xx_get_value(data, reg, regval); return 0; } /* * If we're here then although all write operations succeeded, the * chip still returns 0 in the calibration register. Nothing more we * can do here. */ dev_err(dev, "unable to reinitialize the chip\n"); return -ENODEV; } /* * Turns alert limit values into register values. * Opposite of the formula in ina2xx_get_value(). */ static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val) { switch (reg) { case INA2XX_SHUNT_VOLTAGE: val = clamp_val(val, 0, SHRT_MAX * data->config->shunt_div); val *= data->config->shunt_div; return clamp_val(val, 0, SHRT_MAX); case INA2XX_BUS_VOLTAGE: val = clamp_val(val, 0, 200000); val = (val * 1000) << data->config->bus_voltage_shift; val = DIV_ROUND_CLOSEST(val, data->config->bus_voltage_lsb); return clamp_val(val, 0, USHRT_MAX); case INA2XX_POWER: val = clamp_val(val, 0, UINT_MAX - data->power_lsb_uW); val = DIV_ROUND_CLOSEST(val, data->power_lsb_uW); return clamp_val(val, 0, USHRT_MAX); case INA2XX_CURRENT: val = clamp_val(val, INT_MIN / 1000, INT_MAX / 1000); /* signed register, result in mA */ val = DIV_ROUND_CLOSEST(val * 1000, data->current_lsb_uA); return clamp_val(val, SHRT_MIN, SHRT_MAX); default: /* programmer goofed */ WARN_ON_ONCE(1); return 0; } } static int ina226_alert_limit_read(struct ina2xx_data *data, u32 mask, int reg, long *val) { struct regmap *regmap = data->regmap; int regval; int ret; mutex_lock(&data->config_lock); ret = regmap_read(regmap, INA226_MASK_ENABLE, ®val); if (ret) goto abort; if (regval & mask) { ret = regmap_read(regmap, INA226_ALERT_LIMIT, ®val); if (ret) goto abort; *val = ina2xx_get_value(data, reg, regval); } else { *val = 0; } abort: mutex_unlock(&data->config_lock); return ret; } static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg, long val) { struct regmap *regmap = data->regmap; int ret; if (val < 0) return -EINVAL; /* * Clear all alerts first to avoid accidentally triggering ALERT pin * due to register write sequence. Then, only enable the alert * if the value is non-zero. */ mutex_lock(&data->config_lock); ret = regmap_update_bits(regmap, INA226_MASK_ENABLE, INA226_ALERT_CONFIG_MASK, 0); if (ret < 0) goto abort; ret = regmap_write(regmap, INA226_ALERT_LIMIT, ina226_alert_to_reg(data, reg, val)); if (ret < 0) goto abort; if (val) ret = regmap_update_bits(regmap, INA226_MASK_ENABLE, INA226_ALERT_CONFIG_MASK, mask); abort: mutex_unlock(&data->config_lock); return ret; } static int ina2xx_chip_read(struct device *dev, u32 attr, long *val) { struct ina2xx_data *data = dev_get_drvdata(dev); u32 regval; int ret; switch (attr) { case hwmon_chip_update_interval: ret = regmap_read(data->regmap, INA2XX_CONFIG, ®val); if (ret) return ret; *val = ina226_reg_to_interval(regval); break; default: return -EOPNOTSUPP; } return 0; } static int ina226_alert_read(struct regmap *regmap, u32 mask, long *val) { unsigned int regval; int ret; ret = regmap_read_bypassed(regmap, INA226_MASK_ENABLE, ®val); if (ret) return ret; *val = (regval & mask) && (regval & INA226_ALERT_FUNCTION_FLAG); return 0; } static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val) { int voltage_reg = channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE; u32 under_voltage_mask = channel ? INA226_BUS_UNDER_VOLTAGE_MASK : INA226_SHUNT_UNDER_VOLTAGE_MASK; u32 over_voltage_mask = channel ? INA226_BUS_OVER_VOLTAGE_MASK : INA226_SHUNT_OVER_VOLTAGE_MASK; struct ina2xx_data *data = dev_get_drvdata(dev); struct regmap *regmap = data->regmap; unsigned int regval; int ret; switch (attr) { case hwmon_in_input: ret = regmap_read(regmap, voltage_reg, ®val); if (ret) return ret; *val = ina2xx_get_value(data, voltage_reg, regval); break; case hwmon_in_lcrit: return ina226_alert_limit_read(data, under_voltage_mask, voltage_reg, val); case hwmon_in_crit: return ina226_alert_limit_read(data, over_voltage_mask, voltage_reg, val); case hwmon_in_lcrit_alarm: return ina226_alert_read(regmap, under_voltage_mask, val); case hwmon_in_crit_alarm: return ina226_alert_read(regmap, over_voltage_mask, val); default: return -EOPNOTSUPP; } return 0; } static int ina2xx_power_read(struct device *dev, u32 attr, long *val) { struct ina2xx_data *data = dev_get_drvdata(dev); switch (attr) { case hwmon_power_input: return ina2xx_read_init(dev, INA2XX_POWER, val); case hwmon_power_crit: return ina226_alert_limit_read(data, INA226_POWER_OVER_LIMIT_MASK, INA2XX_POWER, val); case hwmon_power_crit_alarm: return ina226_alert_read(data->regmap, INA226_POWER_OVER_LIMIT_MASK, val); default: return -EOPNOTSUPP; } } static int ina2xx_curr_read(struct device *dev, u32 attr, long *val) { struct ina2xx_data *data = dev_get_drvdata(dev); struct regmap *regmap = data->regmap; unsigned int regval; int ret; /* * While the chips supported by this driver do not directly support * current limits, they do support setting shunt voltage limits. * The shunt voltage divided by the shunt resistor value is the current. * On top of that, calibration values are set such that in the shunt * voltage register and the current register report the same values. * That means we can report and configure current limits based on shunt * voltage limits. */ switch (attr) { case hwmon_curr_input: /* * Since the shunt voltage and the current register report the * same values when the chip is calibrated, we can calculate * the current directly from the shunt voltage without relying * on chip calibration. */ ret = regmap_read(regmap, INA2XX_SHUNT_VOLTAGE, ®val); if (ret) return ret; *val = ina2xx_get_value(data, INA2XX_CURRENT, regval); return 0; case hwmon_curr_lcrit: return ina226_alert_limit_read(data, INA226_SHUNT_UNDER_VOLTAGE_MASK, INA2XX_CURRENT, val); case hwmon_curr_crit: return ina226_alert_limit_read(data, INA226_SHUNT_OVER_VOLTAGE_MASK, INA2XX_CURRENT, val); case hwmon_curr_lcrit_alarm: return ina226_alert_read(regmap, INA226_SHUNT_UNDER_VOLTAGE_MASK, val); case hwmon_curr_crit_alarm: return ina226_alert_read(regmap, INA226_SHUNT_OVER_VOLTAGE_MASK, val); default: return -EOPNOTSUPP; } } static int ina2xx_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { switch (type) { case hwmon_chip: return ina2xx_chip_read(dev, attr, val); case hwmon_in: return ina2xx_in_read(dev, attr, channel, val); case hwmon_power: return ina2xx_power_read(dev, attr, val); case hwmon_curr: return ina2xx_curr_read(dev, attr, val); default: return -EOPNOTSUPP; } } static int ina2xx_chip_write(struct device *dev, u32 attr, long val) { struct ina2xx_data *data = dev_get_drvdata(dev); switch (attr) { case hwmon_chip_update_interval: return regmap_update_bits(data->regmap, INA2XX_CONFIG, INA226_AVG_RD_MASK, ina226_interval_to_reg(val)); default: return -EOPNOTSUPP; } } static int ina2xx_in_write(struct device *dev, u32 attr, int channel, long val) { struct ina2xx_data *data = dev_get_drvdata(dev); switch (attr) { case hwmon_in_lcrit: return ina226_alert_limit_write(data, channel ? INA226_BUS_UNDER_VOLTAGE_MASK : INA226_SHUNT_UNDER_VOLTAGE_MASK, channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE, val); case hwmon_in_crit: return ina226_alert_limit_write(data, channel ? INA226_BUS_OVER_VOLTAGE_MASK : INA226_SHUNT_OVER_VOLTAGE_MASK, channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE, val); default: return -EOPNOTSUPP; } return 0; } static int ina2xx_power_write(struct device *dev, u32 attr, long val) { struct ina2xx_data *data = dev_get_drvdata(dev); switch (attr) { case hwmon_power_crit: return ina226_alert_limit_write(data, INA226_POWER_OVER_LIMIT_MASK, INA2XX_POWER, val); default: return -EOPNOTSUPP; } return 0; } static int ina2xx_curr_write(struct device *dev, u32 attr, long val) { struct ina2xx_data *data = dev_get_drvdata(dev); switch (attr) { case hwmon_curr_lcrit: return ina226_alert_limit_write(data, INA226_SHUNT_UNDER_VOLTAGE_MASK, INA2XX_CURRENT, val); case hwmon_curr_crit: return ina226_alert_limit_write(data, INA226_SHUNT_OVER_VOLTAGE_MASK, INA2XX_CURRENT, val); default: return -EOPNOTSUPP; } return 0; } static int ina2xx_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { switch (type) { case hwmon_chip: return ina2xx_chip_write(dev, attr, val); case hwmon_in: return ina2xx_in_write(dev, attr, channel, val); case hwmon_power: return ina2xx_power_write(dev, attr, val); case hwmon_curr: return ina2xx_curr_write(dev, attr, val); default: return -EOPNOTSUPP; } } static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type, u32 attr, int channel) { const struct ina2xx_data *data = _data; enum ina2xx_ids chip = data->chip; switch (type) { case hwmon_in: switch (attr) { case hwmon_in_input: return 0444; case hwmon_in_lcrit: case hwmon_in_crit: if (chip == ina226) return 0644; break; case hwmon_in_lcrit_alarm: case hwmon_in_crit_alarm: if (chip == ina226) return 0444; break; default: break; } break; case hwmon_curr: switch (attr) { case hwmon_curr_input: return 0444; case hwmon_curr_lcrit: case hwmon_curr_crit: if (chip == ina226) return 0644; break; case hwmon_curr_lcrit_alarm: case hwmon_curr_crit_alarm: if (chip == ina226) return 0444; break; default: break; } break; case hwmon_power: switch (attr) { case hwmon_power_input: return 0444; case hwmon_power_crit: if (chip == ina226) return 0644; break; case hwmon_power_crit_alarm: if (chip == ina226) return 0444; break; default: break; } break; case hwmon_chip: switch (attr) { case hwmon_chip_update_interval: if (chip == ina226) return 0644; break; default: break; } break; default: break; } return 0; } static const struct hwmon_channel_info * const ina2xx_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_CRIT_ALARM | HWMON_I_LCRIT | HWMON_I_LCRIT_ALARM, HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_CRIT_ALARM | HWMON_I_LCRIT | HWMON_I_LCRIT_ALARM ), HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM | HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM), HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM), NULL }; static const struct hwmon_ops ina2xx_hwmon_ops = { .is_visible = ina2xx_is_visible, .read = ina2xx_read, .write = ina2xx_write, }; static const struct hwmon_chip_info ina2xx_chip_info = { .ops = &ina2xx_hwmon_ops, .info = ina2xx_info, }; /* shunt resistance */ /* * In order to keep calibration register value fixed, the product * of current_lsb and shunt_resistor should also be fixed and equal * to shunt_voltage_lsb = 1 / shunt_div multiplied by 10^9 in order * to keep the scale. */ static int ina2xx_set_shunt(struct ina2xx_data *data, unsigned long val) { unsigned int dividend = DIV_ROUND_CLOSEST(1000000000, data->config->shunt_div); if (!val || val > dividend) return -EINVAL; data->rshunt = val; data->current_lsb_uA = DIV_ROUND_CLOSEST(dividend, val); data->power_lsb_uW = data->config->power_lsb_factor * data->current_lsb_uA; return 0; } static ssize_t shunt_resistor_show(struct device *dev, struct device_attribute *da, char *buf) { struct ina2xx_data *data = dev_get_drvdata(dev); return sysfs_emit(buf, "%li\n", data->rshunt); } static ssize_t shunt_resistor_store(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct ina2xx_data *data = dev_get_drvdata(dev); unsigned long val; int status; status = kstrtoul(buf, 10, &val); if (status < 0) return status; mutex_lock(&data->config_lock); status = ina2xx_set_shunt(data, val); mutex_unlock(&data->config_lock); if (status < 0) return status; return count; } static DEVICE_ATTR_RW(shunt_resistor); /* pointers to created device attributes */ static struct attribute *ina2xx_attrs[] = { &dev_attr_shunt_resistor.attr, NULL, }; ATTRIBUTE_GROUPS(ina2xx); /* * Initialize chip */ static int ina2xx_init(struct device *dev, struct ina2xx_data *data) { struct regmap *regmap = data->regmap; u32 shunt; int ret; if (device_property_read_u32(dev, "shunt-resistor", &shunt) < 0) shunt = INA2XX_RSHUNT_DEFAULT; ret = ina2xx_set_shunt(data, shunt); if (ret < 0) return ret; ret = regmap_write(regmap, INA2XX_CONFIG, data->config->config_default); if (ret < 0) return ret; if (data->chip == ina226) { bool active_high = device_property_read_bool(dev, "ti,alert-polarity-active-high"); regmap_update_bits(regmap, INA226_MASK_ENABLE, INA226_ALERT_LATCH_ENABLE | INA226_ALERT_POLARITY, INA226_ALERT_LATCH_ENABLE | FIELD_PREP(INA226_ALERT_POLARITY, active_high)); } /* * Calibration register is set to the best value, which eliminates * truncation errors on calculating current register in hardware. * According to datasheet (eq. 3) the best values are 2048 for * ina226 and 4096 for ina219. They are hardcoded as calibration_value. */ return regmap_write(regmap, INA2XX_CALIBRATION, data->config->calibration_value); } static int ina2xx_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ina2xx_data *data; struct device *hwmon_dev; enum ina2xx_ids chip; int ret; chip = (uintptr_t)i2c_get_match_data(client); data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; /* set the device type */ data->config = &ina2xx_config[chip]; data->chip = chip; mutex_init(&data->config_lock); data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config); if (IS_ERR(data->regmap)) { dev_err(dev, "failed to allocate register map\n"); return PTR_ERR(data->regmap); } ret = devm_regulator_get_enable(dev, "vs"); if (ret) return dev_err_probe(dev, ret, "failed to enable vs regulator\n"); ret = ina2xx_init(dev, data); if (ret < 0) return dev_err_probe(dev, ret, "failed to configure device\n"); hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, &ina2xx_chip_info, ina2xx_groups); if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n", client->name, data->rshunt); return 0; } static const struct i2c_device_id ina2xx_id[] = { { "ina219", ina219 }, { "ina220", ina219 }, { "ina226", ina226 }, { "ina230", ina226 }, { "ina231", ina226 }, { } }; MODULE_DEVICE_TABLE(i2c, ina2xx_id); static const struct of_device_id __maybe_unused ina2xx_of_match[] = { { .compatible = "ti,ina219", .data = (void *)ina219 }, { .compatible = "ti,ina220", .data = (void *)ina219 }, { .compatible = "ti,ina226", .data = (void *)ina226 }, { .compatible = "ti,ina230", .data = (void *)ina226 }, { .compatible = "ti,ina231", .data = (void *)ina226 }, { }, }; MODULE_DEVICE_TABLE(of, ina2xx_of_match); static struct i2c_driver ina2xx_driver = { .driver = { .name = "ina2xx", .of_match_table = of_match_ptr(ina2xx_of_match), }, .probe = ina2xx_probe, .id_table = ina2xx_id, }; module_i2c_driver(ina2xx_driver); MODULE_AUTHOR("Lothar Felten "); MODULE_DESCRIPTION("ina2xx driver"); MODULE_LICENSE("GPL");