Re: [PATCH 2/3] iio: light: vcnl4000: Add enable attributes for vcnl4040

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Sep 22, 2022 at 04:10:54PM +0200, Paul Cercueil wrote:
> 
> 
> Le jeu., sept. 22 2022 at 15:04:47 +0200, Marten Lindahl 
> <martenli@xxxxxxxx> a écrit :
> > On Wed, Sep 21, 2022 at 12:01:24AM +0200, Paul Cercueil wrote:
> >>  Hi Mårten,
> >> 
> >>  Le mar., sept. 20 2022 at 20:09:57 +0200, Mårten Lindahl
> >>  <marten.lindahl@xxxxxxxx> a écrit :
> >>  > Add channel attribute in_illuminance_en and in_proximity_en with
> >>  > read/write access for vcnl4040. If automatic runtime power 
> >> management
> >>  > is
> >>  > turned off (power/control = on), both sensors can be kept on or 
> >> off by
> >>  > userspace.
> >> 
> > 
> > Hi Paul!
> > 
> >>  I don't really understand this. If automatic runtime power 
> >> management
> >>  is turned OFF, I would expect both sensors to be kept ON always.
> >> 
> >>  It's not userspace's job to do power management of the chip. Why are
> >>  these channel attributes needed?
> > 
> > I think I understand the problem here. I added the *_en attributes
> > because I couldn't see any way to turn the sensors on without forcing 
> > it
> > on during the *_raw read operation (with 
> > vcnl4000_set_pm_runtime_state(true))
> > after which it is turned off again (false).
> 
> What's wrong with doing that?

Hi!

No, nothing is wrong with that. I was just confused by the fact that
power/control=on didn't have any effect on the device. 

