- ti,current-warning-limit-ma: Cureent warning limit for the given channel.
- ti,current-critical-limit-ma: Current critical limit for the given channel.
- ti,shunt-resistor-mohm: Shunt register in milli ohm.
+- shunt-volt-offset-uv: reference to shunt-volt-offset node
+
+shunt-volt-offset node properties:
+- offset: value to be subtracted from shunt voltage reading
+
+conditional_offset subnode properties:
+ - shunt_volt_start: conditional offset start voltage
+ - shunt_volt_end: conditional offset end voltage
+ - offset: value to be subtracted from <shunt_volt_start to shunt_volt_end> range
IIO channel properties:
It follows same mechanism for iio properties detailed on ../iio-bindings.txt
#define INA3221_CHAN_INDEX(chan, type, add) (chan * 5 + INA3221_##type + INA3221_##add)
Example:
+ p2180_shuntv_offset: shuntv-offset {
+ offset = <40>;
+ conditional_offset@0 {
+ shunt_volt_start = <100>;
+ shunt_volt_end = <1800>;
+ offset = <80>;
+ };
+ };
+
ina3221x@40 {
compatible = "ti,ina3221x";
reg = <0x40>;
ti,current-warning-limit-ma = <8000>;
ti,current-critical-limit-ma = <9000>;
ti,shunt-resistor-mohm = <1>;
+ shunt-volt-offset-uv = <&p2180_shuntv_offset>;
};
channel@1 {
#define IS_TRIGGERED(x) (!((x) & 2))
#define IS_CONTINUOUS(x) ((x) & 2)
+struct shuntv_conditional_offset {
+ s32 shuntv_start;
+ s32 shuntv_end;
+ s32 offset;
+};
+
+struct shunt_volt_offset {
+ s32 offset;
+ struct shuntv_conditional_offset *cond_offset;
+ s32 cond_offset_size;
+};
+
struct ina3221_chan_pdata {
const char *rail_name;
u32 warn_conf_limits;
u32 crit_conf_limits;
u32 shunt_resistor;
+ struct shunt_volt_offset *shuntv_offset;
};
struct ina3221_platform_data {
}
/* convert shunt voltage register value to current (in mA) */
-static int shuntv_register_to_ma(u16 reg, int resistance)
+static int shuntv_register_to_ma(u16 reg, int resistance,
+ struct shunt_volt_offset *shuntv_offset)
{
int uv, ma;
+ int offset = 0;
+ struct shuntv_conditional_offset *cond_offset;
+ int i;
uv = (s16)reg;
- uv = ((uv >> 3) * 40); /* LSB (4th bit) is 40uV */
+
+ if (uv < 0)
+ uv = ((((uv * -1) >> 3) * 40) * -1);
+ else
+ uv = ((uv >> 3) * 40); /* LSB (4th bit) is 40uV */
+
+ if (shuntv_offset != NULL) {
+ offset = shuntv_offset->offset;
+ cond_offset = shuntv_offset->cond_offset;
+
+ for (i = 0; i < shuntv_offset->cond_offset_size; i++) {
+ if (uv >= cond_offset->shuntv_start &&
+ uv <= cond_offset->shuntv_end) {
+ offset = cond_offset->offset;
+ break;
+ }
+
+ cond_offset++;
+ }
+
+ /* apply shunt volt offset */
+ if (uv < 0)
+ uv += offset;
+ else
+ uv -= offset;
+ }
/*
* calculate uv/resistance with rounding knowing that C99 truncates
* towards zero
goto exit;
}
*current_ma = shuntv_register_to_ma(vsh,
- chip->pdata->cpdata[channel].shunt_resistor);
+ chip->pdata->cpdata[channel].shunt_resistor,
+ chip->pdata->cpdata[channel].shuntv_offset);
exit:
mutex_unlock(&chip->mutex);
return ret;
}
current_ma = shuntv_register_to_ma(vsh,
- chip->pdata->cpdata[channel].shunt_resistor);
+ chip->pdata->cpdata[channel].shunt_resistor,
+ chip->pdata->cpdata[channel].shuntv_offset);
voltage_mv = busv_register_to_mv(vbus);
*power_mw = (voltage_mv * current_ma) / 1000;
exit:
}
*current_ma = shuntv_register_to_ma(vsh,
- chip->pdata->cpdata[channel].shunt_resistor);
+ chip->pdata->cpdata[channel].shunt_resistor,
+ chip->pdata->cpdata[channel].shuntv_offset);
*voltage_mv = busv_register_to_mv(vbus);
exit:
mutex_unlock(&chip->mutex);
}
*curr_limit = shuntv_register_to_ma(be16_to_cpu(ret),
- cpdata->shunt_resistor);
+ cpdata->shunt_resistor, cpdata->shuntv_offset);
ret = 0;
exit:
mutex_unlock(&chip->mutex);
/* convert shunt voltage to current in mA */
*curr_limit = shuntv_register_to_ma(be16_to_cpu(ret),
- cpdata->shunt_resistor);
+ cpdata->shunt_resistor, cpdata->shuntv_offset);
ret = 0;
exit:
mutex_unlock(&chip->mutex);
.read_raw = &ina3221_read_raw,
};
+
+static struct shunt_volt_offset *ina3221_get_shuntv_offset
+ (struct i2c_client *client, struct device_node *channel_np)
+{
+
+ const __be32 *prop;
+ struct device_node *shuntv_np;
+ struct device_node *shuntv_cond_np;
+ struct shunt_volt_offset *shuntv_offset = NULL;
+ struct shuntv_conditional_offset *shuntv_cond_offset;
+ s32 shuntv_start, shuntv_end, offset;
+ int ret;
+
+ prop = of_get_property(channel_np, "shunt-volt-offset-uv", NULL);
+ if (prop != NULL) {
+ shuntv_np = of_find_node_by_phandle(be32_to_cpup(prop));
+ if (shuntv_np == NULL) {
+ dev_err(&client->dev, "could not find shunt volt offset node\n");
+ return NULL;
+ }
+
+ shuntv_offset = devm_kzalloc(&client->dev, sizeof(*shuntv_offset),
+ GFP_KERNEL);
+
+ ret = of_property_read_s32(shuntv_np, "offset", &offset);
+ if (!ret)
+ shuntv_offset->offset = offset;
+
+ shuntv_offset->cond_offset_size = of_get_child_count(shuntv_np);
+ if (shuntv_offset->cond_offset_size) {
+ shuntv_cond_offset = (struct shuntv_conditional_offset *)
+ devm_kzalloc(&client->dev,
+ sizeof(struct shuntv_conditional_offset)
+ * shuntv_offset->cond_offset_size, GFP_KERNEL);
+ shuntv_offset->cond_offset = shuntv_cond_offset;
+
+ for_each_child_of_node(shuntv_np, shuntv_cond_np) {
+ ret = of_property_read_s32(shuntv_cond_np,
+ "shunt_volt_start", &shuntv_start);
+ if (ret) {
+ dev_err(&client->dev, "property shunt_volt_start not found!\n");
+ goto skip_node;
+ }
+
+ ret = of_property_read_s32(shuntv_cond_np,
+ "shunt_volt_end", &shuntv_end);
+ if (ret) {
+ dev_err(&client->dev, "property shunt_volt_end not found!\n");
+ goto skip_node;
+ }
+
+ ret = of_property_read_s32(shuntv_cond_np,
+ "offset", &offset);
+ if (ret) {
+ dev_err(&client->dev, "property offset not found!\n");
+ goto skip_node;
+ }
+
+ shuntv_cond_offset->shuntv_start = shuntv_start;
+ shuntv_cond_offset->shuntv_end = shuntv_end;
+ shuntv_cond_offset->offset = offset;
+skip_node:
+ shuntv_cond_offset++;
+ }
+ }
+ }
+
+ return shuntv_offset;
+}
+
static struct ina3221_platform_data *ina3221_get_platform_data_dt(
struct i2c_client *client)
{
if (!ret)
pdata->cpdata[reg].shunt_resistor = pval;
+ pdata->cpdata[reg].shuntv_offset =
+ ina3221_get_shuntv_offset(client, child);
+
valid_channel++;
}