for (i = 0; i < INA3221_NUM_CHANNELS; i++) { if (input[i].disconnected || !input[i].shunt_resistor ||
input[i].summation_disable) continue; if (!shunt_resistor) { /* Found the reference shunt resistor value */
shunt_resistor = input[i].shunt_resistor;
} else { /* No summation if resistor values are different */ if (shunt_resistor != input[i].shunt_resistor) return0;
}
}
return shunt_resistor;
}
/* Lookup table for Bus and Shunt conversion times in usec */ staticconst u16 ina3221_conv_time[] = { 140, 204, 332, 588, 1100, 2116, 4156, 8244,
};
/* Lookup table for number of samples using in averaging mode */ staticconstint ina3221_avg_samples[] = { 1, 4, 16, 64, 128, 256, 512, 1024,
};
/* Converting update_interval in msec to conversion time in usec */ staticinline u32 ina3221_interval_ms_to_conv_time(u16 config, int interval)
{
u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK);
u32 samples_idx = INA3221_CONFIG_AVG(config);
u32 samples = ina3221_avg_samples[samples_idx];
/* Bisect the result to Bus and Shunt conversion times */ return DIV_ROUND_CLOSEST(interval * 1000 / 2, channels * samples);
}
switch (attr) { case hwmon_curr_input: if (!ina3221_is_enabled(ina, channel)) return -ENODATA;
/* Write CONFIG register to trigger a single-shot measurement */ if (ina->single_shot) {
regmap_write(ina->regmap, INA3221_CONFIG,
ina->reg_config);
ret = ina3221_wait_for_data(ina); if (ret) return ret;
}
fallthrough; case hwmon_curr_crit: case hwmon_curr_max: if (!resistance_uo) return -ENODATA;
ret = ina3221_read_value(ina, reg, ®val); if (ret) return ret;
/* Scale of shunt voltage: LSB is 40uV (40000nV) */
voltage_nv = regval * 40000; /* Return current in mA */
*val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); return0; case hwmon_curr_crit_alarm: case hwmon_curr_max_alarm: /* No actual register read if channel is disabled */ if (!ina3221_is_enabled(ina, channel)) { /* Return 0 for alert flags */
*val = 0; return0;
}
ret = regmap_field_read(ina->fields[reg], ®val); if (ret) return ret;
*val = regval; return0; default: return -EOPNOTSUPP;
}
}
staticint ina3221_write_chip(struct device *dev, u32 attr, long val)
{ struct ina3221_data *ina = dev_get_drvdata(dev); int ret, idx;
u32 tmp;
switch (attr) { case hwmon_chip_samples:
idx = find_closest(val, ina3221_avg_samples,
ARRAY_SIZE(ina3221_avg_samples));
tmp = (ina->reg_config & ~INA3221_CONFIG_AVG_MASK) |
(idx << INA3221_CONFIG_AVG_SHIFT);
ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); if (ret) return ret;
/* Bypass if enable status is not being changed */ if (config_old == config) return0;
/* For enabling routine, increase refcount and resume() at first */ if (enable) {
ret = pm_runtime_resume_and_get(ina->pm_dev); if (ret < 0) {
dev_err(dev, "Failed to get PM runtime\n"); return ret;
}
}
/* Enable or disable the channel */
tmp = (ina->reg_config & ~mask) | (config & mask);
ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); if (ret) goto fail;
/* Cache the latest config register value */
ina->reg_config = tmp;
/* For disabling routine, decrease refcount or suspend() at last */ if (!enable)
pm_runtime_put_sync(ina->pm_dev);
return0;
fail: if (enable) {
dev_err(dev, "Failed to enable channel %d: error %d\n",
channel, ret);
pm_runtime_put_sync(ina->pm_dev);
}
return ret;
}
staticint ina3221_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{ struct ina3221_data *ina = dev_get_drvdata(dev); int ret;
mutex_lock(&ina->lock);
switch (type) { case hwmon_chip:
ret = ina3221_read_chip(dev, attr, val); break; case hwmon_in: /* 0-align channel ID */
ret = ina3221_read_in(dev, attr, channel - 1, val); break; case hwmon_curr:
ret = ina3221_read_curr(dev, attr, channel, val); break; default:
ret = -EOPNOTSUPP; break;
}
mutex_unlock(&ina->lock);
return ret;
}
staticint ina3221_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{ struct ina3221_data *ina = dev_get_drvdata(dev); int ret;
mutex_lock(&ina->lock);
switch (type) { case hwmon_chip:
ret = ina3221_write_chip(dev, attr, val); break; case hwmon_in: /* 0-align channel ID */
ret = ina3221_write_enable(dev, channel - 1, val); break; case hwmon_curr:
ret = ina3221_write_curr(dev, attr, channel, val); break; default:
ret = -EOPNOTSUPP; break;
}
mutex_unlock(&ina->lock);
return ret;
}
staticint ina3221_read_string(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, constchar **str)
{ struct ina3221_data *ina = dev_get_drvdata(dev); int index = channel - 1;
if (channel == 7)
*str = "sum of shunt voltages"; else
*str = ina->inputs[index].label;
ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); if (!ina) return -ENOMEM;
ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config); if (IS_ERR(ina->regmap)) {
dev_err(dev, "Unable to allocate register map\n"); return PTR_ERR(ina->regmap);
}
for (i = 0; i < F_MAX_FIELDS; i++) {
ina->fields[i] = devm_regmap_field_alloc(dev,
ina->regmap,
ina3221_reg_fields[i]); if (IS_ERR(ina->fields[i])) {
dev_err(dev, "Unable to allocate regmap fields\n"); return PTR_ERR(ina->fields[i]);
}
}
for (i = 0; i < INA3221_NUM_CHANNELS; i++)
ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT;
ret = ina3221_probe_from_dt(dev, ina); if (ret) {
dev_err(dev, "Unable to probe from device tree\n"); return ret;
}
/* The driver will be reset, so use reset value */
ina->reg_config = INA3221_CONFIG_DEFAULT;
/* Clear continuous bit to use single-shot mode */ if (ina->single_shot)
ina->reg_config &= ~INA3221_CONFIG_MODE_CONTINUOUS;
/* Disable channels if their inputs are disconnected */ for (i = 0; i < INA3221_NUM_CHANNELS; i++) { if (ina->inputs[i].disconnected)
ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i);
}
/* Initialize summation_shunt_resistor for summation channel control */
ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); for (i = 0; i < INA3221_NUM_CHANNELS; i++) { if (!ina->inputs[i].summation_disable)
ina->summation_channel_control |= BIT(14 - i);
}
/* Enable PM runtime -- status is suspended by default */
pm_runtime_enable(ina->pm_dev);
/* Initialize (resume) the device */ for (i = 0; i < INA3221_NUM_CHANNELS; i++) { if (ina->inputs[i].disconnected) continue; /* Match the refcount with number of enabled channels */
ret = pm_runtime_get_sync(ina->pm_dev); if (ret < 0) goto fail;
}
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina,
&ina3221_chip_info,
ina3221_groups); if (IS_ERR(hwmon_dev)) {
dev_err(dev, "Unable to register hwmon device\n");
ret = PTR_ERR(hwmon_dev); goto fail;
}
for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
scnprintf(name, sizeof(name), "in%d_summation_disable", i);
debugfs_create_bool(name, 0400, client->debugfs,
&ina->inputs[i].summation_disable);
}
return0;
fail:
pm_runtime_disable(ina->pm_dev);
pm_runtime_set_suspended(ina->pm_dev); /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ for (i = 0; i < INA3221_NUM_CHANNELS; i++)
pm_runtime_put_noidle(ina->pm_dev);
mutex_destroy(&ina->lock);
/* Save config register value and enable cache-only */
ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); if (ret) return ret;
/* Set to power-down mode for power saving */
ret = regmap_update_bits(ina->regmap, INA3221_CONFIG,
INA3221_CONFIG_MODE_MASK,
INA3221_CONFIG_MODE_POWERDOWN); if (ret) return ret;
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver");
MODULE_LICENSE("GPL v2");
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.15Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.