> 
> > Even if the power/control is set to 'on', there will be no callback 
> > for
> > changing the state to active.
> > 
> > It seems this does not work in this driver (with or without my 
> > patches) and I
> > was confused by how it was supposed to work. But after some digging I 
> > suspect
> > there could be a bug in the driver since the sysfs control/* nodes 
> > seems to
> > operate on the indio_dev->dev and not on the driver dev, which is 
> > used for
> > the vcnl4000 driver pm_runtime operations.
> 
> I believe this is normal. The devm_iio_device_alloc() creates a new 
> device, whose parent is your i2c_client->dev.

Ok
> 
> > Setting the power/control to 'on' invokes the rpm_resume function 
> > which
> > checks the dev.power.disable_depth attribute before it calls the
> > resume_callback for setting the active state on the driver. But if the
> > dev.power.disable_depth == 1 (which is the init value) the callback 
> > will not
> > be called. And nothing happens. And I suspect the reason why the
> > dev.power.disable_depth is 1 may be that it is not the vcnl4000 dev
> > object that is being checked, but the indio_dev->dev object, which 
> > has not
> > been configured for pm_runtime operations in the driver.
> > 
> > Sorry for a long reply to your question, but I suspect that if the
> > automatic pm_runtime for this driver can be disabled by the sysfs
> > power/control, the *_en attributes wont be needed.
> > 
> > I will look into why it does not work.
> 
> I still don't understand. Why do you *need* to disable runtime PM?

There is no special reason to disable runtime PM for the usecases we
have. The original reason behind this patch is a local patch from the
4.19 kernel when runtime PM did not exist in the driver. The local
patch added *_en attributes for turning the sensors on/off.

I will gladly skip this patch, since it has come clear to me that it
doesn't bring any value to the current version of the driver. I will
probably look at a fix for the power/control=on problem, but any fix
for that will be a separate patch.

Kind regards
Mårten

> 
> -Paul
> 
> > Kind regards
> > Mårten
> > 
> >> 
> >>  Cheers,
> >>  -Paul
> >> 
> >>  > Signed-off-by: Mårten Lindahl <marten.lindahl@xxxxxxxx>
> >>  > ---
> >>  >  drivers/iio/light/vcnl4000.c | 79
> >>  > ++++++++++++++++++++++++++++++++----
> >>  >  1 file changed, 72 insertions(+), 7 deletions(-)
> >>  >
> >>  > diff --git a/drivers/iio/light/vcnl4000.c
> >>  > b/drivers/iio/light/vcnl4000.c
> >>  > index 0b226c684957..9838f0868372 100644
> >>  > --- a/drivers/iio/light/vcnl4000.c
> >>  > +++ b/drivers/iio/light/vcnl4000.c
> >>  > @@ -125,6 +125,9 @@ struct vcnl4000_data {
> >>  >  	enum vcnl4000_device_ids id;
> >>  >  	int rev;
> >>  >  	int al_scale;
> >>  > +	bool als_enable;
> >>  > +	bool ps_enable;
> >>  > +
> >>  >  	const struct vcnl4000_chip_spec *chip_spec;
> >>  >  	struct mutex vcnl4000_lock;
> >>  >  	struct vcnl4200_channel vcnl4200_al;
> >>  > @@ -202,10 +205,13 @@ static ssize_t 
> >> vcnl4000_write_als_enable(struct
> >>  > vcnl4000_data *data, int val)
> >>  >  		if (ret < 0)
> >>  >  			return ret;
> >>  >
> >>  > -		if (val)
> >>  > +		if (val) {
> >>  >  			ret &= ~VCNL4040_ALS_CONF_ALS_SD;
> >>  > -		else
> >>  > +			data->als_enable = true;
> >>  > +		} else {
> >>  >  			ret |= VCNL4040_ALS_CONF_ALS_SD;
> >>  > +			data->als_enable = false;
> >>  > +		}
> >>  >
> >>  >  		return i2c_smbus_write_word_data(data->client, 
> >> VCNL4200_AL_CONF,
> >>  >  						 ret);
> >>  > @@ -225,10 +231,13 @@ static ssize_t 
> >> vcnl4000_write_ps_enable(struct
> >>  > vcnl4000_data *data, int val)
> >>  >  		if (ret < 0)
> >>  >  			return ret;
> >>  >
> >>  > -		if (val)
> >>  > +		if (val) {
> >>  >  			ret &= ~VCNL4040_PS_CONF1_PS_SD;
> >>  > -		else
> >>  > +			data->ps_enable = true;
> >>  > +		} else {
> >>  >  			ret |= VCNL4040_PS_CONF1_PS_SD;
> >>  > +			data->ps_enable = false;
> >>  > +		}
> >>  >
> >>  >  		return i2c_smbus_write_word_data(data->client,
> >>  >  						 VCNL4200_PS_CONF1, ret);
> >>  > @@ -283,6 +292,8 @@ static int vcnl4200_init(struct vcnl4000_data
> >>  > *data)
> >>  >  	dev_dbg(&data->client->dev, "device id 0x%x", id);
> >>  >
> >>  >  	data->rev = (ret >> 8) & 0xf;
> >>  > +	data->als_enable = false;
> >>  > +	data->ps_enable = false;
> >>  >
> >>  >  	data->vcnl4200_al.reg = VCNL4200_AL_DATA;
> >>  >  	data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
> >>  > @@ -459,8 +470,12 @@ static bool 
> >> vcnl4010_is_in_periodic_mode(struct
> >>  > vcnl4000_data *data)
> >>  >  static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data 
> >> *data,
> >>  > bool on)
> >>  >  {
> >>  >  	struct device *dev = &data->client->dev;
> >>  > +	struct iio_dev *indio_dev = i2c_get_clientdata(data->client);
> >>  >  	int ret;
> >>  >
> >>  > +	if (!indio_dev->dev.power.runtime_auto)
> >>  > +		return 0;
> >>  > +
> >>  >  	if (on) {
> >>  >  		ret = pm_runtime_resume_and_get(dev);
> >>  >  	} else {
> >>  > @@ -507,6 +522,38 @@ static int vcnl4000_read_raw(struct iio_dev
> >>  > *indio_dev,
> >>  >  		*val = 0;
> >>  >  		*val2 = data->al_scale;
> >>  >  		return IIO_VAL_INT_PLUS_MICRO;
> >>  > +	case IIO_CHAN_INFO_ENABLE:
> >>  > +		switch (chan->type) {
> >>  > +		case IIO_LIGHT:
> >>  > +			*val = data->als_enable;
> >>  > +			return IIO_VAL_INT;
> >>  > +		case IIO_PROXIMITY:
> >>  > +			*val = data->ps_enable;
> >>  > +			return IIO_VAL_INT;
> >>  > +		default:
> >>  > +			return -EINVAL;
> >>  > +		}
> >>  > +	default:
> >>  > +		return -EINVAL;
> >>  > +	}
> >>  > +}
> >>  > +
> >>  > +static int vcnl4040_write_raw(struct iio_dev *indio_dev,
> >>  > +				struct iio_chan_spec const *chan,
> >>  > +				int val, int val2, long mask)
> >>  > +{
> >>  > +	struct vcnl4000_data *data = iio_priv(indio_dev);
> >>  > +
> >>  > +	switch (mask) {
> >>  > +	case IIO_CHAN_INFO_ENABLE:
> >>  > +		switch (chan->type) {
> >>  > +		case IIO_LIGHT:
> >>  > +			return vcnl4000_write_als_enable(data, val);
> >>  > +		case IIO_PROXIMITY:
> >>  > +			return vcnl4000_write_ps_enable(data, val);
> >>  > +		default:
> >>  > +			return -EINVAL;
> >>  > +		}
> >>  >  	default:
> >>  >  		return -EINVAL;
> >>  >  	}
> >>  > @@ -845,6 +892,19 @@ static const struct iio_chan_spec
> >>  > vcnl4010_channels[] = {
> >>  >  	IIO_CHAN_SOFT_TIMESTAMP(1),
> >>  >  };
> >>  >
> >>  > +static const struct iio_chan_spec vcnl4040_channels[] = {
> >>  > +	{
> >>  > +		.type = IIO_LIGHT,
> >>  > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> >>  > +			BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_ENABLE),
> >>  > +	}, {
> >>  > +		.type = IIO_PROXIMITY,
> >>  > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> >>  > +			BIT(IIO_CHAN_INFO_ENABLE),
> >>  > +		.ext_info = vcnl4000_ext_info,
> >>  > +	}
> >>  > +};
> >>  > +
> >>  >  static const struct iio_info vcnl4000_info = {
> >>  >  	.read_raw = vcnl4000_read_raw,
> >>  >  };
> >>  > @@ -859,6 +919,11 @@ static const struct iio_info vcnl4010_info = 
> >> {
> >>  >  	.write_event_config = vcnl4010_write_event_config,
> >>  >  };
> >>  >
> >>  > +static const struct iio_info vcnl4040_info = {
> >>  > +	.read_raw = vcnl4000_read_raw,
> >>  > +	.write_raw = vcnl4040_write_raw,
> >>  > +};
> >>  > +
> >>  >  static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] 
> >> = {
> >>  >  	[VCNL4000] = {
> >>  >  		.prod = "VCNL4000",
> >>  > @@ -888,9 +953,9 @@ static const struct vcnl4000_chip_spec
> >>  > vcnl4000_chip_spec_cfg[] = {
> >>  >  		.measure_light = vcnl4200_measure_light,
> >>  >  		.measure_proximity = vcnl4200_measure_proximity,
> >>  >  		.set_power_state = vcnl4200_set_power_state,
> >>  > -		.channels = vcnl4000_channels,
> >>  > -		.num_channels = ARRAY_SIZE(vcnl4000_channels),
> >>  > -		.info = &vcnl4000_info,
> >>  > +		.channels = vcnl4040_channels,
> >>  > +		.num_channels = ARRAY_SIZE(vcnl4040_channels),
> >>  > +		.info = &vcnl4040_info,
> >>  >  		.irq_support = false,
> >>  >  	},
> >>  >  	[VCNL4200] = {
> >>  > --
> >>  > 2.30.2
> >>  >
> >> 
> >> 
> 
> 



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux