summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAnshul Jain <anshulj@nvidia.com>2012-10-31 11:44:20 -0700
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-11-09 06:05:30 -0800
commit5ad8d50e26515797a31fb8d2195dab32b52bab34 (patch)
tree18da7506478ea3b298cc91f586d7708352bcd27e /drivers
parentb6404b2d78b03faff7d2ff8fdd669edc2ad7b0cf (diff)
hwmon: ina219: INA219 driver with more sysfs
This new driver allows state change of the INA219 device using this sysds node: To turn the ina219 device on, echo 1 > /<i2c device path>/cur_state To turn it off: echo 0 > /<i2c device path>/cur_state It has new sysfs nodes current2_input and power2_input that contains current and power calculated using shunt resistor and voltage drop across shunt resistor. This driver is backward compatible with the old driver. Bug 1160868 Change-Id: I5e05947e8e3b20a85f02188a48ea4441218e27a8 Signed-off-by: Anshul Jain <anshulj@nvidia.com> Reviewed-on: http://git-master/r/160070 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Tested-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hwmon/ina219.c376
1 files changed, 283 insertions, 93 deletions
diff --git a/drivers/hwmon/ina219.c b/drivers/hwmon/ina219.c
index fda40f4f4fba..a06516a65d42 100644
--- a/drivers/hwmon/ina219.c
+++ b/drivers/hwmon/ina219.c
@@ -51,21 +51,10 @@
#define INA219_CURRENT 4
#define INA219_CAL 5
-/*
- INA219 Sensor defines
- Config info for ina219s
- D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
- rst BRNG PG1 PG0 BADC4 .-.BADC1 SADC4 - SADC1 MODE3 - MODE1
- reset D15
- bus_range=0 (d13)
- pga_gain=0 (D12:D11)
- bus_adc_setting=0x3 (d10:D7) 12-bit w/o oversampling (532uS)
- shunt_adc_setting=0xb (D6:D3) 8x oversampling (4.26ms)
- mode=0x7 (D2:D0) continuous shunt & bus
-*/
-#define INA219_CONFIG_DATA 0x1df
#define INA219_RESET 0x8000
+#define busv_register_to_mv(x) (((x) >> 3) * 4)
+#define shuntv_register_to_uv(x) ((x) * 10)
struct power_mon_data {
s32 voltage;
s32 currentInMillis;
@@ -78,8 +67,12 @@ struct ina219_data {
struct ina219_platform_data *pInfo;
struct power_mon_data pm_data;
struct mutex mutex;
+ int state;
};
+#define STOPPED 0
+#define RUNNING 1
+
/* Set non-zero to enable debug prints */
#define INA219_DEBUG_PRINTS 0
@@ -89,13 +82,6 @@ struct ina219_data {
#define DEBUG_INA219(x)
#endif
-static s16 reorder_bytes(s16 a)
-{
- s16 ret = ((a >> 8) & 0xff) | ((a & 0xff) << 8);
- return ret;
-}
-
-/* set ina219 to power down mode */
static s32 power_down_INA219(struct i2c_client *client)
{
s32 retval;
@@ -105,6 +91,27 @@ static s32 power_down_INA219(struct i2c_client *client)
return retval;
}
+static s32 power_up_INA219(struct i2c_client *client, u16 config_data)
+{
+ s32 retval;
+ struct ina219_data *data = i2c_get_clientdata(client);
+ retval = i2c_smbus_write_word_data(client, INA219_CONFIG,
+ __constant_cpu_to_be16(config_data));
+ if (retval < 0)
+ goto error;
+
+ retval = i2c_smbus_write_word_data(client, INA219_CAL,
+ __constant_cpu_to_be16(data->pInfo->calibration_data));
+ if (retval < 0)
+ goto error;
+
+ return 0;
+error:
+ dev_err(&client->dev, "power up failure sts: 0x%x\n", retval);
+ return retval;
+
+}
+
static s32 show_rail_name(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -120,48 +127,140 @@ static s32 show_voltage(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct ina219_data *data = i2c_get_clientdata(client);
- s32 retval;
s32 voltage_mV;
+ int cur_state;
- /* fill config data */
- retval = i2c_smbus_write_word_data(client, INA219_CONFIG,
- reorder_bytes(INA219_CONFIG_DATA));
- if (retval < 0) {
- dev_err(dev, "config data write failed sts: 0x%x\n", retval);
- goto error;
- }
-
- /* fill calibration data */
- retval = i2c_smbus_write_word_data(client, INA219_CAL,
- reorder_bytes(data->pInfo->calibration_data));
- if (retval < 0) {
- dev_err(dev, "calib data write failed sts: 0x%x\n", retval);
- goto error;
- }
+ mutex_lock(&data->mutex);
+ cur_state = data->state;
+ if (data->state == STOPPED)
+ if (power_up_INA219(client, data->pInfo->trig_conf) < 0)
+ goto error;
/* getting voltage readings in milli volts*/
voltage_mV =
- reorder_bytes(i2c_smbus_read_word_data(client,
+ (s16)be16_to_cpu(i2c_smbus_read_word_data(client,
INA219_VOLTAGE));
+
DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_mV));
if (voltage_mV < 0)
goto error;
- voltage_mV = voltage_mV >> 1;
+ voltage_mV = busv_register_to_mv(voltage_mV);
DEBUG_INA219(("Ina219 voltage in mv: %d\n", voltage_mV));
- /* set ina219 to power down mode */
- retval = power_down_INA219(client);
- if (retval < 0)
- goto error;
-
DEBUG_INA219(("%s volt = %d\n", __func__, voltage_mV));
+
+ if (cur_state == STOPPED)
+ if (power_down_INA219(client) < 0)
+ goto error;
+
+ mutex_unlock(&data->mutex);
return sprintf(buf, "%d mV\n", voltage_mV);
error:
+ mutex_unlock(&data->mutex);
dev_err(dev, "%s: failed\n", __func__);
- return retval;
+ return -EAGAIN;
+}
+
+static s32 show_shunt_voltage(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina219_data *data = i2c_get_clientdata(client);
+ s32 voltage_uV;
+ int cur_state;
+ mutex_lock(&data->mutex);
+ cur_state = data->state;
+ if (data->state == STOPPED)
+ if (power_up_INA219(client, data->pInfo->trig_conf) < 0)
+ goto error;
+ /* getting voltage readings in milli volts*/
+ voltage_uV =
+ be16_to_cpu(i2c_smbus_read_word_data(client,
+ INA219_SHUNT));
+
+ DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_uV));
+ if (voltage_uV < 0)
+ goto error;
+ voltage_uV = shuntv_register_to_uv(voltage_uV);
+
+ if (cur_state == STOPPED)
+ if (power_down_INA219(client) < 0)
+ goto error;
+
+ mutex_unlock(&data->mutex);
+
+ DEBUG_INA219(("%s volt = %d\n", __func__, voltage_uV));
+ return sprintf(buf, "%d uV\n", voltage_uV);
+error:
+ mutex_unlock(&data->mutex);
+ dev_err(dev, "%s: failed\n", __func__);
+ return -EAGAIN;
}
+static s32 show_power2(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina219_data *data = i2c_get_clientdata(client);
+ s32 power_mW;
+ s32 voltage_shunt_uV;
+ s32 voltage_bus_mV;
+ s32 inverse_shunt_resistor;
+ int cur_state;
+#if INA219_DEBUG_PRINTS
+ s32 power_raw;
+#endif
+
+ mutex_lock(&data->mutex);
+ cur_state = data->state;
+ if (data->state == STOPPED)
+ if (power_up_INA219(client, data->pInfo->trig_conf) < 0)
+ goto error;
+
+ voltage_shunt_uV = be16_to_cpu(i2c_smbus_read_word_data(client,
+ INA219_SHUNT));
+ if (voltage_shunt_uV < 0)
+ goto error;
+ voltage_shunt_uV = shuntv_register_to_uv(voltage_shunt_uV);
+
+ voltage_bus_mV = be16_to_cpu(i2c_smbus_read_word_data(client,
+ INA219_VOLTAGE));
+ if (voltage_bus_mV < 0)
+ goto error;
+
+ voltage_bus_mV = busv_register_to_mv(voltage_bus_mV);
+ /*avoid overflow*/
+ inverse_shunt_resistor = 1000/(data->pInfo->shunt_resistor);
+ power_mW = voltage_shunt_uV * inverse_shunt_resistor; /*current uAmps*/
+ power_mW = power_mW / 1000; /*current mAmps*/
+ power_mW = power_mW * (voltage_bus_mV); /*Power uW*/
+ power_mW = power_mW / 1000; /*Power mW*/
+
+#if INA219_DEBUG_PRINTS
+ power_raw = be16_to_cpu(i2c_smbus_read_word_data(client, INA219_POWER));
+ power_raw *= data->pInfo->power_lsb;
+ power_raw /= data->pInfo->precision_multiplier;
+ DEBUG_INA219(("INA219: power_mW: %d, power_raw:%d\n", power_mW,
+ power_raw));
+#endif
+ if (cur_state == STOPPED)
+ if (power_down_INA219(client) < 0)
+ goto error;
+
+
+ mutex_unlock(&data->mutex);
+ DEBUG_INA219(("%s pow = %d\n", __func__, power_mW));
+ return sprintf(buf, "%d mW\n", power_mW);
+error:
+ mutex_unlock(&data->mutex);
+ dev_err(dev, "%s: failed\n", __func__);
+ return -EAGAIN;
+}
+
+/*This function is kept to support INA219 on cardhu*/
static s32 show_power(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -172,28 +271,22 @@ static s32 show_power(struct device *dev,
s32 power_mW;
s32 voltage_mV;
s32 overflow, conversion;
+ int cur_state;
- /* fill config data */
- retval = i2c_smbus_write_word_data(client, INA219_CONFIG,
- reorder_bytes(INA219_CONFIG_DATA));
- if (retval < 0) {
- dev_err(dev, "config data write failed sts: 0x%x\n", retval);
- goto error;
- }
-
- /* fill calib data */
- retval = i2c_smbus_write_word_data(client, INA219_CAL,
- reorder_bytes(data->pInfo->calibration_data));
- if (retval < 0) {
- dev_err(dev, "calibration data write failed sts: 0x%x\n",
- retval);
- goto error;
+ mutex_lock(&data->mutex);
+ cur_state = data->state;
+ if (data->state == STOPPED) {
+ if (power_up_INA219(client, data->pInfo->trig_conf) < 0)
+ goto error;
+ } else {
+ mutex_unlock(&data->mutex);
+ return show_power2(dev, attr, buf);
}
/* check if the readings are valid */
do {
/* read power register to clear conversion bit */
- retval = reorder_bytes(i2c_smbus_read_word_data(client,
+ retval = be16_to_cpu(i2c_smbus_read_word_data(client,
INA219_POWER));
if (retval < 0) {
dev_err(dev, "CNVR bit clearing failure sts: 0x%x\n",
@@ -202,20 +295,20 @@ static s32 show_power(struct device *dev,
}
voltage_mV =
- reorder_bytes(i2c_smbus_read_word_data(client,
+ be16_to_cpu(i2c_smbus_read_word_data(client,
INA219_VOLTAGE));
DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_mV));
overflow = voltage_mV & 1;
if (overflow) {
dev_err(dev, "overflow error\n");
- return 0;
+ goto error;
}
conversion = (voltage_mV >> 1) & 1;
DEBUG_INA219(("\n ina219 CNVR value:%d", conversion));
} while (!conversion);
/* getting power readings in milli watts*/
- power_mW = reorder_bytes(i2c_smbus_read_word_data(client,
+ power_mW = be16_to_cpu(i2c_smbus_read_word_data(client,
INA219_POWER));
DEBUG_INA219(("Ina219 power Reg: 0x%x\n", power_mW));
power_mW *= data->pInfo->power_lsb;
@@ -229,14 +322,66 @@ static s32 show_power(struct device *dev,
retval = power_down_INA219(client);
if (retval < 0)
goto error;
-
+ mutex_unlock(&data->mutex);
DEBUG_INA219(("%s pow = %d\n", __func__, power_mW));
return sprintf(buf, "%d mW\n", power_mW);
error:
+ mutex_unlock(&data->mutex);
dev_err(dev, "%s: failed\n", __func__);
return retval;
}
+static s32 show_current2(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina219_data *data = i2c_get_clientdata(client);
+ s32 current_mA;
+ s32 voltage_uV;
+ s32 inverse_shunt_resistor;
+ int cur_state;
+#if INA219_DEBUG_PRINTS
+ s32 current_raw;
+#endif
+ mutex_lock(&data->mutex);
+ cur_state = data->state;
+ if (data->state == STOPPED)
+ if (power_up_INA219(client, data->pInfo->trig_conf) < 0)
+ goto error;
+
+ voltage_uV =
+ (s16)be16_to_cpu(i2c_smbus_read_word_data(client,
+ INA219_SHUNT));
+ if (voltage_uV < 0)
+ goto error;
+ inverse_shunt_resistor = 1000/(data->pInfo->shunt_resistor);
+ voltage_uV = shuntv_register_to_uv(voltage_uV);
+ current_mA = voltage_uV * inverse_shunt_resistor;
+ current_mA = current_mA / 1000;
+
+#if INA219_DEBUG_PRINTS
+ current_raw =
+ (s16)be16_to_cpu(i2c_smbus_read_word_data(client,
+ INA219_CURRENT));
+ current_raw *= data->pInfo->power_lsb;
+ current_raw /= data->pInfo->divisor;
+ current_raw /= data->pInfo->precision_multiplier;
+
+ DEBUG_INA219(("%s current = %d current_raw=%d\n", __func__, current_mA,
+ current_raw));
+#endif
+ if (cur_state == STOPPED)
+ if (power_down_INA219(client) < 0)
+ goto error;
+ mutex_unlock(&data->mutex);
+ return sprintf(buf, "%d mA\n", current_mA);
+error:
+ dev_err(dev, "%s: failed\n", __func__);
+ mutex_unlock(&data->mutex);
+ return -EAGAIN;
+}
+/*This function is kept to support INA219 on cardhu*/
static s32 show_current(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -247,28 +392,22 @@ static s32 show_current(struct device *dev,
s32 current_mA;
s32 voltage_mV;
s32 overflow, conversion;
+ int cur_state;
- /* fill config data */
- retval = i2c_smbus_write_word_data(client, INA219_CONFIG,
- reorder_bytes(INA219_CONFIG_DATA));
- if (retval < 0) {
- dev_err(dev, "config data write failed sts: 0x%x\n", retval);
- goto error;
- }
+ mutex_lock(&data->mutex);
- /* fill calib data */
- retval = i2c_smbus_write_word_data(client, INA219_CAL,
- reorder_bytes(data->pInfo->calibration_data));
- if (retval < 0) {
- dev_err(dev, "calibration data write failed sts: 0x%x\n",
- retval);
- goto error;
+ cur_state = data->state;
+ if (data->state == STOPPED) {
+ if (power_up_INA219(client, data->pInfo->trig_conf) < 0)
+ goto error;
+ } else {
+ mutex_unlock(&data->mutex);
+ show_current2(dev, attr, buf);
}
-
/* check if the readings are valid */
do {
/* read power register to clear conversion bit */
- retval = reorder_bytes(i2c_smbus_read_word_data(client,
+ retval = be16_to_cpu(i2c_smbus_read_word_data(client,
INA219_POWER));
if (retval < 0) {
dev_err(dev, "CNVR bit clearing failure sts: 0x%x\n",
@@ -277,20 +416,20 @@ static s32 show_current(struct device *dev,
}
voltage_mV =
- reorder_bytes(i2c_smbus_read_word_data(client,
+ be16_to_cpu(i2c_smbus_read_word_data(client,
INA219_VOLTAGE));
DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_mV));
overflow = voltage_mV & 1;
if (overflow) {
dev_err(dev, "overflow error\n");
- return 0;
+ goto error;
}
conversion = (voltage_mV >> 1) & 1;
DEBUG_INA219(("\n ina219 CNVR value:%d", conversion));
} while (!conversion);
/* getting current readings in milli amps*/
- current_mA = reorder_bytes(i2c_smbus_read_word_data(client,
+ current_mA = be16_to_cpu(i2c_smbus_read_word_data(client,
INA219_CURRENT));
DEBUG_INA219(("Ina219 current Reg: 0x%x\n", current_mA));
if (current_mA < 0)
@@ -301,24 +440,74 @@ static s32 show_current(struct device *dev,
current_mA /= data->pInfo->precision_multiplier;
DEBUG_INA219(("Ina219 current Value: %d\n", current_mA));
- /* set ina219 to power down mode */
- retval = power_down_INA219(client);
- if (retval < 0)
- goto error;
+ if (cur_state == STOPPED)
+ if (power_down_INA219(client) < 0)
+ goto error;
+ mutex_unlock(&data->mutex);
DEBUG_INA219(("%s current = %d\n", __func__, current_mA));
return sprintf(buf, "%d mA\n", current_mA);
error:
+ mutex_unlock(&data->mutex);
dev_err(dev, "%s: failed\n", __func__);
return retval;
}
+static int ina219_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina219_data *data = i2c_get_clientdata(client);
+ int count;
+ mutex_lock(&data->mutex);
+ count = sprintf(buf, "%d\n", data->state);
+ mutex_unlock(&data->mutex);
+ return count;
+}
+
+static int ina219_state_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina219_data *data = i2c_get_clientdata(client);
+ int retval = -1;
+ long new;
+ retval = kstrtol(buf, 10, &new);
+ if (retval < 0 || new > INT_MAX || new < INT_MIN)
+ return -EINVAL;
+ mutex_lock(&data->mutex);
+
+ if ((new > 0) && (data->state == STOPPED))
+ retval = power_up_INA219(client, data->pInfo->cont_conf);
+ else if ((new == 0) && (data->state == RUNNING))
+ retval = power_down_INA219(client);
+
+ if (retval < 0) {
+ dev_err(dev, "Error in switching INA on/off!");
+ mutex_unlock(&data->mutex);
+ return -EAGAIN;
+ }
+
+ if (new)
+ data->state = RUNNING;
+ else
+ data->state = STOPPED;
+
+ mutex_unlock(&data->mutex);
+ return 1;
+}
+
static struct sensor_device_attribute ina219[] = {
+ SENSOR_ATTR(shunt_voltage, S_IRUGO, show_shunt_voltage, NULL, 0),
SENSOR_ATTR(rail_name, S_IRUGO, show_rail_name, NULL, 0),
SENSOR_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 0),
SENSOR_ATTR(curr1_input, S_IRUGO, show_current, NULL, 0),
+ SENSOR_ATTR(curr2_input, S_IRUGO, show_current2, NULL, 0),
SENSOR_ATTR(power1_input, S_IRUGO, show_power, NULL, 0),
+ SENSOR_ATTR(power2_input, S_IRUGO, show_power2, NULL, 0),
+ SENSOR_ATTR(cur_state, 0644, ina219_state_show, ina219_state_set, 0),
};
static int __devinit ina219_probe(struct i2c_client *client,
@@ -336,9 +525,11 @@ static int __devinit ina219_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
data->pInfo = client->dev.platform_data;
mutex_init(&data->mutex);
+ power_down_INA219(client);
+ data->state = STOPPED;
/* reset ina219 */
err = i2c_smbus_write_word_data(client, INA219_CONFIG,
- reorder_bytes(INA219_RESET));
+ __constant_cpu_to_be16(INA219_RESET));
if (err < 0) {
dev_err(&client->dev, "ina219 reset failure status: 0x%x\n",
err);
@@ -359,11 +550,6 @@ static int __devinit ina219_probe(struct i2c_client *client,
goto exit_remove;
}
- /* set ina219 to power down mode */
- err = power_down_INA219(client);
- if (err < 0)
- goto exit_remove;
-
return 0;
exit_remove:
@@ -379,6 +565,10 @@ static int __devexit ina219_remove(struct i2c_client *client)
{
u8 i;
struct ina219_data *data = i2c_get_clientdata(client);
+ mutex_lock(&data->mutex);
+ power_down_INA219(client);
+ data->state = STOPPED;
+ mutex_unlock(&data->mutex);
hwmon_device_unregister(data->hwmon_dev);
for (i = 0; i < ARRAY_SIZE(ina219); i++)
device_remove_file(&client->dev, &ina219[i].dev_attr);