Skip to content

Commit

Permalink
hwmon: (ina3221) Add suspend and resume functions
Browse files Browse the repository at this point in the history
Depending on the hardware design, an INA3221 chip might lose
its power during system suspend/resume. So this patch adds
a set of suspend and resume functions to cache the register
values including config register value and limit settings.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
[groeck: Moved call to dev_set_drvdata()]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
  • Loading branch information
Nicolin Chen authored and Guenter Roeck committed Oct 11, 2018
1 parent 791ebc9 commit 59d608e
Showing 1 changed file with 63 additions and 0 deletions.
63 changes: 63 additions & 0 deletions drivers/hwmon/ina3221.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
#define INA3221_WARN3 0x0c
#define INA3221_MASK_ENABLE 0x0f

#define INA3221_CONFIG_MODE_MASK GENMASK(2, 0)
#define INA3221_CONFIG_MODE_POWERDOWN 0
#define INA3221_CONFIG_MODE_SHUNT BIT(0)
#define INA3221_CONFIG_MODE_BUS BIT(1)
#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2)
Expand Down Expand Up @@ -91,11 +93,13 @@ static const unsigned int register_channel[] = {
* @regmap: Register map of the device
* @fields: Register fields of the device
* @shunt_resistors: Array of resistor values per channel
* @reg_config: Register value of INA3221_CONFIG
*/
struct ina3221_data {
struct regmap *regmap;
struct regmap_field *fields[F_MAX_FIELDS];
int shunt_resistors[INA3221_NUM_CHANNELS];
u32 reg_config;
};

static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
Expand Down Expand Up @@ -407,6 +411,8 @@ static int ina3221_probe(struct i2c_client *client,
return ret;
}

dev_set_drvdata(dev, ina);

hwmon_dev = devm_hwmon_device_register_with_groups(dev,
client->name,
ina, ina3221_groups);
Expand All @@ -418,6 +424,62 @@ static int ina3221_probe(struct i2c_client *client,
return 0;
}

#ifdef CONFIG_PM
static int ina3221_suspend(struct device *dev)
{
struct ina3221_data *ina = dev_get_drvdata(dev);
int ret;

/* 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;

regcache_cache_only(ina->regmap, true);
regcache_mark_dirty(ina->regmap);

return 0;
}

static int ina3221_resume(struct device *dev)
{
struct ina3221_data *ina = dev_get_drvdata(dev);
int ret;

regcache_cache_only(ina->regmap, false);

/* Software reset the chip */
ret = regmap_field_write(ina->fields[F_RST], true);
if (ret) {
dev_err(dev, "Unable to reset device\n");
return ret;
}

/* Restore cached register values to hardware */
ret = regcache_sync(ina->regmap);
if (ret)
return ret;

/* Restore config register value to hardware */
ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config);
if (ret)
return ret;

return 0;
}
#endif

static const struct dev_pm_ops ina3221_pm = {
SET_SYSTEM_SLEEP_PM_OPS(ina3221_suspend, ina3221_resume)
};

static const struct of_device_id ina3221_of_match_table[] = {
{ .compatible = "ti,ina3221", },
{ /* sentinel */ }
Expand All @@ -435,6 +497,7 @@ static struct i2c_driver ina3221_i2c_driver = {
.driver = {
.name = INA3221_DRIVER_NAME,
.of_match_table = ina3221_of_match_table,
.pm = &ina3221_pm,
},
.id_table = ina3221_ids,
};
Expand Down

0 comments on commit 59d608e

Please sign in to comment.