public inbox for linux-iio@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-17 20:17 [PATCH 0/2] Maxim MAX1241 driver Alexandru Lazar
@ 2020-03-17 20:17 ` Alexandru Lazar
  2020-03-17 20:33   ` Lars-Peter Clausen
                     ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Alexandru Lazar @ 2020-03-17 20:17 UTC (permalink / raw)
  To: linux-iio
  Cc: jic23, knaack.h, lars, pmeerw, robh+dt, mark.rutland,
	Alexandru Lazar

Add driver for the Maxim MAX1241 12-bit, single-channel ADC. The driver
includes support for this device's low-power operation mode.

Signed-off-by: Alexandru Lazar <alazar@startmail.com>
---
 drivers/iio/adc/Kconfig   |  12 +++
 drivers/iio/adc/Makefile  |   1 +
 drivers/iio/adc/max1241.c | 215 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 228 insertions(+)
 create mode 100644 drivers/iio/adc/max1241.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 5d8540b7b427..3a55beec69c9 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -566,6 +566,18 @@ config MAX1118
 	  To compile this driver as a module, choose M here: the module will be
 	  called max1118.
 
+config MAX1241
+	tristate "Maxim max1241 ADC driver"
+	depends on SPI
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for Maxim max1241 12-bit, single-channel
+          ADC.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called max1118.
+
 config MAX1363
 	tristate "Maxim max1363 ADC driver"
 	depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index a1f1fbec0f87..37d6f17559dc 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o
 obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX11100) += max11100.o
 obj-$(CONFIG_MAX1118) += max1118.o
