mbox series

[v4,0/6] iio: light: stk3310: support powering off during suspend

Message ID 20241102195037.3013934-3-aren@peacevolution.org
Headers show
Series iio: light: stk3310: support powering off during suspend | expand

Message

Aren Nov. 2, 2024, 7:50 p.m. UTC
In the Pine64 PinePhone, the stk3310 chip is powered by a regulator that is
disabled at system boot and can be shut off during suspend. To ensure that
the chip properly initializes, both after boot and suspend, we need to
manage this regulator.

Additionally if the chip is shut off in suspend, we need to make sure that
it gets reinitialized with the same parameters after resume.

Major changes in v4:
 - replace mutex_init with devm_mutex_init
 - code style cleanup

Major changes in v3:
 - Use bulk regulators instead of two individual ones
 - Replace stk3310_remove with devm callbacks

Major changes in v2:
 - Add handling of the IR LED. I was hesitant to include this as it is the
   same as pull-up regulator for the i2c bus on the hardware I have, so I
   can't test it well. I think leaving it out is more likely to cause
   issues than including it.
 - Convert stk3310 to use dev_err_probe for errors.
 - Always enable / disable regulators and rely on dummy devices if they're
   not specified.
 - more listed in individual patches

Aren Moynihan (5):
  dt-bindings: iio: light: stk33xx: add vdd and leda regulators
  iio: light: stk3310: handle all remove logic with devm callbacks
  iio: light: stk3310: Implement vdd and leda supplies
  iio: light: stk3310: use dev_err_probe where possible
  iio: light: stk3310: log error if reading the chip id fails

Ondrej Jirman (1):
  arm64: dts: allwinner: pinephone: Add power supplies to stk3311

 .../bindings/iio/light/stk33xx.yaml           |   4 +
 .../dts/allwinner/sun50i-a64-pinephone.dtsi   |   2 +
 drivers/iio/light/stk3310.c                   | 162 ++++++++++++------
 3 files changed, 120 insertions(+), 48 deletions(-)

Comments

Jonathan Cameron Nov. 3, 2024, 11:22 a.m. UTC | #1
Hi Aren,

> @@ -624,7 +640,7 @@ static int stk3310_probe(struct i2c_client *client)
>  	device_property_read_u32(&client->dev, "proximity-near-level",
>  				 &data->ps_near_level);
>  
> -	mutex_init(&data->lock);
> +	devm_mutex_init(&client->dev, &data->lock);
ret = devm_mutex_init()
if (ret)
	return ret;

It is very unlikely to fail but technically it can.  Andy has been fixing
this up across the kernel (including IIO) so let's not introduce another
case that doesn't check it!

If nothing else comes up I can probably tidy that up whilst applying.

Jonathan

>  
>  	ret = stk3310_regmap_init(data);
>  	if (ret < 0)
> @@ -650,29 +666,17 @@ static int stk3310_probe(struct i2c_client *client)
>  		if (ret < 0) {
>  			dev_err(&client->dev, "request irq %d failed\n",
>  				client->irq);
> -			goto err_standby;
> +			return ret;
>  		}
>  	}
>  
> -	ret = iio_device_register(indio_dev);
> +	ret = devm_iio_device_register(&client->dev, indio_dev);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "device_register failed\n");
> -		goto err_standby;
> +		return ret;
>  	}
>  
>  	return 0;
> -
> -err_standby:
> -	stk3310_set_state(data, STK3310_STATE_STANDBY);
> -	return ret;
> -}
> -
> -static void stk3310_remove(struct i2c_client *client)
> -{
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -
> -	iio_device_unregister(indio_dev);
> -	stk3310_set_state(iio_priv(indio_dev), STK3310_STATE_STANDBY);
>  }
>  
>  static int stk3310_suspend(struct device *dev)
> @@ -736,7 +740,6 @@ static struct i2c_driver stk3310_driver = {
>  		.acpi_match_table = stk3310_acpi_id,
>  	},
>  	.probe =        stk3310_probe,
> -	.remove =           stk3310_remove,
>  	.id_table =         stk3310_i2c_id,
>  };
>
Jonathan Cameron Nov. 3, 2024, 11:31 a.m. UTC | #2
On Sat,  2 Nov 2024 15:50:39 -0400
Aren Moynihan <aren@peacevolution.org> wrote:

> The vdd and leda supplies must be powered on for the chip to function
> and can be powered off during system suspend.
> 
> This was originally based on a patch by Ondrej Jirman[1], but has been
> rewritten since.
> 
> 1: https://codeberg.org/megi/linux/commit/a933aff8b7a0e6e3c9cf1d832dcba07022bbfa82
> 
> Signed-off-by: Aren Moynihan <aren@peacevolution.org>
> ---
> 
> Notes:
>     Changes in v4:
>      - fix variable declaration order in stk3310_resume to match the rest of
>        the driver

For this Andy was asking for consistency.  Generally we don't insist on a
particular ordering in IIO drivers, but we do prefer them to be the same.
Your new ordering is inconsistent between resume and suspend.  Whilst
existing code may be inconsistent, you can still pick most common ordering
and use that for your new code.

If the existing driver is inconsistent then feel free to tidy that up but
do it in a precursor patch so there is a consistent style for you to then
carry on.

>     
>     Changes in v3:
>      - use bulk regulators instead of two individual ones
>      - handle cleanup using devm callbacks instead of the remove function
>     
>     Changes in v2:
>      - always enable / disable regulators and rely on a dummy regulator if
>        one isn't specified
>      - replace usleep_range with fsleep
>      - reorder includes so iio headers are last
>      - add missing error handling to resume
> 
>  drivers/iio/light/stk3310.c | 76 ++++++++++++++++++++++++++++++++++++-
>  1 file changed, 74 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
> index 181b7acb3f96..f93689c61f44 100644
> --- a/drivers/iio/light/stk3310.c
> +++ b/drivers/iio/light/stk3310.c
> @@ -13,6 +13,8 @@
>  #include <linux/module.h>
>  #include <linux/mod_devicetable.h>
>  #include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +
>  #include <linux/iio/events.h>
>  #include <linux/iio/iio.h>
>  #include <linux/iio/sysfs.h>
> @@ -130,6 +132,7 @@ struct stk3310_data {
>  	struct regmap_field *reg_int_ps;
>  	struct regmap_field *reg_flag_psint;
>  	struct regmap_field *reg_flag_nf;
> +	struct regulator_bulk_data supplies[2];
>  };
>  
>  static const struct iio_event_spec stk3310_events[] = {
> @@ -621,6 +624,31 @@ static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
>  	return IRQ_HANDLED;
>  }
>  
> +static int stk3310_regulators_enable(struct stk3310_data *data)
> +{
> +	int ret;
> +
> +	ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
> +	if (ret)
> +		return ret;
> +
> +	/* we need a short delay to allow the chip time to power on */
> +	fsleep(1000);
> +
> +	return 0;
> +}
> +
> +static void stk3310_regulators_disable(void *private)
> +{
> +	int ret;
> +	struct stk3310_data *data = private;
> +	struct device *dev = &data->client->dev;
> +
> +	ret = regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
> +	if (ret)
> +		dev_err(dev, "failed to disable regulators: %d\n", ret);
> +}
> +
>  static int stk3310_probe(struct i2c_client *client)
>  {
>  	int ret;
> @@ -642,6 +670,13 @@ static int stk3310_probe(struct i2c_client *client)
>  
>  	devm_mutex_init(&client->dev, &data->lock);
>  
> +	data->supplies[0].supply = "vdd";
> +	data->supplies[1].supply = "leda";
> +	ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(data->supplies),
> +				      data->supplies);
> +	if (ret)
> +		return dev_err_probe(&client->dev, ret, "get regulators failed\n");
> +
>  	ret = stk3310_regmap_init(data);
>  	if (ret < 0)
>  		return ret;
> @@ -652,6 +687,16 @@ static int stk3310_probe(struct i2c_client *client)
>  	indio_dev->channels = stk3310_channels;
>  	indio_dev->num_channels = ARRAY_SIZE(stk3310_channels);
>  
> +	ret = stk3310_regulators_enable(data);
> +	if (ret)
> +		return dev_err_probe(&client->dev, ret,
> +				     "regulator enable failed\n");
> +
> +	ret = devm_add_action_or_reset(&client->dev, stk3310_regulators_disable, data);
> +	if (ret)
> +		return dev_err_probe(&client->dev, ret,
> +				     "failed to register regulator cleanup\n");
> +
>  	ret = stk3310_init(indio_dev);
>  	if (ret < 0)
>  		return ret;
> @@ -682,18 +727,45 @@ static int stk3310_probe(struct i2c_client *client)
>  static int stk3310_suspend(struct device *dev)
>  {
>  	struct stk3310_data *data;
> +	int ret;
>  
>  	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
>  
> -	return stk3310_set_state(data, STK3310_STATE_STANDBY);
> +	ret = stk3310_set_state(data, STK3310_STATE_STANDBY);
> +	if (ret)
> +		return ret;
> +
> +	regcache_mark_dirty(data->regmap);
> +
> +	ret = regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
> +	if (ret) {
> +		dev_err(dev, "failed to disable regulators: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
>  }
>  
>  static int stk3310_resume(struct device *dev)
>  {
> -	u8 state = 0;
> +	int ret;
>  	struct stk3310_data *data;
> +	u8 state = 0;
>  
>  	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
> +
> +	ret = stk3310_regulators_enable(data);
> +	if (ret) {
> +		dev_err(dev, "Failed to re-enable regulators: %d", ret);
> +		return ret;
> +	}
> +
> +	ret = regcache_sync(data->regmap);
> +	if (ret) {
> +		dev_err(dev, "Failed to restore registers: %d\n", ret);
> +		return ret;
> +	}
> +
>  	if (data->ps_enabled)
>  		state |= STK3310_STATE_EN_PS;
>  	if (data->als_enabled)
Aren Nov. 3, 2024, 4:11 p.m. UTC | #3
On Sun, Nov 03, 2024 at 11:31:03AM +0000, Jonathan Cameron wrote:
> On Sat,  2 Nov 2024 15:50:39 -0400
> Aren Moynihan <aren@peacevolution.org> wrote:
> 
> > The vdd and leda supplies must be powered on for the chip to function
> > and can be powered off during system suspend.
> > 
> > This was originally based on a patch by Ondrej Jirman[1], but has been
> > rewritten since.
> > 
> > 1: https://codeberg.org/megi/linux/commit/a933aff8b7a0e6e3c9cf1d832dcba07022bbfa82
> > 
> > Signed-off-by: Aren Moynihan <aren@peacevolution.org>
> > ---
> > 
> > Notes:
> >     Changes in v4:
> >      - fix variable declaration order in stk3310_resume to match the rest of
> >        the driver
> 
> For this Andy was asking for consistency.  Generally we don't insist on a
> particular ordering in IIO drivers, but we do prefer them to be the same.
> Your new ordering is inconsistent between resume and suspend.  Whilst
> existing code may be inconsistent, you can still pick most common ordering
> and use that for your new code.
> 
> If the existing driver is inconsistent then feel free to tidy that up but
> do it in a precursor patch so there is a consistent style for you to then
> carry on.

Oh right, the order of declarations in stk3310_suspend also needs to be
flipped. Is that simple enough that you can fix it when applying this?

Apparently I was being dense, I checked the rest of the driver to see
what it did (it's consistent about putting shorter lines & ones without
an assignment first), and fixed the case Andy pointed out to match that,
but failed to check the rest of the patch.

Thanks
 - Aren
Aren Nov. 3, 2024, 4:23 p.m. UTC | #4
On Sun, Nov 03, 2024 at 11:22:08AM +0000, Jonathan Cameron wrote:
> Hi Aren,
> 
> > @@ -624,7 +640,7 @@ static int stk3310_probe(struct i2c_client *client)
> >  	device_property_read_u32(&client->dev, "proximity-near-level",
> >  				 &data->ps_near_level);
> >  
> > -	mutex_init(&data->lock);
> > +	devm_mutex_init(&client->dev, &data->lock);
> ret = devm_mutex_init()
> if (ret)
> 	return ret;
> 
> It is very unlikely to fail but technically it can.  Andy has been fixing
> this up across the kernel (including IIO) so let's not introduce another
> case that doesn't check it!

Right, I'll take this as my periodic reminder to read the docs / types
more carefully :)

> If nothing else comes up I can probably tidy that up whilst applying.

That would be great

Thanks
 - Aren
Andy Shevchenko Nov. 4, 2024, 8:32 a.m. UTC | #5
On Sat, Nov 02, 2024 at 03:50:37PM -0400, Aren Moynihan wrote:
> Using devm callbacks helps to make the ordering of probe / remove
> operations easier to reason about and removes some duplicate code
> between the probe error path and driver remove.

Where is SoB?

...

> +	ret = devm_add_action_or_reset(&client->dev, stk3310_set_state_disable, data);

Why not simply 'dev' as in below call?

> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to register cleanup function\n");

...

> -	mutex_init(&data->lock);
> +	devm_mutex_init(&client->dev, &data->lock);

Missed error check, otherwise what's the point?


Also can add a temporary variable for 'dev'.
Andy Shevchenko Nov. 4, 2024, 8:35 a.m. UTC | #6
On Sat, Nov 02, 2024 at 03:50:39PM -0400, Aren Moynihan wrote:
> The vdd and leda supplies must be powered on for the chip to function
> and can be powered off during system suspend.
> 
> This was originally based on a patch by Ondrej Jirman[1], but has been
> rewritten since.
> 
> 1: https://codeberg.org/megi/linux/commit/a933aff8b7a0e6e3c9cf1d832dcba07022bbfa82

Make it a Link tag...

> 

...here

Link: https://codeberg.org/megi/linux/commit/a933aff8b7a0e6e3c9cf1d832dcba07022bbfa82 [1]
> Signed-off-by: Aren Moynihan <aren@peacevolution.org>

...

> +	ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(data->supplies),
> +				      data->supplies);
> +	if (ret)
> +		return dev_err_probe(&client->dev, ret, "get regulators failed\n");

With previously introduced temporary 'dev' variable these become:

	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), data->supplies);
	if (ret)
		return dev_err_probe(dev, ret, "get regulators failed\n");

