Re: [PATCH v5 2/3] iio: pressure: Honeywell mprls0025pa pressure sensor

From: andy . shevchenko
Date: Sun May 28 2023 - 18:29:03 EST


Tue, May 16, 2023 at 01:32:45PM +0200, Andreas Klinger kirjoitti:
> Honeywell mprls0025pa is a series of pressure sensors.
>
> Add initial I2C support.
>
> Note:
> - IIO buffered mode is supported
> - SPI mode is not supported

...

> + * Data sheet:

Datasheet

> + * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/
> + * products/sensors/pressure-sensors/board-mount-pressure-sensors/
> + * micropressure-mpr-series/documents/
> + * sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf

Is it URL? Can we have it clickable, i.e. unwrapped?

...

Missing bits.h

> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/i2c.h>
> +#include <linux/math64.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/property.h>
> +#include <linux/units.h>

...

> +/*
> + * support _RAW sysfs interface:

Support

> + *
> + * Calculation formula from the datasheet:
> + * pressure = (press_cnt - outputmin) * scale + pmin
> + * with:
> + * * pressure - measured pressure in Pascal
> + * * press_cnt - raw value read from sensor
> + * * pmin - minimum pressure range value of sensor (data->pmin)
> + * * pmax - maximum pressure range value of sensor (data->pmax)
> + * * outputmin - minimum numerical range raw value delivered by sensor
> + * (mpr_func_spec.output_min)
> + * * outputmax - maximum numerical range raw value delivered by sensor
> + * (mpr_func_spec.output_max)
> + * * scale - (pmax - pmin) / (outputmax - outputmin)
> + *
> + * formula of the userspace:
> + * pressure = (raw + offset) * scale
> + *
> + * Values given to the userspace in sysfs interface:
> + * * raw - press_cnt
> + * * offset - (-1 * outputmin) - pmin / scale
> + * note: With all sensors from the datasheet pmin = 0
> + * which reduces the offset to (-1 * outputmin)
> + */

...

> +/*
> + * transfer function A: 10% to 90% of 2^24
> + * transfer function B: 2.5% to 22.5% of 2^24
> + * transfer function C: 20% to 80% of 2^24
> + */

Kernel doc?

> +enum mpr_func_id {
> + MPR_FUNCTION_A,
> + MPR_FUNCTION_B,
> + MPR_FUNCTION_C,
> +};

...

> +struct mpr_func_spec {
> + u32 output_min;
> + u32 output_max;
> +};

Can the linear_range.h be used for this?

...

> +struct mpr_data {
> + struct i2c_client *client;
> + struct mutex lock; /*
> + * access to device during read
> + */
> + u32 pmin; /* minimal pressure in pascal */
> + u32 pmax; /* maximal pressure in pascal */
> + enum mpr_func_id function; /* transfer function */
> + u32 outmin; /*
> + * minimal numerical range raw
> + * value from sensor
> + */
> + u32 outmax; /*
> + * maximal numerical range raw
> + * value from sensor
> + */
> + int scale; /* int part of scale */
> + int scale2; /* nano part of scale */
> + int offset; /* int part of offset */
> + int offset2; /* nano part of offset */
> + struct gpio_desc *gpiod_reset; /* reset */
> + int irq; /*
> + * end of conversion irq;
> + * used to distinguish between
> + * irq mode and reading in a
> + * loop until data is ready
> + */
> + struct completion completion; /* handshake from irq to read */
> + struct mpr_chan chan; /*
> + * channel values for buffered
> + * mode
> + */

Why not kernel doc?

> +};

...

> +static void mpr_reset(struct mpr_data *data)
> +{
> + if (data->gpiod_reset) {

Actually this dups gpiod_*() checks, so only needed by udelay().

> + gpiod_set_value(data->gpiod_reset, 0);
> + udelay(10);
> + gpiod_set_value(data->gpiod_reset, 1);

Why not sleeping for all of them?

> + }
> +}

...

> + if (ret != sizeof(wdata)) {
> + dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret,
> + (u32)sizeof(wdata));

Casting? Use proper specifier, i.e. %zu.

> + return -EIO;
> + }

...

> + /* wait until status indicates data is ready */
> + for (i = 0; i < nloops; i++) {
> + /*
> + * datasheet only says to wait at least 5 ms for the

Datasheet

> + * data but leave the maximum response time open
> + * --> let's try it nloops (10) times which seems to be
> + * quite long
> + */
> + usleep_range(5000, 10000);
> + status = i2c_smbus_read_byte(data->client);
> + if (status < 0) {
> + dev_err(dev,
> + "error while reading, status: %d\n",
> + status);
> + return status;
> + }
> + if (!(status & MPR_I2C_BUSY))
> + break;
> + }
> + if (i == nloops) {
> + dev_err(dev, "timeout while reading\n");
> + return -ETIMEDOUT;
> + }

iopoll.h provides a macro for this. Reduces codebase a lot in this case.

> + }

...

> + dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret,
> + (u32)sizeof(buf));

Use proper specifier.

...

> + if (buf[0] & MPR_I2C_BUSY) {
> + /*
> + * it should never be the case that status still indicates
> + * business
> + */
> + dev_err(dev, "data still not ready: %08x\n", buf[0]);

Why 8? Is the buffer is of 32-bit values?

> + return -ETIMEDOUT;
> + }

...

> +err:

err_unlock:

> + mutex_unlock(&data->lock);
> + iio_trigger_notify_done(indio_dev->trig);
> +
> + return IRQ_HANDLED;

...

> + indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
> + if (!indio_dev)
> + return dev_err_probe(dev, -ENOMEM, "couldn't get iio_dev\n");

-ENOMEM shouldn't be without error message, we will get one in that case.

...

> + if (dev_fwnode(dev)) {

Why not simply use defaults?

> + ret = device_property_read_u32(dev, "honeywell,pmin-pascal",
> + &data->pmin);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "honeywell,pmin-pascal could not be read\n");
> + ret = device_property_read_u32(dev, "honeywell,pmax-pascal",
> + &data->pmax);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "honeywell,pmax-pascal could not be read\n");
> + ret = device_property_read_u32(dev,
> + "honeywell,transfer-function", &data->function);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "honeywell,transfer-function could not be read\n");
> + if (data->function > MPR_FUNCTION_C)
> + return dev_err_probe(dev, -EINVAL,

-ERANGE ?

> + "honeywell,transfer-function %d invalid\n",
> + data->function);
> + } else {
> + /* when loaded as i2c device we need to use default values */
> + dev_notice(dev, "firmware node not found; using defaults\n");
> + data->pmin = 0;
> + data->pmax = 172369; /* 25 psi */
> + data->function = MPR_FUNCTION_A;
> + }

...

> + /*
> + * multiply with NANO before dividing by scale and later divide by NANO

Multiply

> + * again.
> + */

...

> + if (ret)
> + return dev_err_probe(dev, ret,
> + "iio triggered buffer setup failed\n");

One line?

...

> + if (ret)
> + return dev_err_probe(dev, ret,
> + "unable to register iio device\n");

Ditto.

--
With Best Regards,
Andy Shevchenko