Add suspend and resume functions
v2 cover Add suspend and resume functions
This series of patches add system suspend and resume functiosn for ina3221 hwmon driver. To do so, it also needs two small fixes.
Changelogv1->v2:
* Added PATCH-2 to fix macros
* Added power-down setting during suspend in PATCH-3
Nicolin Chen (3):
hwmon: ina3221: Add INA3221_CONFIG to volatile_table
hwmon: ina3221: Fix INA3221_CONFIG_MODE macros
hwmon: ina3221: Add suspend and resume functions
drivers/hwmon/ina3221.c | 71 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-)
Signature · 1 line
2.17.1
PATCH v2 1/3 hwmon: ina3221: Add INA3221_CONFIG to volatile_table
The MSB (15th bit) of INA3221_CONFIG is a self-clear reset bit. So this register should be added to the volatile_table of the regmap_config. Otherwise, we will see this bit is sticky in the regcache which might accidentally reset the chip when an actual write happens to the register.
This might not be a severe bug for the current code line since there's no second place touching the INA3221_CONFIG except the reset routine in the probe().
--- drivers/hwmon/ina3221.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/ina3221.c +1 -1
@@ -353,7 +353,7 @@ static struct attribute *ina3221_attrs[] = {ATTRIBUTE_GROUPS (ina3221);static const struct regmap_range ina3221_yes_ranges[] = { -regmap_reg_range (INA3221_SHUNT1 ,INA3221_BUS3 ), +regmap_reg_range (INA3221_CONFIG ,INA3221_BUS3 ),regmap_reg_range (INA3221_MASK_ENABLE ,INA3221_MASK_ENABLE ), };
Signature · 1 line
2.17.1
Re: [PATCH v2 1/3] hwmon: ina3221: Add INA3221_CONFIG to volatile_table
Quoted 11 lines · Nicolin Chen
The MSB (15th bit) of
INA3221_CONFIGis a self-clear reset bit. So this register should be added to thevolatile_tableof theregmap_config. Otherwise, we will see this bit is sticky in the regcache which might accidentally reset the chip when an actual write happens to the register.This might not be a severe bug for the current code line since there's no second place touching the
INA3221_CONFIGexcept the reset routine in theprobe().Signed-off-by Nicolin Chen <[email protected]>
Applied to hwmon-next.
Thanks,
Guenter
Quoted 17 lines
--- drivers/hwmon/ina3221.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/hwmon/ina3221.c +1
-1@@ -353,7 +353,7 @@ static struct attribute *ina3221_attrs[] = {ATTRIBUTE_GROUPS (ina3221);static const struct regmap_range ina3221_yes_ranges[] = { -regmap_reg_range (INA3221_SHUNT1 ,INA3221_BUS3 ), +regmap_reg_range (INA3221_CONFIG ,INA3221_BUS3 ),regmap_reg_range (INA3221_MASK_ENABLE ,INA3221_MASK_ENABLE ), };
PATCH v2 2/3 hwmon: ina3221: Fix INA3221_CONFIG_MODE macros
In reply to Nicolin ChenThe three INA3221_CONFIG_MODE macros are not correctly defined here. The MODE3-1 filed is loacted at BIT 2-0 according to the datasheet.
So this patch just fixes them by shifting all of them with a correct offset. However, this isn't a crital bug fix as the driver does not use any of them at this point.
--- drivers/hwmon/ina3221.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/hwmon/ina3221.c +3 -3
@@ -38,9 +38,9 @@#define INA3221_WARN3 0x0c#define INA3221_MASK_ENABLE 0x0f -#define INA3221_CONFIG_MODE_SHUNT BIT(1) -#define INA3221_CONFIG_MODE_BUS BIT(2) -#define INA3221_CONFIG_MODE_CONTINUOUS BIT(3) +#define INA3221_CONFIG_MODE_SHUNT BIT(0) +#define INA3221_CONFIG_MODE_BUS BIT(1) +#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2)#define INA3221_RSHUNT_DEFAULT 10000
Signature · 1 line
2.17.1
Guenter Roeck
maintainerRe: [PATCH v2 2/3] hwmon: ina3221: Fix INA3221_CONFIG_MODE macros
Quoted 3 lines · Nicolin Chen
The three
INA3221_CONFIG_MODEmacros are not correctly defined here. The MODE3-1 filed is loacted at BIT 2-0 according to the datasheet.
located
Quoted 5 lines
So this patch just fixes them by shifting all of them with a correct offset. However, this isn't a crital bug fix as the driver does not use any of them at this point.
Signed-off-by Nicolin Chen <[email protected]>
No need to resend; I fixed it up. Applied to hwmon-next.
Thanks,
Guenter
Quoted 21 lines
--- drivers/hwmon/ina3221.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)drivers/hwmon/ina3221.c +3
-3@@ -38,9 +38,9 @@#define INA3221_WARN3 0x0c#define INA3221_MASK_ENABLE 0x0f -#define INA3221_CONFIG_MODE_SHUNT BIT(1) -#define INA3221_CONFIG_MODE_BUS BIT(2) -#define INA3221_CONFIG_MODE_CONTINUOUS BIT(3) +#define INA3221_CONFIG_MODE_SHUNT BIT(0) +#define INA3221_CONFIG_MODE_BUS BIT(1) +#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2)#define INA3221_RSHUNT_DEFAULT 10000
PATCH v2 3/3 hwmon: ina3221: Add suspend and resume functions
In reply to Nicolin ChenDepending 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.
---
Changelogv1->v2:
* Added power-down setting during suspend for power saving
drivers/hwmon/ina3221.c | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+)
drivers/hwmon/ina3221.c +63 -0
@@ -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)
@@ -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,
@@ -415,9 +419,67 @@ static int ina3221_probe(struct i2c_client *client,return PTR_ERR (hwmon_dev); } +dev_set_drvdata (dev, ina); +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 */ }
@@ -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, };
Signature · 1 line
2.17.1
Re: [PATCH v2 3/3] hwmon: ina3221: Add suspend and resume functions
Quoted 6 lines · Nicolin Chen
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 <[email protected]>
Applied to hwmon-next, with a minor change; see below.
Thanks,
Guenter
Quoted 36 lines
---
Changelogv1->v2:
* Added power-down setting during suspend for power savingdrivers/hwmon/ina3221.c | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+)drivers/hwmon/ina3221.c +4
-0@@ -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)@@ -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,
drivers/hwmon/ina3221.c static int ina3221_probe(struct i2c_client *client, · line 423
Quoted 5 lines
drivers/hwmon/ina3221.c +2
-0@@ -415,9 +419,67 @@ static int ina3221_probe(struct i2c_client *client,return PTR_ERR (hwmon_dev); } +dev_set_drvdata (dev, ina); +
It is better to call that function before registering the hwmon device, to avoid the theroretical possibility that suspend is called before drvdata is set. I moved the call accordingly.
Quoted 70 lines
drivers/hwmon/ina3221.c +57
-0return 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 */ }@@ -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, };
Re: [PATCH v2 3/3] hwmon: ina3221: Add suspend and resume functions
Quoted 11 lines · Guenter Roeck
drivers/hwmon/ina3221.c static int ina3221_probe(struct i2c_client *client, · line 423
Quoted 7 lines
static int ina3221_read_value(struct
ina3221_data*ina, unsigned int reg,drivers/hwmon/ina3221.c +2
-0@@ -415,9 +419,67 @@ static int ina3221_probe(struct i2c_client *client,return PTR_ERR (hwmon_dev); } +dev_set_drvdata (dev, ina); +It is better to call that function before registering the hwmon device, to avoid the theroretical possibility that suspend is called before drvdata is set. I moved the call accordingly.
Oh..I see. Another lesson learned. Thank you for the fix!