Re: [PATCH v2 6/7] iio: light: rpr0521 triggered buffer added

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

 



On 14.4.2017 18:21, Jonathan Cameron wrote:
> On 12/04/17 14:44, Koivunen, Mikko wrote:
>> On 8.4.2017 18:28, Jonathan Cameron wrote:
>>> On 07/04/17 13:07, Mikko Koivunen wrote:
>>>> Driver sets up and uses triggered buffer if there is irq defined for device in
>>>> device tree. Trigger producer triggers from rpr0521 drdy interrupt line.
>>>> Trigger consumer reads rpr0521 data to scan buffer.
>>>> Depends on previous commits of _scale and _offset.
>>>>
>>>> Signed-off-by: Mikko Koivunen <mikko.koivunen@xxxxxxxxxxxxxxxxx>
>>>> ---
>>> A few comments inline...
>>>
>>> Jonathan
>>>> Tested on LeMaker HiKey with AOSP7.1, IIO_HAL and kernel 4.4.
>>>> Builds OK with torvalds/linux 4.9
>>>> checkpatch.pl OK.
>>>>
>>>> Patch v1->v2 changes:
>>>> removed flagging of the new feature
>>>> removed unnecesssary rpr0521_update_scan_mode()
>>>> removed unnecessary comments.
>>>> added IIO_LE to channel spec
>>>>
>>>>  drivers/iio/light/rpr0521.c |  287 ++++++++++++++++++++++++++++++++++++++++++-
>>>>  1 file changed, 282 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
>>>> index dc522fd..72f608d 100644
>>>> --- a/drivers/iio/light/rpr0521.c
>>>> +++ b/drivers/iio/light/rpr0521.c
>>>> @@ -9,9 +9,10 @@
>>>>   *
>>>>   * IIO driver for RPR-0521RS (7-bit I2C slave address 0x38).
>>>>   *
>>>> - * TODO: illuminance channel, PM support, buffer
>>>> + * TODO: illuminance channel, PM support
>>>>   */
>>>>  
>>>> +
>>> Be careful to clear out stray whitespace changes like this one.
>>> Just add noise to the patch and may mean it takes longer to be accepted...
>> Ack. Need to double check next time.
>>
>>>>  #include <linux/module.h>
>>>>  #include <linux/init.h>
>>>>  #include <linux/i2c.h>
>>>> @@ -20,6 +21,10 @@
>>>>  #include <linux/acpi.h>
>>>>  
>>>>  #include <linux/iio/iio.h>
>>>> +#include <linux/iio/buffer.h>
>>>> +#include <linux/iio/trigger.h>
>>>> +#include <linux/iio/trigger_consumer.h>
>>>> +#include <linux/iio/triggered_buffer.h>
>>>>  #include <linux/iio/sysfs.h>
>>>>  #include <linux/pm_runtime.h>
>>>>  
>>>> @@ -30,6 +35,7 @@
>>>>  #define RPR0521_REG_PXS_DATA		0x44 /* 16-bit, little endian */
>>>>  #define RPR0521_REG_ALS_DATA0		0x46 /* 16-bit, little endian */
>>>>  #define RPR0521_REG_ALS_DATA1		0x48 /* 16-bit, little endian */
>>>> +#define RPR0521_REG_INTERRUPT		0x4A
>>>>  #define RPR0521_PS_OFFSET_LSB		0x53
>>>>  #define RPR0521_PS_OFFSET_MSB		0x54
>>>>  
>>>> @@ -44,16 +50,33 @@
>>>>  #define RPR0521_ALS_DATA1_GAIN_SHIFT	2
>>>>  #define RPR0521_PXS_GAIN_MASK		GENMASK(5, 4)
>>>>  #define RPR0521_PXS_GAIN_SHIFT		4
>>>> +#define RPR0521_PXS_PERSISTENCE_MASK	GENMASK(3, 0)
>>>> +#define RPR0521_INTERRUPT_INT_TRIG_PS_MASK	BIT(0)
>>>> +#define RPR0521_INTERRUPT_INT_TRIG_ALS_MASK	BIT(1)
>>>> +#define RPR0521_INTERRUPT_INT_LATCH_MASK	BIT(2)
>>>> +#define RPR0521_INTERRUPT_INT_REASSERT_MASK	BIT(3)
>>>> +#define RPR0521_INTERRUPT_INT_MODE_MASK		GENMASK(5, 4)
>>>>  
>>>>  #define RPR0521_MODE_ALS_ENABLE		BIT(7)
>>>>  #define RPR0521_MODE_ALS_DISABLE	0x00
>>>>  #define RPR0521_MODE_PXS_ENABLE		BIT(6)
>>>>  #define RPR0521_MODE_PXS_DISABLE	0x00
>>>> +#define RPR0521_PXS_PERSISTENCE_DRDY	0x00
>>>> +#define RPR0521_INTERRUPT_INT_TRIG_PS_ENABLE	BIT(0)
>>>> +#define RPR0521_INTERRUPT_INT_TRIG_PS_DISABLE	0x00
>>>> +#define RPR0521_INTERRUPT_INT_TRIG_ALS_ENABLE	BIT(1)
>>>> +#define RPR0521_INTERRUPT_INT_TRIG_ALS_DISABLE	0x00
>>>> +#define RPR0521_INTERRUPT_INT_LATCH_DISABLE	BIT(2)
>>>> +#define RPR0521_INTERRUPT_INT_LATCH_ENABLE	0x00
>>>> +#define RPR0521_INTERRUPT_INT_REASSERT_ENABLE	BIT(3)
>>>> +#define RPR0521_INTERRUPT_INT_REASSERT_DISABLE	0x00
>>>> +#define RPR0521_INTERRUPT_INT_PS_OUTSIDE_DETECT	BIT(5)
>>>>  
>>>>  #define RPR0521_MANUFACT_ID		0xE0
>>>>  #define RPR0521_DEFAULT_MEAS_TIME	0x06 /* ALS - 100ms, PXS - 100ms */
>>>>  
>>>>  #define RPR0521_DRV_NAME		"RPR0521"
>>>> +#define RPR0521_IRQ_NAME		"rpr0521_event"
>>>>  #define RPR0521_REGMAP_NAME		"rpr0521_regmap"
>>>>  
>>>>  #define RPR0521_SLEEP_DELAY_MS	2000
>>>> @@ -169,6 +192,9 @@ struct rpr0521_data {
>>>>  	bool als_dev_en;
>>>>  	bool pxs_dev_en;
>>>>  
>>>> +	struct iio_trigger *drdy_trigger0;
>>>> +	bool drdy_trigger_on;
>>>> +
>>>>  	/* optimize runtime pm ops - enable device only if needed */
>>>>  	bool als_ps_need_en;
>>>>  	bool pxs_ps_need_en;
>>>> @@ -195,6 +221,13 @@ static const struct attribute_group rpr0521_attribute_group = {
>>>>  	.attrs = rpr0521_attributes,
>>>>  };
>>>>  
>>>> +/* Order of the channel data in buffer */
>>>> +enum rpr0521_scan_index_order {
>>>> +	RPR0521_CHAN_INDEX_PXS,
>>>> +	RPR0521_CHAN_INDEX_BOTH,
>>>> +	RPR0521_CHAN_INDEX_IR,
>>>> +};
>>>> +
>>>>  static const struct iio_chan_spec rpr0521_channels[] = {
>>>>  	{
>>>>  		.type = IIO_PROXIMITY,
>>>> @@ -203,6 +236,14 @@ static const struct iio_chan_spec rpr0521_channels[] = {
>>>>  			BIT(IIO_CHAN_INFO_OFFSET) |
>>>>  			BIT(IIO_CHAN_INFO_SCALE),
>>>>  		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
>>>> +		.scan_index = RPR0521_CHAN_INDEX_PXS,
>>>> +		.scan_type = {
>>>> +			.sign = 'u',
>>>> +			.realbits = 16,
>>>> +			.storagebits = 16,
>>>> +			.shift = 0,
>>>> +			.endianness = IIO_LE,
>>>> +		},
>>>>  	},
>>>>  	{
>>>>  		.type = IIO_INTENSITY,
>>>> @@ -212,6 +253,14 @@ static const struct iio_chan_spec rpr0521_channels[] = {
>>>>  		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
>>>>  			BIT(IIO_CHAN_INFO_SCALE),
>>>>  		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
>>>> +		.scan_index = RPR0521_CHAN_INDEX_BOTH,
>>>> +		.scan_type = {
>>>> +			.sign = 'u',
>>>> +			.realbits = 16,
>>>> +			.storagebits = 16,
>>>> +			.shift = 0,
>>>> +			.endianness = IIO_LE,
>>>> +		},
>>>>  	},
>>>>  	{
>>>>  		.type = IIO_INTENSITY,
>>>> @@ -221,9 +270,154 @@ static const struct iio_chan_spec rpr0521_channels[] = {
>>>>  		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
>>>>  			BIT(IIO_CHAN_INFO_SCALE),
>>>>  		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
>>>> +		.scan_index = RPR0521_CHAN_INDEX_IR,
>>>> +		.scan_type = {
>>>> +			.sign = 'u',
>>>> +			.realbits = 16,
>>>> +			.storagebits = 16,
>>>> +			.shift = 0,
>>> shift default makes sense as 0 so don't bother specifying it
>>> (will be set to 0 anyway)
>> Ack.
>>>> +			.endianness = IIO_LE,
>>>> +		},
>>>>  	},
>>>>  };
>>>>  
>>>> +static int rpr0521_set_power_state(struct rpr0521_data *data, bool on,
>>>> +				   u8 device_mask);
>>>> +static int rpr0521_als_enable(struct rpr0521_data *data, u8 status);
>>>> +static int rpr0521_pxs_enable(struct rpr0521_data *data, u8 status);
>>> These forward definitions rather look like they could be removed with a bit
>>> of reorganization fo the file.  Do that in preference to having these in
>>> the middle of the code.
>> Ok.
>>
>>>> +
>>>> +/* IRQ to trigger -handler */
>>> why the -?
>>>> +static irqreturn_t rpr0521_drdy_irq_handler(int irq, void *private)
>>>> +{
>>>> +	struct iio_dev *indio_dev = private;
>>>> +	struct rpr0521_data *data = iio_priv(indio_dev);
>>>> +
>>>> +	/* Notify trigger0 consumers/subscribers */
>>>> +	if (data->drdy_trigger_on)
>>>> +		iio_trigger_poll(data->drdy_trigger0);
>>> How else are you getting here? Also the core will be fine
>>> if nothing cares and the trigger is polled.
>>> If there is another cause, we aren't handling it so should claim
>>> to be doing so.
>> Sometimes there is static on line and interrupt is generated even though
>> sensor interrupt output is in high impedance mode. What I've seen it's
>> max 2 interrupts in second, usually none. This doesn't matter much for
>> stability if sensor is switched on. It just causes extra reads. But if
>> extra interrupt happens when sensor power is switched off it isn't there
>> to respond to i2c data reading.
>> I don't know enough to know if all systems can handle this gracefully or
>> not. That's why safe playing here.
>> I'm keeping it unless someone can confirm that 2Hz regmap_bulk_read in
>> trigger_consumer_handler will not be causing ill effects on system when
>> there is no answer from sensor.
> Perhaps add a comment to mention that an issue has been observed.
> Normally we don't put this sort of code in to protect against hardware
> bugs like this, but if you have a platform where it is true, then fine
> but it needs to be mentioned, so someone doesn't come along later
> and remove what looks like pointless code!

Ok.

>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static irqreturn_t rpr0521_trigger_consumer_handler(int irq, void *p)
>>>> +{
>>>> +	struct iio_poll_func *pf = p;
>>>> +	struct iio_dev *indio_dev = pf->indio_dev;
>>>> +	struct rpr0521_data *data = iio_priv(indio_dev);
>>>> +	int ret;
>>>> +
>>>> +	u8 buffer[16]; /* 3 16-bit channels + padding + ts */
>>>> +
>>>> +	ret = regmap_bulk_read(data->regmap,
>>>> +		RPR0521_REG_PXS_DATA,
>>>> +		&buffer,
>>>> +		(3*2)+1);	/* 3 * 16-bit + (discarded) int clear reg. */
>>> kernel style is spaces around the * and +
>> Ack.
>>>> +	if (ret < 0)
>>>> +		goto done;
>>>> +
>>>> +	iio_push_to_buffers_with_timestamp(indio_dev,
>>>> +		buffer,
>>> Dont wrap more than you have two.  So make this two lines perhaps.
>>>> +		pf->timestamp);
>>>> +done:
>> Refactoring to v3 to get rid of done:
>>>> +	iio_trigger_notify_done(indio_dev->trig);
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static int rpr0521_write_int_enable(struct rpr0521_data *data)
>>>> +{
>>>> +	int err;
>>>> +
>>>> +	/* Interrupt after each measurement */
>>>> +	err = regmap_update_bits(data->regmap, RPR0521_REG_PXS_CTRL,
>>>> +		RPR0521_PXS_PERSISTENCE_MASK,
>>>> +		RPR0521_PXS_PERSISTENCE_DRDY);
>>>> +	err = err || regmap_update_bits(data->regmap, RPR0521_REG_INTERRUPT,
>>> umm. really?  All of them? Are we looking at a clear the whole register
>>> case?  If so we should probably only clear relevant ones..
>> Hmm. .  Valid point. In drdy case we can write what ever to latch and
>> mode. This will be cleaner with write instead up write_bits.
>> ==> change to v3
>>> I don't like these stacked error handlers (err = err | *).
>>> Just handle each err as and when.  It's more code, but easier
>>> to review / follow.
>> It's (err = err || *), bail out on first error.
>> Matter of taste, ack.
>>
>>>> +		RPR0521_INTERRUPT_INT_REASSERT_MASK |
>>>> +		RPR0521_INTERRUPT_INT_LATCH_MASK |
>>>> +		RPR0521_INTERRUPT_INT_TRIG_ALS_MASK |
>>>> +		RPR0521_INTERRUPT_INT_TRIG_PS_MASK,
>>>> +		RPR0521_INTERRUPT_INT_REASSERT_DISABLE |
>>>> +		RPR0521_INTERRUPT_INT_LATCH_ENABLE |
>>>> +		RPR0521_INTERRUPT_INT_TRIG_ALS_DISABLE |
>>>> +		RPR0521_INTERRUPT_INT_TRIG_PS_ENABLE
>>>> +		);
>>>> +	err = err || regmap_update_bits(data->regmap, RPR0521_REG_INTERRUPT,
>>>> +		RPR0521_INTERRUPT_INT_MODE_MASK,
>>>> +		RPR0521_INTERRUPT_INT_PS_OUTSIDE_DETECT);
>>>> +	if (err) {
>>>> +		dev_err(&data->client->dev, "Interrupt setup write fail.\n");
>>>> +		return -EBUSY;
>>>> +		}
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rpr0521_write_int_disable(struct rpr0521_data *data)
>>>> +{
>>>> +	return regmap_update_bits(data->regmap, RPR0521_REG_INTERRUPT,
>>>> +				RPR0521_INTERRUPT_INT_TRIG_ALS_MASK |
>>>> +				RPR0521_INTERRUPT_INT_TRIG_PS_MASK,
>>>> +				RPR0521_INTERRUPT_INT_TRIG_ALS_DISABLE |
>>>> +				RPR0521_INTERRUPT_INT_TRIG_PS_DISABLE
>>>> +				);
>>>> +}
>>>> +
>>>> +/* Trigger -enable/disable */
>>>> +static int rpr0521_pxs_drdy_set_state(struct iio_trigger *trigger,
>>>> +	bool enable_drdy)
>>>> +{
>>> This may be called from the moment iio_trigger_register is called until
>>> the trigger is unregistered on remove.
>>>
>>> Could that potentially be a problem as it might occur after the device
>>> is powered off in remove?  Hard to be sure without diving into the data
>>> sheet.  If it if safe as it is, then use the devm functions as described
>>> below, but perhaps put a note here about the fact it is safe to have
>>> this potential race.
>> Sensor itself doesn't care much, but since measurement is enabled we are
>> draining power for nothing.
>> I didn't like to touch pm_ -stuff, since I didn't know much of it. But
>> now since I did, I think I found couple of bugs both in the current code
>> and new code.
>>
>> There is another thing for the order. Int pin keeps state on power down.
>> So shutting down sensor before clearing interrupt might cause power
>> drain also on interrupt line.
>>
>> ==>
>> Reordering the _probe() and _remove() for v3.
>> Adding int clear to poweroff.
>> Adding couple commits for pm bugfixes.
>>
>> One question though. Is it ok to register device first, and then
>> trigger/buffer stuff? For now it seems like correct order.
> No.  The moment the register occurs, it's exposed to userspace.
> The buffer at least is hidden until after that.

Ok, I already forgot this was  also said in:
http://lxr.free-electrons.com/source/drivers/iio/buffer/industrialio-triggered-buffer.c?v=4.4#L37
So, setup buffer first, then register device. And on remove, unregister
device first, then remove buffer.

> Trigger vs device is more a matter of convention. Tends to be easier to
> make sure the trigger register doesn't cause trouble if something tries
> to use it early than the whole device (the userspace surface is smaller).
>>>> +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trigger);
>>>> +	struct rpr0521_data *data = iio_priv(indio_dev);
>>>> +	int err;
>>>> +
>>>> +	if (enable_drdy) {
>>>> +		/* ENABLE DRDY */
>>>> +		mutex_lock(&data->lock);
>>>> +		err = rpr0521_set_power_state(data, true,
>>>> +			(RPR0521_MODE_PXS_MASK & RPR0521_MODE_ALS_MASK));
>>>> +		mutex_unlock(&data->lock);
>>>> +		if (err)
>>>> +			goto rpr0521_set_state_err;
>>>> +		err = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE);
>> Removing rpr0521_[pxs/als]_[en/dis]able(), since they are by default
>> enabled from rpr0521_init and _set_power_state sets them on if pm has
>> disabled them.
>>>> +		if (err)
>>>> +			goto rpr0521_set_state_err;
>>>> +		err = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
>>>> +		if (err)
>>>> +			goto rpr0521_set_state_err;
>>>> +		err = rpr0521_write_int_enable(data);
>>>> +		if (err)
>>>> +			goto rpr0521_set_state_err;
>>>> +	} else {
>>>> +		/* DISABLE DRDY */
>>>> +		mutex_lock(&data->lock);
>>>> +		err = rpr0521_set_power_state(data, false,
>>>> +			(RPR0521_MODE_PXS_MASK & RPR0521_MODE_ALS_MASK));
>>>> +		mutex_unlock(&data->lock);
>>>> +		if (err)
>>>> +			goto rpr0521_set_state_err;
>>>> +		err = rpr0521_als_enable(data, RPR0521_MODE_ALS_DISABLE);
>>>> +		if (err)
>>>> +			goto rpr0521_set_state_err;
>>>> +		err = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_DISABLE);
>>>> +		if (err)
>>>> +			goto rpr0521_set_state_err;
>>>> +		err = rpr0521_write_int_disable(data);
>>>> +		if (err)
>>>> +			goto rpr0521_set_state_err;
>>>> +	}
>>>> +	data->drdy_trigger_on = enable_drdy;
>>>> +	return 0;
>>>> +
>>>> +rpr0521_set_state_err:
>>>> +	dev_err(&data->client->dev, "rpr0521_pxs_drdy_set_state failed\n");
>>>> +	return err;
>>>> +}
>>>> +
>>>> +static const struct iio_trigger_ops rpr0521_trigger_ops = {
>>>> +	.set_trigger_state = rpr0521_pxs_drdy_set_state,
>>>> +	.owner = THIS_MODULE,
>>>> +	};
>>>> +
>>>>  static int rpr0521_als_enable(struct rpr0521_data *data, u8 status)
>>>>  {
>>>>  	int ret;
>>>> @@ -454,6 +648,9 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev,
>>>>  		if (chan->type != IIO_INTENSITY && chan->type != IIO_PROXIMITY)
>>>>  			return -EINVAL;
>>>>  
>>>> +		if (iio_buffer_enabled(indio_dev))
>>>> +			return -EBUSY;
>>>> +
>>>>  		device_mask = rpr0521_data_reg[chan->address].device_mask;
>>>>  
>>>>  		mutex_lock(&data->lock);
>>>> @@ -664,20 +861,90 @@ static int rpr0521_probe(struct i2c_client *client,
>>>>  		return ret;
>>>>  	}
>>>>  
>>>> -	ret = pm_runtime_set_active(&client->dev);
>>>> -	if (ret < 0)
>>>> -		return ret;
>>>> +	/* IRQ to trigger setup */
>>>> +	if (client->irq) {
>>>> +		/* Trigger0 producer setup */
>>>> +		data->drdy_trigger0 = devm_iio_trigger_alloc(
>>>> +			indio_dev->dev.parent,
>>>> +			"%s-dev%d",
>>>> +			indio_dev->name,
>>>> +			indio_dev->id);
>>>> +		if (!data->drdy_trigger0) {
>>>> +			ret = -ENOMEM;
>>>> +			return ret;
>>>> +		}
>>>> +		data->drdy_trigger0->dev.parent = indio_dev->dev.parent;
>>>> +		data->drdy_trigger0->ops = &rpr0521_trigger_ops;
>>>> +		iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev);
>>>> +
>>>> +		ret = iio_trigger_register(data->drdy_trigger0);
>>> devm_iio_trigger_register should be fine
>> See below.
>>>> +		if (ret) {
>>>> +			dev_err(&client->dev, "iio trigger register failed\n");
>>>> +			return ret;
>>>> +		}
>>>>  
>>>> +		/* Set trigger0 as default trigger (and inc refcount) */
>>>> +		indio_dev->trig = iio_trigger_get(data->drdy_trigger0);
>>>> +
>>>> +		/* Ties irq to trigger producer handler. */
>>>> +		ret = devm_request_threaded_irq(&client->dev, client->irq,
>>>> +			rpr0521_drdy_irq_handler,
>>>> +			NULL,
>>>> +			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
>>>> +			RPR0521_IRQ_NAME,
>>>> +			indio_dev);
>>>> +		if (ret < 0) {
>>>> +			dev_err(&client->dev, "request irq %d for trigger0 failed\n",
>>>> +				client->irq);
>>>> +			goto err_iio_trigger_put_unregister;
>>>> +			}
>>>> +		/*
>>>> +		 * Now whole pipe from physical interrupt (irq defined by
>>>> +		 * devicetree to device) to trigger0 output is set up.
>>>> +		 */
>>>> +
>>>> +		/* Trigger consumer setup */
>>>> +		ret = iio_triggered_buffer_setup(indio_dev,
>>>> +			&iio_pollfunc_store_time,
>>>> +			rpr0521_trigger_consumer_handler,
>>>> +			NULL);		//Use default _ops
>>>> +		if (ret < 0) {
>>>> +			dev_err(&client->dev, "iio triggered buffer setup failed\n");
>>>> +			/* Count on devm to free_irq */
>>>> +			goto err_iio_trigger_put_unregister;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	ret = pm_runtime_set_active(&client->dev);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&client->dev, "set_active failed\n");
>>> I'm not particularly bothered either way by the change, but technically
>>> adding this error message is unconnected to the subject of this patch so
>>> should not be here.
>>>
>>>> +		goto err_iio_unregister_trigger_consumer;
>>>> +		}
>>>>  	pm_runtime_enable(&client->dev);
>>>>  	pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
>>>>  	pm_runtime_use_autosuspend(&client->dev);
>>>>  
>>>>  	return iio_device_register(indio_dev);
>>>> +
>>> One line is enough.
>> Ok.
>>>> +
>>> Use devm versions and this lot goes away.
>>>> +err_iio_unregister_trigger_consumer:
>>>> +	iio_triggered_buffer_cleanup(indio_dev);
>>>> +err_iio_trigger_put_unregister:
>>>> +	if (indio_dev->trig) {
>>>> +		iio_trigger_put(indio_dev->trig);
>>>> +		indio_dev->trig = NULL;
>>>> +		}
>>>> +	if (data->drdy_trigger0) {
>>>> +		iio_trigger_unregister(data->drdy_trigger0);
>>>> +		data->drdy_trigger0 = NULL;
>>>> +		}
>>>> +	return ret;
>>>>  }
>>>>  
>>>>  static int rpr0521_remove(struct i2c_client *client)
>>>>  {
>>>>  	struct iio_dev *indio_dev = i2c_get_clientdata(client);
>>>> +	struct rpr0521_data *data = iio_priv(indio_dev);
>>>>  
>>>>  	iio_device_unregister(indio_dev);
>>>>  
>>>> @@ -685,8 +952,18 @@ static int rpr0521_remove(struct i2c_client *client)
>>>>  	pm_runtime_set_suspended(&client->dev);
>>>>  	pm_runtime_put_noidle(&client->dev);
>>>>  
>>>> -	rpr0521_poweroff(iio_priv(indio_dev));
>>>> +	rpr0521_poweroff(data);
>>>>  
>>>> +	iio_triggered_buffer_cleanup(indio_dev);
>>>> +	if (indio_dev->trig) {
>>>> +		iio_trigger_put(indio_dev->trig);
>>>> +		indio_dev->trig = NULL;
>>>> +		}
>>>> +	if (data->drdy_trigger0) {
>>>> +		iio_trigger_unregister(data->drdy_trigger0);
>>>> +		data->drdy_trigger0 = NULL;
>>>> +		}
>>>> +	/* Rest of the cleanup is done by devm. */
>>> Givem where you have them, I don't think anything stops you using devm to
>>> handle the trigger registration and buffer cleanup.  No need to set
>>> either of hte magic flags to NULL as far as I can see...
>> For a second let's think we removed this line
>>
>>>> +	if (data->drdy_trigger_on)
>> from irq_handler().
>> If irq handler is not yet unregistered by devm_ and thus interrupt can
>> be generated (f.ex. by static),
> This is one of the nasty reasons why we tend to not spend all that much
> effort dealing with false interrupts. It's almost always possible to find
> a race where they will crash things.
>> then what does
>> iio_trigger_poll(data->drdy_trigger0) do with this unregistered trigger
>> pointer? If call is ok, then no need for NULL I guess.
> Firstly there is always a race here if this is an issue, you are just
> making it smaller.   This is all going to occur very fast in any case.
>
> Still all irrelevant anyway ;)

Removing NULL's for v3.

>>> Use the devm versions and remove should be unchanged...
>> Copy-paste from another post:
>>
>> Can't, since no devm_ on kernel 4.4.
>> I could make another commit to change to devm_, but I don't have target
>> to test it.
>>
>>> OK. We can leave it for someone else to clean up in future.
>>> However - look above - there is a race in how you have it currently ordered
>>> that means you should order it differently and not use the devm versions.
>> Ack.
>>
>>>>  	return 0;
>>>>  }
>>>>  
>>>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[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