linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: Carlos Iglesias <carlos.iglesias@emutex.com>
Cc: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"robh+dt@kernel.org" <robh+dt@kernel.org>,
	"mark.rutland@arm.com" <mark.rutland@arm.com>,
	"knaack.h@gmx.de" <knaack.h@gmx.de>,
	"lars@metafoo.de" <lars@metafoo.de>,
	"pmeerw@pmeerw.net" <pmeerw@pmeerw.net>,
	"linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	Dan O'Donovan <dan.odonovan@emutex.com>
Subject: Re: [PATCH 2/2] iio: pressure: Add support for Honeywell HSC SPI sensors
Date: Sun, 28 Oct 2018 18:44:08 +0000	[thread overview]
Message-ID: <20181028184408.6d354f50@archlinux> (raw)
In-Reply-To: <20181026181406.14545-3-carlos.iglesias@emutex.com>

On Fri, 26 Oct 2018 18:14:37 +0000
Carlos Iglesias <carlos.iglesias@emutex.com> wrote:

> Add device driver for the HSC pressure sensors with SPI interface.
> In addition to the main measurement -pressure- these sensors also
> provide temperature measurement.
> 
> Signed-off-by: Carlos Iglesias <carlos.iglesias@emutex.com>

Hi Carlos,

A few minor things inline.  Note that the spi buffer isn't currently
dma safe which may result in some really hard to find bugs (I've chased
these in the past and they can be really rare and tricky to track down!)

Jonathan
> ---
>  MAINTAINERS                    |   6 +
>  drivers/iio/pressure/Kconfig   |  10 +
>  drivers/iio/pressure/Makefile  |   2 +
>  drivers/iio/pressure/hsc_spi.c | 543 +++++++++++++++++++++++++++++++++
>  4 files changed, 561 insertions(+)
>  create mode 100644 drivers/iio/pressure/hsc_spi.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 556f902b3766..a4af4cbd4b0f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6696,6 +6696,12 @@ W:	http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
>  S:	Maintained
>  F:	fs/hpfs/
>  
> +HSC SERIES PRESSURE SENSORS
> +M;	Carlos Iglesias <carlos.iglesias@emutex.com>
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/iio/pressure/hsc_spi.txt
> +F:	drivers/iio/pressure/hsc_spi.c
> +
>  HSI SUBSYSTEM
>  M:	Sebastian Reichel <sre@kernel.org>
>  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git
> diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
> index eaa7cfcb4c2a..593663d4ffa8 100644
> --- a/drivers/iio/pressure/Kconfig
> +++ b/drivers/iio/pressure/Kconfig
> @@ -227,4 +227,14 @@ config ZPA2326_SPI
>  	tristate
>  	select REGMAP_SPI
>  
> +config HSC_SPI
> +	tristate "Honeywell HSC pressure sensors (SPI)"
> +	depends on SPI_MASTER
> +	help
> +	  Say yes here to build support for the Honeywell HSC range of
> +	  pressure sensors (SPI interface only).
> +
> +	  To compile this driver as a module, choose M here: the module will
> +	  be called hsc_spi.
> +
>  endmenu
> diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
> index c2058d7b2f93..b1db2116e9f6 100644
> --- a/drivers/iio/pressure/Makefile
> +++ b/drivers/iio/pressure/Makefile
> @@ -31,3 +31,5 @@ obj-$(CONFIG_ZPA2326_SPI) += zpa2326_spi.o
>  
>  obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o
>  obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o
> +
> +obj-$(CONFIG_HSC_SPI) += hsc_spi.o
> diff --git a/drivers/iio/pressure/hsc_spi.c b/drivers/iio/pressure/hsc_spi.c
> new file mode 100644
> index 000000000000..efe45a09da8f
> --- /dev/null
> +++ b/drivers/iio/pressure/hsc_spi.c
> @@ -0,0 +1,543 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * hsc_spi.c - Driver for Honeywell HSC pressure sensors with
> + *             SPI interface
> + *
> + * Copyright (c) 2018 Carlos Iglesias <carlos.iglesias@emutex.com>
> + */
> +
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/iio/iio.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/spi/spi.h>
> +
> +#define HSC_MAX_SPI_FREQ_HZ	400000
> +
> +#define HSC_TEMP_BITS		11
> +#define HSC_PRESS_BITS		14
> +#define HSC_TEMP_MASK		(0x7FF)
> +#define HSC_TEMP_SHIFT		(5)
> +
> +#define HSC_STATUS_S0		BIT(14)
> +#define HSC_STATUS_S1		BIT(15)
> +#define HSC_STATUS_MSK		((HSC_STATUS_S0) | (HSC_STATUS_S1))
> +#define HSC_STATUS_CMD		HSC_STATUS_S0
> +#define HSC_STATUS_STALE	HSC_STATUS_S1
> +#define HSC_STATUS_DIAG		((HSC_STATUS_S0) | (HSC_STATUS_S1))
> +
> +static inline int hsc_status_error(struct device dev, int val)
> +{
> +	int st_check = val & HSC_STATUS_MSK;
> +
> +	if (st_check) {
> +		switch (st_check) {
> +		case HSC_STATUS_CMD:
> +			dev_warn(&dev, "%s:Device in COMMAND MODE\n",
> +				 __func__);
> +			return -EIO;
> +		case HSC_STATUS_STALE:
> +			dev_warn(&dev, "%s:Stale data - sampling too fast?\n",
> +				 __func__);
> +			return -EAGAIN;
> +		case HSC_STATUS_DIAG:
> +			dev_warn(&dev, "%s:Calibration signature changed\n",
> +				 __func__);
> +			return -EIO;
> +		default:
> +			dev_err(&dev, "%s:Invalid status code (%d)\n",
> +				__func__, st_check);
> +			return -EIO;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +enum hsc_variant {
> +	/* Note: Only the absolute range sensors are supported */
> +	HSC001BAA, HSC001BAB, HSC001BAC, HSC001BAF,
> +	HSC1_6BAA, HSC1_6BAB, HSC1_6BAC, HSC1_6BAF,
> +	HSC2_5BAA, HSC2_5BAB, HSC2_5BAC, HSC2_5BAF,
> +	HSC004BAA, HSC004BAB, HSC004BAC, HSC004BAF,
> +	HSC006BAA, HSC006BAB, HSC006BAC, HSC006BAF,
> +	HSC010BAA, HSC010BAB, HSC010BAC, HSC010BAF,
> +
> +	HSC100KAA, HSC100KAB, HSC100KAC, HSC100KAF,
> +	HSC160KAA, HSC160KAB, HSC160KAC, HSC160KAF,
> +	HSC250KAA, HSC250KAB, HSC250KAC, HSC250KAF,
> +	HSC400KAA, HSC400KAB, HSC400KAC, HSC400KAF,
> +	HSC600KAA, HSC600KAB, HSC600KAC, HSC600KAF,
> +	HSC001GAA, HSC001GAB, HSC001GAC, HSC001GAF,
> +
> +	HSC015PAA, HSC015PAB, HSC015PAC, HSC015PAF,
> +	HSC030PAA, HSC030PAB, HSC030PAC, HSC030PAF,
> +	HSC060PAA, HSC060PAB, HSC060PAC, HSC060PAF,
> +	HSC100PAA, HSC100PAB, HSC100PAC, HSC100PAF,
> +	HSC150PAA, HSC150PAB, HSC150PAC, HSC150PAF,
> +};
> +
> +enum hsc_meas_channel {
> +	HSC_CH_PRESSURE,
> +	HSC_CH_TEMPERATURE
> +};
> +
> +struct hsc_config {
> +	int pmin;	/* Lower pressure limit */
> +	int pmax;	/* Upper pressure limit */
> +	int rmin;	/* Lower transfer function limit (%) */
> +	int rmax;	/* Upper transfer function limit (%) */
> +	int knum;	/* Pressure kPa conversion factor (numerator) */
> +	int kden;	/* Pressure kPa conversion factor /denominator) */
> +};
> +
> +struct hsc_fract_val {
> +	int num;	/* numerator */
> +	int den;	/* denominator */
> +};
> +
> +struct hsc_state {
> +	struct device *dev;
> +	struct spi_device *spi_dev;
> +	struct spi_transfer spi_xfer;
> +	struct spi_message spi_msg;
> +	__be16 rx_buf[2];
This is not a safe buffer for DMA as it shares its cacheline with other data.
Easiest option is to put it at the end of this structure and mark it
__cacheline_aligned.

We make sure that the private data is always appropriately aligned to allow
this to work.
> +
> +	/* Model-dependent values */
> +	struct hsc_fract_val scale;
> +	struct hsc_fract_val offset;
> +};
> +
> +#define HSC_CONFIG(_pmin, _pmax, _rmin, _rmax, _knum, _kden) {	\
> +		.pmin = (_pmin),				\
> +		.pmax = (_pmax),				\
> +		.rmin = (_rmin),				\
> +		.rmax = (_rmax),				\
> +		.knum = (_knum),				\
> +		.kden = (_kden),				\
> +	}
> +
> +static struct hsc_config hsc_cfg[] = {
> +	/* Absolute range, mbar */
> +	[HSC001BAA] = HSC_CONFIG(0, 1000, 10, 90, 1, 10),
> +	[HSC001BAB] = HSC_CONFIG(0, 1000, 5, 95, 1, 10),
> +	[HSC001BAC] = HSC_CONFIG(0, 1000, 5, 85, 1, 10),
> +	[HSC001BAF] = HSC_CONFIG(0, 1000, 4, 94, 1, 10),
> +	[HSC1_6BAA] = HSC_CONFIG(0, 1600, 10, 90, 1, 10),
> +	[HSC1_6BAB] = HSC_CONFIG(0, 1600, 5, 95, 1, 10),
> +	[HSC1_6BAC] = HSC_CONFIG(0, 1600, 5, 85, 1, 10),
> +	[HSC1_6BAF] = HSC_CONFIG(0, 1600, 4, 94, 1, 10),
> +	[HSC2_5BAA] = HSC_CONFIG(0, 2500, 10, 90, 1, 10),
> +	[HSC2_5BAB] = HSC_CONFIG(0, 2500, 5, 95, 1, 10),
> +	[HSC2_5BAC] = HSC_CONFIG(0, 2500, 5, 85, 1, 10),
> +	[HSC2_5BAF] = HSC_CONFIG(0, 2500, 4, 94, 1, 10),
> +	[HSC004BAA] = HSC_CONFIG(0, 4000, 10, 90, 1, 10),
> +	[HSC004BAB] = HSC_CONFIG(0, 4000, 5, 95, 1, 10),
> +	[HSC004BAC] = HSC_CONFIG(0, 4000, 5, 85, 1, 10),
> +	[HSC004BAF] = HSC_CONFIG(0, 4000, 4, 94, 1, 10),
> +	[HSC006BAA] = HSC_CONFIG(0, 6000, 10, 90, 1, 10),
> +	[HSC006BAB] = HSC_CONFIG(0, 6000, 5, 95, 1, 10),
> +	[HSC006BAC] = HSC_CONFIG(0, 6000, 5, 85, 1, 10),
> +	[HSC006BAF] = HSC_CONFIG(0, 6000, 4, 94, 1, 10),
> +	[HSC010BAA] = HSC_CONFIG(0, 10000, 10, 90, 1, 10),
> +	[HSC010BAB] = HSC_CONFIG(0, 10000, 5, 95, 1, 10),
> +	[HSC010BAC] = HSC_CONFIG(0, 10000, 5, 85, 1, 10),
> +	[HSC010BAF] = HSC_CONFIG(0, 10000, 4, 94, 1, 10),
> +	/* Absolute range, kPa */
> +	[HSC100KAA] = HSC_CONFIG(0, 100, 10, 90, 1, 1),
> +	[HSC100KAB] = HSC_CONFIG(0, 100, 5, 95, 1, 1),
> +	[HSC100KAC] = HSC_CONFIG(0, 100, 5, 85, 1, 1),
> +	[HSC100KAF] = HSC_CONFIG(0, 100, 4, 94, 1, 1),
> +	[HSC160KAA] = HSC_CONFIG(0, 160, 10, 90, 1, 1),
> +	[HSC160KAB] = HSC_CONFIG(0, 160, 5, 95, 1, 1),
> +	[HSC160KAC] = HSC_CONFIG(0, 160, 5, 85, 1, 1),
> +	[HSC160KAF] = HSC_CONFIG(0, 160, 4, 94, 1, 1),
> +	[HSC250KAA] = HSC_CONFIG(0, 250, 10, 90, 1, 1),
> +	[HSC250KAB] = HSC_CONFIG(0, 250, 5, 95, 1, 1),
> +	[HSC250KAC] = HSC_CONFIG(0, 250, 5, 85, 1, 1),
> +	[HSC250KAF] = HSC_CONFIG(0, 250, 4, 94, 1, 1),
> +	[HSC400KAA] = HSC_CONFIG(0, 400, 10, 90, 1, 1),
> +	[HSC400KAB] = HSC_CONFIG(0, 400, 5, 95, 1, 1),
> +	[HSC400KAC] = HSC_CONFIG(0, 400, 5, 85, 1, 1),
> +	[HSC400KAF] = HSC_CONFIG(0, 400, 4, 94, 1, 1),
> +	[HSC600KAA] = HSC_CONFIG(0, 600, 10, 90, 1, 1),
> +	[HSC600KAB] = HSC_CONFIG(0, 600, 5, 95, 1, 1),
> +	[HSC600KAC] = HSC_CONFIG(0, 600, 5, 85, 1, 1),
> +	[HSC600KAF] = HSC_CONFIG(0, 600, 4, 94, 1, 1),
> +	[HSC001GAA] = HSC_CONFIG(0, 1000, 10, 90, 1, 1),
> +	[HSC001GAB] = HSC_CONFIG(0, 1000, 5, 95, 1, 1),
> +	[HSC001GAC] = HSC_CONFIG(0, 1000, 5, 85, 1, 1),
> +	[HSC001GAF] = HSC_CONFIG(0, 1000, 4, 94, 1, 1),
> +	/* Absolute range, psi */
> +	[HSC015PAA] = HSC_CONFIG(0, 15, 10, 90, 6895, 1000),
> +	[HSC015PAB] = HSC_CONFIG(0, 15, 5, 95, 6895, 1000),
> +	[HSC015PAC] = HSC_CONFIG(0, 15, 5, 85, 6895, 1000),
> +	[HSC015PAF] = HSC_CONFIG(0, 15, 4, 94, 6895, 1000),
> +	[HSC030PAA] = HSC_CONFIG(0, 30, 10, 90, 6895, 1000),
> +	[HSC030PAB] = HSC_CONFIG(0, 30, 5, 95, 6895, 1000),
> +	[HSC030PAC] = HSC_CONFIG(0, 30, 5, 85, 6895, 1000),
> +	[HSC030PAF] = HSC_CONFIG(0, 30, 4, 94, 6895, 1000),
> +	[HSC060PAA] = HSC_CONFIG(0, 60, 10, 90, 6895, 1000),
> +	[HSC060PAB] = HSC_CONFIG(0, 60, 5, 95, 6895, 1000),
> +	[HSC060PAC] = HSC_CONFIG(0, 60, 5, 85, 6895, 1000),
> +	[HSC060PAF] = HSC_CONFIG(0, 60, 4, 94, 6895, 1000),
> +	[HSC100PAA] = HSC_CONFIG(0, 100, 10, 90, 6895, 1000),
> +	[HSC100PAB] = HSC_CONFIG(0, 100, 5, 95, 6895, 1000),
> +	[HSC100PAC] = HSC_CONFIG(0, 100, 5, 85, 6895, 1000),
> +	[HSC100PAF] = HSC_CONFIG(0, 100, 4, 94, 6895, 1000),
> +	[HSC150PAA] = HSC_CONFIG(0, 150, 10, 90, 6895, 1000),
> +	[HSC150PAB] = HSC_CONFIG(0, 150, 5, 95, 6895, 1000),
> +	[HSC150PAC] = HSC_CONFIG(0, 150, 5, 85, 6895, 1000),
> +	[HSC150PAF] = HSC_CONFIG(0, 150, 4, 94, 6895, 1000),
> +};
> +
> +static const struct iio_chan_spec hsc_channels[] = {
> +	{
> +		.type = IIO_PRESSURE,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> +				      BIT(IIO_CHAN_INFO_OFFSET) |
> +				      BIT(IIO_CHAN_INFO_SCALE),
> +		.channel = HSC_CH_PRESSURE,
> +		.scan_type = {
> +			.sign = 'u',
> +			.realbits = HSC_PRESS_BITS,
> +			.storagebits = 16,
> +			.shift = 0,
Shift default is 0 so no need to have this.

> +			.endianness = IIO_BE,
> +		}
> +	},
> +	{
> +		.type = IIO_TEMP,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> +				      BIT(IIO_CHAN_INFO_OFFSET) |
> +				      BIT(IIO_CHAN_INFO_SCALE),
> +		.channel = HSC_CH_TEMPERATURE,
> +		.scan_type = {
> +			.sign = 'u',
> +			.realbits = HSC_TEMP_BITS,
> +			.storagebits = 16,
> +			.shift = HSC_TEMP_SHIFT,
> +			.endianness = IIO_BE,
> +		}
> +	}
> +};
> +
> +static int hsc_get_pressure(struct hsc_state *state)
> +{
> +	int ret = 0;
Always set below, so should not init here.

> +	int error;
> +
> +	state->spi_xfer.len = 2;
> +	ret = spi_sync(state->spi_dev, &state->spi_msg);
> +	if (ret)
> +		return ret;
> +
> +	ret = be16_to_cpu(state->rx_buf[0]);
> +
> +	error = hsc_status_error(state->spi_dev->dev, ret);
> +	if (error)
> +		return error;
> +
> +	return ret;
> +}
> +
> +static int hsc_get_temperature(struct hsc_state *state)
> +{
> +	int ret;
> +	int error;
> +
> +	state->spi_xfer.len = 4;
> +	ret = spi_sync(state->spi_dev, &state->spi_msg);
> +	if (ret)
> +		return ret;
As mentioned below I'm not sure the complexity of the spi_sync
instead of spi_read is worthwhile here.
> +
> +	ret = be16_to_cpu(state->rx_buf[0]);
Perhaps just have this inline in the function call.
(there are a few other instances of this, so perhaps all of them)
> +	error = hsc_status_error(state->spi_dev->dev, ret);
> +	if (error)
> +		return error;
> +
> +	ret = be16_to_cpu(state->rx_buf[1]);
Perhaps just put this inline in the next statement?
> +	ret = (ret >> HSC_TEMP_SHIFT) & HSC_TEMP_MASK;
> +
> +	return ret;
return (ret >> HSC_TEMP_SHIFT) & HSC_TEMP_MASK;

> +}
> +
> +static int hsc_read_raw(struct iio_dev *indio_dev,
> +			struct iio_chan_spec const *chan, int *val,
> +			int *val2, long mask)
> +{
> +	struct hsc_state *state = iio_priv(indio_dev);
> +	int ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		switch (chan->channel) {
> +		case HSC_CH_PRESSURE:
> +			ret = hsc_get_pressure(state);
> +			if (ret < 0)
> +				break;
> +			*val = ret;
> +			ret = IIO_VAL_INT;
return IIO_VAL_INT;
> +			break;
> +		case HSC_CH_TEMPERATURE:
> +			ret = hsc_get_temperature(state);
> +			if (ret < 0)
> +				break;
> +			*val = ret;
> +			ret = IIO_VAL_INT;
return IIO_VAL_INT;

> +			break;
> +		default:
> +			ret = -EINVAL;
> +			dev_err(state->dev,
> +				"%s - IIO_CHAN_INFO_RAW-bad channel (%d)\n",
> +				__func__, chan->channel);
> +			break;
return -EINVAL;

> +		}
> +		break;
> +	case IIO_CHAN_INFO_OFFSET:
> +		switch (chan->channel) {
> +		case HSC_CH_PRESSURE:
> +			*val = state->offset.num;
> +			*val2 = state->offset.den;
> +			ret = IIO_VAL_FRACTIONAL;
> +			break;
> +		case HSC_CH_TEMPERATURE:
> +			*val = BIT(HSC_TEMP_BITS) - 1;
> +			*val2 = -200 / 50;
> +			ret = IIO_VAL_FRACTIONAL;
> +			break;
> +		default:
> +			dev_err(state->dev,
> +				"%s - IIO_CHAN_INFO_OFFSET-bad channel (%d)\n",
> +				__func__, chan->channel);
> +			ret = -EINVAL;
> +			break;
> +		}
> +		break;
> +	case IIO_CHAN_INFO_SCALE:
> +		switch (chan->channel) {
> +		case HSC_CH_PRESSURE:		/* output unit is kPa */
> +			*val = state->scale.num;
> +			*val2 = state->scale.den;
> +			ret = IIO_VAL_FRACTIONAL;
> +			break;
> +		case HSC_CH_TEMPERATURE:  /* output unit is milli Celsius */
> +			*val = 200 * 1000;
> +			*val2 = BIT(HSC_TEMP_BITS) - 1;
> +			ret = IIO_VAL_FRACTIONAL;
> +			break;
> +		default:
> +			dev_err(state->dev,
> +				"%s - IIO_CHAN_INFO_SCALE-bad channel (%d)\n",
> +				__func__, chan->channel);
> +			ret = -EINVAL;
> +			break;
> +		}
> +		break;
> +	default:
> +		dev_err(state->dev, "%s - mask = %ld (INVALID)\n",
> +			__func__, mask);
> +		ret = -EINVAL;
return -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
With direct returns everywhere above, no need to return ret here as you can't
get here.

> +}
> +
> +static const struct iio_info hsc_info = {
> +	.read_raw = hsc_read_raw,
> +};
> +
> +static void hsc_init_device(struct iio_dev *indio_dev)
This function seems a little oddly named given it doesn't do anything
to the device at all. Perhaps hsc_init_device_params?
Or more likely you can come up with something better than that.

> +{
> +	struct hsc_state *state = iio_priv(indio_dev);
> +	const struct hsc_config *cfg = of_device_get_match_data(state->dev);
> +
> +	/* Pressure offset value */
> +	state->offset.num = BIT(HSC_PRESS_BITS) *
> +			    (cfg->pmin * cfg->rmax - cfg->pmax * cfg->rmin);
> +	state->offset.den = 100 * (cfg->pmax - cfg->pmin);
> +
> +	/* Pressure scale value */
> +	state->scale.num = 100 * cfg->knum * (cfg->pmax - cfg->pmin);
> +	state->scale.den = BIT(HSC_PRESS_BITS) *
> +			   cfg->kden * (cfg->rmax - cfg->rmin);
> +}
> +
> +static int hsc_spi_probe(struct spi_device *spi)
> +{
> +	struct device *dev = &spi->dev;
> +	struct hsc_state *state;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +
> +	if (spi->max_speed_hz > HSC_MAX_SPI_FREQ_HZ) {
> +		dev_warn(dev, "SPI CLK, %d Hz exceeds %d Hz - changed to max\n",
> +			spi->max_speed_hz,
> +			HSC_MAX_SPI_FREQ_HZ);
> +		spi->max_speed_hz = HSC_MAX_SPI_FREQ_HZ;
> +	}
> +
> +	spi->bits_per_word = 8;
> +	spi->mode = SPI_MODE_0;
> +
> +	ret = spi_setup(spi);
> +	if (ret < 0) {
> +		dev_err(dev, "%s - Error in spi_setup()\n", __func__);
> +		return ret;
> +	}
> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
> +	if (!indio_dev) {
> +		dev_err(dev, "%s - Error allocating iio_device\n", __func__);
> +		return -ENOMEM;
> +	}
> +
> +	state = iio_priv(indio_dev);
> +	spi_set_drvdata(spi, state);
> +	state->spi_dev = spi;
> +	state->dev = dev;
This seems a little excessive as you can get it from spi_dev->dev where ever it
is needed.

> +
> +	indio_dev->dev.parent = dev;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->info = &hsc_info;
> +	indio_dev->channels = hsc_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(hsc_channels);
> +
> +	state->spi_xfer.rx_buf = &state->rx_buf[0];
> +	state->spi_xfer.tx_buf = NULL;
Null is the default so should be no need to set it.
(state is kzalloc)

> +	state->spi_xfer.cs_change = 0;

I would assume that was the default and doesn't need setting...

> +	spi_message_init(&state->spi_msg);
> +	spi_message_add_tail(&state->spi_xfer, &state->spi_msg);
Is this worthwhile doing over a simple spi_read without precreating
the message etc?

> +
> +	hsc_init_device(indio_dev);
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret < 0)
> +		dev_err(dev, "iio_device_register failed: %d\n", ret);
> +
> +	dev_dbg(dev, "%s - scale = %d/%d, offset = %d/%d\n", __func__,
> +		state->scale.num, state->scale.den,
> +		state->offset.num, state->offset.den);
> +
> +	return ret;
> +}
> +
> +static int hsc_spi_remove(struct spi_device *spi)
> +{
> +	struct device *dev = &spi->dev;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +
> +	iio_device_unregister(indio_dev);
If all you have in a remove function is iio_device_unregister, then
it implies you could have used devm_iio_device_register and not had
a remove function at all.

It's fairly unusual that there isn't 'something' to do, but perhaps not
if the interface is very simple, or you are doing tight power control
around individual readings.

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id hsc_of_match[] = {
> +	{ .compatible = "honeywell,hsc001baa", .data = &hsc_cfg[HSC001BAA] },
> +	{ .compatible = "honeywell,hsc001bab", .data = &hsc_cfg[HSC001BAB] },
> +	{ .compatible = "honeywell,hsc001bac", .data = &hsc_cfg[HSC001BAC] },
> +	{ .compatible = "honeywell,hsc001baf", .data = &hsc_cfg[HSC001BAF] },
> +
> +	{ .compatible = "honeywell,hsc1_6baa", .data = &hsc_cfg[HSC1_6BAA] },
> +	{ .compatible = "honeywell,hsc1_6bab", .data = &hsc_cfg[HSC1_6BAB] },
> +	{ .compatible = "honeywell,hsc1_6bac", .data = &hsc_cfg[HSC1_6BAC] },
> +	{ .compatible = "honeywell,hsc1_6baf", .data = &hsc_cfg[HSC1_6BAF] },
> +
> +	{ .compatible = "honeywell,hsc2_5baa", .data = &hsc_cfg[HSC2_5BAA] },
> +	{ .compatible = "honeywell,hsc2_5bab", .data = &hsc_cfg[HSC2_5BAB] },
> +	{ .compatible = "honeywell,hsc2_5bac", .data = &hsc_cfg[HSC2_5BAC] },
> +	{ .compatible = "honeywell,hsc2_5baf", .data = &hsc_cfg[HSC2_5BAF] },
> +
> +	{ .compatible = "honeywell,hsc004baa", .data = &hsc_cfg[HSC004BAA] },
> +	{ .compatible = "honeywell,hsc004bab", .data = &hsc_cfg[HSC004BAB] },
> +	{ .compatible = "honeywell,hsc004bac", .data = &hsc_cfg[HSC004BAC] },
> +	{ .compatible = "honeywell,hsc004baf", .data = &hsc_cfg[HSC004BAF] },
> +
> +	{ .compatible = "honeywell,hsc006baa", .data = &hsc_cfg[HSC006BAA] },
> +	{ .compatible = "honeywell,hsc006bab", .data = &hsc_cfg[HSC006BAB] },
> +	{ .compatible = "honeywell,hsc006bac", .data = &hsc_cfg[HSC006BAC] },
> +	{ .compatible = "honeywell,hsc006baf", .data = &hsc_cfg[HSC006BAF] },
> +
> +	{ .compatible = "honeywell,hsc010baa", .data = &hsc_cfg[HSC010BAA] },
> +	{ .compatible = "honeywell,hsc010bab", .data = &hsc_cfg[HSC010BAB] },
> +	{ .compatible = "honeywell,hsc010bac", .data = &hsc_cfg[HSC010BAC] },
> +	{ .compatible = "honeywell,hsc010baf", .data = &hsc_cfg[HSC010BAF] },
> +
> +	{ .compatible = "honeywell,hsc100kaa", .data = &hsc_cfg[HSC100KAA] },
> +	{ .compatible = "honeywell,hsc100kab", .data = &hsc_cfg[HSC100KAB] },
> +	{ .compatible = "honeywell,hsc100kac", .data = &hsc_cfg[HSC100KAC] },
> +	{ .compatible = "honeywell,hsc100kaf", .data = &hsc_cfg[HSC100KAF] },
> +
> +	{ .compatible = "honeywell,hsc160kaa", .data = &hsc_cfg[HSC160KAA] },
> +	{ .compatible = "honeywell,hsc160kab", .data = &hsc_cfg[HSC160KAB] },
> +	{ .compatible = "honeywell,hsc160kac", .data = &hsc_cfg[HSC160KAC] },
> +	{ .compatible = "honeywell,hsc160kaf", .data = &hsc_cfg[HSC160KAF] },
> +
> +	{ .compatible = "honeywell,hsc250kaa", .data = &hsc_cfg[HSC250KAA] },
> +	{ .compatible = "honeywell,hsc250kab", .data = &hsc_cfg[HSC250KAB] },
> +	{ .compatible = "honeywell,hsc250kac", .data = &hsc_cfg[HSC250KAC] },
> +	{ .compatible = "honeywell,hsc250kaf", .data = &hsc_cfg[HSC250KAF] },
> +
> +	{ .compatible = "honeywell,hsc400kaa", .data = &hsc_cfg[HSC400KAA] },
> +	{ .compatible = "honeywell,hsc400kab", .data = &hsc_cfg[HSC400KAB] },
> +	{ .compatible = "honeywell,hsc400kac", .data = &hsc_cfg[HSC400KAC] },
> +	{ .compatible = "honeywell,hsc400kaf", .data = &hsc_cfg[HSC400KAF] },
> +
> +	{ .compatible = "honeywell,hsc600kaa", .data = &hsc_cfg[HSC600KAA] },
> +	{ .compatible = "honeywell,hsc600kab", .data = &hsc_cfg[HSC600KAB] },
> +	{ .compatible = "honeywell,hsc600kac", .data = &hsc_cfg[HSC600KAC] },
> +	{ .compatible = "honeywell,hsc600kaf", .data = &hsc_cfg[HSC600KAF] },
> +
> +	{ .compatible = "honeywell,hsc001gaa", .data = &hsc_cfg[HSC001GAA] },
> +	{ .compatible = "honeywell,hsc001gab", .data = &hsc_cfg[HSC001GAB] },
> +	{ .compatible = "honeywell,hsc001gac", .data = &hsc_cfg[HSC001GAC] },
> +	{ .compatible = "honeywell,hsc001gaf", .data = &hsc_cfg[HSC001GAF] },
> +
> +	{ .compatible = "honeywell,hsc015paa", .data = &hsc_cfg[HSC015PAA] },
> +	{ .compatible = "honeywell,hsc015pab", .data = &hsc_cfg[HSC015PAB] },
> +	{ .compatible = "honeywell,hsc015pac", .data = &hsc_cfg[HSC015PAC] },
> +	{ .compatible = "honeywell,hsc015paf", .data = &hsc_cfg[HSC015PAF] },
> +
> +	{ .compatible = "honeywell,hsc030paa", .data = &hsc_cfg[HSC030PAA] },
> +	{ .compatible = "honeywell,hsc030pab", .data = &hsc_cfg[HSC030PAB] },
> +	{ .compatible = "honeywell,hsc030pac", .data = &hsc_cfg[HSC030PAC] },
> +	{ .compatible = "honeywell,hsc030paf", .data = &hsc_cfg[HSC030PAF] },
> +
> +	{ .compatible = "honeywell,hsc060paa", .data = &hsc_cfg[HSC060PAA] },
> +	{ .compatible = "honeywell,hsc060pab", .data = &hsc_cfg[HSC060PAB] },
> +	{ .compatible = "honeywell,hsc060pac", .data = &hsc_cfg[HSC060PAC] },
> +	{ .compatible = "honeywell,hsc060paf", .data = &hsc_cfg[HSC060PAF] },
> +
> +	{ .compatible = "honeywell,hsc100paa", .data = &hsc_cfg[HSC100PAA] },
> +	{ .compatible = "honeywell,hsc100pab", .data = &hsc_cfg[HSC100PAB] },
> +	{ .compatible = "honeywell,hsc100pac", .data = &hsc_cfg[HSC100PAC] },
> +	{ .compatible = "honeywell,hsc100paf", .data = &hsc_cfg[HSC100PAF] },
> +
> +	{ .compatible = "honeywell,hsc150paa", .data = &hsc_cfg[HSC150PAA] },
> +	{ .compatible = "honeywell,hsc150pab", .data = &hsc_cfg[HSC150PAB] },
> +	{ .compatible = "honeywell,hsc150pac", .data = &hsc_cfg[HSC150PAC] },
> +	{ .compatible = "honeywell,hsc150paf", .data = &hsc_cfg[HSC150PAF] },
> +
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, hsc_of_match);
> +
> +static struct spi_driver hsc_spi_driver = {
> +	.probe = hsc_spi_probe,
> +	.remove = hsc_spi_remove,
> +	.driver = {
> +		.name = "hsc_spi_pressure_sensor",
> +		.of_match_table = hsc_of_match,
> +	},
> +};
> +
> +module_spi_driver(hsc_spi_driver);
> +
> +MODULE_AUTHOR("Carlos Iglesias <carlosiglesias@emutex.com>");
> +MODULE_DESCRIPTION("Honeywell HSC SPI pressure sensor driver");
> +MODULE_LICENSE("GPL v2");


      reply	other threads:[~2018-10-28 18:44 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-26 18:14 [PATCH 0/2] iio: pressure: Add support for Honeywell HSC SPI sensors Carlos Iglesias
2018-10-26 18:14 ` [PATCH 1/2] dt-bindings: " Carlos Iglesias
2018-10-28 17:38   ` Jonathan Cameron
     [not found]     ` <0dbb2254-8035-b498-6302-26bc3a2219ca@emutex.com>
2018-11-03 10:36       ` Jonathan Cameron
2018-11-06 21:29   ` Rob Herring
2018-10-26 18:14 ` [PATCH 2/2] " Carlos Iglesias
2018-10-28 18:44   ` Jonathan Cameron [this message]

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=20181028184408.6d354f50@archlinux \
    --to=jic23@kernel.org \
    --cc=carlos.iglesias@emutex.com \
    --cc=dan.odonovan@emutex.com \
    --cc=devicetree@vger.kernel.org \
    --cc=knaack.h@gmx.de \
    --cc=lars@metafoo.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=pmeerw@pmeerw.net \
    --cc=robh+dt@kernel.org \
    /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).