summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorTimo Alho <talho@nvidia.com>2013-12-17 22:53:39 +0200
committerJuha Tukkinen <jtukkinen@nvidia.com>2014-01-08 09:47:08 -0800
commit4d60989f32a2ce4033338e2d783205162aba2c8c (patch)
treebc49d3029ec194593c78809be51790227981e58e /drivers/hwmon
parent0b9ceca5a06d07cc8d281a92b76ebef8d4da0c92 (diff)
hwmon: ina3221: improve current calculation precission
Improve the precission of current reading by removing unnecessary computation of resistance inverse. Also add proper rounding. Bug 1400509 Bug 1414772 Change-Id: Idd5f8f0ae4b3d4c723e3249cd96e8422024428e9 Signed-off-by: Timo Alho <talho@nvidia.com> Reviewed-on: http://git-master/r/346966 Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/ina3221.c55
1 files changed, 24 insertions, 31 deletions
diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
index 5f0fd63f7618..db31b579e26e 100644
--- a/drivers/hwmon/ina3221.c
+++ b/drivers/hwmon/ina3221.c
@@ -1,7 +1,7 @@
/*
* ina3221.c - driver for TI INA3221
*
- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software. you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -76,6 +76,20 @@ struct ina3221_data {
int is_suspended;
};
+/* convert shunt voltage register value to current (in mA) */
+static s32 shuntv_register_to_ma(u16 reg, s32 resistance)
+{
+ s32 uv, ma;
+ uv = (s16)reg;
+ uv = ((uv >> 3) * 40); /* LSB (4th bit) is 40uV */
+ /* calculate uv/resistance with rounding knowing that C99 truncates
+ * towards zero */
+ if (uv > 0)
+ ma = ((uv * 2 / resistance) + 1) / 2;
+ else
+ ma = ((uv * 2 / resistance) - 1) / 2;
+ return ma;
+}
static s32
__locked_set_crit_warn_register(struct i2c_client *client,
@@ -239,9 +253,8 @@ static s32 show_current(struct device *dev,
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
u8 index, shunt_volt_reg_addr;
s32 ret;
- s32 voltage_uv;
s32 current_ma;
- s32 inverse_shunt_resistor;
+ s32 resistance;
mutex_lock(&data->mutex);
if (data->shutdown_complete) {
@@ -266,15 +279,9 @@ static s32 show_current(struct device *dev,
shunt_volt_reg_addr);
if (ret < 0)
goto error;
- voltage_uv = be16_to_cpu(ret);
- DEBUG_INA3221(("Ina3221 shunt voltage reg Value: 0x%x\n", voltage_uv));
- voltage_uv = (voltage_uv << 16) >> 16;
- voltage_uv = shuntv_register_to_uv(voltage_uv);
- DEBUG_INA3221(("Ina3221 shunt voltage in uv: %d\n", voltage_uv));
- /* shunt_resistor is received in mOhms */
- inverse_shunt_resistor = 1000 / data->plat_data->shunt_resistor[index];
- current_ma = (voltage_uv * inverse_shunt_resistor) / 1000;
+ resistance = data->plat_data->shunt_resistor[index];
+ current_ma = shuntv_register_to_ma(be16_to_cpu(ret), resistance);
if (data->mode == TRIGGERED) {
/* set ina3221 to power down mode */
@@ -301,9 +308,8 @@ static s32 show_current2(struct device *dev,
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
u8 index, shunt_volt_reg_addr;
s32 ret;
- s32 voltage_uv;
s32 current_ma;
- s32 inverse_shunt_resistor;
+ s32 resistance;
mutex_lock(&data->mutex);
if (data->shutdown_complete) {
@@ -324,15 +330,9 @@ static s32 show_current2(struct device *dev,
shunt_volt_reg_addr);
if (ret < 0)
goto error;
- voltage_uv = be16_to_cpu(ret);
- DEBUG_INA3221(("Ina3221 shunt voltage reg Value: 0x%x\n", voltage_uv));
- voltage_uv = (voltage_uv << 16) >> 16;
- voltage_uv = shuntv_register_to_uv(voltage_uv);
- DEBUG_INA3221(("Ina3221 shunt voltage in uv: %d\n", voltage_uv));
- /* shunt_resistor is received in mOhms */
- inverse_shunt_resistor = 1000 / data->plat_data->shunt_resistor[index];
- current_ma = (voltage_uv * inverse_shunt_resistor) / 1000;
+ resistance = data->plat_data->shunt_resistor[index];
+ current_ma = shuntv_register_to_ma(be16_to_cpu(ret), resistance);
if (data->mode == TRIGGERED) {
/* set ina3221 to power down mode */
@@ -358,8 +358,7 @@ static s32 __locked_calculate_power(struct i2c_client *client,
struct ina3221_data *data = i2c_get_clientdata(client);
s32 voltage_mv;
- s32 voltage_uv;
- s32 inverse_shunt_resistor;
+ s32 resistance;
s32 current_ma;
s32 power_mw;
s32 ret;
@@ -368,11 +367,8 @@ static s32 __locked_calculate_power(struct i2c_client *client,
shunt_volt_reg_addr);
if (ret < 0)
goto error;
- voltage_uv = be16_to_cpu(ret);
- DEBUG_INA3221(("Ina3221 shunt voltage reg Value: 0x%x\n", voltage_uv));
- voltage_uv = (voltage_uv << 16) >> 16;
- voltage_uv = shuntv_register_to_uv(voltage_uv);
- DEBUG_INA3221(("Ina3221 shunt voltage in uv: %d\n", voltage_uv));
+ resistance = data->plat_data->shunt_resistor[index];
+ current_ma = shuntv_register_to_ma(be16_to_cpu(ret), resistance);
/* getting voltage readings in milli volts*/
ret = i2c_smbus_read_word_data(client,
@@ -385,9 +381,6 @@ static s32 __locked_calculate_power(struct i2c_client *client,
voltage_mv = busv_register_to_mv(voltage_mv);
DEBUG_INA3221(("Ina3221 bus voltage in mv: %d\n", voltage_mv));
- /* shunt_resistor is received in mOhms */
- inverse_shunt_resistor = 1000 / data->plat_data->shunt_resistor[index];
- current_ma = voltage_uv * inverse_shunt_resistor / 1000;
power_mw = voltage_mv * current_ma / 1000;
return power_mw & MAX_POWER_MW;
error: