* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-13 12:37 ` [PATCHv2] iio: adc: " Jacopo Mondi
@ 2016-12-13 13:21 ` Geert Uytterhoeven
2016-12-13 15:53 ` Wolfram Sang
2016-12-14 11:54 ` jacopo
2016-12-13 20:33 ` Peter Meerwald-Stadler
` (2 subsequent siblings)
3 siblings, 2 replies; 22+ messages in thread
From: Geert Uytterhoeven @ 2016-12-13 13:21 UTC (permalink / raw)
To: Jacopo Mondi
Cc: Wolfram Sang, Magnus Damm, Jonathan Cameron, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald, linux-iio, Linux-Renesas
Hi Jacopo,
On Tue, Dec 13, 2016 at 1:37 PM, Jacopo Mondi <jacopo@jmondi.org> wrote:
> Add IIO driver for Maxim MAX11100 single-channel ADC.
> Add DT bindings documentation.
>
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
> obj-$(CONFIG_LTC2485) += ltc2485.o
> obj-$(CONFIG_MAX1027) += max1027.o
> +obj-$(CONFIG_MAX11100) += max11100.o
> obj-$(CONFIG_MAX1363) += max1363.o
> obj-$(CONFIG_MCP320X) += mcp320x.o
> obj-$(CONFIG_MCP3422) += mcp3422.o
> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
> new file mode 100644
> index 0000000..f372ad8
> --- /dev/null
> +++ b/drivers/iio/adc/max11100.c
> +/*
> + * LSB is the ADC single digital step
> + * 1 LSB = (vref / 2 ^ 16)
> + * AIN = (DIN * LSB)
> + */
> +#define MAX11100_LSB_DIV (1 << 16)
> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
DIV_ROUND_CLOSEST()?
> +struct max11100_state {
> + const struct max11100_chip_desc *desc;
> + struct spi_device *spi;
> + int vref_uv;
unsi
It's good practice to move the smaller members to the end of the structure,
to avoid gaps due to alignment rules (struct mutex needs to be 64-bit aligned
on 64-bit platforms).
> + struct mutex lock;
> +};
> +static struct max11100_chip_desc {
> + unsigned int num_chan;
> + const struct iio_chan_spec *channels;
Same here (but it won't have any effect for now).
> +} max11100_desc = {
> + .num_chan = ARRAY_SIZE(max11100_channels),
> + .channels = max11100_channels,
> +};
> +static int max11100_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + int ret;
> + struct max11100_state *state = iio_priv(indio_dev);
> + uint8_t buffer[3];
> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
Reading the uint16_t will be an unaligned load, which is not supported on all
platforms. So you either have to use get_unaligned_le16(), or assemble the
value yourself, like you did in v1.
> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
DIV_ROUND_CLOSEST()?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-13 13:21 ` Geert Uytterhoeven
@ 2016-12-13 15:53 ` Wolfram Sang
2016-12-30 16:09 ` Jonathan Cameron
2016-12-14 11:54 ` jacopo
1 sibling, 1 reply; 22+ messages in thread
From: Wolfram Sang @ 2016-12-13 15:53 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Jacopo Mondi, Wolfram Sang, Magnus Damm, Jonathan Cameron,
Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald, linux-iio,
Linux-Renesas
[-- Attachment #1: Type: text/plain, Size: 472 bytes --]
> > +struct max11100_state {
> > + const struct max11100_chip_desc *desc;
> > + struct spi_device *spi;
> > + int vref_uv;
>
> unsi
> It's good practice to move the smaller members to the end of the structure,
> to avoid gaps due to alignment rules (struct mutex needs to be 64-bit aligned
> on 64-bit platforms).
One option. Another idea is to put the most used members to the front to
increase chances of being in the same cacheline.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-13 15:53 ` Wolfram Sang
@ 2016-12-30 16:09 ` Jonathan Cameron
0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2016-12-30 16:09 UTC (permalink / raw)
To: Wolfram Sang, Geert Uytterhoeven
Cc: Jacopo Mondi, Wolfram Sang, Magnus Damm, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald, linux-iio, Linux-Renesas
On 13/12/16 15:53, Wolfram Sang wrote:
>
>>> +struct max11100_state {
>>> + const struct max11100_chip_desc *desc;
>>> + struct spi_device *spi;
>>> + int vref_uv;
>>
>> unsi
>> It's good practice to move the smaller members to the end of the structure,
>> to avoid gaps due to alignment rules (struct mutex needs to be 64-bit aligned
>> on 64-bit platforms).
>
> One option. Another idea is to put the most used members to the front to
> increase chances of being in the same cacheline.
>
Or more cynically, just put them in the order that makes most logical sense
as that gives you fewest grumpy reviewers.
We aren't really talking high performance stuff here!
Jonathan
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-13 13:21 ` Geert Uytterhoeven
2016-12-13 15:53 ` Wolfram Sang
@ 2016-12-14 11:54 ` jacopo
2016-12-14 12:14 ` Geert Uytterhoeven
1 sibling, 1 reply; 22+ messages in thread
From: jacopo @ 2016-12-14 11:54 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Wolfram Sang, Magnus Damm, Jonathan Cameron, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald, linux-iio, Linux-Renesas
Hi Geert,
On 13/12/2016 14:21, Geert Uytterhoeven wrote:
> Hi Jacopo,
>
> On Tue, Dec 13, 2016 at 1:37 PM, Jacopo Mondi <jacopo@jmondi.org> wrote:
>> Add IIO driver for Maxim MAX11100 single-channel ADC.
>> Add DT bindings documentation.
>>
>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
>> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
>> obj-$(CONFIG_LTC2485) += ltc2485.o
>> obj-$(CONFIG_MAX1027) += max1027.o
>> +obj-$(CONFIG_MAX11100) += max11100.o
>> obj-$(CONFIG_MAX1363) += max1363.o
>> obj-$(CONFIG_MCP320X) += mcp320x.o
>> obj-$(CONFIG_MCP3422) += mcp3422.o
>> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
>> new file mode 100644
>> index 0000000..f372ad8
>> --- /dev/null
>> +++ b/drivers/iio/adc/max11100.c
>
>> +/*
>> + * LSB is the ADC single digital step
>> + * 1 LSB = (vref / 2 ^ 16)
>> + * AIN = (DIN * LSB)
>> + */
>> +#define MAX11100_LSB_DIV (1 << 16)
>> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
>
> DIV_ROUND_CLOSEST()?
>
>> +struct max11100_state {
>> + const struct max11100_chip_desc *desc;
>> + struct spi_device *spi;
>> + int vref_uv;
>
> unsi
Was this a suggestion to turn "vref_uv" into unsigned?
As you can see in probe function it can get assigned to -EINVAL when a
dummy regulator is returned from regulator-core.
I had to make it signed for this reason
Thanks
j
> It's good practice to move the smaller members to the end of the structure,
> to avoid gaps due to alignment rules (struct mutex needs to be 64-bit aligned
> on 64-bit platforms).
>
>> + struct mutex lock;
>> +};
>
>> +static struct max11100_chip_desc {
>> + unsigned int num_chan;
>> + const struct iio_chan_spec *channels;
>
> Same here (but it won't have any effect for now).
>
>> +} max11100_desc = {
>> + .num_chan = ARRAY_SIZE(max11100_channels),
>> + .channels = max11100_channels,
>> +};
>
>> +static int max11100_read_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec const *chan,
>> + int *val, int *val2, long mask)
>> +{
>> + int ret;
>> + struct max11100_state *state = iio_priv(indio_dev);
>> + uint8_t buffer[3];
>
>> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
>
> Reading the uint16_t will be an unaligned load, which is not supported on all
> platforms. So you either have to use get_unaligned_le16(), or assemble the
> value yourself, like you did in v1.
>
>> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
>
> DIV_ROUND_CLOSEST()?
>
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
> -- Linus Torvalds
>
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-14 11:54 ` jacopo
@ 2016-12-14 12:14 ` Geert Uytterhoeven
0 siblings, 0 replies; 22+ messages in thread
From: Geert Uytterhoeven @ 2016-12-14 12:14 UTC (permalink / raw)
To: jacopo@jmondi.org
Cc: Wolfram Sang, Magnus Damm, Jonathan Cameron, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald, linux-iio, Linux-Renesas
Hi Jacopo,
On Wed, Dec 14, 2016 at 12:54 PM, jacopo@jmondi.org <jacopo@jmondi.org> wrote:
>>> +struct max11100_state {
>>> + const struct max11100_chip_desc *desc;
>>> + struct spi_device *spi;
>>> + int vref_uv;
>>
>> unsi
>
> Was this a suggestion to turn "vref_uv" into unsigned?
It was a suggestion I started writing, and aborted improperly when noticing
the below ;-)
> As you can see in probe function it can get assigned to -EINVAL when a dummy
> regulator is returned from regulator-core.
> I had to make it signed for this reason
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-13 12:37 ` [PATCHv2] iio: adc: " Jacopo Mondi
2016-12-13 13:21 ` Geert Uytterhoeven
@ 2016-12-13 20:33 ` Peter Meerwald-Stadler
2016-12-14 12:00 ` jacopo
2016-12-30 16:08 ` Jonathan Cameron
2016-12-30 16:35 ` Jonathan Cameron
3 siblings, 1 reply; 22+ messages in thread
From: Peter Meerwald-Stadler @ 2016-12-13 20:33 UTC (permalink / raw)
To: Jacopo Mondi
Cc: wsa+renesas, magnus.damm, jic23, knaack.h, lars, linux-iio,
linux-renesas-soc
> Add IIO driver for Maxim MAX11100 single-channel ADC.
> Add DT bindings documentation.
some more comments
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>
> v1 -> v2:
> - incorporated pmeerw's review comments
> - retrieve vref from dts and use that to convert read_raw result
> to mV
> - add device tree bindings documentation
>
> ---
> .../devicetree/bindings/iio/adc/max11100.txt | 17 +++
> drivers/iio/adc/Kconfig | 9 ++
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/max11100.c | 166 +++++++++++++++++++++
> 4 files changed, 193 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/adc/max11100.txt
> create mode 100644 drivers/iio/adc/max11100.c
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/max11100.txt b/Documentation/devicetree/bindings/iio/adc/max11100.txt
> new file mode 100644
> index 0000000..6877c11
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/max11100.txt
> @@ -0,0 +1,17 @@
> +* Maxim max11100 Analog to Digital Converter (ADC)
> +
> +Required properties:
> + - compatible: Should be "maxim,max11100"
> + - vref-supply: phandle to the regulator that provides reference voltage
> +
> +Optional properties:
> + - spi-max-frequency: SPI maximum frequency
> +
> +Example:
> +
> +adc0: max11100@0 {
> + compatible = "maxim,max11100";
> + vref-supply = <&adc0_vref>;
> + spi-max-frequency = <240000>;
> +};
> +
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 99c0514..a909484 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -285,6 +285,15 @@ config MAX1027
> To compile this driver as a module, choose M here: the module will be
> called max1027.
>
> +config MAX11100
> + tristate "Maxim max11100 ADC driver"
> + depends on SPI
SPI_MASTER is more precise I think
> + help
> + Say yes here to build support for Maxim max11100 SPI ADC
> +
> + To compile this driver as a module, choose M here: the module will be
> + called max11100.
> +
> config MAX1363
> tristate "Maxim max1363 ADC driver"
> depends on I2C
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 7a40c04..1463044 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
> obj-$(CONFIG_LTC2485) += ltc2485.o
> obj-$(CONFIG_MAX1027) += max1027.o
> +obj-$(CONFIG_MAX11100) += max11100.o
> obj-$(CONFIG_MAX1363) += max1363.o
> obj-$(CONFIG_MCP320X) += mcp320x.o
> obj-$(CONFIG_MCP3422) += mcp3422.o
> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
> new file mode 100644
> index 0000000..f372ad8
> --- /dev/null
> +++ b/drivers/iio/adc/max11100.c
> @@ -0,0 +1,166 @@
> +/*
> + * iio/adc/max11100.c
> + * Maxim max11100 ADC Driver with IIO interface
> + *
> + * Copyright (C) 2016 Renesas Electronics Corporation
> + * Copyright (C) 2016 Jacopo Mondi
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/spi/spi.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/driver.h>
> +
> +/*
> + * LSB is the ADC single digital step
> + * 1 LSB = (vref / 2 ^ 16)
> + * AIN = (DIN * LSB)
> + */
> +#define MAX11100_LSB_DIV (1 << 16)
> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
maybe parenthesis around vref
> +
> +struct max11100_state {
> + const struct max11100_chip_desc *desc;
> + struct spi_device *spi;
> + int vref_uv;
> + struct mutex lock;
> +};
> +
> +static struct iio_chan_spec max11100_channels[] = {
> + { /* [0] */
> + .type = IIO_VOLTAGE,
> + .scan_type = {
scan_type not needed since driver does not support buffered reads
> + .sign = 'u',
> + .realbits = 16,
> + .storagebits = 24,
> + .shift = 8,
> + .repeat = 1,
> + .endianness = IIO_BE,
> + },
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> + },
> +};
> +
> +static struct max11100_chip_desc {
> + unsigned int num_chan;
> + const struct iio_chan_spec *channels;
> +} max11100_desc = {
> + .num_chan = ARRAY_SIZE(max11100_channels),
> + .channels = max11100_channels,
> +};
> +
> +static int max11100_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + int ret;
> + struct max11100_state *state = iio_priv(indio_dev);
> + uint8_t buffer[3];
> +
> + mutex_lock(&state->lock);
> +
> + ret = spi_read(state->spi, buffer, sizeof(buffer));
> + if (ret) {
> + mutex_unlock(&state->lock);
> + dev_err(&indio_dev->dev, "SPI transfer failed\n");
> + return ret;
> + }
> + mutex_unlock(&state->lock);
> +
> + /* the first 8 bits sent out from ADC must be 0s */
> + if (buffer[0]) {
> + dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
> + return -EINVAL;
> + }
> +
> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
no, INFO_RAW shall not perform such scaling, use _PROCESSED or add an
INFO_SCALE to indicate the scaling
> +
> + return IIO_VAL_INT;
> +}
> +
> +static const struct iio_info max11100_info = {
> + .driver_module = THIS_MODULE,
> + .read_raw = max11100_read_raw,
> +};
> +
> +static int max11100_probe(struct spi_device *spi)
> +{
> + int ret;
> + struct iio_dev *indio_dev;
> + struct regulator *vref_reg;
> + struct max11100_state *state;
> +
> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + spi_set_drvdata(spi, indio_dev);
> +
> + state = iio_priv(indio_dev);
> + state->spi = spi;
> + state->desc = &max11100_desc;
> +
> + mutex_init(&state->lock);
> +
> + indio_dev->dev.parent = &spi->dev;
> + indio_dev->dev.of_node = spi->dev.of_node;
> + indio_dev->info = &max11100_info;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->channels = state->desc->channels;
> + indio_dev->num_channels = state->desc->num_chan;
> +
> + vref_reg = devm_regulator_get(&spi->dev, "vref");
> + if (IS_ERR(vref_reg))
> + return PTR_ERR(vref_reg);
> +
> + ret = regulator_enable(vref_reg);
> + if (ret)
> + return ret;
> +
> + state->vref_uv = regulator_get_voltage(vref_reg);
> + if (state->vref_uv < 0) {
> + /* dummy regulator "get_voltage" returns -EINVAL as well */
> + ret = -EINVAL;
> + goto disable_regulator;
> + }
> +
> + ret = devm_iio_device_register(&spi->dev, indio_dev);
the regulator needs to be disabled in a _remove() function and since you
need a remove function, devm_iio_device_register() should not be used
> + if (ret)
> + goto disable_regulator;
> +
> + return 0;
> +
> +disable_regulator:
> + regulator_disable(vref_reg);
> + return ret;
> +}
> +
> +static const struct of_device_id max11100_ids[] = {
> + {.compatible = "maxim,max11100"},
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, max11100_ids);
> +
> +static struct spi_driver max11100_driver = {
> + .driver = {
> + .name = "max11100",
> + .owner = THIS_MODULE,
> + .of_match_table = of_match_ptr(max11100_ids),
> + },
> + .probe = max11100_probe,
> +};
> +
> +module_spi_driver(max11100_driver);
> +
> +MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
> +MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
> +MODULE_LICENSE("GPL v2");
>
--
Peter Meerwald-Stadler
+43-664-2444418 (mobile)
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-13 20:33 ` Peter Meerwald-Stadler
@ 2016-12-14 12:00 ` jacopo
2016-12-30 16:31 ` Jonathan Cameron
0 siblings, 1 reply; 22+ messages in thread
From: jacopo @ 2016-12-14 12:00 UTC (permalink / raw)
To: Peter Meerwald-Stadler
Cc: wsa+renesas, magnus.damm, jic23, knaack.h, lars, linux-iio,
linux-renesas-soc
Hello Peter,
thanks for review
On 13/12/2016 21:33, Peter Meerwald-Stadler wrote:
>
>> Add IIO driver for Maxim MAX11100 single-channel ADC.
>> Add DT bindings documentation.
>
> some more comments
>
>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>> ---
>>
>> v1 -> v2:
>> - incorporated pmeerw's review comments
>> - retrieve vref from dts and use that to convert read_raw result
>> to mV
>> - add device tree bindings documentation
>>
>> ---
>> .../devicetree/bindings/iio/adc/max11100.txt | 17 +++
>> drivers/iio/adc/Kconfig | 9 ++
>> drivers/iio/adc/Makefile | 1 +
>> drivers/iio/adc/max11100.c | 166 +++++++++++++++++++++
>> 4 files changed, 193 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/iio/adc/max11100.txt
>> create mode 100644 drivers/iio/adc/max11100.c
>>
>> diff --git a/Documentation/devicetree/bindings/iio/adc/max11100.txt b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>> new file mode 100644
>> index 0000000..6877c11
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>> @@ -0,0 +1,17 @@
>> +* Maxim max11100 Analog to Digital Converter (ADC)
>> +
>> +Required properties:
>> + - compatible: Should be "maxim,max11100"
>> + - vref-supply: phandle to the regulator that provides reference voltage
>> +
>> +Optional properties:
>> + - spi-max-frequency: SPI maximum frequency
>> +
>> +Example:
>> +
>> +adc0: max11100@0 {
>> + compatible = "maxim,max11100";
>> + vref-supply = <&adc0_vref>;
>> + spi-max-frequency = <240000>;
>> +};
>> +
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 99c0514..a909484 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -285,6 +285,15 @@ config MAX1027
>> To compile this driver as a module, choose M here: the module will be
>> called max1027.
>>
>> +config MAX11100
>> + tristate "Maxim max11100 ADC driver"
>> + depends on SPI
>
> SPI_MASTER is more precise I think
>
>> + help
>> + Say yes here to build support for Maxim max11100 SPI ADC
>> +
>> + To compile this driver as a module, choose M here: the module will be
>> + called max11100.
>> +
>> config MAX1363
>> tristate "Maxim max1363 ADC driver"
>> depends on I2C
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index 7a40c04..1463044 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
>> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
>> obj-$(CONFIG_LTC2485) += ltc2485.o
>> obj-$(CONFIG_MAX1027) += max1027.o
>> +obj-$(CONFIG_MAX11100) += max11100.o
>> obj-$(CONFIG_MAX1363) += max1363.o
>> obj-$(CONFIG_MCP320X) += mcp320x.o
>> obj-$(CONFIG_MCP3422) += mcp3422.o
>> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
>> new file mode 100644
>> index 0000000..f372ad8
>> --- /dev/null
>> +++ b/drivers/iio/adc/max11100.c
>> @@ -0,0 +1,166 @@
>> +/*
>> + * iio/adc/max11100.c
>> + * Maxim max11100 ADC Driver with IIO interface
>> + *
>> + * Copyright (C) 2016 Renesas Electronics Corporation
>> + * Copyright (C) 2016 Jacopo Mondi
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +#include <linux/delay.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/spi/spi.h>
>> +
>> +#include <linux/iio/iio.h>
>> +#include <linux/iio/buffer.h>
>> +#include <linux/iio/driver.h>
>> +
>> +/*
>> + * LSB is the ADC single digital step
>> + * 1 LSB = (vref / 2 ^ 16)
>> + * AIN = (DIN * LSB)
>> + */
>> +#define MAX11100_LSB_DIV (1 << 16)
>> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
>
> maybe parenthesis around vref
>
>> +
>> +struct max11100_state {
>> + const struct max11100_chip_desc *desc;
>> + struct spi_device *spi;
>> + int vref_uv;
>> + struct mutex lock;
>> +};
>> +
>> +static struct iio_chan_spec max11100_channels[] = {
>> + { /* [0] */
>> + .type = IIO_VOLTAGE,
>> + .scan_type = {
>
> scan_type not needed since driver does not support buffered reads
>
>> + .sign = 'u',
>> + .realbits = 16,
>> + .storagebits = 24,
>> + .shift = 8,
>> + .repeat = 1,
>> + .endianness = IIO_BE,
>> + },
>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
>> + },
>> +};
>> +
>> +static struct max11100_chip_desc {
>> + unsigned int num_chan;
>> + const struct iio_chan_spec *channels;
>> +} max11100_desc = {
>> + .num_chan = ARRAY_SIZE(max11100_channels),
>> + .channels = max11100_channels,
>> +};
>> +
>> +static int max11100_read_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec const *chan,
>> + int *val, int *val2, long mask)
>> +{
>> + int ret;
>> + struct max11100_state *state = iio_priv(indio_dev);
>> + uint8_t buffer[3];
>> +
>> + mutex_lock(&state->lock);
>> +
>> + ret = spi_read(state->spi, buffer, sizeof(buffer));
>> + if (ret) {
>> + mutex_unlock(&state->lock);
>> + dev_err(&indio_dev->dev, "SPI transfer failed\n");
>> + return ret;
>> + }
>> + mutex_unlock(&state->lock);
>> +
>> + /* the first 8 bits sent out from ADC must be 0s */
>> + if (buffer[0]) {
>> + dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
>> + return -EINVAL;
>> + }
>> +
>> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
>> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
>
> no, INFO_RAW shall not perform such scaling, use _PROCESSED or add an
> INFO_SCALE to indicate the scaling
Here I am not scaling the result, just converting the digital value read
from ADC into millivolts.
The transfer function from Din to Ain depends on vref, in the form
reported in comments in file header:
Ain = Din * (vref / 2^16)
I am using microvolts as "vref" unit otherwise I would have been forced
to deal with floating point arithmetic.
Thanks
j
>
>> +
>> + return IIO_VAL_INT;
>> +}
>> +
>> +static const struct iio_info max11100_info = {
>> + .driver_module = THIS_MODULE,
>> + .read_raw = max11100_read_raw,
>> +};
>> +
>> +static int max11100_probe(struct spi_device *spi)
>> +{
>> + int ret;
>> + struct iio_dev *indio_dev;
>> + struct regulator *vref_reg;
>> + struct max11100_state *state;
>> +
>> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
>> + if (!indio_dev)
>> + return -ENOMEM;
>> +
>> + spi_set_drvdata(spi, indio_dev);
>> +
>> + state = iio_priv(indio_dev);
>> + state->spi = spi;
>> + state->desc = &max11100_desc;
>> +
>> + mutex_init(&state->lock);
>> +
>> + indio_dev->dev.parent = &spi->dev;
>> + indio_dev->dev.of_node = spi->dev.of_node;
>> + indio_dev->info = &max11100_info;
>> + indio_dev->modes = INDIO_DIRECT_MODE;
>> + indio_dev->channels = state->desc->channels;
>> + indio_dev->num_channels = state->desc->num_chan;
>> +
>> + vref_reg = devm_regulator_get(&spi->dev, "vref");
>> + if (IS_ERR(vref_reg))
>> + return PTR_ERR(vref_reg);
>> +
>> + ret = regulator_enable(vref_reg);
>> + if (ret)
>> + return ret;
>> +
>> + state->vref_uv = regulator_get_voltage(vref_reg);
>> + if (state->vref_uv < 0) {
>> + /* dummy regulator "get_voltage" returns -EINVAL as well */
>> + ret = -EINVAL;
>> + goto disable_regulator;
>> + }
>> +
>> + ret = devm_iio_device_register(&spi->dev, indio_dev);
>
> the regulator needs to be disabled in a _remove() function and since you
> need a remove function, devm_iio_device_register() should not be used
>
>> + if (ret)
>> + goto disable_regulator;
>> +
>> + return 0;
>> +
>> +disable_regulator:
>> + regulator_disable(vref_reg);
>> + return ret;
>> +}
>> +
>> +static const struct of_device_id max11100_ids[] = {
>> + {.compatible = "maxim,max11100"},
>> + { },
>> +};
>> +MODULE_DEVICE_TABLE(of, max11100_ids);
>> +
>> +static struct spi_driver max11100_driver = {
>> + .driver = {
>> + .name = "max11100",
>> + .owner = THIS_MODULE,
>> + .of_match_table = of_match_ptr(max11100_ids),
>> + },
>> + .probe = max11100_probe,
>> +};
>> +
>> +module_spi_driver(max11100_driver);
>> +
>> +MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
>> +MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
>> +MODULE_LICENSE("GPL v2");
>>
>
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-14 12:00 ` jacopo
@ 2016-12-30 16:31 ` Jonathan Cameron
2017-01-02 9:19 ` jacopo mondi
0 siblings, 1 reply; 22+ messages in thread
From: Jonathan Cameron @ 2016-12-30 16:31 UTC (permalink / raw)
To: jacopo@jmondi.org, Peter Meerwald-Stadler
Cc: wsa+renesas, magnus.damm, knaack.h, lars, linux-iio,
linux-renesas-soc
On 14/12/16 12:00, jacopo@jmondi.org wrote:
> Hello Peter,
> thanks for review
>
> On 13/12/2016 21:33, Peter Meerwald-Stadler wrote:
>>
>>> Add IIO driver for Maxim MAX11100 single-channel ADC.
>>> Add DT bindings documentation.
>>
>> some more comments
>>
>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>>> ---
>>>
>>> v1 -> v2:
>>> - incorporated pmeerw's review comments
>>> - retrieve vref from dts and use that to convert read_raw result
>>> to mV
>>> - add device tree bindings documentation
>>>
>>> ---
>>> .../devicetree/bindings/iio/adc/max11100.txt | 17 +++
>>> drivers/iio/adc/Kconfig | 9 ++
>>> drivers/iio/adc/Makefile | 1 +
>>> drivers/iio/adc/max11100.c | 166 +++++++++++++++++++++
>>> 4 files changed, 193 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/iio/adc/max11100.txt
>>> create mode 100644 drivers/iio/adc/max11100.c
>>>
>>> diff --git a/Documentation/devicetree/bindings/iio/adc/max11100.txt b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>>> new file mode 100644
>>> index 0000000..6877c11
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>>> @@ -0,0 +1,17 @@
>>> +* Maxim max11100 Analog to Digital Converter (ADC)
>>> +
>>> +Required properties:
>>> + - compatible: Should be "maxim,max11100"
>>> + - vref-supply: phandle to the regulator that provides reference voltage
>>> +
>>> +Optional properties:
>>> + - spi-max-frequency: SPI maximum frequency
>>> +
>>> +Example:
>>> +
>>> +adc0: max11100@0 {
>>> + compatible = "maxim,max11100";
>>> + vref-supply = <&adc0_vref>;
>>> + spi-max-frequency = <240000>;
>>> +};
>>> +
>>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>>> index 99c0514..a909484 100644
>>> --- a/drivers/iio/adc/Kconfig
>>> +++ b/drivers/iio/adc/Kconfig
>>> @@ -285,6 +285,15 @@ config MAX1027
>>> To compile this driver as a module, choose M here: the module will be
>>> called max1027.
>>>
>>> +config MAX11100
>>> + tristate "Maxim max11100 ADC driver"
>>> + depends on SPI
>>
>> SPI_MASTER is more precise I think
>>
>>> + help
>>> + Say yes here to build support for Maxim max11100 SPI ADC
>>> +
>>> + To compile this driver as a module, choose M here: the module will be
>>> + called max11100.
>>> +
>>> config MAX1363
>>> tristate "Maxim max1363 ADC driver"
>>> depends on I2C
>>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>>> index 7a40c04..1463044 100644
>>> --- a/drivers/iio/adc/Makefile
>>> +++ b/drivers/iio/adc/Makefile
>>> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
>>> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
>>> obj-$(CONFIG_LTC2485) += ltc2485.o
>>> obj-$(CONFIG_MAX1027) += max1027.o
>>> +obj-$(CONFIG_MAX11100) += max11100.o
>>> obj-$(CONFIG_MAX1363) += max1363.o
>>> obj-$(CONFIG_MCP320X) += mcp320x.o
>>> obj-$(CONFIG_MCP3422) += mcp3422.o
>>> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
>>> new file mode 100644
>>> index 0000000..f372ad8
>>> --- /dev/null
>>> +++ b/drivers/iio/adc/max11100.c
>>> @@ -0,0 +1,166 @@
>>> +/*
>>> + * iio/adc/max11100.c
>>> + * Maxim max11100 ADC Driver with IIO interface
>>> + *
>>> + * Copyright (C) 2016 Renesas Electronics Corporation
>>> + * Copyright (C) 2016 Jacopo Mondi
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +#include <linux/delay.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/module.h>
>>> +#include <linux/regulator/consumer.h>
>>> +#include <linux/spi/spi.h>
>>> +
>>> +#include <linux/iio/iio.h>
>>> +#include <linux/iio/buffer.h>
>>> +#include <linux/iio/driver.h>
>>> +
>>> +/*
>>> + * LSB is the ADC single digital step
>>> + * 1 LSB = (vref / 2 ^ 16)
>>> + * AIN = (DIN * LSB)
>>> + */
>>> +#define MAX11100_LSB_DIV (1 << 16)
>>> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
>>
>> maybe parenthesis around vref
>>
>>> +
>>> +struct max11100_state {
>>> + const struct max11100_chip_desc *desc;
>>> + struct spi_device *spi;
>>> + int vref_uv;
>>> + struct mutex lock;
>>> +};
>>> +
>>> +static struct iio_chan_spec max11100_channels[] = {
>>> + { /* [0] */
>>> + .type = IIO_VOLTAGE,
>>> + .scan_type = {
>>
>> scan_type not needed since driver does not support buffered reads
>>
>>> + .sign = 'u',
>>> + .realbits = 16,
>>> + .storagebits = 24,
>>> + .shift = 8,
>>> + .repeat = 1,
>>> + .endianness = IIO_BE,
>>> + },
>>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
>>> + },
>>> +};
>>> +
>>> +static struct max11100_chip_desc {
>>> + unsigned int num_chan;
>>> + const struct iio_chan_spec *channels;
>>> +} max11100_desc = {
>>> + .num_chan = ARRAY_SIZE(max11100_channels),
>>> + .channels = max11100_channels,
>>> +};
>>> +
>>> +static int max11100_read_raw(struct iio_dev *indio_dev,
>>> + struct iio_chan_spec const *chan,
>>> + int *val, int *val2, long mask)
>>> +{
>>> + int ret;
>>> + struct max11100_state *state = iio_priv(indio_dev);
>>> + uint8_t buffer[3];
>>> +
>>> + mutex_lock(&state->lock);
>>> +
>>> + ret = spi_read(state->spi, buffer, sizeof(buffer));
>>> + if (ret) {
>>> + mutex_unlock(&state->lock);
>>> + dev_err(&indio_dev->dev, "SPI transfer failed\n");
>>> + return ret;
>>> + }
>>> + mutex_unlock(&state->lock);
>>> +
>>> + /* the first 8 bits sent out from ADC must be 0s */
>>> + if (buffer[0]) {
>>> + dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
>>> + return -EINVAL;
>>> + }
>>> +
>>> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
>>> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
>>
>> no, INFO_RAW shall not perform such scaling, use _PROCESSED or add an
>> INFO_SCALE to indicate the scaling
>
> Here I am not scaling the result, just converting the digital value read from ADC into millivolts.
> The transfer function from Din to Ain depends on vref, in the form reported in comments in file header:
>
> Ain = Din * (vref / 2^16)
>
> I am using microvolts as "vref" unit otherwise I would have been forced to deal with floating point arithmetic.
That's what the _scale elements of the IIO ABI meant for. Make even this simple
conversion the job of userspace which is better placed to do any magic it wishes
to do with how it does the conversion (or whether it does depending on the
application). So expectation is that raw means whatever came from the ADC so
ADC 'counts' not mV or similar.
Jonathan
>
> Thanks
> j
>
>>
>>> +
>>> + return IIO_VAL_INT;
>>> +}
>>> +
>>> +static const struct iio_info max11100_info = {
>>> + .driver_module = THIS_MODULE,
>>> + .read_raw = max11100_read_raw,
>>> +};
>>> +
>>> +static int max11100_probe(struct spi_device *spi)
>>> +{
>>> + int ret;
>>> + struct iio_dev *indio_dev;
>>> + struct regulator *vref_reg;
>>> + struct max11100_state *state;
>>> +
>>> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
>>> + if (!indio_dev)
>>> + return -ENOMEM;
>>> +
>>> + spi_set_drvdata(spi, indio_dev);
>>> +
>>> + state = iio_priv(indio_dev);
>>> + state->spi = spi;
>>> + state->desc = &max11100_desc;
>>> +
>>> + mutex_init(&state->lock);
>>> +
>>> + indio_dev->dev.parent = &spi->dev;
>>> + indio_dev->dev.of_node = spi->dev.of_node;
>>> + indio_dev->info = &max11100_info;
>>> + indio_dev->modes = INDIO_DIRECT_MODE;
>>> + indio_dev->channels = state->desc->channels;
>>> + indio_dev->num_channels = state->desc->num_chan;
>>> +
>>> + vref_reg = devm_regulator_get(&spi->dev, "vref");
>>> + if (IS_ERR(vref_reg))
>>> + return PTR_ERR(vref_reg);
>>> +
>>> + ret = regulator_enable(vref_reg);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + state->vref_uv = regulator_get_voltage(vref_reg);
>>> + if (state->vref_uv < 0) {
>>> + /* dummy regulator "get_voltage" returns -EINVAL as well */
>>> + ret = -EINVAL;
>>> + goto disable_regulator;
>>> + }
>>> +
>>> + ret = devm_iio_device_register(&spi->dev, indio_dev);
>>
>> the regulator needs to be disabled in a _remove() function and since you
>> need a remove function, devm_iio_device_register() should not be used
>>
>>> + if (ret)
>>> + goto disable_regulator;
>>> +
>>> + return 0;
>>> +
>>> +disable_regulator:
>>> + regulator_disable(vref_reg);
>>> + return ret;
>>> +}
>>> +
>>> +static const struct of_device_id max11100_ids[] = {
>>> + {.compatible = "maxim,max11100"},
>>> + { },
>>> +};
>>> +MODULE_DEVICE_TABLE(of, max11100_ids);
>>> +
>>> +static struct spi_driver max11100_driver = {
>>> + .driver = {
>>> + .name = "max11100",
>>> + .owner = THIS_MODULE,
>>> + .of_match_table = of_match_ptr(max11100_ids),
>>> + },
>>> + .probe = max11100_probe,
>>> +};
>>> +
>>> +module_spi_driver(max11100_driver);
>>> +
>>> +MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
>>> +MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
>>> +MODULE_LICENSE("GPL v2");
>>>
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-30 16:31 ` Jonathan Cameron
@ 2017-01-02 9:19 ` jacopo mondi
2017-01-02 18:02 ` Jonathan Cameron
0 siblings, 1 reply; 22+ messages in thread
From: jacopo mondi @ 2017-01-02 9:19 UTC (permalink / raw)
To: Jonathan Cameron, Peter Meerwald-Stadler
Cc: wsa+renesas, magnus.damm, knaack.h, lars, linux-iio,
linux-renesas-soc
Hi Jonathan,
thanks for review
On 30/12/2016 17:31, Jonathan Cameron wrote:
> On 14/12/16 12:00, jacopo@jmondi.org wrote:
>> Hello Peter,
>> thanks for review
>>
>> On 13/12/2016 21:33, Peter Meerwald-Stadler wrote:
>>>
>>>> Add IIO driver for Maxim MAX11100 single-channel ADC.
>>>> Add DT bindings documentation.
>>>
>>> some more comments
>>>
>>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>>>> ---
>>>>
>>>> v1 -> v2:
>>>> - incorporated pmeerw's review comments
>>>> - retrieve vref from dts and use that to convert read_raw result
>>>> to mV
>>>> - add device tree bindings documentation
>>>>
>>>> ---
>>>> .../devicetree/bindings/iio/adc/max11100.txt | 17 +++
>>>> drivers/iio/adc/Kconfig | 9 ++
>>>> drivers/iio/adc/Makefile | 1 +
>>>> drivers/iio/adc/max11100.c | 166 +++++++++++++++++++++
>>>> 4 files changed, 193 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/iio/adc/max11100.txt
>>>> create mode 100644 drivers/iio/adc/max11100.c
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/iio/adc/max11100.txt b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>>>> new file mode 100644
>>>> index 0000000..6877c11
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>>>> @@ -0,0 +1,17 @@
>>>> +* Maxim max11100 Analog to Digital Converter (ADC)
>>>> +
>>>> +Required properties:
>>>> + - compatible: Should be "maxim,max11100"
>>>> + - vref-supply: phandle to the regulator that provides reference voltage
>>>> +
>>>> +Optional properties:
>>>> + - spi-max-frequency: SPI maximum frequency
>>>> +
>>>> +Example:
>>>> +
>>>> +adc0: max11100@0 {
>>>> + compatible = "maxim,max11100";
>>>> + vref-supply = <&adc0_vref>;
>>>> + spi-max-frequency = <240000>;
>>>> +};
>>>> +
>>>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>>>> index 99c0514..a909484 100644
>>>> --- a/drivers/iio/adc/Kconfig
>>>> +++ b/drivers/iio/adc/Kconfig
>>>> @@ -285,6 +285,15 @@ config MAX1027
>>>> To compile this driver as a module, choose M here: the module will be
>>>> called max1027.
>>>>
>>>> +config MAX11100
>>>> + tristate "Maxim max11100 ADC driver"
>>>> + depends on SPI
>>>
>>> SPI_MASTER is more precise I think
>>>
>>>> + help
>>>> + Say yes here to build support for Maxim max11100 SPI ADC
>>>> +
>>>> + To compile this driver as a module, choose M here: the module will be
>>>> + called max11100.
>>>> +
>>>> config MAX1363
>>>> tristate "Maxim max1363 ADC driver"
>>>> depends on I2C
>>>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>>>> index 7a40c04..1463044 100644
>>>> --- a/drivers/iio/adc/Makefile
>>>> +++ b/drivers/iio/adc/Makefile
>>>> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
>>>> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
>>>> obj-$(CONFIG_LTC2485) += ltc2485.o
>>>> obj-$(CONFIG_MAX1027) += max1027.o
>>>> +obj-$(CONFIG_MAX11100) += max11100.o
>>>> obj-$(CONFIG_MAX1363) += max1363.o
>>>> obj-$(CONFIG_MCP320X) += mcp320x.o
>>>> obj-$(CONFIG_MCP3422) += mcp3422.o
>>>> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
>>>> new file mode 100644
>>>> index 0000000..f372ad8
>>>> --- /dev/null
>>>> +++ b/drivers/iio/adc/max11100.c
>>>> @@ -0,0 +1,166 @@
>>>> +/*
>>>> + * iio/adc/max11100.c
>>>> + * Maxim max11100 ADC Driver with IIO interface
>>>> + *
>>>> + * Copyright (C) 2016 Renesas Electronics Corporation
>>>> + * Copyright (C) 2016 Jacopo Mondi
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + */
>>>> +#include <linux/delay.h>
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +#include <linux/spi/spi.h>
>>>> +
>>>> +#include <linux/iio/iio.h>
>>>> +#include <linux/iio/buffer.h>
>>>> +#include <linux/iio/driver.h>
>>>> +
>>>> +/*
>>>> + * LSB is the ADC single digital step
>>>> + * 1 LSB = (vref / 2 ^ 16)
>>>> + * AIN = (DIN * LSB)
>>>> + */
>>>> +#define MAX11100_LSB_DIV (1 << 16)
>>>> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
>>>
>>> maybe parenthesis around vref
>>>
>>>> +
>>>> +struct max11100_state {
>>>> + const struct max11100_chip_desc *desc;
>>>> + struct spi_device *spi;
>>>> + int vref_uv;
>>>> + struct mutex lock;
>>>> +};
>>>> +
>>>> +static struct iio_chan_spec max11100_channels[] = {
>>>> + { /* [0] */
>>>> + .type = IIO_VOLTAGE,
>>>> + .scan_type = {
>>>
>>> scan_type not needed since driver does not support buffered reads
>>>
>>>> + .sign = 'u',
>>>> + .realbits = 16,
>>>> + .storagebits = 24,
>>>> + .shift = 8,
>>>> + .repeat = 1,
>>>> + .endianness = IIO_BE,
>>>> + },
>>>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
>>>> + },
>>>> +};
>>>> +
>>>> +static struct max11100_chip_desc {
>>>> + unsigned int num_chan;
>>>> + const struct iio_chan_spec *channels;
>>>> +} max11100_desc = {
>>>> + .num_chan = ARRAY_SIZE(max11100_channels),
>>>> + .channels = max11100_channels,
>>>> +};
>>>> +
>>>> +static int max11100_read_raw(struct iio_dev *indio_dev,
>>>> + struct iio_chan_spec const *chan,
>>>> + int *val, int *val2, long mask)
>>>> +{
>>>> + int ret;
>>>> + struct max11100_state *state = iio_priv(indio_dev);
>>>> + uint8_t buffer[3];
>>>> +
>>>> + mutex_lock(&state->lock);
>>>> +
>>>> + ret = spi_read(state->spi, buffer, sizeof(buffer));
>>>> + if (ret) {
>>>> + mutex_unlock(&state->lock);
>>>> + dev_err(&indio_dev->dev, "SPI transfer failed\n");
>>>> + return ret;
>>>> + }
>>>> + mutex_unlock(&state->lock);
>>>> +
>>>> + /* the first 8 bits sent out from ADC must be 0s */
>>>> + if (buffer[0]) {
>>>> + dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
>>>> + return -EINVAL;
>>>> + }
>>>> +
>>>> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
>>>> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
>>>
>>> no, INFO_RAW shall not perform such scaling, use _PROCESSED or add an
>>> INFO_SCALE to indicate the scaling
>>
>> Here I am not scaling the result, just converting the digital value read from ADC into millivolts.
>> The transfer function from Din to Ain depends on vref, in the form reported in comments in file header:
>>
>> Ain = Din * (vref / 2^16)
>>
>> I am using microvolts as "vref" unit otherwise I would have been forced to deal with floating point arithmetic.
> That's what the _scale elements of the IIO ABI meant for. Make even this simple
> conversion the job of userspace which is better placed to do any magic it wishes
> to do with how it does the conversion (or whether it does depending on the
> application). So expectation is that raw means whatever came from the ADC so
> ADC 'counts' not mV or similar.
>
Ok, fine, I now get it.
Userspace perform conversion using values returned from _RAW and _SCALE.
As the conversion process is device-specific (in my case is the simple
transfer function reported some lines above), should it be documented
somewhere?
Thanks
j
> Jonathan
>>
>> Thanks
>> j
>>
>>>
>>>> +
>>>> + return IIO_VAL_INT;
>>>> +}
>>>> +
>>>> +static const struct iio_info max11100_info = {
>>>> + .driver_module = THIS_MODULE,
>>>> + .read_raw = max11100_read_raw,
>>>> +};
>>>> +
>>>> +static int max11100_probe(struct spi_device *spi)
>>>> +{
>>>> + int ret;
>>>> + struct iio_dev *indio_dev;
>>>> + struct regulator *vref_reg;
>>>> + struct max11100_state *state;
>>>> +
>>>> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
>>>> + if (!indio_dev)
>>>> + return -ENOMEM;
>>>> +
>>>> + spi_set_drvdata(spi, indio_dev);
>>>> +
>>>> + state = iio_priv(indio_dev);
>>>> + state->spi = spi;
>>>> + state->desc = &max11100_desc;
>>>> +
>>>> + mutex_init(&state->lock);
>>>> +
>>>> + indio_dev->dev.parent = &spi->dev;
>>>> + indio_dev->dev.of_node = spi->dev.of_node;
>>>> + indio_dev->info = &max11100_info;
>>>> + indio_dev->modes = INDIO_DIRECT_MODE;
>>>> + indio_dev->channels = state->desc->channels;
>>>> + indio_dev->num_channels = state->desc->num_chan;
>>>> +
>>>> + vref_reg = devm_regulator_get(&spi->dev, "vref");
>>>> + if (IS_ERR(vref_reg))
>>>> + return PTR_ERR(vref_reg);
>>>> +
>>>> + ret = regulator_enable(vref_reg);
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + state->vref_uv = regulator_get_voltage(vref_reg);
>>>> + if (state->vref_uv < 0) {
>>>> + /* dummy regulator "get_voltage" returns -EINVAL as well */
>>>> + ret = -EINVAL;
>>>> + goto disable_regulator;
>>>> + }
>>>> +
>>>> + ret = devm_iio_device_register(&spi->dev, indio_dev);
>>>
>>> the regulator needs to be disabled in a _remove() function and since you
>>> need a remove function, devm_iio_device_register() should not be used
>>>
>>>> + if (ret)
>>>> + goto disable_regulator;
>>>> +
>>>> + return 0;
>>>> +
>>>> +disable_regulator:
>>>> + regulator_disable(vref_reg);
>>>> + return ret;
>>>> +}
>>>> +
>>>> +static const struct of_device_id max11100_ids[] = {
>>>> + {.compatible = "maxim,max11100"},
>>>> + { },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, max11100_ids);
>>>> +
>>>> +static struct spi_driver max11100_driver = {
>>>> + .driver = {
>>>> + .name = "max11100",
>>>> + .owner = THIS_MODULE,
>>>> + .of_match_table = of_match_ptr(max11100_ids),
>>>> + },
>>>> + .probe = max11100_probe,
>>>> +};
>>>> +
>>>> +module_spi_driver(max11100_driver);
>>>> +
>>>> +MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
>>>> +MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
>>>> +MODULE_LICENSE("GPL v2");
>>>>
>>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2017-01-02 9:19 ` jacopo mondi
@ 2017-01-02 18:02 ` Jonathan Cameron
0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2017-01-02 18:02 UTC (permalink / raw)
To: jacopo mondi, Peter Meerwald-Stadler
Cc: wsa+renesas, magnus.damm, knaack.h, lars, linux-iio,
linux-renesas-soc
On 02/01/17 09:19, jacopo mondi wrote:
> Hi Jonathan,
> thanks for review
>
> On 30/12/2016 17:31, Jonathan Cameron wrote:
>> On 14/12/16 12:00, jacopo@jmondi.org wrote:
>>> Hello Peter,
>>> thanks for review
>>>
>>> On 13/12/2016 21:33, Peter Meerwald-Stadler wrote:
>>>>
>>>>> Add IIO driver for Maxim MAX11100 single-channel ADC.
>>>>> Add DT bindings documentation.
>>>>
>>>> some more comments
>>>>
>>>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>>>>> ---
>>>>>
>>>>> v1 -> v2:
>>>>> - incorporated pmeerw's review comments
>>>>> - retrieve vref from dts and use that to convert read_raw result
>>>>> to mV
>>>>> - add device tree bindings documentation
>>>>>
>>>>> ---
>>>>> .../devicetree/bindings/iio/adc/max11100.txt | 17 +++
>>>>> drivers/iio/adc/Kconfig | 9 ++
>>>>> drivers/iio/adc/Makefile | 1 +
>>>>> drivers/iio/adc/max11100.c | 166 +++++++++++++++++++++
>>>>> 4 files changed, 193 insertions(+)
>>>>> create mode 100644 Documentation/devicetree/bindings/iio/adc/max11100.txt
>>>>> create mode 100644 drivers/iio/adc/max11100.c
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/iio/adc/max11100.txt b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>>>>> new file mode 100644
>>>>> index 0000000..6877c11
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>>>>> @@ -0,0 +1,17 @@
>>>>> +* Maxim max11100 Analog to Digital Converter (ADC)
>>>>> +
>>>>> +Required properties:
>>>>> + - compatible: Should be "maxim,max11100"
>>>>> + - vref-supply: phandle to the regulator that provides reference voltage
>>>>> +
>>>>> +Optional properties:
>>>>> + - spi-max-frequency: SPI maximum frequency
>>>>> +
>>>>> +Example:
>>>>> +
>>>>> +adc0: max11100@0 {
>>>>> + compatible = "maxim,max11100";
>>>>> + vref-supply = <&adc0_vref>;
>>>>> + spi-max-frequency = <240000>;
>>>>> +};
>>>>> +
>>>>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>>>>> index 99c0514..a909484 100644
>>>>> --- a/drivers/iio/adc/Kconfig
>>>>> +++ b/drivers/iio/adc/Kconfig
>>>>> @@ -285,6 +285,15 @@ config MAX1027
>>>>> To compile this driver as a module, choose M here: the module will be
>>>>> called max1027.
>>>>>
>>>>> +config MAX11100
>>>>> + tristate "Maxim max11100 ADC driver"
>>>>> + depends on SPI
>>>>
>>>> SPI_MASTER is more precise I think
>>>>
>>>>> + help
>>>>> + Say yes here to build support for Maxim max11100 SPI ADC
>>>>> +
>>>>> + To compile this driver as a module, choose M here: the module will be
>>>>> + called max11100.
>>>>> +
>>>>> config MAX1363
>>>>> tristate "Maxim max1363 ADC driver"
>>>>> depends on I2C
>>>>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>>>>> index 7a40c04..1463044 100644
>>>>> --- a/drivers/iio/adc/Makefile
>>>>> +++ b/drivers/iio/adc/Makefile
>>>>> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
>>>>> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
>>>>> obj-$(CONFIG_LTC2485) += ltc2485.o
>>>>> obj-$(CONFIG_MAX1027) += max1027.o
>>>>> +obj-$(CONFIG_MAX11100) += max11100.o
>>>>> obj-$(CONFIG_MAX1363) += max1363.o
>>>>> obj-$(CONFIG_MCP320X) += mcp320x.o
>>>>> obj-$(CONFIG_MCP3422) += mcp3422.o
>>>>> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
>>>>> new file mode 100644
>>>>> index 0000000..f372ad8
>>>>> --- /dev/null
>>>>> +++ b/drivers/iio/adc/max11100.c
>>>>> @@ -0,0 +1,166 @@
>>>>> +/*
>>>>> + * iio/adc/max11100.c
>>>>> + * Maxim max11100 ADC Driver with IIO interface
>>>>> + *
>>>>> + * Copyright (C) 2016 Renesas Electronics Corporation
>>>>> + * Copyright (C) 2016 Jacopo Mondi
>>>>> + *
>>>>> + * This program is free software; you can redistribute it and/or modify
>>>>> + * it under the terms of the GNU General Public License version 2 as
>>>>> + * published by the Free Software Foundation.
>>>>> + */
>>>>> +#include <linux/delay.h>
>>>>> +#include <linux/kernel.h>
>>>>> +#include <linux/module.h>
>>>>> +#include <linux/regulator/consumer.h>
>>>>> +#include <linux/spi/spi.h>
>>>>> +
>>>>> +#include <linux/iio/iio.h>
>>>>> +#include <linux/iio/buffer.h>
>>>>> +#include <linux/iio/driver.h>
>>>>> +
>>>>> +/*
>>>>> + * LSB is the ADC single digital step
>>>>> + * 1 LSB = (vref / 2 ^ 16)
>>>>> + * AIN = (DIN * LSB)
>>>>> + */
>>>>> +#define MAX11100_LSB_DIV (1 << 16)
>>>>> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
>>>>
>>>> maybe parenthesis around vref
>>>>
>>>>> +
>>>>> +struct max11100_state {
>>>>> + const struct max11100_chip_desc *desc;
>>>>> + struct spi_device *spi;
>>>>> + int vref_uv;
>>>>> + struct mutex lock;
>>>>> +};
>>>>> +
>>>>> +static struct iio_chan_spec max11100_channels[] = {
>>>>> + { /* [0] */
>>>>> + .type = IIO_VOLTAGE,
>>>>> + .scan_type = {
>>>>
>>>> scan_type not needed since driver does not support buffered reads
>>>>
>>>>> + .sign = 'u',
>>>>> + .realbits = 16,
>>>>> + .storagebits = 24,
>>>>> + .shift = 8,
>>>>> + .repeat = 1,
>>>>> + .endianness = IIO_BE,
>>>>> + },
>>>>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
>>>>> + },
>>>>> +};
>>>>> +
>>>>> +static struct max11100_chip_desc {
>>>>> + unsigned int num_chan;
>>>>> + const struct iio_chan_spec *channels;
>>>>> +} max11100_desc = {
>>>>> + .num_chan = ARRAY_SIZE(max11100_channels),
>>>>> + .channels = max11100_channels,
>>>>> +};
>>>>> +
>>>>> +static int max11100_read_raw(struct iio_dev *indio_dev,
>>>>> + struct iio_chan_spec const *chan,
>>>>> + int *val, int *val2, long mask)
>>>>> +{
>>>>> + int ret;
>>>>> + struct max11100_state *state = iio_priv(indio_dev);
>>>>> + uint8_t buffer[3];
>>>>> +
>>>>> + mutex_lock(&state->lock);
>>>>> +
>>>>> + ret = spi_read(state->spi, buffer, sizeof(buffer));
>>>>> + if (ret) {
>>>>> + mutex_unlock(&state->lock);
>>>>> + dev_err(&indio_dev->dev, "SPI transfer failed\n");
>>>>> + return ret;
>>>>> + }
>>>>> + mutex_unlock(&state->lock);
>>>>> +
>>>>> + /* the first 8 bits sent out from ADC must be 0s */
>>>>> + if (buffer[0]) {
>>>>> + dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
>>>>> + return -EINVAL;
>>>>> + }
>>>>> +
>>>>> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
>>>>> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
>>>>
>>>> no, INFO_RAW shall not perform such scaling, use _PROCESSED or add an
>>>> INFO_SCALE to indicate the scaling
>>>
>>> Here I am not scaling the result, just converting the digital value read from ADC into millivolts.
>>> The transfer function from Din to Ain depends on vref, in the form reported in comments in file header:
>>>
>>> Ain = Din * (vref / 2^16)
>>>
>>> I am using microvolts as "vref" unit otherwise I would have been forced to deal with floating point arithmetic.
>> That's what the _scale elements of the IIO ABI meant for. Make even this simple
>> conversion the job of userspace which is better placed to do any magic it wishes
>> to do with how it does the conversion (or whether it does depending on the
>> application). So expectation is that raw means whatever came from the ADC so
>> ADC 'counts' not mV or similar.
>>
>
> Ok, fine, I now get it.
> Userspace perform conversion using values returned from _RAW and _SCALE.
>
> As the conversion process is device-specific (in my case is the
> simple transfer function reported some lines above), should it be
> documented somewhere?
It should conform to the documentation in
Documentation/ABI/test/sysfs-bus-iio
Userspace needs to be sure that is the case, otherwise it'll never know what
to do with it.
Jonathan
>
> Thanks j
>
>> Jonathan
>>>
>>> Thanks
>>> j
>>>
>>>>
>>>>> +
>>>>> + return IIO_VAL_INT;
>>>>> +}
>>>>> +
>>>>> +static const struct iio_info max11100_info = {
>>>>> + .driver_module = THIS_MODULE,
>>>>> + .read_raw = max11100_read_raw,
>>>>> +};
>>>>> +
>>>>> +static int max11100_probe(struct spi_device *spi)
>>>>> +{
>>>>> + int ret;
>>>>> + struct iio_dev *indio_dev;
>>>>> + struct regulator *vref_reg;
>>>>> + struct max11100_state *state;
>>>>> +
>>>>> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
>>>>> + if (!indio_dev)
>>>>> + return -ENOMEM;
>>>>> +
>>>>> + spi_set_drvdata(spi, indio_dev);
>>>>> +
>>>>> + state = iio_priv(indio_dev);
>>>>> + state->spi = spi;
>>>>> + state->desc = &max11100_desc;
>>>>> +
>>>>> + mutex_init(&state->lock);
>>>>> +
>>>>> + indio_dev->dev.parent = &spi->dev;
>>>>> + indio_dev->dev.of_node = spi->dev.of_node;
>>>>> + indio_dev->info = &max11100_info;
>>>>> + indio_dev->modes = INDIO_DIRECT_MODE;
>>>>> + indio_dev->channels = state->desc->channels;
>>>>> + indio_dev->num_channels = state->desc->num_chan;
>>>>> +
>>>>> + vref_reg = devm_regulator_get(&spi->dev, "vref");
>>>>> + if (IS_ERR(vref_reg))
>>>>> + return PTR_ERR(vref_reg);
>>>>> +
>>>>> + ret = regulator_enable(vref_reg);
>>>>> + if (ret)
>>>>> + return ret;
>>>>> +
>>>>> + state->vref_uv = regulator_get_voltage(vref_reg);
>>>>> + if (state->vref_uv < 0) {
>>>>> + /* dummy regulator "get_voltage" returns -EINVAL as well */
>>>>> + ret = -EINVAL;
>>>>> + goto disable_regulator;
>>>>> + }
>>>>> +
>>>>> + ret = devm_iio_device_register(&spi->dev, indio_dev);
>>>>
>>>> the regulator needs to be disabled in a _remove() function and since you
>>>> need a remove function, devm_iio_device_register() should not be used
>>>>
>>>>> + if (ret)
>>>>> + goto disable_regulator;
>>>>> +
>>>>> + return 0;
>>>>> +
>>>>> +disable_regulator:
>>>>> + regulator_disable(vref_reg);
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> +static const struct of_device_id max11100_ids[] = {
>>>>> + {.compatible = "maxim,max11100"},
>>>>> + { },
>>>>> +};
>>>>> +MODULE_DEVICE_TABLE(of, max11100_ids);
>>>>> +
>>>>> +static struct spi_driver max11100_driver = {
>>>>> + .driver = {
>>>>> + .name = "max11100",
>>>>> + .owner = THIS_MODULE,
>>>>> + .of_match_table = of_match_ptr(max11100_ids),
>>>>> + },
>>>>> + .probe = max11100_probe,
>>>>> +};
>>>>> +
>>>>> +module_spi_driver(max11100_driver);
>>>>> +
>>>>> +MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
>>>>> +MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
>>>>> +MODULE_LICENSE("GPL v2");
>>>>>
>>>>
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-13 12:37 ` [PATCHv2] iio: adc: " Jacopo Mondi
2016-12-13 13:21 ` Geert Uytterhoeven
2016-12-13 20:33 ` Peter Meerwald-Stadler
@ 2016-12-30 16:08 ` Jonathan Cameron
2017-01-02 8:41 ` jacopo mondi
2016-12-30 16:35 ` Jonathan Cameron
3 siblings, 1 reply; 22+ messages in thread
From: Jonathan Cameron @ 2016-12-30 16:08 UTC (permalink / raw)
To: Jacopo Mondi, wsa+renesas, magnus.damm, knaack.h, lars, pmeerw
Cc: linux-iio, linux-renesas-soc
On 13/12/16 12:37, Jacopo Mondi wrote:
> Add IIO driver for Maxim MAX11100 single-channel ADC.
> Add DT bindings documentation.
>
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
A quick process related thing. Please don't post a new
version of a driver as a reply to an old version. It very rapidly
leads to deep and difficult to follow threads.
Much easier to just start a new thread.
> ---
>
> v1 -> v2:
> - incorporated pmeerw's review comments
> - retrieve vref from dts and use that to convert read_raw result
> to mV
> - add device tree bindings documentation
>
> ---
> .../devicetree/bindings/iio/adc/max11100.txt | 17 +++
> drivers/iio/adc/Kconfig | 9 ++
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/max11100.c | 166 +++++++++++++++++++++
> 4 files changed, 193 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/adc/max11100.txt
> create mode 100644 drivers/iio/adc/max11100.c
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/max11100.txt b/Documentation/devicetree/bindings/iio/adc/max11100.txt
> new file mode 100644
> index 0000000..6877c11
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/max11100.txt
> @@ -0,0 +1,17 @@
> +* Maxim max11100 Analog to Digital Converter (ADC)
> +
> +Required properties:
> + - compatible: Should be "maxim,max11100"
> + - vref-supply: phandle to the regulator that provides reference voltage
> +
> +Optional properties:
> + - spi-max-frequency: SPI maximum frequency
> +
> +Example:
> +
> +adc0: max11100@0 {
> + compatible = "maxim,max11100";
> + vref-supply = <&adc0_vref>;
> + spi-max-frequency = <240000>;
> +};
> +
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 99c0514..a909484 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -285,6 +285,15 @@ config MAX1027
> To compile this driver as a module, choose M here: the module will be
> called max1027.
>
> +config MAX11100
> + tristate "Maxim max11100 ADC driver"
> + depends on SPI
> + help
> + Say yes here to build support for Maxim max11100 SPI ADC
> +
> + To compile this driver as a module, choose M here: the module will be
> + called max11100.
> +
> config MAX1363
> tristate "Maxim max1363 ADC driver"
> depends on I2C
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 7a40c04..1463044 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
> obj-$(CONFIG_LTC2485) += ltc2485.o
> obj-$(CONFIG_MAX1027) += max1027.o
> +obj-$(CONFIG_MAX11100) += max11100.o
> obj-$(CONFIG_MAX1363) += max1363.o
> obj-$(CONFIG_MCP320X) += mcp320x.o
> obj-$(CONFIG_MCP3422) += mcp3422.o
> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
> new file mode 100644
> index 0000000..f372ad8
> --- /dev/null
> +++ b/drivers/iio/adc/max11100.c
> @@ -0,0 +1,166 @@
> +/*
> + * iio/adc/max11100.c
> + * Maxim max11100 ADC Driver with IIO interface
> + *
> + * Copyright (C) 2016 Renesas Electronics Corporation
> + * Copyright (C) 2016 Jacopo Mondi
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/spi/spi.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/driver.h>
> +
> +/*
> + * LSB is the ADC single digital step
> + * 1 LSB = (vref / 2 ^ 16)
> + * AIN = (DIN * LSB)
> + */
> +#define MAX11100_LSB_DIV (1 << 16)
> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
> +
> +struct max11100_state {
> + const struct max11100_chip_desc *desc;
> + struct spi_device *spi;
> + int vref_uv;
> + struct mutex lock;
> +};
> +
> +static struct iio_chan_spec max11100_channels[] = {
> + { /* [0] */
> + .type = IIO_VOLTAGE,
> + .scan_type = {
> + .sign = 'u',
> + .realbits = 16,
> + .storagebits = 24,
> + .shift = 8,
> + .repeat = 1,
> + .endianness = IIO_BE,
> + },
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> + },
> +};
> +
> +static struct max11100_chip_desc {
> + unsigned int num_chan;
> + const struct iio_chan_spec *channels;
> +} max11100_desc = {
> + .num_chan = ARRAY_SIZE(max11100_channels),
> + .channels = max11100_channels,
> +};
> +
> +static int max11100_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + int ret;
> + struct max11100_state *state = iio_priv(indio_dev);
> + uint8_t buffer[3];
> +
> + mutex_lock(&state->lock);
> +
> + ret = spi_read(state->spi, buffer, sizeof(buffer));
> + if (ret) {
> + mutex_unlock(&state->lock);
> + dev_err(&indio_dev->dev, "SPI transfer failed\n");
> + return ret;
> + }
> + mutex_unlock(&state->lock);
> +
> + /* the first 8 bits sent out from ADC must be 0s */
> + if (buffer[0]) {
> + dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
> + return -EINVAL;
> + }
> +
> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
> +
> + return IIO_VAL_INT;
> +}
> +
> +static const struct iio_info max11100_info = {
> + .driver_module = THIS_MODULE,
> + .read_raw = max11100_read_raw,
> +};
> +
> +static int max11100_probe(struct spi_device *spi)
> +{
> + int ret;
> + struct iio_dev *indio_dev;
> + struct regulator *vref_reg;
> + struct max11100_state *state;
> +
> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + spi_set_drvdata(spi, indio_dev);
> +
> + state = iio_priv(indio_dev);
> + state->spi = spi;
> + state->desc = &max11100_desc;
> +
> + mutex_init(&state->lock);
> +
> + indio_dev->dev.parent = &spi->dev;
> + indio_dev->dev.of_node = spi->dev.of_node;
> + indio_dev->info = &max11100_info;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->channels = state->desc->channels;
> + indio_dev->num_channels = state->desc->num_chan;
> +
> + vref_reg = devm_regulator_get(&spi->dev, "vref");
> + if (IS_ERR(vref_reg))
> + return PTR_ERR(vref_reg);
> +
> + ret = regulator_enable(vref_reg);
> + if (ret)
> + return ret;
> +
> + state->vref_uv = regulator_get_voltage(vref_reg);
> + if (state->vref_uv < 0) {
> + /* dummy regulator "get_voltage" returns -EINVAL as well */
> + ret = -EINVAL;
> + goto disable_regulator;
> + }
> +
> + ret = devm_iio_device_register(&spi->dev, indio_dev);
> + if (ret)
> + goto disable_regulator;
> +
> + return 0;
> +
> +disable_regulator:
> + regulator_disable(vref_reg);
> + return ret;
> +}
> +
> +static const struct of_device_id max11100_ids[] = {
> + {.compatible = "maxim,max11100"},
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, max11100_ids);
> +
> +static struct spi_driver max11100_driver = {
> + .driver = {
> + .name = "max11100",
> + .owner = THIS_MODULE,
> + .of_match_table = of_match_ptr(max11100_ids),
> + },
> + .probe = max11100_probe,
> +};
> +
> +module_spi_driver(max11100_driver);
> +
> +MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
> +MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
> +MODULE_LICENSE("GPL v2");
>
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-30 16:08 ` Jonathan Cameron
@ 2017-01-02 8:41 ` jacopo mondi
0 siblings, 0 replies; 22+ messages in thread
From: jacopo mondi @ 2017-01-02 8:41 UTC (permalink / raw)
To: Jonathan Cameron, wsa+renesas, magnus.damm, knaack.h, lars,
pmeerw
Cc: linux-iio, linux-renesas-soc
Hi Jonathan,
On 30/12/2016 17:08, Jonathan Cameron wrote:
> On 13/12/16 12:37, Jacopo Mondi wrote:
>> Add IIO driver for Maxim MAX11100 single-channel ADC.
>> Add DT bindings documentation.
>>
>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> A quick process related thing. Please don't post a new
> version of a driver as a reply to an old version. It very rapidly
> leads to deep and difficult to follow threads.
>
> Much easier to just start a new thread.
>
Noted!
Thanks for suggestion ;)
j
>> ---
>>
>> v1 -> v2:
>> - incorporated pmeerw's review comments
>> - retrieve vref from dts and use that to convert read_raw result
>> to mV
>> - add device tree bindings documentation
>>
>> ---
>> .../devicetree/bindings/iio/adc/max11100.txt | 17 +++
>> drivers/iio/adc/Kconfig | 9 ++
>> drivers/iio/adc/Makefile | 1 +
>> drivers/iio/adc/max11100.c | 166 +++++++++++++++++++++
>> 4 files changed, 193 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/iio/adc/max11100.txt
>> create mode 100644 drivers/iio/adc/max11100.c
>>
>> diff --git a/Documentation/devicetree/bindings/iio/adc/max11100.txt b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>> new file mode 100644
>> index 0000000..6877c11
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/adc/max11100.txt
>> @@ -0,0 +1,17 @@
>> +* Maxim max11100 Analog to Digital Converter (ADC)
>> +
>> +Required properties:
>> + - compatible: Should be "maxim,max11100"
>> + - vref-supply: phandle to the regulator that provides reference voltage
>> +
>> +Optional properties:
>> + - spi-max-frequency: SPI maximum frequency
>> +
>> +Example:
>> +
>> +adc0: max11100@0 {
>> + compatible = "maxim,max11100";
>> + vref-supply = <&adc0_vref>;
>> + spi-max-frequency = <240000>;
>> +};
>> +
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 99c0514..a909484 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -285,6 +285,15 @@ config MAX1027
>> To compile this driver as a module, choose M here: the module will be
>> called max1027.
>>
>> +config MAX11100
>> + tristate "Maxim max11100 ADC driver"
>> + depends on SPI
>> + help
>> + Say yes here to build support for Maxim max11100 SPI ADC
>> +
>> + To compile this driver as a module, choose M here: the module will be
>> + called max11100.
>> +
>> config MAX1363
>> tristate "Maxim max1363 ADC driver"
>> depends on I2C
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index 7a40c04..1463044 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
>> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
>> obj-$(CONFIG_LTC2485) += ltc2485.o
>> obj-$(CONFIG_MAX1027) += max1027.o
>> +obj-$(CONFIG_MAX11100) += max11100.o
>> obj-$(CONFIG_MAX1363) += max1363.o
>> obj-$(CONFIG_MCP320X) += mcp320x.o
>> obj-$(CONFIG_MCP3422) += mcp3422.o
>> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
>> new file mode 100644
>> index 0000000..f372ad8
>> --- /dev/null
>> +++ b/drivers/iio/adc/max11100.c
>> @@ -0,0 +1,166 @@
>> +/*
>> + * iio/adc/max11100.c
>> + * Maxim max11100 ADC Driver with IIO interface
>> + *
>> + * Copyright (C) 2016 Renesas Electronics Corporation
>> + * Copyright (C) 2016 Jacopo Mondi
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +#include <linux/delay.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/spi/spi.h>
>> +
>> +#include <linux/iio/iio.h>
>> +#include <linux/iio/buffer.h>
>> +#include <linux/iio/driver.h>
>> +
>> +/*
>> + * LSB is the ADC single digital step
>> + * 1 LSB = (vref / 2 ^ 16)
>> + * AIN = (DIN * LSB)
>> + */
>> +#define MAX11100_LSB_DIV (1 << 16)
>> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
>> +
>> +struct max11100_state {
>> + const struct max11100_chip_desc *desc;
>> + struct spi_device *spi;
>> + int vref_uv;
>> + struct mutex lock;
>> +};
>> +
>> +static struct iio_chan_spec max11100_channels[] = {
>> + { /* [0] */
>> + .type = IIO_VOLTAGE,
>> + .scan_type = {
>> + .sign = 'u',
>> + .realbits = 16,
>> + .storagebits = 24,
>> + .shift = 8,
>> + .repeat = 1,
>> + .endianness = IIO_BE,
>> + },
>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
>> + },
>> +};
>> +
>> +static struct max11100_chip_desc {
>> + unsigned int num_chan;
>> + const struct iio_chan_spec *channels;
>> +} max11100_desc = {
>> + .num_chan = ARRAY_SIZE(max11100_channels),
>> + .channels = max11100_channels,
>> +};
>> +
>> +static int max11100_read_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec const *chan,
>> + int *val, int *val2, long mask)
>> +{
>> + int ret;
>> + struct max11100_state *state = iio_priv(indio_dev);
>> + uint8_t buffer[3];
>> +
>> + mutex_lock(&state->lock);
>> +
>> + ret = spi_read(state->spi, buffer, sizeof(buffer));
>> + if (ret) {
>> + mutex_unlock(&state->lock);
>> + dev_err(&indio_dev->dev, "SPI transfer failed\n");
>> + return ret;
>> + }
>> + mutex_unlock(&state->lock);
>> +
>> + /* the first 8 bits sent out from ADC must be 0s */
>> + if (buffer[0]) {
>> + dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
>> + return -EINVAL;
>> + }
>> +
>> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
>> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
>> +
>> + return IIO_VAL_INT;
>> +}
>> +
>> +static const struct iio_info max11100_info = {
>> + .driver_module = THIS_MODULE,
>> + .read_raw = max11100_read_raw,
>> +};
>> +
>> +static int max11100_probe(struct spi_device *spi)
>> +{
>> + int ret;
>> + struct iio_dev *indio_dev;
>> + struct regulator *vref_reg;
>> + struct max11100_state *state;
>> +
>> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
>> + if (!indio_dev)
>> + return -ENOMEM;
>> +
>> + spi_set_drvdata(spi, indio_dev);
>> +
>> + state = iio_priv(indio_dev);
>> + state->spi = spi;
>> + state->desc = &max11100_desc;
>> +
>> + mutex_init(&state->lock);
>> +
>> + indio_dev->dev.parent = &spi->dev;
>> + indio_dev->dev.of_node = spi->dev.of_node;
>> + indio_dev->info = &max11100_info;
>> + indio_dev->modes = INDIO_DIRECT_MODE;
>> + indio_dev->channels = state->desc->channels;
>> + indio_dev->num_channels = state->desc->num_chan;
>> +
>> + vref_reg = devm_regulator_get(&spi->dev, "vref");
>> + if (IS_ERR(vref_reg))
>> + return PTR_ERR(vref_reg);
>> +
>> + ret = regulator_enable(vref_reg);
>> + if (ret)
>> + return ret;
>> +
>> + state->vref_uv = regulator_get_voltage(vref_reg);
>> + if (state->vref_uv < 0) {
>> + /* dummy regulator "get_voltage" returns -EINVAL as well */
>> + ret = -EINVAL;
>> + goto disable_regulator;
>> + }
>> +
>> + ret = devm_iio_device_register(&spi->dev, indio_dev);
>> + if (ret)
>> + goto disable_regulator;
>> +
>> + return 0;
>> +
>> +disable_regulator:
>> + regulator_disable(vref_reg);
>> + return ret;
>> +}
>> +
>> +static const struct of_device_id max11100_ids[] = {
>> + {.compatible = "maxim,max11100"},
>> + { },
>> +};
>> +MODULE_DEVICE_TABLE(of, max11100_ids);
>> +
>> +static struct spi_driver max11100_driver = {
>> + .driver = {
>> + .name = "max11100",
>> + .owner = THIS_MODULE,
>> + .of_match_table = of_match_ptr(max11100_ids),
>> + },
>> + .probe = max11100_probe,
>> +};
>> +
>> +module_spi_driver(max11100_driver);
>> +
>> +MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
>> +MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
>> +MODULE_LICENSE("GPL v2");
>>
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCHv2] iio: adc: Add Maxim MAX11100 driver
2016-12-13 12:37 ` [PATCHv2] iio: adc: " Jacopo Mondi
` (2 preceding siblings ...)
2016-12-30 16:08 ` Jonathan Cameron
@ 2016-12-30 16:35 ` Jonathan Cameron
3 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2016-12-30 16:35 UTC (permalink / raw)
To: Jacopo Mondi, wsa+renesas, magnus.damm, knaack.h, lars, pmeerw
Cc: linux-iio, linux-renesas-soc
On 13/12/16 12:37, Jacopo Mondi wrote:
> Add IIO driver for Maxim MAX11100 single-channel ADC.
> Add DT bindings documentation.
>
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
Nothing significant to add, but a few comments inline.
Jonathan
> ---
>
> v1 -> v2:
> - incorporated pmeerw's review comments
> - retrieve vref from dts and use that to convert read_raw result
> to mV
> - add device tree bindings documentation
>
> ---
> .../devicetree/bindings/iio/adc/max11100.txt | 17 +++
> drivers/iio/adc/Kconfig | 9 ++
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/max11100.c | 166 +++++++++++++++++++++
> 4 files changed, 193 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/adc/max11100.txt
> create mode 100644 drivers/iio/adc/max11100.c
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/max11100.txt b/Documentation/devicetree/bindings/iio/adc/max11100.txt
> new file mode 100644
> index 0000000..6877c11
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/max11100.txt
> @@ -0,0 +1,17 @@
> +* Maxim max11100 Analog to Digital Converter (ADC)
> +
> +Required properties:
> + - compatible: Should be "maxim,max11100"
> + - vref-supply: phandle to the regulator that provides reference voltage
> +
> +Optional properties:
> + - spi-max-frequency: SPI maximum frequency
> +
> +Example:
> +
> +adc0: max11100@0 {
> + compatible = "maxim,max11100";
> + vref-supply = <&adc0_vref>;
> + spi-max-frequency = <240000>;
> +};
> +
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 99c0514..a909484 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -285,6 +285,15 @@ config MAX1027
> To compile this driver as a module, choose M here: the module will be
> called max1027.
>
> +config MAX11100
> + tristate "Maxim max11100 ADC driver"
> + depends on SPI
> + help
> + Say yes here to build support for Maxim max11100 SPI ADC
> +
> + To compile this driver as a module, choose M here: the module will be
> + called max11100.
> +
> config MAX1363
> tristate "Maxim max1363 ADC driver"
> depends on I2C
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 7a40c04..1463044 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
> obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
> obj-$(CONFIG_LTC2485) += ltc2485.o
> obj-$(CONFIG_MAX1027) += max1027.o
> +obj-$(CONFIG_MAX11100) += max11100.o
> obj-$(CONFIG_MAX1363) += max1363.o
> obj-$(CONFIG_MCP320X) += mcp320x.o
> obj-$(CONFIG_MCP3422) += mcp3422.o
> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
> new file mode 100644
> index 0000000..f372ad8
> --- /dev/null
> +++ b/drivers/iio/adc/max11100.c
> @@ -0,0 +1,166 @@
> +/*
> + * iio/adc/max11100.c
> + * Maxim max11100 ADC Driver with IIO interface
> + *
> + * Copyright (C) 2016 Renesas Electronics Corporation
> + * Copyright (C) 2016 Jacopo Mondi
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/spi/spi.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/driver.h>
> +
> +/*
> + * LSB is the ADC single digital step
> + * 1 LSB = (vref / 2 ^ 16)
> + * AIN = (DIN * LSB)
> + */
> +#define MAX11100_LSB_DIV (1 << 16)
> +#define MAX11100_LSB(vref) (vref / MAX11100_LSB_DIV)
> +
> +struct max11100_state {
> + const struct max11100_chip_desc *desc;
> + struct spi_device *spi;
> + int vref_uv;
> + struct mutex lock;
> +};
> +
> +static struct iio_chan_spec max11100_channels[] = {
> + { /* [0] */
> + .type = IIO_VOLTAGE,
> + .scan_type = {
> + .sign = 'u',
> + .realbits = 16,
> + .storagebits = 24,
> + .shift = 8,
> + .repeat = 1,
> + .endianness = IIO_BE,
> + },
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> + },
> +};
> +
> +static struct max11100_chip_desc {
> + unsigned int num_chan;
> + const struct iio_chan_spec *channels;
> +} max11100_desc = {
> + .num_chan = ARRAY_SIZE(max11100_channels),
> + .channels = max11100_channels,
> +};
> +
> +static int max11100_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + int ret;
> + struct max11100_state *state = iio_priv(indio_dev);
> + uint8_t buffer[3];
> +
> + mutex_lock(&state->lock);
> +
> + ret = spi_read(state->spi, buffer, sizeof(buffer));
> + if (ret) {
> + mutex_unlock(&state->lock);
> + dev_err(&indio_dev->dev, "SPI transfer failed\n");
> + return ret;
> + }
> + mutex_unlock(&state->lock);
> +
> + /* the first 8 bits sent out from ADC must be 0s */
> + if (buffer[0]) {
> + dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
> + return -EINVAL;
> + }
> +
> + *val = be16_to_cpu(*(uint16_t *)&buffer[1]);
> + *val = *val * MAX11100_LSB(state->vref_uv) / 1000;
What Peter said.
> +
> + return IIO_VAL_INT;
> +}
> +
> +static const struct iio_info max11100_info = {
> + .driver_module = THIS_MODULE,
> + .read_raw = max11100_read_raw,
> +};
> +
> +static int max11100_probe(struct spi_device *spi)
> +{
> + int ret;
> + struct iio_dev *indio_dev;
> + struct regulator *vref_reg;
> + struct max11100_state *state;
> +
> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + spi_set_drvdata(spi, indio_dev);
> +
> + state = iio_priv(indio_dev);
> + state->spi = spi;
> + state->desc = &max11100_desc;
> +
> + mutex_init(&state->lock);
> +
> + indio_dev->dev.parent = &spi->dev;
> + indio_dev->dev.of_node = spi->dev.of_node;
> + indio_dev->info = &max11100_info;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->channels = state->desc->channels;
> + indio_dev->num_channels = state->desc->num_chan;
> +
> + vref_reg = devm_regulator_get(&spi->dev, "vref");
> + if (IS_ERR(vref_reg))
> + return PTR_ERR(vref_reg);
> +
> + ret = regulator_enable(vref_reg);
> + if (ret)
> + return ret;
> +
> + state->vref_uv = regulator_get_voltage(vref_reg);
If possible, do this as late as you can. There are boards out there
were, to save hardware, reference voltages are fed from power supply lines
and and exactly what is on those lines may change as the board boots up.
Once you've moved the use of this value to the the _scale bit of read_raw
then it won't get called very often so just do the actual voltage request
there. Do leave the enabling etc here though as otherwise power management
code might turn it off as unused.
> + if (state->vref_uv < 0) {
> + /* dummy regulator "get_voltage" returns -EINVAL as well */
> + ret = -EINVAL;
> + goto disable_regulator;
> + }
> +
> + ret = devm_iio_device_register(&spi->dev, indio_dev);
> + if (ret)
> + goto disable_regulator;
> +
> + return 0;
> +
> +disable_regulator:
> + regulator_disable(vref_reg);
> + return ret;
> +}
> +
> +static const struct of_device_id max11100_ids[] = {
> + {.compatible = "maxim,max11100"},
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, max11100_ids);
> +
> +static struct spi_driver max11100_driver = {
> + .driver = {
> + .name = "max11100",
> + .owner = THIS_MODULE,
> + .of_match_table = of_match_ptr(max11100_ids),
> + },
> + .probe = max11100_probe,
> +};
> +
> +module_spi_driver(max11100_driver);
> +
> +MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
> +MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
> +MODULE_LICENSE("GPL v2");
>
^ permalink raw reply [flat|nested] 22+ messages in thread