linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: Tomasz Duszynski <tomasz.duszynski@octakon.com>
Cc: <linux-iio@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<devicetree@vger.kernel.org>, <robh+dt@kernel.org>
Subject: Re: [PATCH 1/6] iio: chemical: scd30: add core driver
Date: Sat, 2 May 2020 17:37:38 +0100	[thread overview]
Message-ID: <20200502173738.66dbc888@archlinux> (raw)
In-Reply-To: <20200428075101.GA6908@arch>

On Tue, 28 Apr 2020 09:51:01 +0200
Tomasz Duszynski <tomasz.duszynski@octakon.com> wrote:

> On Sat, Apr 25, 2020 at 07:55:34PM +0100, Jonathan Cameron wrote:
> > On Wed, 22 Apr 2020 16:11:30 +0200
> > Tomasz Duszynski <tomasz.duszynski@octakon.com> wrote:
> >  
> > > Add Sensirion SCD30 carbon dioxide core driver.
> > >
> > > Signed-off-by: Tomasz Duszynski <tomasz.duszynski@octakon.com>  
> > Hi Tomasz
> >
> > As you've probably guessed the big questions are around the custom ABI.
> >
> > Few other things inline.
> >
> > Jonathan
> >  
...

> > > +static int scd30_read_meas(struct scd30_state *state)
> > > +{
> > > +	int i, ret;
> > > +
> > > +	ret = scd30_command(state, CMD_READ_MEAS, 0, (char *)state->meas,
> > > +			    sizeof(state->meas));
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(state->meas); i++)
> > > +		state->meas[i] = scd30_float_to_fp(state->meas[i]);  
> >
> > We have previously discussed proving direct floating point channel types
> > for the rare devices that actually provide floating point data in
> > a standard format.
> >
> > I'm happy to revisit that if you would like to.
> >  
> 
> Thanks for reminding me :).
> 
> In that case I admit that some float helper in iio would be a good thing to
> have. Especially that there will be at least 2 sensors using it.
> 
> I'd work on that after this driver makes it into the tree.
> 
> How does it sound?

The problem is that, if we do it in that order we have ABI for this
device that we should really maintain.  We can probably get away
with changing it on the basis the channel type is self describing anyway
but it's not ideal.  

So probably fine but not best practice...

> 
> > > +
> > > +	/*
> > > +	 * Accuracy within calibrated operating range is
> > > +	 * +-(30ppm + 3% measurement) so fractional part does
> > > +	 * not add real value. Moreover, ppm is an integer.
> > > +	 */
> > > +	state->meas[CONC] /= 100;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int scd30_wait_meas_irq(struct scd30_state *state)
> > > +{
> > > +	int ret, timeout = msecs_to_jiffies(state->meas_interval * 1250);
> > > +
> > > +	reinit_completion(&state->meas_ready);
> > > +	enable_irq(state->irq);  
> >
> > So this is just 'grab the next one'?
> >  
> 
> Yes, grab the fresh one. Moreover enabling interrupts only when necessary can
> limit pointless buss traffic. Reason being irq is acknowledged by reading data
> from sensor.
> 

As mentioned below, it seems to me that we should really be starting this
device only when we want a reading.  Hence any interrupt (subject to possible
races) should be valid.  Hence we would not be enabling and disabling the
interrupt controller mask on this line.


> > > +static int scd30_setup_trigger(struct iio_dev *indio_dev)
> > > +{
> > > +	struct scd30_state *state = iio_priv(indio_dev);
> > > +	struct device *dev = indio_dev->dev.parent;
> > > +	struct iio_trigger *trig;
> > > +	int ret;
> > > +
> > > +	trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
> > > +				      indio_dev->id);
> > > +	if (!trig) {
> > > +		dev_err(dev, "failed to allocate trigger\n");
> > > +		return -ENOMEM;
> > > +	}
> > > +
> > > +	trig->dev.parent = dev;
> > > +	trig->ops = &scd30_trigger_ops;
> > > +	iio_trigger_set_drvdata(trig, indio_dev);
> > > +
> > > +	ret = devm_iio_trigger_register(dev, trig);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	indio_dev->trig = iio_trigger_get(trig);
> > > +
> > > +	ret = devm_request_threaded_irq(dev, state->irq, scd30_irq_handler,
> > > +					scd30_irq_thread_handler,
> > > +					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> > > +					indio_dev->name, indio_dev);
> > > +	if (ret)
> > > +		dev_err(dev, "failed to request irq\n");  
> >
> > I'm guessing this is a device without any means to disable the interrupt
> > being generated?  In which case are you safe against a race before you
> > disable here?
> >  
> 
> IRQs can be actually disabled by telling device to stop taking measurements.
> There is dedicated command for that. If irq fires off before being disabled
> nothing bad should happen as everything necessary is in place already.

Hmm. I wonder if we'd be better off starting it on demand - or only when running
with it as a data ready trigger. That would make the the polled read a case
of starting the sampling for one sample rather than just 'picking' one from
the stream of actual samples.

> 
> Another thing is that without disabling interrupt here we would get warning
> about unbalanced irq whilst enabling trigger.
> 
> > > +
> > > +	disable_irq(state->irq);
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
> > > +		int (*command)(struct scd30_state *state, enum scd30_cmd cmd,
> > > +			       u16 arg, char *rsp, int size))
> > > +{
> > > +	static const unsigned long scd30_scan_masks[] = { 0x07, 0x00 };
> > > +	struct scd30_state *state;
> > > +	struct iio_dev *indio_dev;
> > > +	int ret;
> > > +	u16 val;
> > > +
> > > +	indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
> > > +	if (!indio_dev)
> > > +		return -ENOMEM;
> > > +
> > > +	dev_set_drvdata(dev, indio_dev);
> > > +
> > > +	state = iio_priv(indio_dev);
> > > +	state->dev = dev;
> > > +	state->priv = priv;
> > > +	state->irq = irq;
> > > +	state->pressure_comp = SCD30_PRESSURE_COMP_DEFAULT;
> > > +	state->meas_interval = SCD30_MEAS_INTERVAL_DEFAULT;
> > > +	state->command = command;
> > > +	mutex_init(&state->lock);
> > > +	init_completion(&state->meas_ready);
> > > +
> > > +	indio_dev->dev.parent = dev;
> > > +	indio_dev->info = &scd30_info;
> > > +	indio_dev->name = name;
> > > +	indio_dev->channels = scd30_channels;
> > > +	indio_dev->num_channels = ARRAY_SIZE(scd30_channels);
> > > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > > +	indio_dev->available_scan_masks = scd30_scan_masks;
> > > +
> > > +	state->vdd = devm_regulator_get(dev, "vdd");
> > > +	if (IS_ERR(state->vdd)) {  
> >
> > This is very noisy if we have deferred probing going on.
> > Either explicitly check for that case or just don't bother
> > with an error message in this path.
> >  
> 
> Okay.
> 
> > > +		dev_err(dev, "failed to get vdd regulator\n");
> > > +		return PTR_ERR(state->vdd);
> > > +	}
> > > +
> > > +	ret = regulator_enable(state->vdd);
> > > +	if (ret) {
> > > +		dev_err(dev, "failed to enable vdd regulator\n");
> > > +		return ret;
> > > +	}
> > > +
> > > +	ret = devm_add_action_or_reset(dev, scd30_exit, state);
> > > +	if (ret)  
> >
> > This should match exactly against the item above it. Whilst stop
> > measurement may be safe from here on, it is not easy to review
> > unless we can clearly see where the equivalent start is.
> >  
> 
> Well, naming might be confusing. The thing is that sensor after being
> powered up reverts itself to the much the same state it left.
> 
> If we have real regulator then scd30_exit would disable regulator and
> that's it. But, in case of a dummy one and sensor starting in
> continuous mode we waste power for no real reason (for example 19mA
> at 0.5Hz).
> 
> So it's explanation for doing 2 things inside early on but not excuse
> for unintuitive naming.

I'd rather see two devm_add_action_or_reset calls one handling the regulator
and one handling the register write.  Then it will be clear what each
one is doing and that there are no possible races.  Basically it lets
a reviewer not bother thinking which is always good :)

> 
> > > +		return ret;
> > > +
> > > +	ret = scd30_reset(state);
> > > +	if (ret) {
> > > +		dev_err(dev, "failed to reset device: %d\n", ret);
> > > +		return ret;
> > > +	}

  reply	other threads:[~2020-05-02 16:37 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-22 14:11 [PATCH 0/6] Add support for SCD30 sensor Tomasz Duszynski
2020-04-22 14:11 ` [PATCH 1/6] iio: chemical: scd30: add core driver Tomasz Duszynski
2020-04-22 19:49   ` Andy Shevchenko
2020-04-24 19:04     ` Tomasz Duszynski
2020-04-25 11:43       ` Andy Shevchenko
2020-04-25 17:59         ` Jonathan Cameron
2020-04-25 18:41         ` Tomasz Duszynski
2020-04-25 18:52           ` Andy Shevchenko
2020-04-28  7:56             ` Tomasz Duszynski
2020-04-28 10:16               ` Andy Shevchenko
2020-04-28 14:06                 ` Tomasz Duszynski
2020-04-25 18:55   ` Jonathan Cameron
2020-04-25 19:00     ` Jonathan Cameron
2020-04-28  7:51     ` Tomasz Duszynski
2020-05-02 16:37       ` Jonathan Cameron [this message]
2020-05-03 10:53         ` Tomasz Duszynski
2020-04-22 14:11 ` [PATCH 2/6] iio: chemical: scd30: add I2C interface driver Tomasz Duszynski
2020-04-22 14:11 ` [PATCH 3/6] iio: chemical: scd30: add serial " Tomasz Duszynski
2020-04-22 19:55   ` Andy Shevchenko
2020-04-23 16:23     ` Tomasz Duszynski
2020-04-22 14:11 ` [PATCH 4/6] Documentation: ABI: testing: scd30: document iio attributes Tomasz Duszynski
2020-04-22 16:40   ` Peter Meerwald-Stadler
2020-04-23 15:53     ` Tomasz Duszynski
2020-04-25 19:20       ` Jonathan Cameron
2020-04-26 11:11         ` Tomasz Duszynski
2020-04-27  9:44           ` Jonathan Cameron
2020-04-22 14:11 ` [PATCH 5/6] dt-bindings: iio: scd30: add device binding file Tomasz Duszynski
2020-04-25 19:23   ` Jonathan Cameron
2020-04-26  8:28     ` Tomasz Duszynski
2020-04-27 21:28   ` Rob Herring
2020-04-28  8:10     ` Tomasz Duszynski
2020-04-22 14:11 ` [PATCH 6/6] MAINTAINERS: add myself as a SCD30 driver maintainer Tomasz Duszynski
2020-04-22 19:25   ` Andy Shevchenko
2020-04-23 16:01     ` Tomasz Duszynski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200502173738.66dbc888@archlinux \
    --to=jic23@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=tomasz.duszynski@octakon.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).