17cb6dcffSAndrew F. Davis /* 27cb6dcffSAndrew F. Davis * INA3221 Triple Current/Voltage Monitor 37cb6dcffSAndrew F. Davis * 47cb6dcffSAndrew F. Davis * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ 57cb6dcffSAndrew F. Davis * Andrew F. Davis <afd@ti.com> 67cb6dcffSAndrew F. Davis * 77cb6dcffSAndrew F. Davis * This program is free software; you can redistribute it and/or modify 87cb6dcffSAndrew F. Davis * it under the terms of the GNU General Public License version 2 as 97cb6dcffSAndrew F. Davis * published by the Free Software Foundation. 107cb6dcffSAndrew F. Davis * 117cb6dcffSAndrew F. Davis * This program is distributed in the hope that it will be useful, but 127cb6dcffSAndrew F. Davis * WITHOUT ANY WARRANTY; without even the implied warranty of 137cb6dcffSAndrew F. Davis * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 147cb6dcffSAndrew F. Davis * General Public License for more details. 157cb6dcffSAndrew F. Davis */ 167cb6dcffSAndrew F. Davis 177cb6dcffSAndrew F. Davis #include <linux/hwmon.h> 187cb6dcffSAndrew F. Davis #include <linux/hwmon-sysfs.h> 197cb6dcffSAndrew F. Davis #include <linux/i2c.h> 207cb6dcffSAndrew F. Davis #include <linux/module.h> 2187625b24SNicolin Chen #include <linux/mutex.h> 227cb6dcffSAndrew F. Davis #include <linux/of.h> 23323aeb0eSNicolin Chen #include <linux/pm_runtime.h> 247cb6dcffSAndrew F. Davis #include <linux/regmap.h> 257cb6dcffSAndrew F. Davis 267cb6dcffSAndrew F. Davis #define INA3221_DRIVER_NAME "ina3221" 277cb6dcffSAndrew F. Davis 287cb6dcffSAndrew F. Davis #define INA3221_CONFIG 0x00 297cb6dcffSAndrew F. Davis #define INA3221_SHUNT1 0x01 307cb6dcffSAndrew F. Davis #define INA3221_BUS1 0x02 317cb6dcffSAndrew F. Davis #define INA3221_SHUNT2 0x03 327cb6dcffSAndrew F. Davis #define INA3221_BUS2 0x04 337cb6dcffSAndrew F. Davis #define INA3221_SHUNT3 0x05 347cb6dcffSAndrew F. Davis #define INA3221_BUS3 0x06 357cb6dcffSAndrew F. Davis #define INA3221_CRIT1 0x07 367cb6dcffSAndrew F. Davis #define INA3221_WARN1 0x08 377cb6dcffSAndrew F. Davis #define INA3221_CRIT2 0x09 387cb6dcffSAndrew F. Davis #define INA3221_WARN2 0x0a 397cb6dcffSAndrew F. Davis #define INA3221_CRIT3 0x0b 407cb6dcffSAndrew F. Davis #define INA3221_WARN3 0x0c 417cb6dcffSAndrew F. Davis #define INA3221_MASK_ENABLE 0x0f 427cb6dcffSAndrew F. Davis 4359d608e1SNicolin Chen #define INA3221_CONFIG_MODE_MASK GENMASK(2, 0) 4459d608e1SNicolin Chen #define INA3221_CONFIG_MODE_POWERDOWN 0 45791ebc9dSNicolin Chen #define INA3221_CONFIG_MODE_SHUNT BIT(0) 46791ebc9dSNicolin Chen #define INA3221_CONFIG_MODE_BUS BIT(1) 47791ebc9dSNicolin Chen #define INA3221_CONFIG_MODE_CONTINUOUS BIT(2) 484c0415a3SNicolin Chen #define INA3221_CONFIG_VSH_CT_SHIFT 3 494c0415a3SNicolin Chen #define INA3221_CONFIG_VSH_CT_MASK GENMASK(5, 3) 504c0415a3SNicolin Chen #define INA3221_CONFIG_VSH_CT(x) (((x) & GENMASK(5, 3)) >> 3) 514c0415a3SNicolin Chen #define INA3221_CONFIG_VBUS_CT_SHIFT 6 524c0415a3SNicolin Chen #define INA3221_CONFIG_VBUS_CT_MASK GENMASK(8, 6) 534c0415a3SNicolin Chen #define INA3221_CONFIG_VBUS_CT(x) (((x) & GENMASK(8, 6)) >> 6) 544c0415a3SNicolin Chen #define INA3221_CONFIG_CHs_EN_MASK GENMASK(14, 12) 55a9e9dd9cSNicolin Chen #define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) 567cb6dcffSAndrew F. Davis 57323aeb0eSNicolin Chen #define INA3221_CONFIG_DEFAULT 0x7127 587cb6dcffSAndrew F. Davis #define INA3221_RSHUNT_DEFAULT 10000 597cb6dcffSAndrew F. Davis 607cb6dcffSAndrew F. Davis enum ina3221_fields { 617cb6dcffSAndrew F. Davis /* Configuration */ 627cb6dcffSAndrew F. Davis F_RST, 637cb6dcffSAndrew F. Davis 644c0415a3SNicolin Chen /* Status Flags */ 654c0415a3SNicolin Chen F_CVRF, 664c0415a3SNicolin Chen 677cb6dcffSAndrew F. Davis /* Alert Flags */ 687cb6dcffSAndrew F. Davis F_WF3, F_WF2, F_WF1, 697cb6dcffSAndrew F. Davis F_CF3, F_CF2, F_CF1, 707cb6dcffSAndrew F. Davis 717cb6dcffSAndrew F. Davis /* sentinel */ 727cb6dcffSAndrew F. Davis F_MAX_FIELDS 737cb6dcffSAndrew F. Davis }; 747cb6dcffSAndrew F. Davis 757cb6dcffSAndrew F. Davis static const struct reg_field ina3221_reg_fields[] = { 767cb6dcffSAndrew F. Davis [F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15), 777cb6dcffSAndrew F. Davis 784c0415a3SNicolin Chen [F_CVRF] = REG_FIELD(INA3221_MASK_ENABLE, 0, 0), 797cb6dcffSAndrew F. Davis [F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3), 807cb6dcffSAndrew F. Davis [F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4), 817cb6dcffSAndrew F. Davis [F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5), 827cb6dcffSAndrew F. Davis [F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7), 837cb6dcffSAndrew F. Davis [F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8), 847cb6dcffSAndrew F. Davis [F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9), 857cb6dcffSAndrew F. Davis }; 867cb6dcffSAndrew F. Davis 877cb6dcffSAndrew F. Davis enum ina3221_channels { 887cb6dcffSAndrew F. Davis INA3221_CHANNEL1, 897cb6dcffSAndrew F. Davis INA3221_CHANNEL2, 907cb6dcffSAndrew F. Davis INA3221_CHANNEL3, 917cb6dcffSAndrew F. Davis INA3221_NUM_CHANNELS 927cb6dcffSAndrew F. Davis }; 937cb6dcffSAndrew F. Davis 947cb6dcffSAndrew F. Davis /** 95a9e9dd9cSNicolin Chen * struct ina3221_input - channel input source specific information 96a9e9dd9cSNicolin Chen * @label: label of channel input source 97a9e9dd9cSNicolin Chen * @shunt_resistor: shunt resistor value of channel input source 98a9e9dd9cSNicolin Chen * @disconnected: connection status of channel input source 99a9e9dd9cSNicolin Chen */ 100a9e9dd9cSNicolin Chen struct ina3221_input { 101a9e9dd9cSNicolin Chen const char *label; 102a9e9dd9cSNicolin Chen int shunt_resistor; 103a9e9dd9cSNicolin Chen bool disconnected; 104a9e9dd9cSNicolin Chen }; 105a9e9dd9cSNicolin Chen 106a9e9dd9cSNicolin Chen /** 1077cb6dcffSAndrew F. Davis * struct ina3221_data - device specific information 108323aeb0eSNicolin Chen * @pm_dev: Device pointer for pm runtime 1097cb6dcffSAndrew F. Davis * @regmap: Register map of the device 1107cb6dcffSAndrew F. Davis * @fields: Register fields of the device 111a9e9dd9cSNicolin Chen * @inputs: Array of channel input source specific structures 11287625b24SNicolin Chen * @lock: mutex lock to serialize sysfs attribute accesses 11359d608e1SNicolin Chen * @reg_config: Register value of INA3221_CONFIG 11443dece16SNicolin Chen * @single_shot: running in single-shot operating mode 1157cb6dcffSAndrew F. Davis */ 1167cb6dcffSAndrew F. Davis struct ina3221_data { 117323aeb0eSNicolin Chen struct device *pm_dev; 1187cb6dcffSAndrew F. Davis struct regmap *regmap; 1197cb6dcffSAndrew F. Davis struct regmap_field *fields[F_MAX_FIELDS]; 120a9e9dd9cSNicolin Chen struct ina3221_input inputs[INA3221_NUM_CHANNELS]; 12187625b24SNicolin Chen struct mutex lock; 12259d608e1SNicolin Chen u32 reg_config; 12343dece16SNicolin Chen 12443dece16SNicolin Chen bool single_shot; 1257cb6dcffSAndrew F. Davis }; 1267cb6dcffSAndrew F. Davis 127a9e9dd9cSNicolin Chen static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel) 128a9e9dd9cSNicolin Chen { 129323aeb0eSNicolin Chen return pm_runtime_active(ina->pm_dev) && 130323aeb0eSNicolin Chen (ina->reg_config & INA3221_CONFIG_CHx_EN(channel)); 131a9e9dd9cSNicolin Chen } 132a9e9dd9cSNicolin Chen 1334c0415a3SNicolin Chen /* Lookup table for Bus and Shunt conversion times in usec */ 1344c0415a3SNicolin Chen static const u16 ina3221_conv_time[] = { 1354c0415a3SNicolin Chen 140, 204, 332, 588, 1100, 2116, 4156, 8244, 1364c0415a3SNicolin Chen }; 1374c0415a3SNicolin Chen 1384c0415a3SNicolin Chen static inline int ina3221_wait_for_data(struct ina3221_data *ina) 1394c0415a3SNicolin Chen { 1404c0415a3SNicolin Chen u32 channels = hweight16(ina->reg_config & INA3221_CONFIG_CHs_EN_MASK); 1414c0415a3SNicolin Chen u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(ina->reg_config); 1424c0415a3SNicolin Chen u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(ina->reg_config); 1434c0415a3SNicolin Chen u32 vbus_ct = ina3221_conv_time[vbus_ct_idx]; 1444c0415a3SNicolin Chen u32 vsh_ct = ina3221_conv_time[vsh_ct_idx]; 1454c0415a3SNicolin Chen u32 wait, cvrf; 1464c0415a3SNicolin Chen 1474c0415a3SNicolin Chen /* Calculate total conversion time */ 1484c0415a3SNicolin Chen wait = channels * (vbus_ct + vsh_ct); 1494c0415a3SNicolin Chen 1504c0415a3SNicolin Chen /* Polling the CVRF bit to make sure read data is ready */ 1514c0415a3SNicolin Chen return regmap_field_read_poll_timeout(ina->fields[F_CVRF], 1524c0415a3SNicolin Chen cvrf, cvrf, wait, 100000); 1534c0415a3SNicolin Chen } 1544c0415a3SNicolin Chen 1557cb6dcffSAndrew F. Davis static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, 1567cb6dcffSAndrew F. Davis int *val) 1577cb6dcffSAndrew F. Davis { 1587cb6dcffSAndrew F. Davis unsigned int regval; 1597cb6dcffSAndrew F. Davis int ret; 1607cb6dcffSAndrew F. Davis 1617cb6dcffSAndrew F. Davis ret = regmap_read(ina->regmap, reg, ®val); 1627cb6dcffSAndrew F. Davis if (ret) 1637cb6dcffSAndrew F. Davis return ret; 1647cb6dcffSAndrew F. Davis 1657cb6dcffSAndrew F. Davis *val = sign_extend32(regval >> 3, 12); 1667cb6dcffSAndrew F. Davis 1677cb6dcffSAndrew F. Davis return 0; 1687cb6dcffSAndrew F. Davis } 1697cb6dcffSAndrew F. Davis 170d4b0166dSNicolin Chen static const u8 ina3221_in_reg[] = { 171d4b0166dSNicolin Chen INA3221_BUS1, 172d4b0166dSNicolin Chen INA3221_BUS2, 173d4b0166dSNicolin Chen INA3221_BUS3, 174d4b0166dSNicolin Chen INA3221_SHUNT1, 175d4b0166dSNicolin Chen INA3221_SHUNT2, 176d4b0166dSNicolin Chen INA3221_SHUNT3, 177d4b0166dSNicolin Chen }; 1787cb6dcffSAndrew F. Davis 179d4b0166dSNicolin Chen static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val) 180d4b0166dSNicolin Chen { 181d4b0166dSNicolin Chen const bool is_shunt = channel > INA3221_CHANNEL3; 182d4b0166dSNicolin Chen struct ina3221_data *ina = dev_get_drvdata(dev); 183d4b0166dSNicolin Chen u8 reg = ina3221_in_reg[channel]; 184d4b0166dSNicolin Chen int regval, ret; 185d4b0166dSNicolin Chen 186d4b0166dSNicolin Chen /* Translate shunt channel index to sensor channel index */ 187d4b0166dSNicolin Chen channel %= INA3221_NUM_CHANNELS; 188d4b0166dSNicolin Chen 189d4b0166dSNicolin Chen switch (attr) { 190d4b0166dSNicolin Chen case hwmon_in_input: 191d4b0166dSNicolin Chen if (!ina3221_is_enabled(ina, channel)) 192a9e9dd9cSNicolin Chen return -ENODATA; 193a9e9dd9cSNicolin Chen 19443dece16SNicolin Chen /* Write CONFIG register to trigger a single-shot measurement */ 19543dece16SNicolin Chen if (ina->single_shot) 19643dece16SNicolin Chen regmap_write(ina->regmap, INA3221_CONFIG, 19743dece16SNicolin Chen ina->reg_config); 19843dece16SNicolin Chen 1994c0415a3SNicolin Chen ret = ina3221_wait_for_data(ina); 2004c0415a3SNicolin Chen if (ret) 2014c0415a3SNicolin Chen return ret; 2024c0415a3SNicolin Chen 203d4b0166dSNicolin Chen ret = ina3221_read_value(ina, reg, ®val); 2047cb6dcffSAndrew F. Davis if (ret) 2057cb6dcffSAndrew F. Davis return ret; 2067cb6dcffSAndrew F. Davis 207d4b0166dSNicolin Chen /* 208d4b0166dSNicolin Chen * Scale of shunt voltage (uV): LSB is 40uV 209d4b0166dSNicolin Chen * Scale of bus voltage (mV): LSB is 8mV 210d4b0166dSNicolin Chen */ 211d4b0166dSNicolin Chen *val = regval * (is_shunt ? 40 : 8); 212d4b0166dSNicolin Chen return 0; 213d4b0166dSNicolin Chen case hwmon_in_enable: 214d4b0166dSNicolin Chen *val = ina3221_is_enabled(ina, channel); 215d4b0166dSNicolin Chen return 0; 216d4b0166dSNicolin Chen default: 217d4b0166dSNicolin Chen return -EOPNOTSUPP; 218d4b0166dSNicolin Chen } 2197cb6dcffSAndrew F. Davis } 2207cb6dcffSAndrew F. Davis 221d4b0166dSNicolin Chen static const u8 ina3221_curr_reg[][INA3221_NUM_CHANNELS] = { 222d4b0166dSNicolin Chen [hwmon_curr_input] = { INA3221_SHUNT1, INA3221_SHUNT2, INA3221_SHUNT3 }, 223d4b0166dSNicolin Chen [hwmon_curr_max] = { INA3221_WARN1, INA3221_WARN2, INA3221_WARN3 }, 224d4b0166dSNicolin Chen [hwmon_curr_crit] = { INA3221_CRIT1, INA3221_CRIT2, INA3221_CRIT3 }, 225d4b0166dSNicolin Chen [hwmon_curr_max_alarm] = { F_WF1, F_WF2, F_WF3 }, 226d4b0166dSNicolin Chen [hwmon_curr_crit_alarm] = { F_CF1, F_CF2, F_CF3 }, 227d4b0166dSNicolin Chen }; 228d4b0166dSNicolin Chen 229d4b0166dSNicolin Chen static int ina3221_read_curr(struct device *dev, u32 attr, 230d4b0166dSNicolin Chen int channel, long *val) 2317cb6dcffSAndrew F. Davis { 2327cb6dcffSAndrew F. Davis struct ina3221_data *ina = dev_get_drvdata(dev); 233a9e9dd9cSNicolin Chen struct ina3221_input *input = &ina->inputs[channel]; 234a9e9dd9cSNicolin Chen int resistance_uo = input->shunt_resistor; 235d4b0166dSNicolin Chen u8 reg = ina3221_curr_reg[attr][channel]; 236d4b0166dSNicolin Chen int regval, voltage_nv, ret; 2377cb6dcffSAndrew F. Davis 238d4b0166dSNicolin Chen switch (attr) { 239d4b0166dSNicolin Chen case hwmon_curr_input: 240d4b0166dSNicolin Chen if (!ina3221_is_enabled(ina, channel)) 241a9e9dd9cSNicolin Chen return -ENODATA; 2424c0415a3SNicolin Chen 24343dece16SNicolin Chen /* Write CONFIG register to trigger a single-shot measurement */ 24443dece16SNicolin Chen if (ina->single_shot) 24543dece16SNicolin Chen regmap_write(ina->regmap, INA3221_CONFIG, 24643dece16SNicolin Chen ina->reg_config); 24743dece16SNicolin Chen 2484c0415a3SNicolin Chen ret = ina3221_wait_for_data(ina); 2494c0415a3SNicolin Chen if (ret) 2504c0415a3SNicolin Chen return ret; 2514c0415a3SNicolin Chen 252d4b0166dSNicolin Chen /* fall through */ 253d4b0166dSNicolin Chen case hwmon_curr_crit: 254d4b0166dSNicolin Chen case hwmon_curr_max: 255d4b0166dSNicolin Chen ret = ina3221_read_value(ina, reg, ®val); 2567cb6dcffSAndrew F. Davis if (ret) 2577cb6dcffSAndrew F. Davis return ret; 2587cb6dcffSAndrew F. Davis 259d4b0166dSNicolin Chen /* Scale of shunt voltage: LSB is 40uV (40000nV) */ 260d4b0166dSNicolin Chen voltage_nv = regval * 40000; 261d4b0166dSNicolin Chen /* Return current in mA */ 262d4b0166dSNicolin Chen *val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); 263d4b0166dSNicolin Chen return 0; 264d4b0166dSNicolin Chen case hwmon_curr_crit_alarm: 265d4b0166dSNicolin Chen case hwmon_curr_max_alarm: 266efb0489eSNicolin Chen /* No actual register read if channel is disabled */ 267efb0489eSNicolin Chen if (!ina3221_is_enabled(ina, channel)) { 268efb0489eSNicolin Chen /* Return 0 for alert flags */ 269efb0489eSNicolin Chen *val = 0; 270efb0489eSNicolin Chen return 0; 271efb0489eSNicolin Chen } 272d4b0166dSNicolin Chen ret = regmap_field_read(ina->fields[reg], ®val); 273d4b0166dSNicolin Chen if (ret) 274d4b0166dSNicolin Chen return ret; 275d4b0166dSNicolin Chen *val = regval; 276d4b0166dSNicolin Chen return 0; 277d4b0166dSNicolin Chen default: 278d4b0166dSNicolin Chen return -EOPNOTSUPP; 279d4b0166dSNicolin Chen } 2807cb6dcffSAndrew F. Davis } 2817cb6dcffSAndrew F. Davis 282d4b0166dSNicolin Chen static int ina3221_write_curr(struct device *dev, u32 attr, 283d4b0166dSNicolin Chen int channel, long val) 2847cb6dcffSAndrew F. Davis { 2857cb6dcffSAndrew F. Davis struct ina3221_data *ina = dev_get_drvdata(dev); 286a9e9dd9cSNicolin Chen struct ina3221_input *input = &ina->inputs[channel]; 287a9e9dd9cSNicolin Chen int resistance_uo = input->shunt_resistor; 288d4b0166dSNicolin Chen u8 reg = ina3221_curr_reg[attr][channel]; 289d4b0166dSNicolin Chen int regval, current_ma, voltage_uv; 2907cb6dcffSAndrew F. Davis 2917cb6dcffSAndrew F. Davis /* clamp current */ 292d4b0166dSNicolin Chen current_ma = clamp_val(val, 2937cb6dcffSAndrew F. Davis INT_MIN / resistance_uo, 2947cb6dcffSAndrew F. Davis INT_MAX / resistance_uo); 2957cb6dcffSAndrew F. Davis 2967cb6dcffSAndrew F. Davis voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); 2977cb6dcffSAndrew F. Davis 2987cb6dcffSAndrew F. Davis /* clamp voltage */ 2997cb6dcffSAndrew F. Davis voltage_uv = clamp_val(voltage_uv, -163800, 163800); 3007cb6dcffSAndrew F. Davis 3017cb6dcffSAndrew F. Davis /* 1 / 40uV(scale) << 3(register shift) = 5 */ 302d4b0166dSNicolin Chen regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; 3037cb6dcffSAndrew F. Davis 304d4b0166dSNicolin Chen return regmap_write(ina->regmap, reg, regval); 305d4b0166dSNicolin Chen } 306d4b0166dSNicolin Chen 307d4b0166dSNicolin Chen static int ina3221_write_enable(struct device *dev, int channel, bool enable) 308d4b0166dSNicolin Chen { 309d4b0166dSNicolin Chen struct ina3221_data *ina = dev_get_drvdata(dev); 310d4b0166dSNicolin Chen u16 config, mask = INA3221_CONFIG_CHx_EN(channel); 311323aeb0eSNicolin Chen u16 config_old = ina->reg_config & mask; 312d4b0166dSNicolin Chen int ret; 313d4b0166dSNicolin Chen 314d4b0166dSNicolin Chen config = enable ? mask : 0; 315d4b0166dSNicolin Chen 316323aeb0eSNicolin Chen /* Bypass if enable status is not being changed */ 317323aeb0eSNicolin Chen if (config_old == config) 318323aeb0eSNicolin Chen return 0; 319323aeb0eSNicolin Chen 320323aeb0eSNicolin Chen /* For enabling routine, increase refcount and resume() at first */ 321323aeb0eSNicolin Chen if (enable) { 322323aeb0eSNicolin Chen ret = pm_runtime_get_sync(ina->pm_dev); 323323aeb0eSNicolin Chen if (ret < 0) { 324323aeb0eSNicolin Chen dev_err(dev, "Failed to get PM runtime\n"); 325323aeb0eSNicolin Chen return ret; 326323aeb0eSNicolin Chen } 327323aeb0eSNicolin Chen } 328323aeb0eSNicolin Chen 329d4b0166dSNicolin Chen /* Enable or disable the channel */ 330d4b0166dSNicolin Chen ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config); 3317cb6dcffSAndrew F. Davis if (ret) 332323aeb0eSNicolin Chen goto fail; 3337cb6dcffSAndrew F. Davis 334d4b0166dSNicolin Chen /* Cache the latest config register value */ 335d4b0166dSNicolin Chen ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); 336d4b0166dSNicolin Chen if (ret) 337323aeb0eSNicolin Chen goto fail; 338323aeb0eSNicolin Chen 339323aeb0eSNicolin Chen /* For disabling routine, decrease refcount or suspend() at last */ 340323aeb0eSNicolin Chen if (!enable) 341323aeb0eSNicolin Chen pm_runtime_put_sync(ina->pm_dev); 342d4b0166dSNicolin Chen 343d4b0166dSNicolin Chen return 0; 344323aeb0eSNicolin Chen 345323aeb0eSNicolin Chen fail: 346323aeb0eSNicolin Chen if (enable) { 347323aeb0eSNicolin Chen dev_err(dev, "Failed to enable channel %d: error %d\n", 348323aeb0eSNicolin Chen channel, ret); 349323aeb0eSNicolin Chen pm_runtime_put_sync(ina->pm_dev); 350323aeb0eSNicolin Chen } 351323aeb0eSNicolin Chen 352323aeb0eSNicolin Chen return ret; 3537cb6dcffSAndrew F. Davis } 3547cb6dcffSAndrew F. Davis 355d4b0166dSNicolin Chen static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, 356d4b0166dSNicolin Chen u32 attr, int channel, long *val) 357d4b0166dSNicolin Chen { 35887625b24SNicolin Chen struct ina3221_data *ina = dev_get_drvdata(dev); 35987625b24SNicolin Chen int ret; 36087625b24SNicolin Chen 36187625b24SNicolin Chen mutex_lock(&ina->lock); 36287625b24SNicolin Chen 363d4b0166dSNicolin Chen switch (type) { 364d4b0166dSNicolin Chen case hwmon_in: 365d4b0166dSNicolin Chen /* 0-align channel ID */ 36687625b24SNicolin Chen ret = ina3221_read_in(dev, attr, channel - 1, val); 36787625b24SNicolin Chen break; 368d4b0166dSNicolin Chen case hwmon_curr: 36987625b24SNicolin Chen ret = ina3221_read_curr(dev, attr, channel, val); 37087625b24SNicolin Chen break; 371d4b0166dSNicolin Chen default: 37287625b24SNicolin Chen ret = -EOPNOTSUPP; 37387625b24SNicolin Chen break; 374d4b0166dSNicolin Chen } 37587625b24SNicolin Chen 37687625b24SNicolin Chen mutex_unlock(&ina->lock); 37787625b24SNicolin Chen 37887625b24SNicolin Chen return ret; 379d4b0166dSNicolin Chen } 380d4b0166dSNicolin Chen 381d4b0166dSNicolin Chen static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, 382d4b0166dSNicolin Chen u32 attr, int channel, long val) 383d4b0166dSNicolin Chen { 38487625b24SNicolin Chen struct ina3221_data *ina = dev_get_drvdata(dev); 38587625b24SNicolin Chen int ret; 38687625b24SNicolin Chen 38787625b24SNicolin Chen mutex_lock(&ina->lock); 38887625b24SNicolin Chen 389d4b0166dSNicolin Chen switch (type) { 390d4b0166dSNicolin Chen case hwmon_in: 391d4b0166dSNicolin Chen /* 0-align channel ID */ 39287625b24SNicolin Chen ret = ina3221_write_enable(dev, channel - 1, val); 39387625b24SNicolin Chen break; 394d4b0166dSNicolin Chen case hwmon_curr: 39587625b24SNicolin Chen ret = ina3221_write_curr(dev, attr, channel, val); 39687625b24SNicolin Chen break; 397d4b0166dSNicolin Chen default: 39887625b24SNicolin Chen ret = -EOPNOTSUPP; 39987625b24SNicolin Chen break; 400d4b0166dSNicolin Chen } 40187625b24SNicolin Chen 40287625b24SNicolin Chen mutex_unlock(&ina->lock); 40387625b24SNicolin Chen 40487625b24SNicolin Chen return ret; 405d4b0166dSNicolin Chen } 406d4b0166dSNicolin Chen 407d4b0166dSNicolin Chen static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type, 408d4b0166dSNicolin Chen u32 attr, int channel, const char **str) 409d4b0166dSNicolin Chen { 410d4b0166dSNicolin Chen struct ina3221_data *ina = dev_get_drvdata(dev); 411d4b0166dSNicolin Chen int index = channel - 1; 412d4b0166dSNicolin Chen 413d4b0166dSNicolin Chen *str = ina->inputs[index].label; 414d4b0166dSNicolin Chen 415d4b0166dSNicolin Chen return 0; 416d4b0166dSNicolin Chen } 417d4b0166dSNicolin Chen 418d4b0166dSNicolin Chen static umode_t ina3221_is_visible(const void *drvdata, 419d4b0166dSNicolin Chen enum hwmon_sensor_types type, 420d4b0166dSNicolin Chen u32 attr, int channel) 421d4b0166dSNicolin Chen { 422d4b0166dSNicolin Chen const struct ina3221_data *ina = drvdata; 423d4b0166dSNicolin Chen const struct ina3221_input *input = NULL; 424d4b0166dSNicolin Chen 425d4b0166dSNicolin Chen switch (type) { 426d4b0166dSNicolin Chen case hwmon_in: 427d4b0166dSNicolin Chen /* Ignore in0_ */ 428d4b0166dSNicolin Chen if (channel == 0) 429d4b0166dSNicolin Chen return 0; 430d4b0166dSNicolin Chen 431d4b0166dSNicolin Chen switch (attr) { 432d4b0166dSNicolin Chen case hwmon_in_label: 433d4b0166dSNicolin Chen if (channel - 1 <= INA3221_CHANNEL3) 434d4b0166dSNicolin Chen input = &ina->inputs[channel - 1]; 435d4b0166dSNicolin Chen /* Hide label node if label is not provided */ 436d4b0166dSNicolin Chen return (input && input->label) ? 0444 : 0; 437d4b0166dSNicolin Chen case hwmon_in_input: 438d4b0166dSNicolin Chen return 0444; 439d4b0166dSNicolin Chen case hwmon_in_enable: 440d4b0166dSNicolin Chen return 0644; 441d4b0166dSNicolin Chen default: 442d4b0166dSNicolin Chen return 0; 443d4b0166dSNicolin Chen } 444d4b0166dSNicolin Chen case hwmon_curr: 445d4b0166dSNicolin Chen switch (attr) { 446d4b0166dSNicolin Chen case hwmon_curr_input: 447d4b0166dSNicolin Chen case hwmon_curr_crit_alarm: 448d4b0166dSNicolin Chen case hwmon_curr_max_alarm: 449d4b0166dSNicolin Chen return 0444; 450d4b0166dSNicolin Chen case hwmon_curr_crit: 451d4b0166dSNicolin Chen case hwmon_curr_max: 452d4b0166dSNicolin Chen return 0644; 453d4b0166dSNicolin Chen default: 454d4b0166dSNicolin Chen return 0; 455d4b0166dSNicolin Chen } 456d4b0166dSNicolin Chen default: 457d4b0166dSNicolin Chen return 0; 458d4b0166dSNicolin Chen } 459d4b0166dSNicolin Chen } 460d4b0166dSNicolin Chen 461d4b0166dSNicolin Chen static const u32 ina3221_in_config[] = { 462d4b0166dSNicolin Chen /* 0: dummy, skipped in is_visible */ 463d4b0166dSNicolin Chen HWMON_I_INPUT, 464d4b0166dSNicolin Chen /* 1-3: input voltage Channels */ 465d4b0166dSNicolin Chen HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, 466d4b0166dSNicolin Chen HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, 467d4b0166dSNicolin Chen HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, 468d4b0166dSNicolin Chen /* 4-6: shunt voltage Channels */ 469d4b0166dSNicolin Chen HWMON_I_INPUT, 470d4b0166dSNicolin Chen HWMON_I_INPUT, 471d4b0166dSNicolin Chen HWMON_I_INPUT, 472d4b0166dSNicolin Chen 0 473d4b0166dSNicolin Chen }; 474d4b0166dSNicolin Chen 475d4b0166dSNicolin Chen static const struct hwmon_channel_info ina3221_in = { 476d4b0166dSNicolin Chen .type = hwmon_in, 477d4b0166dSNicolin Chen .config = ina3221_in_config, 478d4b0166dSNicolin Chen }; 479d4b0166dSNicolin Chen 480d4b0166dSNicolin Chen #define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \ 481d4b0166dSNicolin Chen HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \ 482d4b0166dSNicolin Chen HWMON_C_MAX | HWMON_C_MAX_ALARM) 483d4b0166dSNicolin Chen 484d4b0166dSNicolin Chen static const u32 ina3221_curr_config[] = { 485d4b0166dSNicolin Chen INA3221_HWMON_CURR_CONFIG, 486d4b0166dSNicolin Chen INA3221_HWMON_CURR_CONFIG, 487d4b0166dSNicolin Chen INA3221_HWMON_CURR_CONFIG, 488d4b0166dSNicolin Chen 0 489d4b0166dSNicolin Chen }; 490d4b0166dSNicolin Chen 491d4b0166dSNicolin Chen static const struct hwmon_channel_info ina3221_curr = { 492d4b0166dSNicolin Chen .type = hwmon_curr, 493d4b0166dSNicolin Chen .config = ina3221_curr_config, 494d4b0166dSNicolin Chen }; 495d4b0166dSNicolin Chen 496d4b0166dSNicolin Chen static const struct hwmon_channel_info *ina3221_info[] = { 497d4b0166dSNicolin Chen &ina3221_in, 498d4b0166dSNicolin Chen &ina3221_curr, 499d4b0166dSNicolin Chen NULL 500d4b0166dSNicolin Chen }; 501d4b0166dSNicolin Chen 502d4b0166dSNicolin Chen static const struct hwmon_ops ina3221_hwmon_ops = { 503d4b0166dSNicolin Chen .is_visible = ina3221_is_visible, 504d4b0166dSNicolin Chen .read_string = ina3221_read_string, 505d4b0166dSNicolin Chen .read = ina3221_read, 506d4b0166dSNicolin Chen .write = ina3221_write, 507d4b0166dSNicolin Chen }; 508d4b0166dSNicolin Chen 509d4b0166dSNicolin Chen static const struct hwmon_chip_info ina3221_chip_info = { 510d4b0166dSNicolin Chen .ops = &ina3221_hwmon_ops, 511d4b0166dSNicolin Chen .info = ina3221_info, 512d4b0166dSNicolin Chen }; 513d4b0166dSNicolin Chen 514d4b0166dSNicolin Chen /* Extra attribute groups */ 515a4ec92edSGuenter Roeck static ssize_t ina3221_shunt_show(struct device *dev, 5167cb6dcffSAndrew F. Davis struct device_attribute *attr, char *buf) 5177cb6dcffSAndrew F. Davis { 5187cb6dcffSAndrew F. Davis struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); 5197cb6dcffSAndrew F. Davis struct ina3221_data *ina = dev_get_drvdata(dev); 5207cb6dcffSAndrew F. Davis unsigned int channel = sd_attr->index; 521a9e9dd9cSNicolin Chen struct ina3221_input *input = &ina->inputs[channel]; 5227cb6dcffSAndrew F. Davis 523a9e9dd9cSNicolin Chen return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor); 5247cb6dcffSAndrew F. Davis } 5257cb6dcffSAndrew F. Davis 526a4ec92edSGuenter Roeck static ssize_t ina3221_shunt_store(struct device *dev, 5277cb6dcffSAndrew F. Davis struct device_attribute *attr, 5287cb6dcffSAndrew F. Davis const char *buf, size_t count) 5297cb6dcffSAndrew F. Davis { 5307cb6dcffSAndrew F. Davis struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); 5317cb6dcffSAndrew F. Davis struct ina3221_data *ina = dev_get_drvdata(dev); 5327cb6dcffSAndrew F. Davis unsigned int channel = sd_attr->index; 533a9e9dd9cSNicolin Chen struct ina3221_input *input = &ina->inputs[channel]; 5349ad0df1aSGuenter Roeck int val; 5357cb6dcffSAndrew F. Davis int ret; 5367cb6dcffSAndrew F. Davis 5379ad0df1aSGuenter Roeck ret = kstrtoint(buf, 0, &val); 5387cb6dcffSAndrew F. Davis if (ret) 5397cb6dcffSAndrew F. Davis return ret; 5407cb6dcffSAndrew F. Davis 5419ad0df1aSGuenter Roeck val = clamp_val(val, 1, INT_MAX); 5427cb6dcffSAndrew F. Davis 543a9e9dd9cSNicolin Chen input->shunt_resistor = val; 5447cb6dcffSAndrew F. Davis 5457cb6dcffSAndrew F. Davis return count; 5467cb6dcffSAndrew F. Davis } 5477cb6dcffSAndrew F. Davis 5487cb6dcffSAndrew F. Davis /* shunt resistance */ 549a4ec92edSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(shunt1_resistor, ina3221_shunt, INA3221_CHANNEL1); 550a4ec92edSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(shunt2_resistor, ina3221_shunt, INA3221_CHANNEL2); 551a4ec92edSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(shunt3_resistor, ina3221_shunt, INA3221_CHANNEL3); 5527cb6dcffSAndrew F. Davis 5537cb6dcffSAndrew F. Davis static struct attribute *ina3221_attrs[] = { 5547cb6dcffSAndrew F. Davis &sensor_dev_attr_shunt1_resistor.dev_attr.attr, 5557cb6dcffSAndrew F. Davis &sensor_dev_attr_shunt2_resistor.dev_attr.attr, 5567cb6dcffSAndrew F. Davis &sensor_dev_attr_shunt3_resistor.dev_attr.attr, 5577cb6dcffSAndrew F. Davis NULL, 5587cb6dcffSAndrew F. Davis }; 559d4b0166dSNicolin Chen ATTRIBUTE_GROUPS(ina3221); 5607cb6dcffSAndrew F. Davis 5617cb6dcffSAndrew F. Davis static const struct regmap_range ina3221_yes_ranges[] = { 562c20217b3SNicolin Chen regmap_reg_range(INA3221_CONFIG, INA3221_BUS3), 5637cb6dcffSAndrew F. Davis regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE), 5647cb6dcffSAndrew F. Davis }; 5657cb6dcffSAndrew F. Davis 5667cb6dcffSAndrew F. Davis static const struct regmap_access_table ina3221_volatile_table = { 5677cb6dcffSAndrew F. Davis .yes_ranges = ina3221_yes_ranges, 5687cb6dcffSAndrew F. Davis .n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges), 5697cb6dcffSAndrew F. Davis }; 5707cb6dcffSAndrew F. Davis 5717cb6dcffSAndrew F. Davis static const struct regmap_config ina3221_regmap_config = { 5727cb6dcffSAndrew F. Davis .reg_bits = 8, 5737cb6dcffSAndrew F. Davis .val_bits = 16, 5747cb6dcffSAndrew F. Davis 5757cb6dcffSAndrew F. Davis .cache_type = REGCACHE_RBTREE, 5767cb6dcffSAndrew F. Davis .volatile_table = &ina3221_volatile_table, 5777cb6dcffSAndrew F. Davis }; 5787cb6dcffSAndrew F. Davis 579a9e9dd9cSNicolin Chen static int ina3221_probe_child_from_dt(struct device *dev, 580a9e9dd9cSNicolin Chen struct device_node *child, 581a9e9dd9cSNicolin Chen struct ina3221_data *ina) 582a9e9dd9cSNicolin Chen { 583a9e9dd9cSNicolin Chen struct ina3221_input *input; 584a9e9dd9cSNicolin Chen u32 val; 585a9e9dd9cSNicolin Chen int ret; 586a9e9dd9cSNicolin Chen 587a9e9dd9cSNicolin Chen ret = of_property_read_u32(child, "reg", &val); 588a9e9dd9cSNicolin Chen if (ret) { 5891b1f4efaSRob Herring dev_err(dev, "missing reg property of %pOFn\n", child); 590a9e9dd9cSNicolin Chen return ret; 591a9e9dd9cSNicolin Chen } else if (val > INA3221_CHANNEL3) { 5921b1f4efaSRob Herring dev_err(dev, "invalid reg %d of %pOFn\n", val, child); 593a9e9dd9cSNicolin Chen return ret; 594a9e9dd9cSNicolin Chen } 595a9e9dd9cSNicolin Chen 596a9e9dd9cSNicolin Chen input = &ina->inputs[val]; 597a9e9dd9cSNicolin Chen 598a9e9dd9cSNicolin Chen /* Log the disconnected channel input */ 599a9e9dd9cSNicolin Chen if (!of_device_is_available(child)) { 600a9e9dd9cSNicolin Chen input->disconnected = true; 601a9e9dd9cSNicolin Chen return 0; 602a9e9dd9cSNicolin Chen } 603a9e9dd9cSNicolin Chen 604a9e9dd9cSNicolin Chen /* Save the connected input label if available */ 605a9e9dd9cSNicolin Chen of_property_read_string(child, "label", &input->label); 606a9e9dd9cSNicolin Chen 607a9e9dd9cSNicolin Chen /* Overwrite default shunt resistor value optionally */ 608a6e43263SNicolin Chen if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) { 609a6e43263SNicolin Chen if (val < 1 || val > INT_MAX) { 6101b1f4efaSRob Herring dev_err(dev, "invalid shunt resistor value %u of %pOFn\n", 6111b1f4efaSRob Herring val, child); 612a6e43263SNicolin Chen return -EINVAL; 613a6e43263SNicolin Chen } 614a9e9dd9cSNicolin Chen input->shunt_resistor = val; 615a6e43263SNicolin Chen } 616a9e9dd9cSNicolin Chen 617a9e9dd9cSNicolin Chen return 0; 618a9e9dd9cSNicolin Chen } 619a9e9dd9cSNicolin Chen 620a9e9dd9cSNicolin Chen static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) 621a9e9dd9cSNicolin Chen { 622a9e9dd9cSNicolin Chen const struct device_node *np = dev->of_node; 623a9e9dd9cSNicolin Chen struct device_node *child; 624a9e9dd9cSNicolin Chen int ret; 625a9e9dd9cSNicolin Chen 626a9e9dd9cSNicolin Chen /* Compatible with non-DT platforms */ 627a9e9dd9cSNicolin Chen if (!np) 628a9e9dd9cSNicolin Chen return 0; 629a9e9dd9cSNicolin Chen 63043dece16SNicolin Chen ina->single_shot = of_property_read_bool(np, "ti,single-shot"); 63143dece16SNicolin Chen 632a9e9dd9cSNicolin Chen for_each_child_of_node(np, child) { 633a9e9dd9cSNicolin Chen ret = ina3221_probe_child_from_dt(dev, child, ina); 634a9e9dd9cSNicolin Chen if (ret) 635a9e9dd9cSNicolin Chen return ret; 636a9e9dd9cSNicolin Chen } 637a9e9dd9cSNicolin Chen 638a9e9dd9cSNicolin Chen return 0; 639a9e9dd9cSNicolin Chen } 640a9e9dd9cSNicolin Chen 6417cb6dcffSAndrew F. Davis static int ina3221_probe(struct i2c_client *client, 6427cb6dcffSAndrew F. Davis const struct i2c_device_id *id) 6437cb6dcffSAndrew F. Davis { 6447cb6dcffSAndrew F. Davis struct device *dev = &client->dev; 6457cb6dcffSAndrew F. Davis struct ina3221_data *ina; 6467cb6dcffSAndrew F. Davis struct device *hwmon_dev; 6477cb6dcffSAndrew F. Davis int i, ret; 6487cb6dcffSAndrew F. Davis 6497cb6dcffSAndrew F. Davis ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); 6507cb6dcffSAndrew F. Davis if (!ina) 6517cb6dcffSAndrew F. Davis return -ENOMEM; 6527cb6dcffSAndrew F. Davis 6537cb6dcffSAndrew F. Davis ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config); 6547cb6dcffSAndrew F. Davis if (IS_ERR(ina->regmap)) { 6557cb6dcffSAndrew F. Davis dev_err(dev, "Unable to allocate register map\n"); 6567cb6dcffSAndrew F. Davis return PTR_ERR(ina->regmap); 6577cb6dcffSAndrew F. Davis } 6587cb6dcffSAndrew F. Davis 6597cb6dcffSAndrew F. Davis for (i = 0; i < F_MAX_FIELDS; i++) { 6607cb6dcffSAndrew F. Davis ina->fields[i] = devm_regmap_field_alloc(dev, 6617cb6dcffSAndrew F. Davis ina->regmap, 6627cb6dcffSAndrew F. Davis ina3221_reg_fields[i]); 6637cb6dcffSAndrew F. Davis if (IS_ERR(ina->fields[i])) { 6647cb6dcffSAndrew F. Davis dev_err(dev, "Unable to allocate regmap fields\n"); 6657cb6dcffSAndrew F. Davis return PTR_ERR(ina->fields[i]); 6667cb6dcffSAndrew F. Davis } 6677cb6dcffSAndrew F. Davis } 6687cb6dcffSAndrew F. Davis 6697cb6dcffSAndrew F. Davis for (i = 0; i < INA3221_NUM_CHANNELS; i++) 670a9e9dd9cSNicolin Chen ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT; 671a9e9dd9cSNicolin Chen 672a9e9dd9cSNicolin Chen ret = ina3221_probe_from_dt(dev, ina); 673a9e9dd9cSNicolin Chen if (ret) { 674a9e9dd9cSNicolin Chen dev_err(dev, "Unable to probe from device tree\n"); 675a9e9dd9cSNicolin Chen return ret; 676a9e9dd9cSNicolin Chen } 6777cb6dcffSAndrew F. Davis 678323aeb0eSNicolin Chen /* The driver will be reset, so use reset value */ 679323aeb0eSNicolin Chen ina->reg_config = INA3221_CONFIG_DEFAULT; 680a9e9dd9cSNicolin Chen 68143dece16SNicolin Chen /* Clear continuous bit to use single-shot mode */ 68243dece16SNicolin Chen if (ina->single_shot) 68343dece16SNicolin Chen ina->reg_config &= ~INA3221_CONFIG_MODE_CONTINUOUS; 68443dece16SNicolin Chen 685a9e9dd9cSNicolin Chen /* Disable channels if their inputs are disconnected */ 686a9e9dd9cSNicolin Chen for (i = 0; i < INA3221_NUM_CHANNELS; i++) { 687a9e9dd9cSNicolin Chen if (ina->inputs[i].disconnected) 688a9e9dd9cSNicolin Chen ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i); 689a9e9dd9cSNicolin Chen } 690a9e9dd9cSNicolin Chen 691323aeb0eSNicolin Chen ina->pm_dev = dev; 69287625b24SNicolin Chen mutex_init(&ina->lock); 69359d608e1SNicolin Chen dev_set_drvdata(dev, ina); 69459d608e1SNicolin Chen 695323aeb0eSNicolin Chen /* Enable PM runtime -- status is suspended by default */ 696323aeb0eSNicolin Chen pm_runtime_enable(ina->pm_dev); 697323aeb0eSNicolin Chen 698323aeb0eSNicolin Chen /* Initialize (resume) the device */ 699323aeb0eSNicolin Chen for (i = 0; i < INA3221_NUM_CHANNELS; i++) { 700323aeb0eSNicolin Chen if (ina->inputs[i].disconnected) 701323aeb0eSNicolin Chen continue; 702323aeb0eSNicolin Chen /* Match the refcount with number of enabled channels */ 703323aeb0eSNicolin Chen ret = pm_runtime_get_sync(ina->pm_dev); 704323aeb0eSNicolin Chen if (ret < 0) 705323aeb0eSNicolin Chen goto fail; 706323aeb0eSNicolin Chen } 707323aeb0eSNicolin Chen 708d4b0166dSNicolin Chen hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina, 709d4b0166dSNicolin Chen &ina3221_chip_info, 710d4b0166dSNicolin Chen ina3221_groups); 7117cb6dcffSAndrew F. Davis if (IS_ERR(hwmon_dev)) { 7127cb6dcffSAndrew F. Davis dev_err(dev, "Unable to register hwmon device\n"); 713323aeb0eSNicolin Chen ret = PTR_ERR(hwmon_dev); 714323aeb0eSNicolin Chen goto fail; 7157cb6dcffSAndrew F. Davis } 7167cb6dcffSAndrew F. Davis 7177cb6dcffSAndrew F. Davis return 0; 718323aeb0eSNicolin Chen 719323aeb0eSNicolin Chen fail: 720323aeb0eSNicolin Chen pm_runtime_disable(ina->pm_dev); 721323aeb0eSNicolin Chen pm_runtime_set_suspended(ina->pm_dev); 722323aeb0eSNicolin Chen /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ 723323aeb0eSNicolin Chen for (i = 0; i < INA3221_NUM_CHANNELS; i++) 724323aeb0eSNicolin Chen pm_runtime_put_noidle(ina->pm_dev); 725323aeb0eSNicolin Chen mutex_destroy(&ina->lock); 726323aeb0eSNicolin Chen 727323aeb0eSNicolin Chen return ret; 7287cb6dcffSAndrew F. Davis } 7297cb6dcffSAndrew F. Davis 73087625b24SNicolin Chen static int ina3221_remove(struct i2c_client *client) 73187625b24SNicolin Chen { 73287625b24SNicolin Chen struct ina3221_data *ina = dev_get_drvdata(&client->dev); 733323aeb0eSNicolin Chen int i; 734323aeb0eSNicolin Chen 735323aeb0eSNicolin Chen pm_runtime_disable(ina->pm_dev); 736323aeb0eSNicolin Chen pm_runtime_set_suspended(ina->pm_dev); 737323aeb0eSNicolin Chen 738323aeb0eSNicolin Chen /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ 739323aeb0eSNicolin Chen for (i = 0; i < INA3221_NUM_CHANNELS; i++) 740323aeb0eSNicolin Chen pm_runtime_put_noidle(ina->pm_dev); 74187625b24SNicolin Chen 74287625b24SNicolin Chen mutex_destroy(&ina->lock); 74387625b24SNicolin Chen 74487625b24SNicolin Chen return 0; 74587625b24SNicolin Chen } 74687625b24SNicolin Chen 747ead21c77SArnd Bergmann static int __maybe_unused ina3221_suspend(struct device *dev) 74859d608e1SNicolin Chen { 74959d608e1SNicolin Chen struct ina3221_data *ina = dev_get_drvdata(dev); 75059d608e1SNicolin Chen int ret; 75159d608e1SNicolin Chen 75259d608e1SNicolin Chen /* Save config register value and enable cache-only */ 75359d608e1SNicolin Chen ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); 75459d608e1SNicolin Chen if (ret) 75559d608e1SNicolin Chen return ret; 75659d608e1SNicolin Chen 75759d608e1SNicolin Chen /* Set to power-down mode for power saving */ 75859d608e1SNicolin Chen ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, 75959d608e1SNicolin Chen INA3221_CONFIG_MODE_MASK, 76059d608e1SNicolin Chen INA3221_CONFIG_MODE_POWERDOWN); 76159d608e1SNicolin Chen if (ret) 76259d608e1SNicolin Chen return ret; 76359d608e1SNicolin Chen 76459d608e1SNicolin Chen regcache_cache_only(ina->regmap, true); 76559d608e1SNicolin Chen regcache_mark_dirty(ina->regmap); 76659d608e1SNicolin Chen 76759d608e1SNicolin Chen return 0; 76859d608e1SNicolin Chen } 76959d608e1SNicolin Chen 770ead21c77SArnd Bergmann static int __maybe_unused ina3221_resume(struct device *dev) 77159d608e1SNicolin Chen { 77259d608e1SNicolin Chen struct ina3221_data *ina = dev_get_drvdata(dev); 77359d608e1SNicolin Chen int ret; 77459d608e1SNicolin Chen 77559d608e1SNicolin Chen regcache_cache_only(ina->regmap, false); 77659d608e1SNicolin Chen 77759d608e1SNicolin Chen /* Software reset the chip */ 77859d608e1SNicolin Chen ret = regmap_field_write(ina->fields[F_RST], true); 77959d608e1SNicolin Chen if (ret) { 78059d608e1SNicolin Chen dev_err(dev, "Unable to reset device\n"); 78159d608e1SNicolin Chen return ret; 78259d608e1SNicolin Chen } 78359d608e1SNicolin Chen 78459d608e1SNicolin Chen /* Restore cached register values to hardware */ 78559d608e1SNicolin Chen ret = regcache_sync(ina->regmap); 78659d608e1SNicolin Chen if (ret) 78759d608e1SNicolin Chen return ret; 78859d608e1SNicolin Chen 78959d608e1SNicolin Chen /* Restore config register value to hardware */ 79059d608e1SNicolin Chen ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); 79159d608e1SNicolin Chen if (ret) 79259d608e1SNicolin Chen return ret; 79359d608e1SNicolin Chen 79459d608e1SNicolin Chen return 0; 79559d608e1SNicolin Chen } 79659d608e1SNicolin Chen 79759d608e1SNicolin Chen static const struct dev_pm_ops ina3221_pm = { 798323aeb0eSNicolin Chen SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 799323aeb0eSNicolin Chen pm_runtime_force_resume) 800323aeb0eSNicolin Chen SET_RUNTIME_PM_OPS(ina3221_suspend, ina3221_resume, NULL) 80159d608e1SNicolin Chen }; 80259d608e1SNicolin Chen 8037cb6dcffSAndrew F. Davis static const struct of_device_id ina3221_of_match_table[] = { 8047cb6dcffSAndrew F. Davis { .compatible = "ti,ina3221", }, 8057cb6dcffSAndrew F. Davis { /* sentinel */ } 8067cb6dcffSAndrew F. Davis }; 8077cb6dcffSAndrew F. Davis MODULE_DEVICE_TABLE(of, ina3221_of_match_table); 8087cb6dcffSAndrew F. Davis 8097cb6dcffSAndrew F. Davis static const struct i2c_device_id ina3221_ids[] = { 8107cb6dcffSAndrew F. Davis { "ina3221", 0 }, 8117cb6dcffSAndrew F. Davis { /* sentinel */ } 8127cb6dcffSAndrew F. Davis }; 8137cb6dcffSAndrew F. Davis MODULE_DEVICE_TABLE(i2c, ina3221_ids); 8147cb6dcffSAndrew F. Davis 8157cb6dcffSAndrew F. Davis static struct i2c_driver ina3221_i2c_driver = { 8167cb6dcffSAndrew F. Davis .probe = ina3221_probe, 81787625b24SNicolin Chen .remove = ina3221_remove, 8187cb6dcffSAndrew F. Davis .driver = { 8197cb6dcffSAndrew F. Davis .name = INA3221_DRIVER_NAME, 8207cb6dcffSAndrew F. Davis .of_match_table = ina3221_of_match_table, 82159d608e1SNicolin Chen .pm = &ina3221_pm, 8227cb6dcffSAndrew F. Davis }, 8237cb6dcffSAndrew F. Davis .id_table = ina3221_ids, 8247cb6dcffSAndrew F. Davis }; 8257cb6dcffSAndrew F. Davis module_i2c_driver(ina3221_i2c_driver); 8267cb6dcffSAndrew F. Davis 8277cb6dcffSAndrew F. Davis MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); 8287cb6dcffSAndrew F. Davis MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver"); 8297cb6dcffSAndrew F. Davis MODULE_LICENSE("GPL v2"); 830