...

> +	ret = stk3310_regulators_enable(data);
> +	if (ret)
> +		return dev_err_probe(&client->dev, ret,
> +				     "regulator enable failed\n");
> +
> +	ret = devm_add_action_or_reset(&client->dev, stk3310_regulators_disable, data);
> +	if (ret)
> +		return dev_err_probe(&client->dev, ret,
> +				     "failed to register regulator cleanup\n");

So do these...

...

> +	ret = regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);

Is array_size.h included?

> +	if (ret) {
> +		dev_err(dev, "failed to disable regulators: %d\n", ret);
> +		return ret;
> +	}

...

> -	u8 state = 0;
> +	int ret;
>  	struct stk3310_data *data;
> +	u8 state = 0;

Can we try to make it RCT ordered?
Andy Shevchenko Nov. 4, 2024, 8:37 a.m. UTC | #7
On Sun, Nov 03, 2024 at 11:11:13AM -0500, Aren wrote:
> On Sun, Nov 03, 2024 at 11:31:03AM +0000, Jonathan Cameron wrote:
> > On Sat,  2 Nov 2024 15:50:39 -0400
> > Aren Moynihan <aren@peacevolution.org> wrote:

...

> > For this Andy was asking for consistency.  Generally we don't insist on a
> > particular ordering in IIO drivers, but we do prefer them to be the same.
> > Your new ordering is inconsistent between resume and suspend.  Whilst
> > existing code may be inconsistent, you can still pick most common ordering
> > and use that for your new code.
> > 
> > If the existing driver is inconsistent then feel free to tidy that up but
> > do it in a precursor patch so there is a consistent style for you to then
> > carry on.
> 
> Oh right, the order of declarations in stk3310_suspend also needs to be
> flipped. Is that simple enough that you can fix it when applying this?
> 
> Apparently I was being dense, I checked the rest of the driver to see
> what it did (it's consistent about putting shorter lines & ones without
> an assignment first), and fixed the case Andy pointed out to match that,
> but failed to check the rest of the patch.

Thanks!

You may ignore my comment about RCT order if it's not that one that being
commonly used in the driver.
Andy Shevchenko Nov. 4, 2024, 8:40 a.m. UTC | #8
On Sat, Nov 02, 2024 at 03:50:41PM -0400, Aren Moynihan wrote:
> Using dev_err_probe instead of dev_err and return makes the errors
> easier to understand by including the error name, and saves a little
> code.

...

>  #define STK3310_REGFIELD(name)						    \
>  	do {								    \
>  		data->reg_##name =					    \
> -			devm_regmap_field_alloc(&client->dev, regmap,	    \
> +			devm_regmap_field_alloc(dev, regmap,		    \
>  				stk3310_reg_field_##name);		    \
> -		if (IS_ERR(data->reg_##name)) {				    \
> -			dev_err(&client->dev, "reg field alloc failed.\n"); \
> -			return PTR_ERR(data->reg_##name);		    \
> -		}							    \
> +		if (IS_ERR(data->reg_##name))				    \

> +			return dev_err_probe(dev,			    \
> +				PTR_ERR(data->reg_##name),		    \

AFAICS these two can be put on one.

> +				"reg field alloc failed.\n");		    \
>  	} while (0)


...

> @@ -654,12 +652,11 @@ static int stk3310_probe(struct i2c_client *client)
>  	int ret;
>  	struct iio_dev *indio_dev;
>  	struct stk3310_data *data;
> +	struct device *dev = &client->dev;

This should has been done a few patches earlier...
Andy Shevchenko Nov. 4, 2024, 8:41 a.m. UTC | #9
On Sat, Nov 02, 2024 at 03:50:43PM -0400, Aren Moynihan wrote:
> If the chip isn't powered, this call is likely to return an error.
> Without a log here the driver will silently fail to probe. Potential
> errors include ENXIO (when the chip isn't powered) and ETIMEDOUT (when
> the i2c bus isn't powered).
> 
> This function is only called from stk3310_probe, and this condition
> should return an error, which fits what dev_err_probe is designed for.

...

> +		return dev_err_probe(dev, ret, "failed to read chip id\n");

Please, make sure you have consistent style in the messages. Most of what
I have seen use period at the end. This one doesn't.