From: Abhisit Sangjan <s.abhisit@gmail.com>
To: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: jic23@kernel.org, knaack.h@gmx.de, lars@metafoo.de,
Peter Meerwald-Stadler <pmeerw@pmeerw.net>,
fabrice.gasnier@st.com, Lee Jones <lee.jones@linaro.org>,
robh@kernel.org, Akinobu Mita <akinobu.mita@gmail.com>,
marek.vasut+renesas@gmail.com, jacopo+renesas@jmondi.org,
linux-kernel@vger.kernel.org, linux-iio@vger.kernel.org
Subject: Re: [PATCH 2/5] iio: Add support for LMP92001 ADC
Date: Wed, 2 Aug 2017 14:06:50 +0700 [thread overview]
Message-ID: <CAMV_pUYOMdb_e1xYEkhhuO2GN4FDFSRy6BpHUK5GqO0o8yO1fA@mail.gmail.com> (raw)
In-Reply-To: <CAMV_pUaV54qUc1wOhL5cAP8mEX1k0VsL3aEGG+wziqPPnZGHWg@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 26336 bytes --]
Hi Jonathan,
Please find my comment on in line.
Thank you.
Abhisit S.
On Wed, Aug 2, 2017 at 11:43 AM, Abhisit Sangjan <s.abhisit@gmail.com>
wrote:
> Hi Jonathan,
>
> Thank you for your review and good suggestion. This is my first driver,
> first work for Linux. I will be follow your advice and send new once in
> soon. Please help me to review.
>
> Thank you,
> Abhisit S.
>
> On Tue, Aug 1, 2017 at 5:10 PM, Jonathan Cameron <
> Jonathan.Cameron@huawei.com> wrote:
>
>> On Tue, 1 Aug 2017 16:12:22 +0700
>> <s.abhisit@gmail.com> wrote:
>>
>> > From: Abhisit Sangjan <s.abhisit@gmail.com>
>> Hi,
>>
>> A very quick initial review covering stuff you'll want to clean up before
>> you get some in depth reviews.
>>
>
> Abhisit: OK, I will do.
>
>
>> 1) Please cc linux-iio on the whole series - it's useful to see the mfd
>> driver and review it as well.
>>
>
> Abhisit: OK.
>
>
>> 2) Description of the patch is needed. For a new driver, a quick run down
>> of what it is and what is supported.
>
>
> Abhisit: I will do.
>
>
>>
> More comments inline.
>>
>> Note this is not a full review by any means, just a starting point whilst
>> I'm waiting for a board to boot... Will do a full review once these bits
>> are tidied up.
>>
>> Fundamental code looks fine, it's docs and coding style that need work
>> (plus locking ;)
>>
>> Jonathan
>> >
>> > ---
>> > drivers/iio/adc/Kconfig | 10 +
>> > drivers/iio/adc/Makefile | 1 +
>> > drivers/iio/adc/lmp92001-adc.c | 479 ++++++++++++++++++++++++++++++
>> +++++++++++
>> > 3 files changed, 490 insertions(+)
>> > create mode 100644 drivers/iio/adc/lmp92001-adc.c
>> >
>> > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> > index 614fa41..b623b4d 100644
>> > --- a/drivers/iio/adc/Kconfig
>> > +++ b/drivers/iio/adc/Kconfig
>> > @@ -857,4 +857,14 @@ config XILINX_XADC
>> > The driver can also be build as a module. If so, the module
>> will be called
>> > xilinx-xadc.
>> >
>> > +config LMP92001_ADC
>> Alphabetical order please.
>>
>
> Abhisit: I got you.
>
>
>> > + tristate "TI LMP92001 ADC Driver"
>> > + depends on MFD_LMP92001
>> > + help
>> > + If you say yes here you get support for TI LMP92001 ADCs
>> > + conversion.
>> > +
>> > + This driver can also be built as a module. If so, the module
>> will
>> > + be called lmp92001_adc.
>> > +
>> > endmenu
>> > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> > index b546736a..75b24b1 100644
>> > --- a/drivers/iio/adc/Makefile
>> > +++ b/drivers/iio/adc/Makefile
>> > @@ -78,3 +78,4 @@ obj-$(CONFIG_VF610_ADC) += vf610_adc.o
>> > obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
>> > xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o
>> > obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o
>> > +obj-$(CONFIG_LMP92001_ADC) += lmp92001-adc.o
>> Alphabetical order please.
>>
>
> Abhisit: I got you.
>
>
>>
>> > diff --git a/drivers/iio/adc/lmp92001-adc.c
>> b/drivers/iio/adc/lmp92001-adc.c
>> > new file mode 100644
>> > index 0000000..909ff47
>> > --- /dev/null
>> > +++ b/drivers/iio/adc/lmp92001-adc.c
>> > @@ -0,0 +1,479 @@
>> > +/*
>> > + * lmp92001-adc.c - Support for TI LMP92001 ADCs
>> > + *
>> > + * Copyright 2016-2017 Celestica Ltd.
>> > + *
>> > + * Author: Abhisit Sangjan <s.abhisit@gmail.com>
>> > + *
>> > + * Inspired by wm831x and ad5064 drivers.
>> > + *
>> > + * This program is free software; you can redistribute it and/or modify
>> > + * it under the terms of the GNU General Public License as published by
>> > + * the Free Software Foundation; either version 2 of the License, or
>> > + * (at your option) any later version.
>> > + *
>> > + * This program is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> > + * GNU General Public License for more details.
>> > + *
>> > + */
>> > +
>> > +#include <linux/kernel.h>
>> > +#include <linux/module.h>
>> > +#include <linux/iio/iio.h>
>> > +#include <linux/mfd/core.h>
>> > +#include <linux/platform_device.h>
>> > +#include <linux/interrupt.h>
>> > +
>> > +#include <linux/mfd/lmp92001/core.h>
>> > +
>> > +static int lmp92001_read_raw(struct iio_dev *indio_dev,
>> > + struct iio_chan_spec const *channel,
>> int *val,
>> > + int *val2, long mask)
>> > +{
>> Nothing prevents multiple simultaneous runs of this function.
>> Given the write then read cycles below, I'm guessing you'll be wanting
>> a local lock in your lmp92001 structure.
>>
>
> Abhisit: It is hardware lock register to prevent multiple access.
>
Abhisit: I thought, the function regmap_read(), regmap_update_bits()
and regmap_write() are managed the lock access.
Do I need to lock it by myself?
Example function regmap_read().
/**
* regmap_read() - Read a value from a single register
*
* @map: Register map to read from
* @reg: Register to be read from
* @val: Pointer to store read value
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
{
int ret;
if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
map->lock(map->lock_arg);
ret = _regmap_read(map, reg, val);
map->unlock(map->lock_arg);
return ret;
}
>
>
>> > + struct lmp92001 *lmp92001 = iio_device_get_drvdata(indio_dev);
>> > + unsigned int code, cgen, sgen, try;
>> > + int ret;
>> > +
>> > + ret = regmap_read(lmp92001->regmap, LMP92001_CGEN, &cgen);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + /*
>> > + * Is not continuous conversion?
>> > + * Lock the registers (if needed).
>> > + * Triggering single-short conversion.
>> > + * Waiting for conversion successfully.
>> > + */
>> > + if (!(cgen & 1))
>> Kernel goes with K&R style on if statements and brackets.
>> if (!(cgen & 1)) {
>>
>> 1 is a magic value - so please add a define telling us what it
>> represents.
>>
>
> Abhisit: I will double check again for all my source code for K&R and no
> magic number.
>
>
>>
>> > + {
>> > + if (!(cgen & 2))
>> > + {
>> > + ret = regmap_update_bits(lmp92001->regmap,
>> > + LMP92001_CGEN,
>> 2, 2);
>> Register field values and masks should use defined constants so the code
>> lets
>> us know what they are without consulting the datasheet.
>>
>
> Abhisit: I will give them to be defined.
>
>
>>
>> > + if (ret < 0)
>> > + return ret;
>> > + }
>> > +
>> > + ret = regmap_write(lmp92001->regmap, LMP92001_CTRIG,
>> 1);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + try = 10;
>> Why - a try look doing repeats like this need an explanatory comment.
>>
>
> Abhisit: Do you think, should be jiffies time?
>
>
>> > + do {
>> > + ret = regmap_read(lmp92001->regmap,
>> > + LMP92001_SGEN, &sgen);
>> > + if(ret < 0)
>> > + return ret;
>> > + } while ((sgen & 1<<7) && (--try > 0));
>> > +
>> > + if (!try)
>> > + return -ETIME;
>> > + }
>> > +
>> > + ret = regmap_read(lmp92001->regmap, 0x1F + channel->channel,
>> &code);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + switch (mask)
>> > + {
>> switch (mask) {
>>
>> Please run checkpatch over this - preferably with --strict
>> and fix everything it comes up with. Saves everyone time in reviews!
>>
>
> Abhisit: Thank you for your suggestion. It is my first driver :)
>
>
>> > + case IIO_CHAN_INFO_RAW:
>> > + switch (channel->type) {
>> > + case IIO_VOLTAGE:
>> > + case IIO_TEMP:
>> > + *val = code;
>> > + return IIO_VAL_INT;
>> > + default:
>> return directly here if still possible after considering locking.
>> > + break;
>> > + }
>> > + break;
>> > + default:
>> > + break;
>> > + }
>> > +
>> > + return -EINVAL;
>> > +}
>> > +
>> > +/*
>> > + * TODO: do your attributes even handler for
>> > + * Current limit low/high for CH 1-3, 9-11!
>> > + * In case INT1 and INT2 were connected to i.MX6.
>> > + */
>> > +static const struct iio_info lmp92001_info = {
>> > + .read_raw = lmp92001_read_raw,
>> > + .driver_module = THIS_MODULE,
>> > +};
>> > +
>> > +static ssize_t lmp92001_avref_read(struct iio_dev *indio_dev,
>> uintptr_t private,
>> > + struct iio_chan_spec const *channel, char *buf)
>> > +{
>> > + struct lmp92001 *lmp92001 = iio_device_get_drvdata(indio_dev);
>> > + unsigned int cref;
>> > + int ret;
>> > +
>> > + ret = regmap_read(lmp92001->regmap, LMP92001_CREF, &cref);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + return sprintf(buf, "%s\n", cref & 2 ? "external" :
>> "internal");
>> This looks like new ABI. Please add ABI docs so that we can discuss this
>> interface
>> without having to pull it from the code.
>>
>> Docuentation/ABI/testing/sysfs-bus-iio-lmp920001 is probably the right
>> place.
>>
>
> Abhisit: I will do.
>
>
>>
>> Note IIO also has some nice utility functions to deal with enums like
>> this.
>>
>
> Abhisit: I have my enums version. No compile error, no work! Lets me add
> it later on, after this once is working.
>
>
>> > +}
>> > +
>> > +static ssize_t lmp92001_avref_write(struct iio_dev *indio_dev,
>> uintptr_t private,
>> > + struct iio_chan_spec const *channel, const
>> char *buf,
>> > + size_t len)
>> > +{
>> > + struct lmp92001 *lmp92001 = iio_device_get_drvdata(indio_dev);
>> > + unsigned int cref;
>> > + int ret;
>> > +
>> > + if (strcmp("external\n", buf) == 0)
>> > + cref = 2;
>> > + else if (strcmp("internal\n", buf) == 0)
>> > + cref = 0;
>> > + else
>> > + return -EINVAL;
>> > +
>> > + ret = regmap_update_bits(lmp92001->regmap, LMP92001_CREF, 2,
>> cref);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + return len;
>> > +}
>> > +
>> > +static ssize_t lmp92001_enable_read(struct iio_dev *indio_dev,
>> uintptr_t private,
>> > + struct iio_chan_spec const *channel, char *buf)
>> > +{
>> > + struct lmp92001 *lmp92001 = iio_device_get_drvdata(indio_dev);
>> > + unsigned int reg, cad;
>> > + int ret;
>> > +
>> > + switch (channel->channel)
>> > + {
>> > + case 1 ... 8:
>> > + reg = LMP92001_CAD1;
>> > + break;
>> > + case 9 ... 16:
>> > + reg = LMP92001_CAD2;
>> > + break;
>> > + case 17:
>> > + reg = LMP92001_CAD3;
>> > + break;
>> > + default:
>> > + return -EINVAL;
>> > + }
>> > +
>> > + ret = regmap_read(lmp92001->regmap, reg, &cad);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + if (channel->channel <= 8)
>> > + cad >>= channel->channel - 1;
>> > + else if(channel->channel > 8)
>> > + cad >>= channel->channel - 9;
>> > + else if(channel->channel > 16)
>> > + cad >>= channel->channel - 17;
>> > + else
>> > + return -EINVAL;
>> > +
>> > + return sprintf(buf, "%s\n", cad & 1 ? "enable" : "disable");
>> Again this is new ABI. Need documenting in this series and detailed
>> discussion.
>>
>
> Abhisit: I will do.
>
>
>> > +}
>> > +
>> > +static ssize_t lmp92001_enable_write(struct iio_dev *indio_dev,
>> uintptr_t private,
>> > + struct iio_chan_spec const *channel, const
>> char *buf,
>> > + size_t len)
>> > +{
>> > + struct lmp92001 *lmp92001 = iio_device_get_drvdata(indio_dev);
>> > + unsigned int reg, enable, shif, mask;
>> > + int ret;
>> > +
>> > + switch (channel->channel)
>> > + {
>> > + case 1 ... 8:
>> > + reg = LMP92001_CAD1;
>> > + shif = (channel->channel - 1);
>> > + break;
>> > + case 9 ... 16:
>> > + reg = LMP92001_CAD2;
>> > + shif = (channel->channel - 9);
>> > + break;
>> > + case 17:
>> > + reg = LMP92001_CAD3;
>> > + shif = (channel->channel - 17);
>> > + break;
>> > + default:
>> > + return -EINVAL;
>> > + }
>> > +
>> > + if (strcmp("enable\n", buf) == 0)
>> > + enable = 1;
>> > + else if (strcmp("disable\n", buf) == 0)
>> > + enable = 0;
>> > + else
>> > + return -EINVAL;
>> > +
>> > + enable <<= shif;
>> > + mask = 1 << shif;
>> > +
>> > + ret = regmap_update_bits(lmp92001->regmap, reg, mask, enable);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + return len;
>> > +}
>> > +
>> > +static ssize_t lmp92001_mode_read(struct iio_dev *indio_dev, uintptr_t
>> private,
>> > + struct iio_chan_spec const *channel, char *buf)
>> > +{
>> > + struct lmp92001 *lmp92001 = iio_device_get_drvdata(indio_dev);
>> > + unsigned int cgen;
>> > + int ret;
>> > +
>> > + ret = regmap_read(lmp92001->regmap, LMP92001_CGEN, &cgen);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + return sprintf(buf, "%s\n", cgen & 1 ? "continuous" :
>> "single-shot");
>> Again, documentation. Note that exposing explicit controls for single-shot
>> or continuous capture hasn't yet made sense in any other drivers.
>> Normally this is something that can be optimized in driver.
>>
>> There is always a trade off between flexibility and keeping the userspace
>> ABI
>> short and clean.
>>
>
> Abhisit: Basically, It is hardware conversion mode operation. I will take
> a look on how to optimize.
>
>
>> > +}
>> > +
>> > +static ssize_t lmp92001_mode_write(struct iio_dev *indio_dev,
>> uintptr_t private,
>> > + struct iio_chan_spec const *channel, const
>> char *buf,
>> > + size_t len)
>> > +{
>> > + struct lmp92001 *lmp92001 = iio_device_get_drvdata(indio_dev);
>> > + unsigned int cgen;
>> > + int ret;
>> > +
>> > + if (strcmp("continuous\n", buf) == 0)
>> > + cgen = 1;
>> > + else if (strcmp("single-shot\n", buf) == 0)
>> > + cgen = 0;
>> > + else
>> > + return -EINVAL;
>> > +
>> > + /*
>> > + * Unlock the registers.
>> > + * Set conversion mode.
>> > + * Lock the registers.
>> > + */
>> > + ret = regmap_update_bits(lmp92001->regmap, LMP92001_CGEN, 2,
>> 0);
>> > + if (ret < 0)
>> > + return ret;
>> What stops a race with this lock? You need a driver lock to prevent
>> multiple
>> simultaneous sysfs actions from messing things up.
>>
>
> Abhisit: The lock is hardware register function for prevent multiple
> access to change the chip configuration.
>
>
>> > +
>> > + ret = regmap_update_bits(lmp92001->regmap, LMP92001_CGEN, 1,
>> cgen);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + ret = regmap_update_bits(lmp92001->regmap, LMP92001_CGEN, 2,
>> 2);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + return len;
>> > +}
>> > +
>> > +static const struct iio_chan_spec_ext_info lmp92001_ext_info[] = {
>> > + {
>> > + .name = "vref",
>> > + .read = lmp92001_avref_read,
>> > + .write = lmp92001_avref_write,
>> > + .shared = IIO_SHARED_BY_ALL,
>> > + },
>> > + {
>> > + .name = "en",
>> > + .read = lmp92001_enable_read,
>> > + .write = lmp92001_enable_write,
>> > + .shared = IIO_SEPARATE,
>> > + },
>> > + {
>> > + .name = "mode",
>> > + .read = lmp92001_mode_read,
>> > + .write = lmp92001_mode_write,
>> > + .shared = IIO_SHARED_BY_ALL,
>> All of this must be defined in the documentation.
>>
>> Vref is almost always a board specific element.
>> You don't fit an external reference if you are intending to
>> use the internal one.
>>
>> If necessary we can use differential channels to represent the two
>> possible voltage references, but that is rather ugly.
>>
>
> Abhisit: I would like to design for changeable vref source.
>
>
>> > + },
>> > + { },
>> > +};
>> > +
>> > +static const struct iio_event_spec lmp92001_events[] = {
>> > + {
>> > + .type = IIO_EV_TYPE_THRESH,
>> > + .dir = IIO_EV_DIR_RISING,
>> > + .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
>> > + BIT(IIO_EV_INFO_VALUE),
>> > + },
>> > + {
>> > + .type = IIO_EV_TYPE_THRESH,
>> > + .dir = IIO_EV_DIR_FALLING,
>> > + .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
>> > + BIT(IIO_EV_INFO_VALUE),
>> > + },
>> > + { },
>> > +};
>> > +
>> > +#define LMP92001_CHAN_SPEC(_ch, _type, _event, _nevent) \
>> > +{ \
>> > + .channel = _ch, \
>> > + .scan_index = _ch, \
>> > + .scan_type = { \
>> > + .sign = 'u', \
>> > + .realbits = 12, \
>> > + .storagebits = 16, \
>> > + .repeat = 1, \
>> > + .endianness = IIO_BE, \
>> Don't specify stuff you aren't using. The scan stuff only
>> typically becomes relevant when you providing the 'push'
>> or buffered interfaces. This driver isn't yet.
>>
>
> Abhisit: Could you help me to coding this, I have no idea, what is your
> point. This is my first iio driver.
>
>
>> > + }, \
>> > + .type = _type, \
>> > + .indexed = 1, \
>> > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
>> > + .event_spec = _event, \
>> > + .num_event_specs = _nevent, \
>> > + .ext_info = lmp92001_ext_info, \
>> > +}
>> > +
>> > +/*
>> > + * TODO: do your ext_info for current low/high limit.
>> > + * Example driver/iio/dac/ad5064.c
>> > + */
>> > +static const struct iio_chan_spec lmp92001_adc_channels[] = {
>> > + LMP92001_CHAN_SPEC( 1, IIO_VOLTAGE, lmp92001_events,
>> ARRAY_SIZE(lmp92001_events)),
>> > + LMP92001_CHAN_SPEC( 2, IIO_VOLTAGE, lmp92001_events,
>> ARRAY_SIZE(lmp92001_events)),
>> > + LMP92001_CHAN_SPEC( 3, IIO_VOLTAGE, lmp92001_events,
>> ARRAY_SIZE(lmp92001_events)),
>> > + LMP92001_CHAN_SPEC( 4, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC( 5, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC( 6, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC( 7, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC( 8, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC( 9, IIO_VOLTAGE, lmp92001_events,
>> ARRAY_SIZE(lmp92001_events)),
>> > + LMP92001_CHAN_SPEC(10, IIO_VOLTAGE, lmp92001_events,
>> ARRAY_SIZE(lmp92001_events)),
>> > + LMP92001_CHAN_SPEC(11, IIO_VOLTAGE, lmp92001_events,
>> ARRAY_SIZE(lmp92001_events)),
>> > + LMP92001_CHAN_SPEC(12, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC(13, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC(14, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC(15, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC(16, IIO_VOLTAGE, NULL, 0),
>> > + LMP92001_CHAN_SPEC(17, IIO_TEMP, NULL, 0),
>> > +};
>> > +
>> > +static int lmp92001_adc_probe(struct platform_device *pdev)
>> > +{
>> > + struct lmp92001 *lmp92001 = dev_get_drvdata(pdev->dev.parent);
>> > + struct iio_dev *indio_dev;
>> > + struct device_node *np = pdev->dev.of_node;
>> > + const char *conversion;
>> > + unsigned int cgen = 0, cad1, cad2, cad3;
>> > + u32 mask;
>> > + int ret;
>> > +
>> > + indio_dev = devm_iio_device_alloc(&pdev->dev,
>> sizeof(*lmp92001));
>> > + if (!indio_dev)
>> > + return -ENOMEM;
>> > +
>> > + iio_device_set_drvdata(indio_dev, lmp92001);
>> > +
>> > + indio_dev->name = pdev->name;
>> > + indio_dev->dev.parent = &pdev->dev;
>> > + indio_dev->modes = INDIO_DIRECT_MODE;
>> > + indio_dev->info = &lmp92001_info;
>> > + indio_dev->channels = lmp92001_adc_channels;
>> > + indio_dev->num_channels = ARRAY_SIZE(lmp92001_adc_channels);
>> > +
>> > + ret = regmap_update_bits(lmp92001->regmap, LMP92001_CGEN,
>> 0x80, 0x80);
>> > + if (ret < 0)
>> 0x80 is a magic number. Use a #define to give it meaning to someone who
>> can't be bothered to find the datasheet (i.e. me ;)
>>
>
> Abhisit: I will defined it.
>
>
>> > + {
>> > + dev_err(&pdev->dev,"failed to self reset all
>> registers\n");
>> > + return ret;
>> > + }
>> > +
>> > + ret = of_property_read_u32(np, "ti,lmp92001-adc-mask", &mask);
>> > + if (ret < 0)
>> > + {
>> > + cad1 = cad2 = cad3 = 0xFF;
>> > + dev_info(&pdev->dev, "turn on all of channels by
>> default\n");
>> Talk me through this - why can we not turn them on when we want a reading?
>> Just how slow is this device to start up?
>> Or are we looking at stopping certain channels from being used because
>> the pin
>> is in use for something else?
>>
>
> Abhisit: I would like to design to support initialization on start-up.
>
>
>>
>> > + }
>> > + else
>> > + {
>> > + cad1 = mask & 0xFF;
>> > + cad2 = (mask >> 8) & 0xFF;
>> > + cad3 = (mask >> 16) & 0xFF;
>> > + }
>> > +
>> > + ret = regmap_update_bits(lmp92001->regmap, LMP92001_CAD1,
>> 0xFF, cad1);
>> > + if (ret < 0)
>> > + {
>> > + dev_err(&pdev->dev,"failed to enable channels 1-8\n");
>> > + return ret;
>> > + }
>> > +
>> > + ret = regmap_update_bits(lmp92001->regmap, LMP92001_CAD2,
>> 0xFF, cad2);
>> > + if (ret < 0)
>> > + {
>> > + dev_err(&pdev->dev, "failed to enable channels
>> 9-16\n");
>> > + return ret;
>> > + }
>> > +
>> > + ret = regmap_update_bits(lmp92001->regmap, LMP92001_CAD3, 1,
>> cad3);
>> > + if (ret < 0)
>> > + {
>> > + dev_err(&pdev->dev, "failed to enable channel 17
>> (temperature)\n");
>> > + return ret;
>> These presumably need disabling again on remove or error to save power?
>>
>> Basic rule of thumb is that if something is setup in the probe routine, we
>> expect it to be reversed in the remove and any error path in probe.
>>
>
> Abhisit: This chip can not stop. We have no to do remove or disable it.
>
>
>> > + }
>> > +
>> > + ret = of_property_read_string_index(np,
>> "ti,lmp92001-adc-mode", 0,
>> > + &conversion);
>> > + if (!ret)
>> > + {
>> > + if (strcmp("continuous", conversion) == 0)
>> > + cgen |= 1;
>> > + else if (strcmp("single-shot", conversion) == 0)
>> > + { /* Okay */ }
>> > + else
>> > + dev_warn(&pdev->dev,
>> > + "wrong adc mode! set to single-short
>> conversion\n");
>> Is this a characteristic of the hardware? Don't think so and isn't a
>> policy
>> that makes much sense to push into the devicetree. Just pick one as
>> the default and let the driver figure out when to change.
>>
>
> Abhisit: I will set continuous mode as default.
>
>
>>
>> > + }
>> > + else
>> > + dev_info(&pdev->dev,
>> > + "single-short conversion was chosen by default\n");
>> > +
>> > + /*
>> > + * Lock the registers and set conversion mode.
>> > + */
>> > + ret = regmap_update_bits(lmp92001->regmap,
>> > + LMP92001_CGEN, 3, cgen | 2);
>> > + if (ret < 0)
>> > + return ret;
>> > +
>> > + platform_set_drvdata(pdev, indio_dev);
>> > +
>> > + return iio_device_register(indio_dev);
>> > +}
>> > +
>> > +static int lmp92001_adc_remove(struct platform_device *pdev)
>> > +{
>> > + struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> > +
>> > + iio_device_unregister(indio_dev);
>> No disabling of the device to be done?
>>
>
> Abhisit: HW is no way to stop.
>
>
>> > +
>> > + return 0;
>> > +}
>> > +
>> > +static struct platform_driver lmp92001_adc_driver = {
>> > + .driver.name = "lmp92001-adc",
>> > + .driver.owner = THIS_MODULE,
>> > + .probe = lmp92001_adc_probe,
>> > + .remove = lmp92001_adc_remove,
>> > +};
>> > +
>> > +static int __init lmp92001_adc_init(void)
>> > +{
>> > + return platform_driver_register(&lmp92001_adc_driver);
>> > +}
>> > +subsys_initcall(lmp92001_adc_init);
>> > +
>> > +static void __exit lmp92001_adc_exit(void)
>> > +{
>> > + platform_driver_unregister(&lmp92001_adc_driver);
>> > +}
>> > +module_exit(lmp92001_adc_exit);
>> > +
>> > +MODULE_AUTHOR("Abhisit Sangjan <s.abhisit@gmail.com>");
>> > +MODULE_DESCRIPTION("IIO ADC interface for TI LMP92001");
>> > +MODULE_LICENSE("GPL");
>> > +MODULE_ALIAS("platform:lmp92001-adc");
>>
>>
>
[-- Attachment #2: Type: text/html, Size: 39907 bytes --]
next prev parent reply other threads:[~2017-08-02 7:06 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-08-01 9:12 [PATCH 2/5] iio: Add support for LMP92001 ADC s.abhisit
2017-08-01 10:10 ` Jonathan Cameron
[not found] ` <CAMV_pUaV54qUc1wOhL5cAP8mEX1k0VsL3aEGG+wziqPPnZGHWg@mail.gmail.com>
2017-08-02 7:06 ` Abhisit Sangjan [this message]
2017-08-09 14:22 ` Jonathan Cameron
2017-08-03 10:40 ` Peter Meerwald-Stadler
2017-08-05 4:49 ` Abhisit Sangjan
2017-08-11 14:38 ` jmondi
2017-08-18 2:34 ` Abhisit Sangjan
2017-08-18 2:58 ` jmondi
2017-08-18 3:15 ` Abhisit Sangjan
2017-08-18 7:42 ` Abhisit Sangjan
2017-08-20 10:31 ` Jonathan Cameron
2017-08-21 17:29 ` jmondi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAMV_pUYOMdb_e1xYEkhhuO2GN4FDFSRy6BpHUK5GqO0o8yO1fA@mail.gmail.com \
--to=s.abhisit@gmail.com \
--cc=Jonathan.Cameron@huawei.com \
--cc=akinobu.mita@gmail.com \
--cc=fabrice.gasnier@st.com \
--cc=jacopo+renesas@jmondi.org \
--cc=jic23@kernel.org \
--cc=knaack.h@gmx.de \
--cc=lars@metafoo.de \
--cc=lee.jones@linaro.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=marek.vasut+renesas@gmail.com \
--cc=pmeerw@pmeerw.net \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).