+obj-$(CONFIG_MAX1241) += max1241.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MAX9611) += max9611.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
new file mode 100644
index 000000000000..2bd31f22fb2c
--- /dev/null
+++ b/drivers/iio/adc/max1241.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MAX1241 low-power, 12-bit serial ADC
+ *
+ * Copyright (c) 2020 Ioan-Alexandru Lazar <alazar@startmail.com>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf
+ */
+
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#define MAX1241_VAL_MASK 0xFFF
+#define MAX1241_SHDN_DELAY_USEC 4
+
+enum max1241_id {
+	max1241,
+};
+
+struct max1241 {
+	struct spi_device *spi;
+	struct mutex lock;
+	struct regulator *reg;
+	struct gpio_desc *shdn;
+
+	__be16 data ____cacheline_aligned;
+};
+
+static const struct iio_chan_spec max1241_channels[] = {
+	{
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 0,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	},
+};
+
+static int max1241_read(struct max1241 *adc)
+{
+	int ret;
+	struct spi_device *spi = adc->spi;
+	struct spi_transfer xfers[] = {
+		/*
+		 * Begin conversion by bringing /CS low for at least
+		 * tconv us.
+		 */
+		{
+			.len = 0,
+			.delay_usecs = 8,
+		},
+		/*
+		 * Then read two bytes of data in our RX buffer.
+		 */
+		{
+			.rx_buf = &adc->data,
+			.len = 2,
+		},
+	};
+
+	ret = spi_sync_transfer(spi, xfers, 2);
+
+	return ret;
+}
+
+static int max1241_read_raw(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val, int *val2, long mask)
+{
+	int ret, vref_uV;
+	struct max1241 *adc = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&adc->lock);
+
+		if (adc->shdn) {
+			gpiod_set_value(adc->shdn, 0);
+			udelay(MAX1241_SHDN_DELAY_USEC);
+		}
+
+		ret = max1241_read(adc);
+
+		if (adc->shdn)
+			gpiod_set_value(adc->shdn, 1);
+
+		if (ret) {
+			mutex_unlock(&adc->lock);
+			return ret;
+		}
+
+		*val = (be16_to_cpu(adc->data) >> 3) & MAX1241_VAL_MASK;
+
+		mutex_unlock(&adc->lock);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		vref_uV = regulator_get_voltage(adc->reg);
+
+		if (vref_uV < 0)
+			return vref_uV;
+
+		*val = vref_uV / 1000;
+		*val2 = 12;
+
+		return IIO_VAL_FRACTIONAL_LOG2;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info max1241_info = {
+	.read_raw = max1241_read_raw,
+};
+
+static int max1241_probe(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev;
+	struct max1241 *adc;
+	int ret = 0;
+
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	adc = iio_priv(indio_dev);
+	adc->spi = spi;
+	mutex_init(&adc->lock);
+
+	spi_set_drvdata(spi, indio_dev);
+
+	adc->reg = devm_regulator_get(&spi->dev, "vref");
+	if (IS_ERR(adc->reg)) {
+		dev_err(&spi->dev, "failed to get vref regulator\n");
+		return PTR_ERR(adc->reg);
+	}
+
+	ret = regulator_enable(adc->reg);
+	if (ret)
+		return ret;
+
+	adc->shdn = devm_gpiod_get_optional(&spi->dev, "shdn", GPIOD_OUT_HIGH);
+	if (!adc->shdn)
+		dev_info(&spi->dev, "no shdn pin passed, low-power mode disabled");
+	else
+		dev_info(&spi->dev, "shdn pin passed, low-power mode enabled");
+
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->info = &max1241_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = max1241_channels;
+	indio_dev->num_channels = ARRAY_SIZE(max1241_channels);
+
+	ret = iio_device_register(indio_dev);
+
+	return ret;
+}
+
+static int max1241_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct max1241 *adc = iio_priv(indio_dev);
+	int ret = 0;
+
+	iio_device_unregister(indio_dev);
+	ret = regulator_disable(adc->reg);
+
+	return ret;
+}
+
+static const struct spi_device_id max1241_id[] = {
+	{ "max1241", max1241 },
+	{},
+};
+
+#ifdef CONFIG_OF
+
+static const struct of_device_id max1241_dt_ids[] = {
+	{ .compatible = "maxim,max1241" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, max1241_dt_ids);
+
+#endif
+
+static struct spi_driver max1241_spi_driver = {
+	.driver = {
+		.name = "max1241",
+		.of_match_table = of_match_ptr(max1241_dt_ids),
+	},
+	.probe = max1241_probe,
+	.remove = max1241_remove,
+	.id_table = max1241_id,
+};
+module_spi_driver(max1241_spi_driver);
+
+MODULE_AUTHOR("Alexandru Lazar <alazar@startmail.com>");
+MODULE_DESCRIPTION("MAX1241 ADC driver");
+MODULE_LICENSE("GPL v2");
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-17 20:17 ` [PATCH 1/2] iio: adc: Add " Alexandru Lazar
@ 2020-03-17 20:33   ` Lars-Peter Clausen
  2020-03-17 20:40     ` Lars-Peter Clausen
  2020-03-17 21:28     ` Alexandru Lazar
  2020-03-17 21:03   ` Lars-Peter Clausen
  2020-03-18  6:50   ` Ardelean, Alexandru
  2 siblings, 2 replies; 16+ messages in thread
From: Lars-Peter Clausen @ 2020-03-17 20:33 UTC (permalink / raw)
  To: Alexandru Lazar, linux-iio; +Cc: jic23, knaack.h, pmeerw, robh+dt, mark.rutland

On 3/17/20 9:17 PM, Alexandru Lazar wrote:
> Add driver for the Maxim MAX1241 12-bit, single-channel ADC. The driver
> includes support for this device's low-power operation mode.
> 
> Signed-off-by: Alexandru Lazar <alazar@startmail.com>

Hi,

Looks very good, small clean driver. Few comments inline

> ---
>   drivers/iio/adc/Kconfig   |  12 +++
>   drivers/iio/adc/Makefile  |   1 +
>   drivers/iio/adc/max1241.c | 215 ++++++++++++++++++++++++++++++++++++++
>   3 files changed, 228 insertions(+)
>   create mode 100644 drivers/iio/adc/max1241.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 5d8540b7b427..3a55beec69c9 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -566,6 +566,18 @@ config MAX1118
>   	  To compile this driver as a module, choose M here: the module will be
>   	  called max1118.
>   
> +config MAX1241
> +	tristate "Maxim max1241 ADC driver"
> +	depends on SPI

depends on SPI_MASTER

There is also SPI_SLAVE support no in the kernel and just SPI does not 
imply SPI_MASTER.

> +	select IIO_BUFFER
> +	select IIO_TRIGGERED_BUFFER
> +	help
> +	  Say yes here to build support for Maxim max1241 12-bit, single-channel
> +          ADC.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called max1118.
> +
> diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
> new file mode 100644
> index 000000000000..2bd31f22fb2c
> --- /dev/null
> +++ b/drivers/iio/adc/max1241.c
> @@ -0,0 +1,215 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * MAX1241 low-power, 12-bit serial ADC
> + *
> + * Copyright (c) 2020 Ioan-Alexandru Lazar <alazar@startmail.com>
> + *
> + * This file is subject to the terms and conditions of version 2 of
> + * the GNU General Public License.  See the file COPYING in the main
> + * directory of this archive for more details.
> + *
> + * Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf
> + */
> +
> +#include <linux/regulator/consumer.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/gpio.h>

Probably only needs the gpio/consumer.h, but not the other two gpio 
includes.

> +#include <linux/iio/iio.h>
> +#include <linux/module.h>
> +#include <linux/spi/spi.h>
> +
> [...]
> +
> +static int max1241_read(struct max1241 *adc)
> +{
> +	int ret;
> +	struct spi_device *spi = adc->spi;

I'd go without the spi variable here and just use adc->spi directly when 
calling spi_sync_transfer().

> +	struct spi_transfer xfers[] = {
> +		/*
> +		 * Begin conversion by bringing /CS low for at least
> +		 * tconv us.
> +		 */
> +		{
> +			.len = 0,
> +			.delay_usecs = 8,
> +		},
> +		/*
> +		 * Then read two bytes of data in our RX buffer.
> +		 */
> +		{
> +			.rx_buf = &adc->data,
> +			.len = 2,
> +		},
> +	};
> +
> +	ret = spi_sync_transfer(spi, xfers, 2);

ARRAY_SIZE(xfers) instead of 2.

Maybe also directly 'return spi_sync_transfer()'.

> +
> +	return ret;
> +}
> [...]
> +static int max1241_probe(struct spi_device *spi)
> +{
> +	struct iio_dev *indio_dev;
> +	struct max1241 *adc;
> +	int ret = 0;
> +
> +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	adc = iio_priv(indio_dev);
> +	adc->spi = spi;
> +	mutex_init(&adc->lock);
> +
> +	spi_set_drvdata(spi, indio_dev);
> +
> +	adc->reg = devm_regulator_get(&spi->dev, "vref");
> +	if (IS_ERR(adc->reg)) {
> +		dev_err(&spi->dev, "failed to get vref regulator\n");
> +		return PTR_ERR(adc->reg);
> +	}
> +
> +	ret = regulator_enable(adc->reg);
> +	if (ret)
> +		return ret;
> +
> +	adc->shdn = devm_gpiod_get_optional(&spi->dev, "shdn", GPIOD_OUT_HIGH);

Makes sense to check for IS_ERR(adc->shdn) here and return if there is 
an error. This allows you to handle both probe deferral as well as if 
there is a mistake in the GPIO specification in the devicetree.

> +	if (!adc->shdn)
> +		dev_info(&spi->dev, "no shdn pin passed, low-power mode disabled");
> +	else
> +		dev_info(&spi->dev, "shdn pin passed, low-power mode enabled");

I can see how these message above are useful during development, but I'd 
remove them or turn them into dev_dbg() for the "production" version of 
the driver. Imagine every driver printed something like this, there 
would be a lot of spam in the bootlog.

> +
> +	indio_dev->name = spi_get_device_id(spi)->name;
> +	indio_dev->dev.parent = &spi->dev;
> +	indio_dev->info = &max1241_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = max1241_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(max1241_channels);
> +
> +	ret = iio_device_register(indio_dev);
> +
> +	return ret;

I'd go with just "return iio_device_register()".

> +}
> +
> +static int max1241_remove(struct spi_device *spi)
> +{
> +	struct iio_dev *indio_dev = spi_get_drvdata(spi);
> +	struct max1241 *adc = iio_priv(indio_dev);
> +	int ret = 0;
> +
> +	iio_device_unregister(indio_dev);
> +	ret = regulator_disable(adc->reg);
> +
> +	return ret;

Remove can't really fail, the return type is only int for historic 
reasons. The function should always return 0.

> +}


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-17 20:33   ` Lars-Peter Clausen
@ 2020-03-17 20:40     ` Lars-Peter Clausen
  2020-03-17 21:28     ` Alexandru Lazar
  1 sibling, 0 replies; 16+ messages in thread
From: Lars-Peter Clausen @ 2020-03-17 20:40 UTC (permalink / raw)
  To: Alexandru Lazar, linux-iio; +Cc: jic23, knaack.h, pmeerw, robh+dt, mark.rutland

On 3/17/20 9:33 PM, Lars-Peter Clausen wrote:
> On 3/17/20 9:17 PM, Alexandru Lazar wrote:
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 5d8540b7b427..3a55beec69c9 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -566,6 +566,18 @@ config MAX1118
>>         To compile this driver as a module, choose M here: the module 
>> will be
>>         called max1118.
>> +config MAX1241
>> +    tristate "Maxim max1241 ADC driver"
>> +    depends on SPI
> 
> depends on SPI_MASTER
> 
> There is also SPI_SLAVE support no in the kernel and just SPI does not 
> imply SPI_MASTER.

Sorry, that is of course not true. SPI does imply SPI_MASTER. Still 
SPI_MASTER is the correct dependency here.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-17 20:17 ` [PATCH 1/2] iio: adc: Add " Alexandru Lazar
  2020-03-17 20:33   ` Lars-Peter Clausen
@ 2020-03-17 21:03   ` Lars-Peter Clausen
  2020-03-18  6:50   ` Ardelean, Alexandru
  2 siblings, 0 replies; 16+ messages in thread
From: Lars-Peter Clausen @ 2020-03-17 21:03 UTC (permalink / raw)
  To: Alexandru Lazar, linux-iio; +Cc: jic23, knaack.h, pmeerw, robh+dt, mark.rutland

On 3/17/20 9:17 PM, Alexandru Lazar wrote:

> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -566,6 +566,18 @@ config MAX1118
>   	  To compile this driver as a module, choose M here: the module will be
>   	  called max1118.
>   
> +config MAX1241
> +	tristate "Maxim max1241 ADC driver"
> +	depends on SPI
> +	select IIO_BUFFER
> +	select IIO_TRIGGERED_BUFFER

One more bit.

Your driver currently does not support buffered mode, so the two select 
statements above are not required.

> +	help
> +	  Say yes here to build support for Maxim max1241 12-bit, single-channel
> +          ADC.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called max1118.
> +
>   config MAX1363
>   	tristate "Maxim max1363 ADC driver"
>   	depends on I2C

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-17 20:33   ` Lars-Peter Clausen
  2020-03-17 20:40     ` Lars-Peter Clausen
@ 2020-03-17 21:28     ` Alexandru Lazar
  2020-03-17 21:40       ` Lars-Peter Clausen
  1 sibling, 1 reply; 16+ messages in thread
From: Alexandru Lazar @ 2020-03-17 21:28 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: linux-iio, jic23, knaack.h, pmeerw, robh+dt, mark.rutland

Hi Lars,

Thank you very much for your comments! I'll send a version with the
fixes in a day or two (ar as soon as there's no more feedback, anyways)
-- in the meantime I have a question about this one:

> > +	if (!adc->shdn)
> > +		dev_info(&spi->dev, "no shdn pin passed, low-power mode disabled");
> > +	else
> > +		dev_info(&spi->dev, "shdn pin passed, low-power mode enabled");
> 
> I can see how these message above are useful during development, but I'd
> remove them or turn them into dev_dbg() for the "production" version of the
> driver. Imagine every driver printed something like this, there would be a
> lot of spam in the bootlog.

I thought this should go under info, rather than debug, because it's
(possibly) relevant runtime information. It doesn't require any action,
but it's something that a user of this driver may want to be aware
of. The timing (and power consumption, of course) in low-power mode are
different. It's akin to e.g.:

./at91_adc.c:782: dev_info(&idev->dev, "Resolution used: %u bits\n", st->res);
./at91_adc.c:842: dev_info(dev, "ADC Touch screen is disabled.\n");
./at91_adc.c:955: dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");

or:

./ti-ads124s08.c:320: dev_info(&spi->dev, "Reset GPIO not defined\n");

which is why I figured I'd do the same in my code (what can I say, I
wear my code monkey badge with pride!).

Needless to say, since you've seen more IIO subsystem drivers than I've
seen, I totally trust your assessment of whether this is debug or info
more than I trust mine. If this was a false positive on your "looks like
a leftover debug message", let me know (and while I'm at it I might make
the message more useful/friendly...). Otherwise it'll get bumped down to
dev_dbg in my next revision.

Thanks,
Alex

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-17 21:28     ` Alexandru Lazar
@ 2020-03-17 21:40       ` Lars-Peter Clausen
  0 siblings, 0 replies; 16+ messages in thread
From: Lars-Peter Clausen @ 2020-03-17 21:40 UTC (permalink / raw)
  To: Alexandru Lazar; +Cc: linux-iio, jic23, knaack.h, pmeerw, robh+dt, mark.rutland

On 3/17/20 10:28 PM, Alexandru Lazar wrote:
> Hi Lars,
> 
> Thank you very much for your comments! I'll send a version with the
> fixes in a day or two (ar as soon as there's no more feedback, anyways)
> -- in the meantime I have a question about this one:
> 
>>> +	if (!adc->shdn)
>>> +		dev_info(&spi->dev, "no shdn pin passed, low-power mode disabled");
>>> +	else
>>> +		dev_info(&spi->dev, "shdn pin passed, low-power mode enabled");
>>
>> I can see how these message above are useful during development, but I'd
>> remove them or turn them into dev_dbg() for the "production" version of the
>> driver. Imagine every driver printed something like this, there would be a
>> lot of spam in the bootlog.
> 
> I thought this should go under info, rather than debug, because it's
> (possibly) relevant runtime information. It doesn't require any action,
> but it's something that a user of this driver may want to be aware
> of. The timing (and power consumption, of course) in low-power mode are
> different. It's akin to e.g.:
> 
> ./at91_adc.c:782: dev_info(&idev->dev, "Resolution used: %u bits\n", st->res);
> ./at91_adc.c:842: dev_info(dev, "ADC Touch screen is disabled.\n");
> ./at91_adc.c:955: dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
> 
> or:
> 
> ./ti-ads124s08.c:320: dev_info(&spi->dev, "Reset GPIO not defined\n");
> 
> which is why I figured I'd do the same in my code (what can I say, I
> wear my code monkey badge with pride!).
> 
> Needless to say, since you've seen more IIO subsystem drivers than I've
> seen, I totally trust your assessment of whether this is debug or info
> more than I trust mine. If this was a false positive on your "looks like
> a leftover debug message", let me know (and while I'm at it I might make
> the message more useful/friendly...). Otherwise it'll get bumped down to
> dev_dbg in my next revision.

If I was to write this driver I would not make it dev_info(). In my 
opinion drivers should only print essential information during probe, 
like when something goes wrong. Otherwise the boot log gets very noisy 
quickly.

- Lars

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-17 20:17 ` [PATCH 1/2] iio: adc: Add " Alexandru Lazar
  2020-03-17 20:33   ` Lars-Peter Clausen
  2020-03-17 21:03   ` Lars-Peter Clausen
@ 2020-03-18  6:50   ` Ardelean, Alexandru
  2020-03-18  9:14     ` Alexandru Lazar
                       ` (2 more replies)
  2 siblings, 3 replies; 16+ messages in thread
From: Ardelean, Alexandru @ 2020-03-18  6:50 UTC (permalink / raw)
  To: alazar@startmail.com, linux-iio@vger.kernel.org
  Cc: jic23@kernel.org, mark.rutland@arm.com, knaack.h@gmx.de,
	lars@metafoo.de, pmeerw@pmeerw.net, robh+dt@kernel.org

On Tue, 2020-03-17 at 22:17 +0200, Alexandru Lazar wrote:
> [External]
> 
> Add driver for the Maxim MAX1241 12-bit, single-channel ADC. The driver
> includes support for this device's low-power operation mode.

hey,

overall looks good;

i'd run ./scripts/checpatch.pl on the patches a bit;
you can run it on the patch file, or on the git commit with
./scripts/checpatch.pl -g <git-commits>

i usually do ./scripts/checpatch.pl -g HEAD~2.. [or something like that] before
generating patches;
i sometimes forget to do that;  

some more comments inline


> 
> Signed-off-by: Alexandru Lazar <alazar@startmail.com>
> ---
>  drivers/iio/adc/Kconfig   |  12 +++
>  drivers/iio/adc/Makefile  |   1 +
>  drivers/iio/adc/max1241.c | 215 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 228 insertions(+)
>  create mode 100644 drivers/iio/adc/max1241.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 5d8540b7b427..3a55beec69c9 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -566,6 +566,18 @@ config MAX1118
>  	  To compile this driver as a module, choose M here: the module will be
>  	  called max1118.
>  
> +config MAX1241
> +	tristate "Maxim max1241 ADC driver"
> +	depends on SPI
> +	select IIO_BUFFER
> +	select IIO_TRIGGERED_BUFFER
> +	help
> +	  Say yes here to build support for Maxim max1241 12-bit, single-channel
> +          ADC.

nitpick: this looks inconsistently indented

> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called max1118.
> +
>  config MAX1363
>  	tristate "Maxim max1363 ADC driver"
>  	depends on I2C
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index a1f1fbec0f87..37d6f17559dc 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -54,6 +54,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o
>  obj-$(CONFIG_MAX1027) += max1027.o
>  obj-$(CONFIG_MAX11100) += max11100.o
>  obj-$(CONFIG_MAX1118) += max1118.o
> +obj-$(CONFIG_MAX1241) += max1241.o
>  obj-$(CONFIG_MAX1363) += max1363.o
>  obj-$(CONFIG_MAX9611) += max9611.o
>  obj-$(CONFIG_MCP320X) += mcp320x.o
> diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
> new file mode 100644
> index 000000000000..2bd31f22fb2c
> --- /dev/null
> +++ b/drivers/iio/adc/max1241.c
> @@ -0,0 +1,215 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * MAX1241 low-power, 12-bit serial ADC
> + *
> + * Copyright (c) 2020 Ioan-Alexandru Lazar <alazar@startmail.com>
> + *
> + * This file is subject to the terms and conditions of version 2 of
> + * the GNU General Public License.  See the file COPYING in the main
> + * directory of this archive for more details.

This license text is no longer needed.
The SPDX-License-Identifier header should handle that.

> + *
> + * Datasheet: 
> https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf
> + */
> +
> +#include <linux/regulator/consumer.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/gpio.h>
> +#include <linux/iio/iio.h>
> +#include <linux/module.h>
> +#include <linux/spi/spi.h>
> +
> +#define MAX1241_VAL_MASK 0xFFF
> +#define MAX1241_SHDN_DELAY_USEC 4
> +
> +enum max1241_id {
> +	max1241,
> +};
> +
> +struct max1241 {
> +	struct spi_device *spi;
> +	struct mutex lock;
> +	struct regulator *reg;
> +	struct gpio_desc *shdn;
> +
> +	__be16 data ____cacheline_aligned;

Jonathan may know better than me here, but you could technically avoid needing
to explicitly use the __be16 datatype; and just use u16;

i think the SPI framework should have some handling for that;
maybe using the 'bits_per_word' field;
you'd probably still need to do the shifting though;
i remember some discussion about this on ad7949.c
though there may be other drivers doing this as well

though, this isn't a big deal; and i don't feel strongly about doing like this
or some other way;
this comment tries to be more informative [or just noisy]


> +};
> +
> +static const struct iio_chan_spec max1241_channels[] = {
> +	{
> +		.type = IIO_VOLTAGE,
> +		.indexed = 1,
> +		.channel = 0,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> +				BIT(IIO_CHAN_INFO_SCALE),
> +		.scan_index = 0,
> +		.scan_type = {
> +			.sign = 'u',
> +			.realbits = 12,
> +			.storagebits = 16,
> +		},
> +	},
> +};
> +
> +static int max1241_read(struct max1241 *adc)
> +{
> +	int ret;
> +	struct spi_device *spi = adc->spi;
> +	struct spi_transfer xfers[] = {
> +		/*
> +		 * Begin conversion by bringing /CS low for at least
> +		 * tconv us.
> +		 */
> +		{
> +			.len = 0,
> +			.delay_usecs = 8,

'delay_usecs' is going to go away.
Can you change this to?
.delay.value = 8,
.delay.unit = SPI_DELAY_UNIT_USECS.

SPI_DELAY_UNIT_USECS is 0, so if you don't assign it's fine, but it's a good
idea to assign it, to make it clear it's usecs



> +		},
> +		/*
> +		 * Then read two bytes of data in our RX buffer.
> +		 */
> +		{
> +			.rx_buf = &adc->data,
> +			.len = 2,
> +		},
> +	};
> +
> +	ret = spi_sync_transfer(spi, xfers, 2);
> +
> +	return ret;
> +}
> +
> +static int max1241_read_raw(struct iio_dev *indio_dev,
> +			struct iio_chan_spec const *chan,
> +			int *val, int *val2, long mask)
> +{
> +	int ret, vref_uV;
> +	struct max1241 *adc = iio_priv(indio_dev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		mutex_lock(&adc->lock);
> +
> +		if (adc->shdn) {
> +			gpiod_set_value(adc->shdn, 0);
> +			udelay(MAX1241_SHDN_DELAY_USEC);
> +		}
> +
> +		ret = max1241_read(adc);
> +
> +		if (adc->shdn)
> +			gpiod_set_value(adc->shdn, 1);
> +
> +		if (ret) {
> +			mutex_unlock(&adc->lock);
> +			return ret;
> +		}
> +
> +		*val = (be16_to_cpu(adc->data) >> 3) & MAX1241_VAL_MASK;
> +
> +		mutex_unlock(&adc->lock);
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_SCALE:
> +		vref_uV = regulator_get_voltage(adc->reg);
> +
> +		if (vref_uV < 0)
> +			return vref_uV;
> +
> +		*val = vref_uV / 1000;
> +		*val2 = 12;
> +
> +		return IIO_VAL_FRACTIONAL_LOG2;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct iio_info max1241_info = {
> +	.read_raw = max1241_read_raw,
> +};
> +
> +static int max1241_probe(struct spi_device *spi)
> +{
> +	struct iio_dev *indio_dev;
> +	struct max1241 *adc;
> +	int ret = 0;
> +
> +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	adc = iio_priv(indio_dev);
> +	adc->spi = spi;
> +	mutex_init(&adc->lock);
> +
> +	spi_set_drvdata(spi, indio_dev);
> +
> +	adc->reg = devm_regulator_get(&spi->dev, "vref");
> +	if (IS_ERR(adc->reg)) {
> +		dev_err(&spi->dev, "failed to get vref regulator\n");
> +		return PTR_ERR(adc->reg);
> +	}
> +
> +	ret = regulator_enable(adc->reg);
> +	if (ret)
> +		return ret;
> +

[1]

> +	adc->shdn = devm_gpiod_get_optional(&spi->dev, "shdn", GPIOD_OUT_HIGH);
> +	if (!adc->shdn)
> +		dev_info(&spi->dev, "no shdn pin passed, low-power mode
> disabled");
> +	else
> +		dev_info(&spi->dev, "shdn pin passed, low-power mode enabled");
> +
> +	indio_dev->name = spi_get_device_id(spi)->name;
> +	indio_dev->dev.parent = &spi->dev;
> +	indio_dev->info = &max1241_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = max1241_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(max1241_channels);
> +
> +	ret = iio_device_register(indio_dev);

This should disable the regulator on the error path.
if (ret) {
     regulator_disable(adc->reg);
     return ret;
}

return 0;

Though, I would argue in favor of adding a devm_add_action_or_reset() callback
to disable the regulator on error & remove.
This should be placed at [1]

Example:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/iio/light/isl29018.c#n762

I've started to grow quite fond of these type of callbacks.
For one part, you can remove the 'remove' part of the driver.
On another part you can do neat stuff to simplify/reduce error paths in probe.
We typically suggest these during our internal reviews.


> +
> +	return ret;
> +}
> +
> +static int max1241_remove(struct spi_device *spi)
> +{
> +	struct iio_dev *indio_dev = spi_get_drvdata(spi);
> +	struct max1241 *adc = iio_priv(indio_dev);
> +	int ret = 0;
> +
> +	iio_device_unregister(indio_dev);
> +	ret = regulator_disable(adc->reg);
> +
> +	return ret;
> +}
> +
> +static const struct spi_device_id max1241_id[] = {
> +	{ "max1241", max1241 },
> +	{},
> +};
> +
> +#ifdef CONFIG_OF

i'd remove this CONFIG_OF
i guess this was copied from max1118.c
see [2]

> +
> +static const struct of_device_id max1241_dt_ids[] = {
> +	{ .compatible = "maxim,max1241" },

the datasheet mentions also max1240
you could add that to the list as well
typically, it's a good idea, since some people get hung-up on the naming [which
is not a bad idea]
so, if you add max1240 to this list, the driver officially supports both max1240
& max1241
 

> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, max1241_dt_ids);
> +
> +#endif
> +
> +static struct spi_driver max1241_spi_driver = {
> +	.driver = {
> +		.name = "max1241",
> +		.of_match_table = of_match_ptr(max1241_dt_ids),

[2]
i'd remove of_match_ptr() and make it just

.of_match_table = max1241_dt_ids,

there's this code in the kernel that parses of_match_table for ACPI as well;
might as well allow it to work

> +	},
> +	.probe = max1241_probe,
> +	.remove = max1241_remove,
> +	.id_table = max1241_id,
> +};
> +module_spi_driver(max1241_spi_driver);
> +
> +MODULE_AUTHOR("Alexandru Lazar <alazar@startmail.com>");
> +MODULE_DESCRIPTION("MAX1241 ADC driver");
> +MODULE_LICENSE("GPL v2");

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-18  6:50   ` Ardelean, Alexandru
@ 2020-03-18  9:14     ` Alexandru Lazar
  2020-03-18  9:31     ` Lars-Peter Clausen
  2020-03-18 16:00     ` Rohit Sarkar
  2 siblings, 0 replies; 16+ messages in thread
From: Alexandru Lazar @ 2020-03-18  9:14 UTC (permalink / raw)
  To: Ardelean, Alexandru
  Cc: linux-iio@vger.kernel.org, jic23@kernel.org, mark.rutland@arm.com,
	knaack.h@gmx.de, lars@metafoo.de, pmeerw@pmeerw.net,
	robh+dt@kernel.org

Hey,

Thanks for the comments! I'll make the changes that you suggested!

I did run checkpatch.pl -- the only thing it complained about was
that the length of a line in the commit message was too long, and I
don't think I can do anything about it because the line in question is a
file path :-).

otoh I definitely didn't do dt_binding_check, I had no idea that was a
thing. I'll run it and integrate any necessary changes in the revised
version. Thanks!

Best regards,
Alex

On Wed, Mar 18, 2020 at 06:50:41AM +0000, Ardelean, Alexandru wrote:
> On Tue, 2020-03-17 at 22:17 +0200, Alexandru Lazar wrote:
> > [External]
> > 
> > Add driver for the Maxim MAX1241 12-bit, single-channel ADC. The driver
> > includes support for this device's low-power operation mode.
> 
> hey,
> 
> overall looks good;
> 
> i'd run ./scripts/checpatch.pl on the patches a bit;
> you can run it on the patch file, or on the git commit with
> ./scripts/checpatch.pl -g <git-commits>
> 
> i usually do ./scripts/checpatch.pl -g HEAD~2.. [or something like that] before
> generating patches;
> i sometimes forget to do that;  
> 
> some more comments inline
> 
> 
> > 
> > Signed-off-by: Alexandru Lazar <alazar@startmail.com>
> > ---
> >  drivers/iio/adc/Kconfig   |  12 +++
> >  drivers/iio/adc/Makefile  |   1 +
> >  drivers/iio/adc/max1241.c | 215 ++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 228 insertions(+)
> >  create mode 100644 drivers/iio/adc/max1241.c
> > 
> > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> > index 5d8540b7b427..3a55beec69c9 100644
> > --- a/drivers/iio/adc/Kconfig
> > +++ b/drivers/iio/adc/Kconfig
> > @@ -566,6 +566,18 @@ config MAX1118
> >  	  To compile this driver as a module, choose M here: the module will be
> >  	  called max1118.
> >  
> > +config MAX1241
> > +	tristate "Maxim max1241 ADC driver"
> > +	depends on SPI
> > +	select IIO_BUFFER
> > +	select IIO_TRIGGERED_BUFFER
> > +	help
> > +	  Say yes here to build support for Maxim max1241 12-bit, single-channel
> > +          ADC.
> 
> nitpick: this looks inconsistently indented
> 
> > +
> > +	  To compile this driver as a module, choose M here: the module will be
> > +	  called max1118.
> > +
> >  config MAX1363
> >  	tristate "Maxim max1363 ADC driver"
> >  	depends on I2C
> > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> > index a1f1fbec0f87..37d6f17559dc 100644
> > --- a/drivers/iio/adc/Makefile
> > +++ b/drivers/iio/adc/Makefile
> > @@ -54,6 +54,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o
> >  obj-$(CONFIG_MAX1027) += max1027.o
> >  obj-$(CONFIG_MAX11100) += max11100.o
> >  obj-$(CONFIG_MAX1118) += max1118.o
> > +obj-$(CONFIG_MAX1241) += max1241.o
> >  obj-$(CONFIG_MAX1363) += max1363.o
> >  obj-$(CONFIG_MAX9611) += max9611.o
> >  obj-$(CONFIG_MCP320X) += mcp320x.o
> > diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
> > new file mode 100644
> > index 000000000000..2bd31f22fb2c
> > --- /dev/null
> > +++ b/drivers/iio/adc/max1241.c
> > @@ -0,0 +1,215 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * MAX1241 low-power, 12-bit serial ADC
> > + *
> > + * Copyright (c) 2020 Ioan-Alexandru Lazar <alazar@startmail.com>
> > + *
> > + * This file is subject to the terms and conditions of version 2 of
> > + * the GNU General Public License.  See the file COPYING in the main
> > + * directory of this archive for more details.
> 
> This license text is no longer needed.
> The SPDX-License-Identifier header should handle that.
> 
> > + *
> > + * Datasheet: 
> > https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf
> > + */
> > +
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/delay.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/gpio/driver.h>
> > +#include <linux/gpio.h>
> > +#include <linux/iio/iio.h>
> > +#include <linux/module.h>
> > +#include <linux/spi/spi.h>
> > +
> > +#define MAX1241_VAL_MASK 0xFFF
> > +#define MAX1241_SHDN_DELAY_USEC 4
> > +
> > +enum max1241_id {
> > +	max1241,
> > +};
> > +
> > +struct max1241 {
> > +	struct spi_device *spi;
> > +	struct mutex lock;
> > +	struct regulator *reg;
> > +	struct gpio_desc *shdn;
> > +
> > +	__be16 data ____cacheline_aligned;
> 
> Jonathan may know better than me here, but you could technically avoid needing
> to explicitly use the __be16 datatype; and just use u16;
> 
> i think the SPI framework should have some handling for that;
> maybe using the 'bits_per_word' field;
> you'd probably still need to do the shifting though;
> i remember some discussion about this on ad7949.c
> though there may be other drivers doing this as well
> 
> though, this isn't a big deal; and i don't feel strongly about doing like this
> or some other way;
> this comment tries to be more informative [or just noisy]
> 
> 
> > +};
> > +
> > +static const struct iio_chan_spec max1241_channels[] = {
> > +	{
> > +		.type = IIO_VOLTAGE,
> > +		.indexed = 1,
> > +		.channel = 0,
> > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> > +				BIT(IIO_CHAN_INFO_SCALE),
> > +		.scan_index = 0,
> > +		.scan_type = {
> > +			.sign = 'u',
> > +			.realbits = 12,
> > +			.storagebits = 16,
> > +		},
> > +	},
> > +};
> > +
> > +static int max1241_read(struct max1241 *adc)
> > +{
> > +	int ret;
> > +	struct spi_device *spi = adc->spi;
> > +	struct spi_transfer xfers[] = {
> > +		/*
> > +		 * Begin conversion by bringing /CS low for at least
> > +		 * tconv us.
> > +		 */
> > +		{
> > +			.len = 0,
> > +			.delay_usecs = 8,
> 
> 'delay_usecs' is going to go away.
> Can you change this to?
> .delay.value = 8,
> .delay.unit = SPI_DELAY_UNIT_USECS.
> 
> SPI_DELAY_UNIT_USECS is 0, so if you don't assign it's fine, but it's a good
> idea to assign it, to make it clear it's usecs
> 
> 
> 
> > +		},
> > +		/*
> > +		 * Then read two bytes of data in our RX buffer.
> > +		 */
> > +		{
> > +			.rx_buf = &adc->data,
> > +			.len = 2,
> > +		},
> > +	};
> > +
> > +	ret = spi_sync_transfer(spi, xfers, 2);
> > +
> > +	return ret;
> > +}
> > +
> > +static int max1241_read_raw(struct iio_dev *indio_dev,
> > +			struct iio_chan_spec const *chan,
> > +			int *val, int *val2, long mask)
> > +{
> > +	int ret, vref_uV;
> > +	struct max1241 *adc = iio_priv(indio_dev);
> > +
> > +	switch (mask) {
> > +	case IIO_CHAN_INFO_RAW:
> > +		mutex_lock(&adc->lock);
> > +
> > +		if (adc->shdn) {
> > +			gpiod_set_value(adc->shdn, 0);
> > +			udelay(MAX1241_SHDN_DELAY_USEC);
> > +		}
> > +
> > +		ret = max1241_read(adc);
> > +
> > +		if (adc->shdn)
> > +			gpiod_set_value(adc->shdn, 1);
> > +
> > +		if (ret) {
> > +			mutex_unlock(&adc->lock);
> > +			return ret;
> > +		}
> > +
> > +		*val = (be16_to_cpu(adc->data) >> 3) & MAX1241_VAL_MASK;
> > +
> > +		mutex_unlock(&adc->lock);
> > +		return IIO_VAL_INT;
> > +	case IIO_CHAN_INFO_SCALE:
> > +		vref_uV = regulator_get_voltage(adc->reg);
> > +
> > +		if (vref_uV < 0)
> > +			return vref_uV;
> > +
> > +		*val = vref_uV / 1000;
> > +		*val2 = 12;
> > +
> > +		return IIO_VAL_FRACTIONAL_LOG2;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static const struct iio_info max1241_info = {
> > +	.read_raw = max1241_read_raw,
> > +};
> > +
> > +static int max1241_probe(struct spi_device *spi)
> > +{
> > +	struct iio_dev *indio_dev;
> > +	struct max1241 *adc;
> > +	int ret = 0;
> > +
> > +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
> > +	if (!indio_dev)
> > +		return -ENOMEM;
> > +
> > +	adc = iio_priv(indio_dev);
> > +	adc->spi = spi;
> > +	mutex_init(&adc->lock);
> > +
> > +	spi_set_drvdata(spi, indio_dev);
> > +
> > +	adc->reg = devm_regulator_get(&spi->dev, "vref");
> > +	if (IS_ERR(adc->reg)) {
> > +		dev_err(&spi->dev, "failed to get vref regulator\n");
> > +		return PTR_ERR(adc->reg);
> > +	}
> > +
> > +	ret = regulator_enable(adc->reg);
> > +	if (ret)
> > +		return ret;
> > +
> 
> [1]
> 
> > +	adc->shdn = devm_gpiod_get_optional(&spi->dev, "shdn", GPIOD_OUT_HIGH);
> > +	if (!adc->shdn)
> > +		dev_info(&spi->dev, "no shdn pin passed, low-power mode
> > disabled");
> > +	else
> > +		dev_info(&spi->dev, "shdn pin passed, low-power mode enabled");
> > +
> > +	indio_dev->name = spi_get_device_id(spi)->name;
> > +	indio_dev->dev.parent = &spi->dev;
> > +	indio_dev->info = &max1241_info;
> > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > +	indio_dev->channels = max1241_channels;
> > +	indio_dev->num_channels = ARRAY_SIZE(max1241_channels);
> > +
> > +	ret = iio_device_register(indio_dev);
> 
> This should disable the regulator on the error path.
> if (ret) {
>      regulator_disable(adc->reg);
>      return ret;
> }
> 
> return 0;
> 
> Though, I would argue in favor of adding a devm_add_action_or_reset() callback
> to disable the regulator on error & remove.
> This should be placed at [1]
> 
> Example:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/iio/light/isl29018.c#n762
> 
> I've started to grow quite fond of these type of callbacks.
> For one part, you can remove the 'remove' part of the driver.
> On another part you can do neat stuff to simplify/reduce error paths in probe.
> We typically suggest these during our internal reviews.
> 
> 
> > +
> > +	return ret;
> > +}
> > +
> > +static int max1241_remove(struct spi_device *spi)
> > +{
> > +	struct iio_dev *indio_dev = spi_get_drvdata(spi);
> > +	struct max1241 *adc = iio_priv(indio_dev);
> > +	int ret = 0;
> > +
> > +	iio_device_unregister(indio_dev);
> > +	ret = regulator_disable(adc->reg);
> > +
> > +	return ret;
> > +}
> > +
> > +static const struct spi_device_id max1241_id[] = {
> > +	{ "max1241", max1241 },
> > +	{},
> > +};
> > +
> > +#ifdef CONFIG_OF
> 
> i'd remove this CONFIG_OF
> i guess this was copied from max1118.c
> see [2]
> 
> > +
> > +static const struct of_device_id max1241_dt_ids[] = {
> > +	{ .compatible = "maxim,max1241" },
> 
> the datasheet mentions also max1240
> you could add that to the list as well
> typically, it's a good idea, since some people get hung-up on the naming [which
> is not a bad idea]
> so, if you add max1240 to this list, the driver officially supports both max1240
> & max1241
>  
> 
> > +	{},
> > +};
> > +MODULE_DEVICE_TABLE(of, max1241_dt_ids);
> > +
> > +#endif
> > +
> > +static struct spi_driver max1241_spi_driver = {
> > +	.driver = {
> > +		.name = "max1241",
> > +		.of_match_table = of_match_ptr(max1241_dt_ids),
> 
> [2]
> i'd remove of_match_ptr() and make it just
> 
> .of_match_table = max1241_dt_ids,
> 
> there's this code in the kernel that parses of_match_table for ACPI as well;
> might as well allow it to work
> 
> > +	},
> > +	.probe = max1241_probe,
> > +	.remove = max1241_remove,
> > +	.id_table = max1241_id,
> > +};
> > +module_spi_driver(max1241_spi_driver);
> > +
> > +MODULE_AUTHOR("Alexandru Lazar <alazar@startmail.com>");
> > +MODULE_DESCRIPTION("MAX1241 ADC driver");
> > +MODULE_LICENSE("GPL v2");

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-18  6:50   ` Ardelean, Alexandru
  2020-03-18  9:14     ` Alexandru Lazar
@ 2020-03-18  9:31     ` Lars-Peter Clausen
  2020-03-18  9:54       ` Ardelean, Alexandru
  2020-03-18 16:00     ` Rohit Sarkar
  2 siblings, 1 reply; 16+ messages in thread
From: Lars-Peter Clausen @ 2020-03-18  9:31 UTC (permalink / raw)
  To: Ardelean, Alexandru, alazar@startmail.com,
	linux-iio@vger.kernel.org
  Cc: jic23@kernel.org, mark.rutland@arm.com, knaack.h@gmx.de,
	pmeerw@pmeerw.net, robh+dt@kernel.org

On 3/18/20 7:50 AM, Ardelean, Alexandru wrote:
> On Tue, 2020-03-17 at 22:17 +0200, Alexandru Lazar wrote:
>> [External]
>>
>> Add driver for the Maxim MAX1241 12-bit, single-channel ADC. The driver
>> includes support for this device's low-power operation mode.
> 
> hey,
> 
> overall looks good;
> 
> i'd run ./scripts/checpatch.pl on the patches a bit;
> you can run it on the patch file, or on the git commit with
> ./scripts/checpatch.pl -g <git-commits>
> 
> i usually do ./scripts/checpatch.pl -g HEAD~2.. [or something like that] before
> generating patches;
> i sometimes forget to do that;
> 
> some more comments inline
> 
> 
>>
>> Signed-off-by: Alexandru Lazar <alazar@startmail.com>
>> ---
>>   drivers/iio/adc/Kconfig   |  12 +++
>>   drivers/iio/adc/Makefile  |   1 +
>>   drivers/iio/adc/max1241.c | 215 ++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 228 insertions(+)
>>   create mode 100644 drivers/iio/adc/max1241.c
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 5d8540b7b427..3a55beec69c9 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -566,6 +566,18 @@ config MAX1118
>>   	  To compile this driver as a module, choose M here: the module will be
>>   	  called max1118.
>>   
>> +config MAX1241
>> +	tristate "Maxim max1241 ADC driver"
>> +	depends on SPI
>> +	select IIO_BUFFER
>> +	select IIO_TRIGGERED_BUFFER
>> +	help
>> +	  Say yes here to build support for Maxim max1241 12-bit, single-channel
>> +          ADC.
> 
> nitpick: this looks inconsistently indented
> 
>> +
>> +	  To compile this driver as a module, choose M here: the module will be
>> +	  called max1118.
>> +
>>   config MAX1363
>>   	tristate "Maxim max1363 ADC driver"
>>   	depends on I2C
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index a1f1fbec0f87..37d6f17559dc 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -54,6 +54,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o
>>   obj-$(CONFIG_MAX1027) += max1027.o
>>   obj-$(CONFIG_MAX11100) += max11100.o
>>   obj-$(CONFIG_MAX1118) += max1118.o
>> +obj-$(CONFIG_MAX1241) += max1241.o
>>   obj-$(CONFIG_MAX1363) += max1363.o
>>   obj-$(CONFIG_MAX9611) += max9611.o
>>   obj-$(CONFIG_MCP320X) += mcp320x.o
>> diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
>> new file mode 100644
>> index 000000000000..2bd31f22fb2c
>> --- /dev/null
>> +++ b/drivers/iio/adc/max1241.c
>> @@ -0,0 +1,215 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * MAX1241 low-power, 12-bit serial ADC
>> + *
>> + * Copyright (c) 2020 Ioan-Alexandru Lazar <alazar@startmail.com>
>> + *
>> + * This file is subject to the terms and conditions of version 2 of
>> + * the GNU General Public License.  See the file COPYING in the main
>> + * directory of this archive for more details.
> 
> This license text is no longer needed.
> The SPDX-License-Identifier header should handle that.
> 
>> + *
>> + * Datasheet:
>> https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf
>> + */
>> +
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/delay.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/gpio/driver.h>
>> +#include <linux/gpio.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/module.h>
>> +#include <linux/spi/spi.h>
>> +
>> +#define MAX1241_VAL_MASK 0xFFF
>> +#define MAX1241_SHDN_DELAY_USEC 4
>> +
>> +enum max1241_id {
>> +	max1241,
>> +};
>> +
>> +struct max1241 {
>> +	struct spi_device *spi;
>> +	struct mutex lock;
>> +	struct regulator *reg;
>> +	struct gpio_desc *shdn;
>> +
>> +	__be16 data ____cacheline_aligned;
> 
> Jonathan may know better than me here, but you could technically avoid needing
> to explicitly use the __be16 datatype; and just use u16;
> 
> i think the SPI framework should have some handling for that;
> maybe using the 'bits_per_word' field;
> you'd probably still need to do the shifting though;
> i remember some discussion about this on ad7949.c
> though there may be other drivers doing this as well

I'd keep it as it is. Which bits_per_word values are supported depends 
on the SPI master driver. All of them support 8-bit, but many don't 
support 16-bit.

- Lars

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-18  9:31     ` Lars-Peter Clausen
@ 2020-03-18  9:54       ` Ardelean, Alexandru
  0 siblings, 0 replies; 16+ messages in thread
From: Ardelean, Alexandru @ 2020-03-18  9:54 UTC (permalink / raw)
  To: alazar@startmail.com, lars@metafoo.de, linux-iio@vger.kernel.org
  Cc: jic23@kernel.org, mark.rutland@arm.com, knaack.h@gmx.de,
	pmeerw@pmeerw.net, robh+dt@kernel.org

On Wed, 2020-03-18 at 10:31 +0100, Lars-Peter Clausen wrote:
> On 3/18/20 7:50 AM, Ardelean, Alexandru wrote:
> > On Tue, 2020-03-17 at 22:17 +0200, Alexandru Lazar wrote:
> > > [External]
> > > 
> > > Add driver for the Maxim MAX1241 12-bit, single-channel ADC. The driver
> > > includes support for this device's low-power operation mode.
> > 
> > hey,
> > 
> > overall looks good;
> > 
> > i'd run ./scripts/checpatch.pl on the patches a bit;
> > you can run it on the patch file, or on the git commit with
> > ./scripts/checpatch.pl -g <git-commits>
> > 
> > i usually do ./scripts/checpatch.pl -g HEAD~2.. [or something like that]
> > before
> > generating patches;
> > i sometimes forget to do that;
> > 
> > some more comments inline
> > 
> > 
> > > Signed-off-by: Alexandru Lazar <alazar@startmail.com>
> > > ---
> > >   drivers/iio/adc/Kconfig   |  12 +++
> > >   drivers/iio/adc/Makefile  |   1 +
> > >   drivers/iio/adc/max1241.c | 215 ++++++++++++++++++++++++++++++++++++++
> > >   3 files changed, 228 insertions(+)
> > >   create mode 100644 drivers/iio/adc/max1241.c
> > > 
> > > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> > > index 5d8540b7b427..3a55beec69c9 100644
> > > --- a/drivers/iio/adc/Kconfig
> > > +++ b/drivers/iio/adc/Kconfig
> > > @@ -566,6 +566,18 @@ config MAX1118
> > >   	  To compile this driver as a module, choose M here: the module
> > > will be
> > >   	  called max1118.
> > >   
> > > +config MAX1241
> > > +	tristate "Maxim max1241 ADC driver"
> > > +	depends on SPI
> > > +	select IIO_BUFFER
> > > +	select IIO_TRIGGERED_BUFFER
> > > +	help
> > > +	  Say yes here to build support for Maxim max1241 12-bit, single-channel
> > > +          ADC.
> > 
> > nitpick: this looks inconsistently indented
> > 
> > > +
> > > +	  To compile this driver as a module, choose M here: the module will be
> > > +	  called max1118.
> > > +
> > >   config MAX1363
> > >   	tristate "Maxim max1363 ADC driver"
> > >   	depends on I2C
> > > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> > > index a1f1fbec0f87..37d6f17559dc 100644
> > > --- a/drivers/iio/adc/Makefile
> > > +++ b/drivers/iio/adc/Makefile
> > > @@ -54,6 +54,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o
> > >   obj-$(CONFIG_MAX1027) += max1027.o
> > >   obj-$(CONFIG_MAX11100) += max11100.o
> > >   obj-$(CONFIG_MAX1118) += max1118.o
> > > +obj-$(CONFIG_MAX1241) += max1241.o
> > >   obj-$(CONFIG_MAX1363) += max1363.o
> > >   obj-$(CONFIG_MAX9611) += max9611.o
> > >   obj-$(CONFIG_MCP320X) += mcp320x.o
> > > diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
> > > new file mode 100644
> > > index 000000000000..2bd31f22fb2c
> > > --- /dev/null
> > > +++ b/drivers/iio/adc/max1241.c
> > > @@ -0,0 +1,215 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * MAX1241 low-power, 12-bit serial ADC
> > > + *
> > > + * Copyright (c) 2020 Ioan-Alexandru Lazar <alazar@startmail.com>
> > > + *
> > > + * This file is subject to the terms and conditions of version 2 of
> > > + * the GNU General Public License.  See the file COPYING in the main
> > > + * directory of this archive for more details.
> > 
> > This license text is no longer needed.
> > The SPDX-License-Identifier header should handle that.
> > 
> > > + *
> > > + * Datasheet:
> > > https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf
> > > + */
> > > +
> > > +#include <linux/regulator/consumer.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/gpio/consumer.h>
> > > +#include <linux/gpio/driver.h>
> > > +#include <linux/gpio.h>
> > > +#include <linux/iio/iio.h>
> > > +#include <linux/module.h>
> > > +#include <linux/spi/spi.h>
> > > +
> > > +#define MAX1241_VAL_MASK 0xFFF
> > > +#define MAX1241_SHDN_DELAY_USEC 4
> > > +
> > > +enum max1241_id {
> > > +	max1241,
> > > +};
> > > +
> > > +struct max1241 {
> > > +	struct spi_device *spi;
> > > +	struct mutex lock;
> > > +	struct regulator *reg;
> > > +	struct gpio_desc *shdn;
> > > +
> > > +	__be16 data ____cacheline_aligned;
> > 
> > Jonathan may know better than me here, but you could technically avoid
> > needing
> > to explicitly use the __be16 datatype; and just use u16;
> > 
> > i think the SPI framework should have some handling for that;
> > maybe using the 'bits_per_word' field;
> > you'd probably still need to do the shifting though;
> > i remember some discussion about this on ad7949.c
> > though there may be other drivers doing this as well
> 
> I'd keep it as it is. Which bits_per_word values are supported depends 
> on the SPI master driver. All of them support 8-bit, but many don't 
> support 16-bit.

Fair enough.
I'm a bit vague on the details here.

> 
> - Lars

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-18  6:50   ` Ardelean, Alexandru
  2020-03-18  9:14     ` Alexandru Lazar
  2020-03-18  9:31     ` Lars-Peter Clausen
@ 2020-03-18 16:00     ` Rohit Sarkar
  2 siblings, 0 replies; 16+ messages in thread
From: Rohit Sarkar @ 2020-03-18 16:00 UTC (permalink / raw)
  To: Ardelean, Alexandru
  Cc: alazar@startmail.com, linux-iio@vger.kernel.org, jic23@kernel.org,
	mark.rutland@arm.com, knaack.h@gmx.de, lars@metafoo.de,
	pmeerw@pmeerw.net, robh+dt@kernel.org

On Wed, Mar 18, 2020 at 06:50:41AM +0000, Ardelean, Alexandru wrote:
> On Tue, 2020-03-17 at 22:17 +0200, Alexandru Lazar wrote:
> > [External]
> > 
> > Add driver for the Maxim MAX1241 12-bit, single-channel ADC. The driver
> > includes support for this device's low-power operation mode.
> 
> hey,
> 
> overall looks good;
> 
> i'd run ./scripts/checpatch.pl on the patches a bit;
> you can run it on the patch file, or on the git commit with
> ./scripts/checpatch.pl -g <git-commits>
> 
> i usually do ./scripts/checpatch.pl -g HEAD~2.. [or something like that] before
> generating patches;
> i sometimes forget to do that;  
> 
Another good idea might be to set up a post-commit hook that runs
checkpatch for you! 

Reference: Git post-commit hooks section of https://kernelnewbies.org/FirstKernelPatch

Thanks,
Rohit

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 0/2] Maxim MAX1241 driver, v2
@ 2020-03-18 20:28 Alexandru Lazar
  2020-03-18 20:28 ` [PATCH 1/2] iio: adc: Add MAX1241 driver Alexandru Lazar
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Alexandru Lazar @ 2020-03-18 20:28 UTC (permalink / raw)
  To: linux-iio
  Cc: jic23, knaack.h, lars, pmeerw, robh+dt, mark.rutland,
	Alexandru Lazar

Hello again,

Here's version 2 of a patch series which adds support for the Maxim
MAX1241, a 12-bit, single-channel, SPI-connected ADC. The previous
version is here:

https://lore.kernel.org/linux-iio/20200317201710.23180-1-alazar@startmail.com/

I've integrated pretty much all of the suggestions I got here, and fixed
the issues that you all pointed out (thanks again! Did I say thanks
lately? Thanks!!!). A short list of the changes is at the end of this
message. checkpatch.pl is happy, it just warns me about the MAINTAINERS
file, where I don't think an entry is necessary. dt_bindings_check is
happy, too.

The only suggestion that I haven't incorporated is adding max1240 to the
list of compatible devices. I've thought about it, but there are
timing-related differences between the two devices, so simply validating
what my machine sends wouldn't be definitive. I think it would be
disingenious to claim compatibility under these circumstances. I do plan
to get a 1240 asap, anyway, and with any luck my patch would just update
the compat string.

Now, here's what I changed:

* Removed useeless header includes

* Dropped needlessly verbose stuff in _read and _probe functions

* Dropped useless GPL notice

* Lowered log level of shdn pin status in probe function, now it's
  dev_dbg
  
* Added proper error checking for the GPIO shutdown pin

* remove now always returns zero (man, I've been wrong about this for
  *years* now...)
  
* Added regulator disable action, cleanup is now handled via devm

* Drop delay_usecs, use delay.value, delay.unit

* Drop config_of, of_match_ptr call

* Dropped IIO_BUFFER, IIO_TRIGGERED_BUFFER dependencies, set SPI_MASTER
  as dependency, fix indenting.
  
* DT binding: use correct id, add reg description (looks pretty
  standard), dropped spi-max-frequency, fixed dt_binding_check
  complaints (oops!)

Thanks!

Alex

Alexandru Lazar (2):
  iio: adc: Add MAX1241 driver
  dt-bindings: iio: adc: Add MAX1241 device tree bindings in
    documentation

 .../bindings/iio/adc/maxim,max1241.yaml       |  62 ++++++
 drivers/iio/adc/Kconfig                       |  10 +
 drivers/iio/adc/Makefile                      |   1 +
 drivers/iio/adc/max1241.c                     | 206 ++++++++++++++++++
 4 files changed, 279 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml
 create mode 100644 drivers/iio/adc/max1241.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-18 20:28 [PATCH 0/2] Maxim MAX1241 driver, v2 Alexandru Lazar
@ 2020-03-18 20:28 ` Alexandru Lazar
  2020-03-19  6:51   ` Ardelean, Alexandru
  2020-03-18 20:28 ` [PATCH 2/2] dt-bindings: iio: adc: Add MAX1241 device tree bindings in documentation Alexandru Lazar
  2020-03-19  7:31 ` [PATCH 0/2] Maxim MAX1241 driver, v2 Ardelean, Alexandru
  2 siblings, 1 reply; 16+ messages in thread
From: Alexandru Lazar @ 2020-03-18 20:28 UTC (permalink / raw)
  To: linux-iio
  Cc: jic23, knaack.h, lars, pmeerw, robh+dt, mark.rutland,
	Alexandru Lazar

Add driver for the Maxim MAX1241 12-bit, single-channel ADC. The driver
includes support for this device's low-power operation mode.

Signed-off-by: Alexandru Lazar <alazar@startmail.com>
---
 drivers/iio/adc/Kconfig   |  10 ++
 drivers/iio/adc/Makefile  |   1 +
 drivers/iio/adc/max1241.c | 206 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 217 insertions(+)
 create mode 100644 drivers/iio/adc/max1241.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 5d8540b7b427..4254633147af 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -566,6 +566,16 @@ config MAX1118
 	  To compile this driver as a module, choose M here: the module will be
 	  called max1118.
 
+config MAX1241
+	tristate "Maxim max1241 ADC driver"
+	depends on SPI_MASTER
+	help
+	  Say yes here to build support for Maxim max1241 12-bit, single-channel
+	  ADC.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called max1118.
+
 config MAX1363
 	tristate "Maxim max1363 ADC driver"
 	depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index a1f1fbec0f87..37d6f17559dc 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o
 obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX11100) += max11100.o
 obj-$(CONFIG_MAX1118) += max1118.o
+obj-$(CONFIG_MAX1241) += max1241.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MAX9611) += max9611.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
new file mode 100644
index 000000000000..0278510ec346
--- /dev/null
+++ b/drivers/iio/adc/max1241.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MAX1241 low-power, 12-bit serial ADC
+ *
+ * Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf
+ */
+
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#define MAX1241_VAL_MASK 0xFFF
+#define MAX1241_SHDN_DELAY_USEC 4
+
+enum max1241_id {
+	max1241,
+};
+
+struct max1241 {
+	struct spi_device *spi;
+	struct mutex lock;
+	struct regulator *reg;
+	struct gpio_desc *shdn;
+
+	__be16 data ____cacheline_aligned;
+};
+
+static const struct iio_chan_spec max1241_channels[] = {
+	{
+		.type = IIO_VOLTAGE,
+		.indexed = 1,
+		.channel = 0,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 12,
+			.storagebits = 16,
+		},
+	},
+};
+
+static int max1241_read(struct max1241 *adc)
+{
+	struct spi_transfer xfers[] = {
+		/*
+		 * Begin conversion by bringing /CS low for at least
+		 * tconv us.
+		 */
+		{
+			.len = 0,
+			.delay.value = 8,
+			.delay.unit = SPI_DELAY_UNIT_USECS,
+		},
+		/*
+		 * Then read two bytes of data in our RX buffer.
+		 */
+		{
+			.rx_buf = &adc->data,
+			.len = 2,
+		},
+	};
+
+	return spi_sync_transfer(adc->spi, xfers, ARRAY_SIZE(xfers));
+}
+
+static int max1241_read_raw(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val, int *val2, long mask)
+{
+	int ret, vref_uV;
+	struct max1241 *adc = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&adc->lock);
+
+		if (adc->shdn) {
+			gpiod_set_value(adc->shdn, 0);
+			udelay(MAX1241_SHDN_DELAY_USEC);
+		}
+
+		ret = max1241_read(adc);
+
+		if (adc->shdn)
+			gpiod_set_value(adc->shdn, 1);
+
+		if (ret) {
+			mutex_unlock(&adc->lock);
+			return ret;
+		}
+
+		*val = (be16_to_cpu(adc->data) >> 3) & MAX1241_VAL_MASK;
+
+		mutex_unlock(&adc->lock);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		vref_uV = regulator_get_voltage(adc->reg);
+
+		if (vref_uV < 0)
+			return vref_uV;
+
+		*val = vref_uV / 1000;
+		*val2 = 12;
+
+		return IIO_VAL_FRACTIONAL_LOG2;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info max1241_info = {
+	.read_raw = max1241_read_raw,
+};
+
+static void max1241_disable_reg_action(void *data)
+{
+	struct max1241 *adc = data;
+	int err;
+
+	err = regulator_disable(adc->reg);
+	if (err)
+		dev_err(&adc->spi->dev, "could not disable reference regulator.\n");
+}
+
+static int max1241_probe(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev;
+	struct max1241 *adc;
+	int ret = 0;
+
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	adc = iio_priv(indio_dev);
+	adc->spi = spi;
+	mutex_init(&adc->lock);
+
+	spi_set_drvdata(spi, indio_dev);
+
+	adc->reg = devm_regulator_get(&spi->dev, "vref");
+	if (IS_ERR(adc->reg)) {
+		dev_err(&spi->dev, "failed to get vref regulator\n");
+		return PTR_ERR(adc->reg);
+	}
+
+	ret = regulator_enable(adc->reg);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(&spi->dev, max1241_disable_reg_action,
+					adc);
+	if (ret) {
+		dev_err(&spi->dev, "could not set up regulator cleanup action!\n");
+		return ret;
+	}
+
+	adc->shdn = devm_gpiod_get_optional(&spi->dev, "shdn", GPIOD_OUT_HIGH);
+
+	if (IS_ERR(adc->shdn))
+		return PTR_ERR(adc->shdn);
+
+	if (!adc->shdn)
+		dev_dbg(&spi->dev, "no shdn pin passed, low-power mode disabled");
+	else
+		dev_dbg(&spi->dev, "shdn pin passed, low-power mode enabled");
+
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->info = &max1241_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = max1241_channels;
+	indio_dev->num_channels = ARRAY_SIZE(max1241_channels);
+
+	return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id max1241_id[] = {
+	{ "max1241", max1241 },
+	{},
+};
+
+static const struct of_device_id max1241_dt_ids[] = {
+	{ .compatible = "maxim,max1241" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, max1241_dt_ids);
+
+static struct spi_driver max1241_spi_driver = {
+	.driver = {
+		.name = "max1241",
+		.of_match_table = max1241_dt_ids,
+	},
+	.probe = max1241_probe,
+	.id_table = max1241_id,
+};
+module_spi_driver(max1241_spi_driver);
+
+MODULE_AUTHOR("Alexandru Lazar <alazar@startmail.com>");
+MODULE_DESCRIPTION("MAX1241 ADC driver");
+MODULE_LICENSE("GPL v2");
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/2] dt-bindings: iio: adc: Add MAX1241 device tree bindings in documentation
  2020-03-18 20:28 [PATCH 0/2] Maxim MAX1241 driver, v2 Alexandru Lazar
  2020-03-18 20:28 ` [PATCH 1/2] iio: adc: Add MAX1241 driver Alexandru Lazar
@ 2020-03-18 20:28 ` Alexandru Lazar
  2020-03-19  7:31 ` [PATCH 0/2] Maxim MAX1241 driver, v2 Ardelean, Alexandru
  2 siblings, 0 replies; 16+ messages in thread
From: Alexandru Lazar @ 2020-03-18 20:28 UTC (permalink / raw)
  To: linux-iio
  Cc: jic23, knaack.h, lars, pmeerw, robh+dt, mark.rutland,
	Alexandru Lazar

Add device-tree bindings documentation for the MAX1241 device driver.

Signed-off-by: Alexandru Lazar <alazar@startmail.com>
---
 .../bindings/iio/adc/maxim,max1241.yaml       | 62 +++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml

diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml
new file mode 100644
index 000000000000..28c73ed795aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright 2020 Ioan-Alexandru Lazar
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/maxim,max1241.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim MAX1241 12-bit, single-channel analog to digital converter
+
+maintainers:
+  - Ioan-Alexandru Lazar <alazar@startmail.com>
+
+description: |
+  Bindings for the max1241 12-bit, single-channel ADC device. This
+  driver supports voltage reading and can optionally be configured for
+  power-down mode operation. The datasheet can be found at:
+    https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf
+
+properties:
+  compatible:
+    enum:
+      - maxim,max1241
+
+  reg:
+    description: SPI chip select number for this device
+    maxItems: 1
+
+  vref-supply:
+    description:
+      Device tree identifier of the regulator that provides the external
+      reference voltage.
+    maxItems: 1
+
+  shdn-gpios:
+    description:
+      GPIO spec for the GPIO pin connected to the ADC's /SHDN pin. If
+      specified, the /SHDN pin will be asserted between conversions,
+      thus enabling power-down mode.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - vref-supply
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    spi0 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+        adc@0 {
+            compatible = "maxim,max1241";
+            reg = <0>;
+            vref-supply = <&vdd_3v3_reg>;
+            spi-max-frequency = <1000000>;
+            shdn-gpios = <&gpio 26 1>;
+        };
+    };
+
+
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/2] iio: adc: Add MAX1241 driver
  2020-03-18 20:28 ` [PATCH 1/2] iio: adc: Add MAX1241 driver Alexandru Lazar
@ 2020-03-19  6:51   ` Ardelean, Alexandru
  0 siblings, 0 replies; 16+ messages in thread
From: Ardelean, Alexandru @ 2020-03-19  6:51 UTC (permalink / raw)
  To: alazar@startmail.com, linux-iio@vger.kernel.org
  Cc: jic23@kernel.org, mark.rutland@arm.com, knaack.h@gmx.de,
	lars@metafoo.de, pmeerw@pmeerw.net, robh+dt@kernel.org

On Wed, 2020-03-18 at 22:28 +0200, Alexandru Lazar wrote:
> Add driver for the Maxim MAX1241 12-bit, single-channel ADC. The driver
> includes support for this device's low-power operation mode.

Just one minor typo I see.


> 
> Signed-off-by: Alexandru Lazar <alazar@startmail.com>
> ---
>  drivers/iio/adc/Kconfig   |  10 ++
>  drivers/iio/adc/Makefile  |   1 +
>  drivers/iio/adc/max1241.c | 206 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 217 insertions(+)
>  create mode 100644 drivers/iio/adc/max1241.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 5d8540b7b427..4254633147af 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -566,6 +566,16 @@ config MAX1118
>  	  To compile this driver as a module, choose M here: the module will be
>  	  called max1118.
>  
> +config MAX1241
> +	tristate "Maxim max1241 ADC driver"
> +	depends on SPI_MASTER
> +	help
> +	  Say yes here to build support for Maxim max1241 12-bit, single-channel
> +	  ADC.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called max1118.

Apologies if I did not notice this before.  'called max1118' -> 'called max1241'


> +
>  config MAX1363
>  	tristate "Maxim max1363 ADC driver"
>  	depends on I2C
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index a1f1fbec0f87..37d6f17559dc 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -54,6 +54,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o
>  obj-$(CONFIG_MAX1027) += max1027.o
>  obj-$(CONFIG_MAX11100) += max11100.o
>  obj-$(CONFIG_MAX1118) += max1118.o
> +obj-$(CONFIG_MAX1241) += max1241.o
>  obj-$(CONFIG_MAX1363) += max1363.o
>  obj-$(CONFIG_MAX9611) += max9611.o
>  obj-$(CONFIG_MCP320X) += mcp320x.o
> diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
> new file mode 100644
> index 000000000000..0278510ec346
> --- /dev/null
> +++ b/drivers/iio/adc/max1241.c
> @@ -0,0 +1,206 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * MAX1241 low-power, 12-bit serial ADC
> + *
> + * Datasheet: 
> https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf
> + */
> +
> +#include <linux/regulator/consumer.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/iio/iio.h>
> +#include <linux/module.h>
> +#include <linux/spi/spi.h>
> +
> +#define MAX1241_VAL_MASK 0xFFF
> +#define MAX1241_SHDN_DELAY_USEC 4
> +
> +enum max1241_id {
> +	max1241,
> +};
> +
> +struct max1241 {
> +	struct spi_device *spi;
> +	struct mutex lock;
> +	struct regulator *reg;
> +	struct gpio_desc *shdn;
> +
> +	__be16 data ____cacheline_aligned;
> +};
> +
> +static const struct iio_chan_spec max1241_channels[] = {
> +	{
> +		.type = IIO_VOLTAGE,
> +		.indexed = 1,
> +		.channel = 0,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> +				BIT(IIO_CHAN_INFO_SCALE),
> +		.scan_index = 0,
> +		.scan_type = {
> +			.sign = 'u',
> +			.realbits = 12,
> +			.storagebits = 16,
> +		},
> +	},
> +};
> +
> +static int max1241_read(struct max1241 *adc)
> +{
> +	struct spi_transfer xfers[] = {
> +		/*
> +		 * Begin conversion by bringing /CS low for at least
> +		 * tconv us.
> +		 */
> +		{
> +			.len = 0,
> +			.delay.value = 8,
> +			.delay.unit = SPI_DELAY_UNIT_USECS,
> +		},
> +		/*
> +		 * Then read two bytes of data in our RX buffer.
> +		 */
> +		{
> +			.rx_buf = &adc->data,
> +			.len = 2,
> +		},
> +	};
> +
> +	return spi_sync_transfer(adc->spi, xfers, ARRAY_SIZE(xfers));
> +}
> +
> +static int max1241_read_raw(struct iio_dev *indio_dev,
> +			struct iio_chan_spec const *chan,
> +			int *val, int *val2, long mask)
> +{
> +	int ret, vref_uV;
> +	struct max1241 *adc = iio_priv(indio_dev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		mutex_lock(&adc->lock);
> +
> +		if (adc->shdn) {
> +			gpiod_set_value(adc->shdn, 0);
> +			udelay(MAX1241_SHDN_DELAY_USEC);
> +		}
> +
> +		ret = max1241_read(adc);
> +
> +		if (adc->shdn)
> +			gpiod_set_value(adc->shdn, 1);
> +
> +		if (ret) {
> +			mutex_unlock(&adc->lock);
> +			return ret;
> +		}
> +
> +		*val = (be16_to_cpu(adc->data) >> 3) & MAX1241_VAL_MASK;
> +
> +		mutex_unlock(&adc->lock);
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_SCALE:
> +		vref_uV = regulator_get_voltage(adc->reg);
> +
> +		if (vref_uV < 0)
> +			return vref_uV;
> +
> +		*val = vref_uV / 1000;
> +		*val2 = 12;
> +
> +		return IIO_VAL_FRACTIONAL_LOG2;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct iio_info max1241_info = {
> +	.read_raw = max1241_read_raw,
> +};
> +
> +static void max1241_disable_reg_action(void *data)
> +{
> +	struct max1241 *adc = data;
> +	int err;
> +
> +	err = regulator_disable(adc->reg);
> +	if (err)
> +		dev_err(&adc->spi->dev, "could not disable reference
> regulator.\n");
> +}
> +
> +static int max1241_probe(struct spi_device *spi)
> +{
> +	struct iio_dev *indio_dev;
> +	struct max1241 *adc;
> +	int ret = 0;
> +
> +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	adc = iio_priv(indio_dev);
> +	adc->spi = spi;
> +	mutex_init(&adc->lock);
> +
> +	spi_set_drvdata(spi, indio_dev);
> +
> +	adc->reg = devm_regulator_get(&spi->dev, "vref");
> +	if (IS_ERR(adc->reg)) {
> +		dev_err(&spi->dev, "failed to get vref regulator\n");
> +		return PTR_ERR(adc->reg);
> +	}
> +
> +	ret = regulator_enable(adc->reg);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_add_action_or_reset(&spi->dev, max1241_disable_reg_action,
> +					adc);
> +	if (ret) {
> +		dev_err(&spi->dev, "could not set up regulator cleanup
> action!\n");
> +		return ret;
> +	}
> +
> +	adc->shdn = devm_gpiod_get_optional(&spi->dev, "shdn", GPIOD_OUT_HIGH);
> +
> +	if (IS_ERR(adc->shdn))
> +		return PTR_ERR(adc->shdn);
> +
> +	if (!adc->shdn)
> +		dev_dbg(&spi->dev, "no shdn pin passed, low-power mode
> disabled");
> +	else
> +		dev_dbg(&spi->dev, "shdn pin passed, low-power mode enabled");
> +
> +	indio_dev->name = spi_get_device_id(spi)->name;
> +	indio_dev->dev.parent = &spi->dev;
> +	indio_dev->info = &max1241_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = max1241_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(max1241_channels);
> +
> +	return devm_iio_device_register(&spi->dev, indio_dev);
> +}
> +
> +static const struct spi_device_id max1241_id[] = {
> +	{ "max1241", max1241 },
> +	{},
> +};
> +
> +static const struct of_device_id max1241_dt_ids[] = {
> +	{ .compatible = "maxim,max1241" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, max1241_dt_ids);
> +
> +static struct spi_driver max1241_spi_driver = {
> +	.driver = {
> +		.name = "max1241",
> +		.of_match_table = max1241_dt_ids,
> +	},
> +	.probe = max1241_probe,
> +	.id_table = max1241_id,
> +};
> +module_spi_driver(max1241_spi_driver);
> +
> +MODULE_AUTHOR("Alexandru Lazar <alazar@startmail.com>");
> +MODULE_DESCRIPTION("MAX1241 ADC driver");
> +MODULE_LICENSE("GPL v2");

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] Maxim MAX1241 driver, v2
  2020-03-18 20:28 [PATCH 0/2] Maxim MAX1241 driver, v2 Alexandru Lazar
  2020-03-18 20:28 ` [PATCH 1/2] iio: adc: Add MAX1241 driver Alexandru Lazar
  2020-03-18 20:28 ` [PATCH 2/2] dt-bindings: iio: adc: Add MAX1241 device tree bindings in documentation Alexandru Lazar
@ 2020-03-19  7:31 ` Ardelean, Alexandru
  2 siblings, 0 replies; 16+ messages in thread
From: Ardelean, Alexandru @ 2020-03-19  7:31 UTC (permalink / raw)
  To: alazar@startmail.com, linux-iio@vger.kernel.org
  Cc: jic23@kernel.org, mark.rutland@arm.com, knaack.h@gmx.de,
	lars@metafoo.de, pmeerw@pmeerw.net, robh+dt@kernel.org

On Wed, 2020-03-18 at 22:28 +0200, Alexandru Lazar wrote:
> Hello again,
> 
> Here's version 2 of a patch series which adds support for the Maxim
> MAX1241, a 12-bit, single-channel, SPI-connected ADC. The previous
> version is here:
> 

as a quick note, when generating patches with V2 it's useful to do:

git format-patch -v2 <commit-range>

that way, the V2 gets appended to all patches;
makes it easier for maintainers to see which is V2,3,4,etc

no need to re-spin V2;
but when going to V3, you can try it


> https://lore.kernel.org/linux-iio/20200317201710.23180-1-alazar@startmail.com/
> 
> I've integrated pretty much all of the suggestions I got here, and fixed
> the issues that you all pointed out (thanks again! Did I say thanks
> lately? Thanks!!!). A short list of the changes is at the end of this
> message. checkpatch.pl is happy, it just warns me about the MAINTAINERS
> file, where I don't think an entry is necessary. dt_bindings_check is
> happy, too.
> 
> The only suggestion that I haven't incorporated is adding max1240 to the
> list of compatible devices. I've thought about it, but there are
> timing-related differences between the two devices, so simply validating
> what my machine sends wouldn't be definitive. I think it would be
> disingenious to claim compatibility under these circumstances. I do plan
> to get a 1240 asap, anyway, and with any luck my patch would just update
> the compat string.
> 
> Now, here's what I changed:
> 
> * Removed useeless header includes
> 
> * Dropped needlessly verbose stuff in _read and _probe functions
> 
> * Dropped useless GPL notice
> 
> * Lowered log level of shdn pin status in probe function, now it's
>   dev_dbg
>   
> * Added proper error checking for the GPIO shutdown pin
> 
> * remove now always returns zero (man, I've been wrong about this for
>   *years* now...)
>   
> * Added regulator disable action, cleanup is now handled via devm
> 
> * Drop delay_usecs, use delay.value, delay.unit
> 
> * Drop config_of, of_match_ptr call
> 
> * Dropped IIO_BUFFER, IIO_TRIGGERED_BUFFER dependencies, set SPI_MASTER
>   as dependency, fix indenting.
>   
> * DT binding: use correct id, add reg description (looks pretty
>   standard), dropped spi-max-frequency, fixed dt_binding_check
>   complaints (oops!)
> 
> Thanks!
> 
> Alex
> 
> Alexandru Lazar (2):
>   iio: adc: Add MAX1241 driver
>   dt-bindings: iio: adc: Add MAX1241 device tree bindings in
>     documentation
> 
>  .../bindings/iio/adc/maxim,max1241.yaml       |  62 ++++++
>  drivers/iio/adc/Kconfig                       |  10 +
>  drivers/iio/adc/Makefile                      |   1 +
>  drivers/iio/adc/max1241.c                     | 206 ++++++++++++++++++
>  4 files changed, 279 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml
>  create mode 100644 drivers/iio/adc/max1241.c
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2020-03-19  7:32 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-18 20:28 [PATCH 0/2] Maxim MAX1241 driver, v2 Alexandru Lazar
2020-03-18 20:28 ` [PATCH 1/2] iio: adc: Add MAX1241 driver Alexandru Lazar
2020-03-19  6:51   ` Ardelean, Alexandru
2020-03-18 20:28 ` [PATCH 2/2] dt-bindings: iio: adc: Add MAX1241 device tree bindings in documentation Alexandru Lazar
2020-03-19  7:31 ` [PATCH 0/2] Maxim MAX1241 driver, v2 Ardelean, Alexandru
  -- strict thread matches above, loose matches on Subject: below --
2020-03-17 20:17 [PATCH 0/2] Maxim MAX1241 driver Alexandru Lazar
2020-03-17 20:17 ` [PATCH 1/2] iio: adc: Add " Alexandru Lazar
2020-03-17 20:33   ` Lars-Peter Clausen
2020-03-17 20:40     ` Lars-Peter Clausen
2020-03-17 21:28     ` Alexandru Lazar
2020-03-17 21:40       ` Lars-Peter Clausen
2020-03-17 21:03   ` Lars-Peter Clausen
2020-03-18  6:50   ` Ardelean, Alexandru
2020-03-18  9:14     ` Alexandru Lazar
2020-03-18  9:31     ` Lars-Peter Clausen
2020-03-18  9:54       ` Ardelean, Alexandru
2020-03-18 16:00     ` Rohit Sarkar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox