[PATCH v2 1/2] staging: iio: frequency: ad9833: Get frequency value statically
From: Beniamin Bia The values from platform data were replaced by statically values. This was just a intermediate step of taking this driver out of staging and load data from device tree. Signed-off-by: Beniamin Bia --- Changes in v2: - The platform data structure was removed and the values are written directly drivers/staging/iio/frequency/ad9834.c | 21 +++ drivers/staging/iio/frequency/ad9834.h | 28 -- 2 files changed, 7 insertions(+), 42 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 995acdd7c942..f4f5eaa15e30 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -391,16 +391,11 @@ static const struct iio_info ad9833_info = { static int ad9834_probe(struct spi_device *spi) { - struct ad9834_platform_data *pdata = dev_get_platdata(&spi->dev); struct ad9834_state *st; struct iio_dev *indio_dev; struct regulator *reg; int ret; - if (!pdata) { - dev_dbg(&spi->dev, "no platform data?\n"); - return -ENODEV; - } reg = devm_regulator_get(&spi->dev, "avdd"); if (IS_ERR(reg)) @@ -420,7 +415,7 @@ static int ad9834_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); st = iio_priv(indio_dev); mutex_init(&st->lock); - st->mclk = pdata->mclk; + st->mclk = 2500; st->spi = spi; st->devid = spi_get_device_id(spi)->driver_data; st->reg = reg; @@ -456,11 +451,9 @@ static int ad9834_probe(struct spi_device *spi) spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg); st->control = AD9834_B28 | AD9834_RESET; + st->control |= AD9834_DIV2; - if (!pdata->en_div2) - st->control |= AD9834_DIV2; - - if (!pdata->en_signbit_msb_out && (st->devid == ID_AD9834)) + if (st->devid == ID_AD9834) st->control |= AD9834_SIGN_PIB; st->data = cpu_to_be16(AD9834_REG_CMD | st->control); @@ -470,19 +463,19 @@ static int ad9834_probe(struct spi_device *spi) goto error_disable_reg; } - ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0); + ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, 100); if (ret) goto error_disable_reg; - ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1); + ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, 500); if (ret) goto error_disable_reg; - ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0); + ret = ad9834_write_phase(st, AD9834_REG_PHASE0, 512); if (ret) goto error_disable_reg; - ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1); + ret = ad9834_write_phase(st, AD9834_REG_PHASE1, 1024); if (ret) goto error_disable_reg; diff --git a/drivers/staging/iio/frequency/ad9834.h b/drivers/staging/iio/frequency/ad9834.h index ae620f38eb49..da7e83ceedad 100644 --- a/drivers/staging/iio/frequency/ad9834.h +++ b/drivers/staging/iio/frequency/ad9834.h @@ -8,32 +8,4 @@ #ifndef IIO_DDS_AD9834_H_ #define IIO_DDS_AD9834_H_ -/* - * TODO: struct ad7887_platform_data needs to go into include/linux/iio - */ - -/** - * struct ad9834_platform_data - platform specific information - * @mclk: master clock in Hz - * @freq0: power up freq0 tuning word in Hz - * @freq1: power up freq1 tuning word in Hz - * @phase0:power up phase0 value [0..4095] correlates with 0..2PI - * @phase1:power up phase1 value [0..4095] correlates with 0..2PI - * @en_div2: digital output/2 is passed to the SIGN BIT OUT pin - * @en_signbit_msb_out:the MSB (or MSB/2) of the DAC data is connected to the - * SIGN BIT OUT pin. en_div2 controls whether it is the MSB - * or MSB/2 that is output. if en_signbit_msb_out=false, - * the on-board comparator is connected to SIGN BIT OUT - */ - -struct ad9834_platform_data { - unsigned intmclk; - unsigned intfreq0; - unsigned intfreq1; - unsigned short phase0; - unsigned short phase1; - boolen_div2; - boolen_signbit_msb_out; -}; - #endif /* IIO_DDS_AD9834_H_ */ -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v2 2/2] staging: iio: frequency: ad9833: Load clock using clock framework
From: Beniamin Bia The clock frequency is loaded from device-tree using clock framework instead of statically value. The change allow configuration of the device via device-trees and better initialization sequence. This is part of broader effort to add device-tree support to this driver and take it out from staging. Signed-off-by: Beniamin Bia --- Changes in v2: -the intermidiate clk variable was replaced by the variable in device state -st variable may be uninitialized warning was fixed by adding a new error label drivers/staging/iio/frequency/ad9834.c | 35 ++ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index f4f5eaa15e30..f036f75d1f22 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -6,6 +6,7 @@ * Licensed under the GPL-2. */ +#include #include #include #include @@ -71,7 +72,7 @@ struct ad9834_state { struct spi_device *spi; struct regulator*reg; - unsigned intmclk; + struct clk *mclk; unsigned short control; unsigned short devid; struct spi_transfer xfer; @@ -110,12 +111,15 @@ static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout) static int ad9834_write_frequency(struct ad9834_state *st, unsigned long addr, unsigned long fout) { + unsigned long clk_freq; unsigned long regval; - if (fout > (st->mclk / 2)) + clk_freq = clk_get_rate(st->mclk); + + if (fout > (clk_freq / 2)) return -EINVAL; - regval = ad9834_calc_freqreg(st->mclk, fout); + regval = ad9834_calc_freqreg(clk_freq, fout); st->freq_data[0] = cpu_to_be16(addr | (regval & RES_MASK(AD9834_FREQ_BITS / 2))); @@ -415,7 +419,14 @@ static int ad9834_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); st = iio_priv(indio_dev); mutex_init(&st->lock); - st->mclk = 2500; + st->mclk = devm_clk_get(&spi->dev, NULL); + + ret = clk_prepare_enable(st->mclk); + if (ret) { + dev_err(&spi->dev, "Failed to enable master clock\n"); + goto error_disable_reg; + } + st->spi = spi; st->devid = spi_get_device_id(spi)->driver_data; st->reg = reg; @@ -460,31 +471,32 @@ static int ad9834_probe(struct spi_device *spi) ret = spi_sync(st->spi, &st->msg); if (ret) { dev_err(&spi->dev, "device init failed\n"); - goto error_disable_reg; + goto error_clock_unprepare; } ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, 100); if (ret) - goto error_disable_reg; + goto error_clock_unprepare; ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, 500); if (ret) - goto error_disable_reg; + goto error_clock_unprepare; ret = ad9834_write_phase(st, AD9834_REG_PHASE0, 512); if (ret) - goto error_disable_reg; + goto error_clock_unprepare; ret = ad9834_write_phase(st, AD9834_REG_PHASE1, 1024); if (ret) - goto error_disable_reg; + goto error_clock_unprepare; ret = iio_device_register(indio_dev); if (ret) - goto error_disable_reg; + goto error_clock_unprepare; return 0; - +error_clock_unprepare: + clk_disable_unprepare(st->mclk); error_disable_reg: regulator_disable(reg); @@ -497,6 +509,7 @@ static int ad9834_remove(struct spi_device *spi) struct ad9834_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); + clk_disable_unprepare(st->mclk); regulator_disable(st->reg); return 0; -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 2/2] staging: iio: frequency: ad9834: Move phase and scale to standard iio attribute
From: Beniamin Bia The custom phase and scale attributes were moved to standard iio types. Signed-off-by: Beniamin Bia --- drivers/staging/iio/frequency/ad9834.c | 54 +++--- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 370e8263899e..3ecf976ddefe 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -30,8 +30,7 @@ #define AD9834_REG_CMD 0 #define AD9834_REG_FREQ(chann) (BIT(14) << (chann)) -#define AD9834_REG_PHASE0 (BIT(15) | BIT(14)) -#define AD9834_REG_PHASE1 (BIT(15) | BIT(14) | BIT(13)) +#define AD9834_REG_PHASE(chann)(BIT(15) | BIT(14) | ((chann) << 13UL)) /* Command Control Bits */ @@ -82,6 +81,8 @@ struct ad9834_state { unsigned long frequency0; unsigned long frequency1; + unsigned long phase0; + unsigned long phase1; /* * DMA (thus cache coherency maintenance) requires the @@ -109,6 +110,8 @@ enum ad9834_supported_device_ids { .address = (_chan), \ .channel = (_chan), \ .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) \ + | BIT(IIO_CHAN_INFO_PHASE),\ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ } static const struct iio_chan_spec ad9833_channels[] = { @@ -164,11 +167,22 @@ static int ad9834_write_frequency(struct ad9834_state *st, static int ad9834_write_phase(struct ad9834_state *st, unsigned long addr, unsigned long phase) { + int ret; + if (phase > BIT(AD9834_PHASE_BITS)) return -EINVAL; - st->data = cpu_to_be16(addr | phase); + st->data = cpu_to_be16(AD9834_REG_PHASE(addr) | phase); + + ret = spi_sync(st->spi, &st->msg); + if (ret) + return ret; - return spi_sync(st->spi, &st->msg); + if (addr == 0) + st->phase0 = phase; + else + st->phase1 = phase; + + return 0; } static int ad9834_read_raw(struct iio_dev *indio_dev, @@ -184,6 +198,16 @@ static int ad9834_read_raw(struct iio_dev *indio_dev, else *val = st->frequency1; return IIO_VAL_INT; + case IIO_CHAN_INFO_PHASE: + if (chan->address == 0) + *val = st->phase0; + else + *val = st->phase1; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /*1 hz */ + *val = 1; + return IIO_VAL_INT; } return -EINVAL; @@ -198,6 +222,8 @@ static int ad9834_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_FREQUENCY: return ad9834_write_frequency(st, chan->address, val); + case IIO_CHAN_INFO_PHASE: + return ad9834_write_phase(st, chan->address, val); default: return -EINVAL; } @@ -222,10 +248,6 @@ static ssize_t ad9834_write(struct device *dev, mutex_lock(&st->lock); switch ((u32)this_attr->address) { - case AD9834_REG_PHASE0: - case AD9834_REG_PHASE1: - ret = ad9834_write_phase(st, this_attr->address, val); - break; case AD9834_OPBITEN: if (st->control & AD9834_MODE) { ret = -EINVAL; /* AD9843 reserved mode */ @@ -385,12 +407,8 @@ static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, 0444, */ static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9834_write, AD9834_FSEL); -static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ -static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9834_write, AD9834_REG_PHASE0); -static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9834_write, AD9834_REG_PHASE1); static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL, ad9834_write, AD9834_PSEL); -static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/ static IIO_DEV_ATTR_PINCONTROL_EN(0, 0200, NULL, ad9834_write, AD9834_PIN_SW); @@ -401,10 +419,6 @@ static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0); static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1); static struct attribute *ad9834_attributes[] = { - &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr, - &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr, - &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr, - &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr, &
[PATCH 1/2] staging: iio: frequency: ad9834: Move frequency to standard iio types
From: Beniamin Bia Frequency attribute is added with a standard type from iio framework instead of custom attribute. This is a small step towards removing any unnecessary custom attribute. Signed-off-by: Beniamin Bia --- drivers/staging/iio/frequency/ad9834.c | 97 +- 1 file changed, 80 insertions(+), 17 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index f036f75d1f22..370e8263899e 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -29,8 +29,7 @@ /* Registers */ #define AD9834_REG_CMD 0 -#define AD9834_REG_FREQ0 BIT(14) -#define AD9834_REG_FREQ1 BIT(15) +#define AD9834_REG_FREQ(chann) (BIT(14) << (chann)) #define AD9834_REG_PHASE0 (BIT(15) | BIT(14)) #define AD9834_REG_PHASE1 (BIT(15) | BIT(14) | BIT(13)) @@ -81,6 +80,9 @@ struct ad9834_state { struct spi_message freq_msg; struct mutexlock; /* protect sensor state */ + unsigned long frequency0; + unsigned long frequency1; + /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. @@ -100,6 +102,25 @@ enum ad9834_supported_device_ids { ID_AD9838, }; +#define AD9833_CHANNEL(_chan) { \ + .type = IIO_ALTVOLTAGE, \ + .indexed = 1, \ + .output = 1,\ + .address = (_chan), \ + .channel = (_chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) \ +} + +static const struct iio_chan_spec ad9833_channels[] = { + AD9833_CHANNEL(0), + AD9833_CHANNEL(1), +}; + +static const struct iio_chan_spec ad9834_channels[] = { + AD9833_CHANNEL(0), + AD9833_CHANNEL(1), +}; + static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout) { unsigned long long freqreg = (u64)fout * (u64)BIT(AD9834_FREQ_BITS); @@ -113,6 +134,7 @@ static int ad9834_write_frequency(struct ad9834_state *st, { unsigned long clk_freq; unsigned long regval; + int ret; clk_freq = clk_get_rate(st->mclk); @@ -121,13 +143,22 @@ static int ad9834_write_frequency(struct ad9834_state *st, regval = ad9834_calc_freqreg(clk_freq, fout); - st->freq_data[0] = cpu_to_be16(addr | (regval & + st->freq_data[0] = cpu_to_be16(AD9834_REG_FREQ(addr) | (regval & RES_MASK(AD9834_FREQ_BITS / 2))); - st->freq_data[1] = cpu_to_be16(addr | ((regval >> + st->freq_data[1] = cpu_to_be16(AD9834_REG_FREQ(addr) | ((regval >> (AD9834_FREQ_BITS / 2)) & RES_MASK(AD9834_FREQ_BITS / 2))); - return spi_sync(st->spi, &st->freq_msg); + ret = spi_sync(st->spi, &st->freq_msg); + if (ret) + return ret; + + if (addr == 0) + st->frequency0 = fout; + else + st->frequency1 = fout; + + return 0; } static int ad9834_write_phase(struct ad9834_state *st, @@ -140,6 +171,40 @@ static int ad9834_write_phase(struct ad9834_state *st, return spi_sync(st->spi, &st->msg); } +static int ad9834_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad9834_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + if (chan->address == 0) + *val = st->frequency0; + else + *val = st->frequency1; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int ad9834_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad9834_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + return ad9834_write_frequency(st, chan->address, val); + default: + return -EINVAL; + } + + return 0; +} + static ssize_t ad9834_write(struct device *dev, struct device_attribute *attr, const char *buf, @@ -157,10 +222,6 @@ static ssize_t ad9834_write(struct device *dev, mutex_lock(&st->lock); switch ((u32)this_attr->address) { - case AD98
[PATCH 2/2] staging: iio: frequency: ad9834: Move phase and scale to standard iio attribute
The custom phase and scale attributes were moved to standard iio types. Signed-off-by: Beniamin Bia --- drivers/staging/iio/frequency/ad9834.c | 54 +++--- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 370e8263899e..3ecf976ddefe 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -30,8 +30,7 @@ #define AD9834_REG_CMD 0 #define AD9834_REG_FREQ(chann) (BIT(14) << (chann)) -#define AD9834_REG_PHASE0 (BIT(15) | BIT(14)) -#define AD9834_REG_PHASE1 (BIT(15) | BIT(14) | BIT(13)) +#define AD9834_REG_PHASE(chann)(BIT(15) | BIT(14) | ((chann) << 13UL)) /* Command Control Bits */ @@ -82,6 +81,8 @@ struct ad9834_state { unsigned long frequency0; unsigned long frequency1; + unsigned long phase0; + unsigned long phase1; /* * DMA (thus cache coherency maintenance) requires the @@ -109,6 +110,8 @@ enum ad9834_supported_device_ids { .address = (_chan), \ .channel = (_chan), \ .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) \ + | BIT(IIO_CHAN_INFO_PHASE),\ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ } static const struct iio_chan_spec ad9833_channels[] = { @@ -164,11 +167,22 @@ static int ad9834_write_frequency(struct ad9834_state *st, static int ad9834_write_phase(struct ad9834_state *st, unsigned long addr, unsigned long phase) { + int ret; + if (phase > BIT(AD9834_PHASE_BITS)) return -EINVAL; - st->data = cpu_to_be16(addr | phase); + st->data = cpu_to_be16(AD9834_REG_PHASE(addr) | phase); + + ret = spi_sync(st->spi, &st->msg); + if (ret) + return ret; - return spi_sync(st->spi, &st->msg); + if (addr == 0) + st->phase0 = phase; + else + st->phase1 = phase; + + return 0; } static int ad9834_read_raw(struct iio_dev *indio_dev, @@ -184,6 +198,16 @@ static int ad9834_read_raw(struct iio_dev *indio_dev, else *val = st->frequency1; return IIO_VAL_INT; + case IIO_CHAN_INFO_PHASE: + if (chan->address == 0) + *val = st->phase0; + else + *val = st->phase1; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /*1 hz */ + *val = 1; + return IIO_VAL_INT; } return -EINVAL; @@ -198,6 +222,8 @@ static int ad9834_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_FREQUENCY: return ad9834_write_frequency(st, chan->address, val); + case IIO_CHAN_INFO_PHASE: + return ad9834_write_phase(st, chan->address, val); default: return -EINVAL; } @@ -222,10 +248,6 @@ static ssize_t ad9834_write(struct device *dev, mutex_lock(&st->lock); switch ((u32)this_attr->address) { - case AD9834_REG_PHASE0: - case AD9834_REG_PHASE1: - ret = ad9834_write_phase(st, this_attr->address, val); - break; case AD9834_OPBITEN: if (st->control & AD9834_MODE) { ret = -EINVAL; /* AD9843 reserved mode */ @@ -385,12 +407,8 @@ static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, 0444, */ static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9834_write, AD9834_FSEL); -static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ -static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9834_write, AD9834_REG_PHASE0); -static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9834_write, AD9834_REG_PHASE1); static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL, ad9834_write, AD9834_PSEL); -static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/ static IIO_DEV_ATTR_PINCONTROL_EN(0, 0200, NULL, ad9834_write, AD9834_PIN_SW); @@ -401,10 +419,6 @@ static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0); static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1); static struct attribute *ad9834_attributes[] = { - &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr, - &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr, - &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr, - &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr, &iio_dev_attr_out_altvoltage0_pincontrol_en.dev_attr.attr,
[PATCH 1/2] staging: iio: frequency: ad9834: Move frequency to standard iio types
Frequency attribute is added with a standard type from iio framework instead of custom attribute. This is a small step towards removing any unnecessary custom attribute. Signed-off-by: Beniamin Bia --- drivers/staging/iio/frequency/ad9834.c | 97 +- 1 file changed, 80 insertions(+), 17 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index f036f75d1f22..370e8263899e 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -29,8 +29,7 @@ /* Registers */ #define AD9834_REG_CMD 0 -#define AD9834_REG_FREQ0 BIT(14) -#define AD9834_REG_FREQ1 BIT(15) +#define AD9834_REG_FREQ(chann) (BIT(14) << (chann)) #define AD9834_REG_PHASE0 (BIT(15) | BIT(14)) #define AD9834_REG_PHASE1 (BIT(15) | BIT(14) | BIT(13)) @@ -81,6 +80,9 @@ struct ad9834_state { struct spi_message freq_msg; struct mutexlock; /* protect sensor state */ + unsigned long frequency0; + unsigned long frequency1; + /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. @@ -100,6 +102,25 @@ enum ad9834_supported_device_ids { ID_AD9838, }; +#define AD9833_CHANNEL(_chan) { \ + .type = IIO_ALTVOLTAGE, \ + .indexed = 1, \ + .output = 1,\ + .address = (_chan), \ + .channel = (_chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) \ +} + +static const struct iio_chan_spec ad9833_channels[] = { + AD9833_CHANNEL(0), + AD9833_CHANNEL(1), +}; + +static const struct iio_chan_spec ad9834_channels[] = { + AD9833_CHANNEL(0), + AD9833_CHANNEL(1), +}; + static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout) { unsigned long long freqreg = (u64)fout * (u64)BIT(AD9834_FREQ_BITS); @@ -113,6 +134,7 @@ static int ad9834_write_frequency(struct ad9834_state *st, { unsigned long clk_freq; unsigned long regval; + int ret; clk_freq = clk_get_rate(st->mclk); @@ -121,13 +143,22 @@ static int ad9834_write_frequency(struct ad9834_state *st, regval = ad9834_calc_freqreg(clk_freq, fout); - st->freq_data[0] = cpu_to_be16(addr | (regval & + st->freq_data[0] = cpu_to_be16(AD9834_REG_FREQ(addr) | (regval & RES_MASK(AD9834_FREQ_BITS / 2))); - st->freq_data[1] = cpu_to_be16(addr | ((regval >> + st->freq_data[1] = cpu_to_be16(AD9834_REG_FREQ(addr) | ((regval >> (AD9834_FREQ_BITS / 2)) & RES_MASK(AD9834_FREQ_BITS / 2))); - return spi_sync(st->spi, &st->freq_msg); + ret = spi_sync(st->spi, &st->freq_msg); + if (ret) + return ret; + + if (addr == 0) + st->frequency0 = fout; + else + st->frequency1 = fout; + + return 0; } static int ad9834_write_phase(struct ad9834_state *st, @@ -140,6 +171,40 @@ static int ad9834_write_phase(struct ad9834_state *st, return spi_sync(st->spi, &st->msg); } +static int ad9834_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad9834_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + if (chan->address == 0) + *val = st->frequency0; + else + *val = st->frequency1; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int ad9834_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad9834_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + return ad9834_write_frequency(st, chan->address, val); + default: + return -EINVAL; + } + + return 0; +} + static ssize_t ad9834_write(struct device *dev, struct device_attribute *attr, const char *buf, @@ -157,10 +222,6 @@ static ssize_t ad9834_write(struct device *dev, mutex_lock(&st->lock); switch ((u32)this_attr->address) { - case AD9834_REG_FREQ0:
[PATCH v2 1/2] staging: iio: frequency: ad9834: Move frequency to standard iio types
Frequency attribute is added with a standard type from iio framework instead of custom attribute. This is a small step towards removing any unnecessary custom attribute. Ad9834 will diverge from ad9833 in the future, that is why we have two identical arrays for ad9834 and 9833. Signed-off-by: Beniamin Bia --- Changes in v2: -the personal email address was replaced by the work email -separate define for frequency channel -address field from channel specification was removed -frequency variables were replaced by an array -specified in comment why we have differente chan_spec for ad9834 and ad9833 -enum used for write_frequency function drivers/staging/iio/frequency/ad9834.c | 110 - 1 file changed, 91 insertions(+), 19 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index f036f75d1f22..561617046c20 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -81,6 +81,8 @@ struct ad9834_state { struct spi_message freq_msg; struct mutexlock; /* protect sensor state */ + unsigned long frequency[2]; + /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. @@ -89,6 +91,11 @@ struct ad9834_state { __be16 freq_data[2]; }; +enum ad9834_ch_addr { + AD9834_CHANNEL_ADDRESS0, + AD9834_CHANNEL_ADDRESS1, +}; + /** * ad9834_supported_device_ids: */ @@ -100,6 +107,24 @@ enum ad9834_supported_device_ids { ID_AD9838, }; +#define AD9833_CHANNEL(chan) { \ + .type = IIO_ALTVOLTAGE, \ + .indexed = 1, \ + .output = 1,\ + .channel = (chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) \ +} + +static const struct iio_chan_spec ad9833_channels[] = { + AD9833_CHANNEL(0), + AD9833_CHANNEL(1), +}; + +static const struct iio_chan_spec ad9834_channels[] = { + AD9833_CHANNEL(0), + AD9833_CHANNEL(1), +}; + static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout) { unsigned long long freqreg = (u64)fout * (u64)BIT(AD9834_FREQ_BITS); @@ -109,10 +134,12 @@ static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout) } static int ad9834_write_frequency(struct ad9834_state *st, - unsigned long addr, unsigned long fout) + enum ad9834_ch_addr addr, + unsigned long fout) { unsigned long clk_freq; unsigned long regval; + int ret; clk_freq = clk_get_rate(st->mclk); @@ -121,13 +148,27 @@ static int ad9834_write_frequency(struct ad9834_state *st, regval = ad9834_calc_freqreg(clk_freq, fout); - st->freq_data[0] = cpu_to_be16(addr | (regval & - RES_MASK(AD9834_FREQ_BITS / 2))); - st->freq_data[1] = cpu_to_be16(addr | ((regval >> - (AD9834_FREQ_BITS / 2)) & - RES_MASK(AD9834_FREQ_BITS / 2))); + if (addr == AD9834_CHANNEL_ADDRESS0) { + st->freq_data[0] = cpu_to_be16(AD9834_REG_FREQ0 | (regval & + RES_MASK(AD9834_FREQ_BITS / 2))); + st->freq_data[1] = cpu_to_be16(AD9834_REG_FREQ0 | ((regval >> + (AD9834_FREQ_BITS / 2)) & + RES_MASK(AD9834_FREQ_BITS / 2))); + } else { + st->freq_data[0] = cpu_to_be16(AD9834_REG_FREQ1 | (regval & + RES_MASK(AD9834_FREQ_BITS / 2))); + st->freq_data[1] = cpu_to_be16(AD9834_REG_FREQ1 | ((regval >> + (AD9834_FREQ_BITS / 2)) & + RES_MASK(AD9834_FREQ_BITS / 2))); + } + + ret = spi_sync(st->spi, &st->freq_msg); + if (ret) + return ret; + + st->frequency[(int)addr] = fout; - return spi_sync(st->spi, &st->freq_msg); + return 0; } static int ad9834_write_phase(struct ad9834_state *st, @@ -140,6 +181,39 @@ static int ad9834_write_phase(struct ad9834_state *st, return spi_sync(st->spi, &st->msg); } +static int ad9834_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, +
[PATCH v2 2/2] staging: iio: frequency: ad9834: Move phase and scale to standard iio attribute
The custom phase and scale attributes were moved to standard iio types. Signed-off-by: Beniamin Bia --- Changes in v2: -the personal email address was replaced by the work email -separate define for every phase channel -enum used for write_phase functions -phase variables were replaced by an array drivers/staging/iio/frequency/ad9834.c | 53 -- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 561617046c20..4366b6121154 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -82,6 +82,7 @@ struct ad9834_state { struct mutexlock; /* protect sensor state */ unsigned long frequency[2]; + unsigned long phase[2]; /* * DMA (thus cache coherency maintenance) requires the @@ -113,6 +114,8 @@ enum ad9834_supported_device_ids { .output = 1,\ .channel = (chan), \ .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) \ + | BIT(IIO_CHAN_INFO_PHASE),\ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ } static const struct iio_chan_spec ad9833_channels[] = { @@ -172,13 +175,26 @@ static int ad9834_write_frequency(struct ad9834_state *st, } static int ad9834_write_phase(struct ad9834_state *st, - unsigned long addr, unsigned long phase) + enum ad9834_ch_addr addr, + unsigned long phase) { + int ret; + if (phase > BIT(AD9834_PHASE_BITS)) return -EINVAL; - st->data = cpu_to_be16(addr | phase); - return spi_sync(st->spi, &st->msg); + if (addr == AD9834_CHANNEL_ADDRESS0) + st->data = cpu_to_be16(AD9834_REG_PHASE0 | phase); + else + st->data = cpu_to_be16(AD9834_REG_PHASE1 | phase); + + ret = spi_sync(st->spi, &st->msg); + if (ret) + return ret; + + st->phase[(int)addr] = phase; + + return 0; } static int ad9834_read_raw(struct iio_dev *indio_dev, @@ -191,6 +207,13 @@ static int ad9834_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_FREQUENCY: *val = st->frequency[chan->channel]; return IIO_VAL_INT; + case IIO_CHAN_INFO_PHASE: + *val = st->phase[chan->channel]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /*1 hz */ + *val = 1; + return IIO_VAL_INT; } return -EINVAL; @@ -207,6 +230,10 @@ static int ad9834_write_raw(struct iio_dev *indio_dev, return ad9834_write_frequency(st, (enum ad9834_ch_addr)chan->channel, val); + case IIO_CHAN_INFO_PHASE: + return ad9834_write_phase(st, + (enum ad9834_ch_addr)chan->channel, + val); default: return -EINVAL; } @@ -231,10 +258,6 @@ static ssize_t ad9834_write(struct device *dev, mutex_lock(&st->lock); switch ((u32)this_attr->address) { - case AD9834_REG_PHASE0: - case AD9834_REG_PHASE1: - ret = ad9834_write_phase(st, this_attr->address, val); - break; case AD9834_OPBITEN: if (st->control & AD9834_MODE) { ret = -EINVAL; /* AD9843 reserved mode */ @@ -394,12 +417,8 @@ static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, 0444, */ static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9834_write, AD9834_FSEL); -static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ -static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9834_write, AD9834_REG_PHASE0); -static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9834_write, AD9834_REG_PHASE1); static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL, ad9834_write, AD9834_PSEL); -static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/ static IIO_DEV_ATTR_PINCONTROL_EN(0, 0200, NULL, ad9834_write, AD9834_PIN_SW); @@ -410,10 +429,6 @@ static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0); static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1); static struct attribute *ad9834_attributes[] = { - &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr, - &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr, - &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr, - &iio_const_attr
[PATCH v3 1/3] staging: iio: frequency: ad9834: Move frequency to standard iio types
Frequency attribute is added with a standard type from iio framework instead of custom attribute. This is a small step towards removing any unnecessary custom attribute. Ad9834 will diverge from ad9833 in the future, that is why we have two identical arrays for ad9834 and 9833. Signed-off-by: Beniamin Bia --- Changed in v3: -based on Jonathan suggestion, i replaced default option with Ad9834 DeviceId -added a local variable in frequency to simplify the code -added ABI documentation .../testing/sysfs-bus-iio-frequency-ad9834| 129 ++ drivers/staging/iio/frequency/ad9834.c| 104 +++--- 2 files changed, 216 insertions(+), 17 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9834 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9834 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9834 new file mode 100644 index ..b912b49473a3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9834 @@ -0,0 +1,129 @@ +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_frequency +KernelVersion: 3.5.0 +Date: April 2012 +Contact: linux-...@vger.kernel.org +Description: + Represents the value from frequency register 0 of device. The + value is between 0 and clock frequency / 2. + Reading returns the value of frequency written in register 0. + +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage1_frequency +KernelVersion: 3.5.0 +Date: April 2012 +Contact: linux-...@vger.kernel.org +Description: + Represents the value from frequency register 1 of device. The + value is between 0 and clock frequency / 2. + Reading returns the value of frequency written in register 1. + +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_phase0 +KernelVersion: 3.5.0 +Date: April 2012 +Contact: linux-...@vger.kernel.org +Description: + Represents the value from phase register 0 of device. The value + is between 0 and 4096 rad. + Reading returns the value of phase written in register 0. + +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_phase1 +KernelVersion: 3.5.0 +Date: April 2012 +Date: February 2019 +Contact: linux-...@vger.kernel.org +Description: + Represents the value from phase register 1 of device. + The value is between 0 and 4096 rad + Reading returns the value of phase written in register 1. + +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_out0_wavetype_available +KernelVersion: 3.5.0 +Date: April 2012 +Contact: linux-...@vger.kernel.org +Description: + Reading returns the possible waveform of output: + sine - for a sinewave + triangle - for a triangle signal + square - squarewave, this is only available on ad9833/7 + +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_out0_wavetype +KernelVersion: 3.5.0 +Date: April 2012 +Contact: linux-...@vger.kernel.org +Description: + Represents the output waveform of channel: + sine - for a sinewave + triangle - for a triangle signal + square - squarewave, this is only available on ad9833/7 + +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_out1_wavetype_available +KernelVersion: 3.5.0 +Date: April 2012 +Contact: linux-...@vger.kernel.org +Description: + Reading returns the possible waveform type for accumulator + output: + square - for a squarewave output + nothing - when orbiten is activated + This is only available on ad9834 + +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_out1_wavetype +KernelVersion: 3.5.0 +Date: April 2012 +Contact: linux-...@vger.kernel.org +Description: + Represents the accumulator output waveform: + square or nothing when orbiten is activated + +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_pincontrol_en +KernelVersion: 3.5.0 +Date: April 2012 +Contact: linux-...@vger.kernel.org +Description: + Represents the PIN_SW bit and determines if the device is + control by spi or by gpio pins. + Reading returns the selected method. + Is only available for ad9834. + +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_frequencysymbol +KernelVersion: 3.5.0 +Date: April 2012 +Contact: linux-...@vger.kernel.org +Description: + Represents which frequency register is selected. These devices + have two registers for frequency and phase but only one + output. The
[PATCH v3 2/3] staging: iio: frequency: ad9834: Move phase and scale to standard iio attribute
The custom phase and scale attributes were moved to standard iio types. Signed-off-by: Beniamin Bia --- Changes in v3: -abi documentation added .../testing/sysfs-bus-iio-frequency-ad9834| 10 ++-- drivers/staging/iio/frequency/ad9834.c| 53 +++ 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9834 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9834 index b912b49473a3..656aa5b6d22b 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9834 +++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9834 @@ -1,3 +1,5 @@ +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage_scale + What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_frequency KernelVersion: 3.5.0 Date: April 2012 @@ -16,7 +18,7 @@ Description: value is between 0 and clock frequency / 2. Reading returns the value of frequency written in register 1. -What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_phase0 +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_phase KernelVersion: 3.5.0 Date: April 2012 Contact: linux-...@vger.kernel.org @@ -25,7 +27,7 @@ Description: is between 0 and 4096 rad. Reading returns the value of phase written in register 0. -What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_phase1 +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage1_phase KernelVersion: 3.5.0 Date: April 2012 Date: February 2019 @@ -106,9 +108,9 @@ Description: have two registers for frequency and phase but only one output. The user can select which one controls the output. 0 represents phase 0 which is mapped to - out_altvoltage0_phase0 + out_altvoltage0_phase 1 represents phase 1 which is mapped to - out_altvoltage0_phase1 + out_altvoltage1_phase What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage0_out0_enable KernelVersion: 3.5.0 diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 8465dac656dd..107d859dadd7 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -82,6 +82,7 @@ struct ad9834_state { struct mutexlock; /* protect sensor state */ unsigned long frequency[2]; + unsigned long phase[2]; /* * DMA (thus cache coherency maintenance) requires the @@ -113,6 +114,8 @@ enum ad9834_supported_device_ids { .output = 1,\ .channel = (chan), \ .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) \ + | BIT(IIO_CHAN_INFO_PHASE),\ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ } static const struct iio_chan_spec ad9833_channels[] = { @@ -170,13 +173,26 @@ static int ad9834_write_frequency(struct ad9834_state *st, } static int ad9834_write_phase(struct ad9834_state *st, - unsigned long addr, unsigned long phase) + enum ad9834_ch_addr addr, + unsigned long phase) { + int ret; + if (phase > BIT(AD9834_PHASE_BITS)) return -EINVAL; - st->data = cpu_to_be16(addr | phase); - return spi_sync(st->spi, &st->msg); + if (addr == AD9834_CHANNEL_ADDRESS0) + st->data = cpu_to_be16(AD9834_REG_PHASE0 | phase); + else + st->data = cpu_to_be16(AD9834_REG_PHASE1 | phase); + + ret = spi_sync(st->spi, &st->msg); + if (ret) + return ret; + + st->phase[(int)addr] = phase; + + return 0; } static int ad9834_read_raw(struct iio_dev *indio_dev, @@ -189,6 +205,13 @@ static int ad9834_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_FREQUENCY: *val = st->frequency[chan->channel]; return IIO_VAL_INT; + case IIO_CHAN_INFO_PHASE: + *val = st->phase[chan->channel]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /*1 hz */ + *val = 1; + return IIO_VAL_INT; } return -EINVAL; @@ -205,6 +228,10 @@ static int ad9834_write_raw(struct iio_dev *indio_dev, return ad9834_write_frequency(st, (enum ad9834_ch_addr)chan->channel, val); + case IIO_CHAN_INFO_PHASE: + return ad9834_write_phase(st, +
[PATCH 3/3] dt-bindings: iio: adc: Add AD7616 ADC documentation
Document support for AD7616 Analog to Digital Converter. Signed-off-by: Beniamin Bia --- Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt index d7b6241ca881..d8652460198e 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt @@ -7,6 +7,7 @@ Required properties for the AD7606: * "adi,ad7606-8" * "adi,ad7606-6" * "adi,ad7606-4" + * "adi,ad7616" - reg: SPI chip select number for the device - spi-max-frequency: Max SPI frequency to use see: Documentation/devicetree/bindings/spi/spi-bus.txt -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 2/3] iio: adc: ad7616: Add support for AD7616 ADC
The AD7616 is a 12-bit ADC with 16 channels. The AD7616 can be configured to work in hardware mode by controlling it via gpio pins and read data via spi. No support for software mode yet, but it is a work in progress. This device requires a reset in order to update oversampling, so chip info has got a new attribute to mark this. The current assumption that this driver makes for AD7616, is that it's working in Hardware Mode with Serial, Burst and Sequencer modes activated. To activate them, following pins must be pulled high: -SER/PAR -SEQEN And following must be pulled low: -WR/BURST -DB4/SEQEN Datasheets: Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ad7616.pdf Signed-off-by: Beniamin Bia Signed-off-by: Alexandru Ardelean --- drivers/iio/adc/ad7606.c | 46 drivers/iio/adc/ad7606.h | 9 --- drivers/iio/adc/ad7606_spi.c | 2 ++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 6b87ed410c93..24c70c3cefb4 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -39,6 +39,10 @@ static const unsigned int ad7606_oversampling_avail[7] = { 1, 2, 4, 8, 16, 32, 64, }; +static const unsigned int ad7616_oversampling_avail[8] = { + 1, 2, 4, 8, 16, 32, 64, 128, +}; + static int ad7606_reset(struct ad7606_state *st) { if (st->gpio_reset) { @@ -220,6 +224,11 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, mutex_lock(&st->lock); gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, st->gpio_os->info, values); + + /* AD7616 requires a reset to update value */ + if (st->chip_info->os_req_reset) + ad7606_reset(st); + st->oversampling = st->oversampling_avail[i]; mutex_unlock(&st->lock); @@ -314,6 +323,36 @@ static const struct iio_chan_spec ad7606_channels[] = { AD7606_CHANNEL(7), }; +/* + * The current assumption that this driver makes for AD7616, is that it's + * working in Hardware Mode with Serial, Burst and Sequencer modes activated. + * To activate them, following pins must be pulled high: + * -SER/PAR + * -SEQEN + * And following pins must be pulled low: + * -WR/BURST + * -DB4/SER1W + */ +static const struct iio_chan_spec ad7616_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(16), + AD7606_CHANNEL(0), + AD7606_CHANNEL(1), + AD7606_CHANNEL(2), + AD7606_CHANNEL(3), + AD7606_CHANNEL(4), + AD7606_CHANNEL(5), + AD7606_CHANNEL(6), + AD7606_CHANNEL(7), + AD7606_CHANNEL(8), + AD7606_CHANNEL(9), + AD7606_CHANNEL(10), + AD7606_CHANNEL(11), + AD7606_CHANNEL(12), + AD7606_CHANNEL(13), + AD7606_CHANNEL(14), + AD7606_CHANNEL(15), +}; + static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { /* More devices added in future */ [ID_AD7605_4] = { @@ -338,6 +377,13 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), }, + [ID_AD7616] = { + .channels = ad7616_channels, + .num_channels = 17, + .oversampling_avail = ad7616_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), + .os_req_reset = true, + }, }; static int ad7606_request_gpios(struct ad7606_state *st) diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index 8c91bd427c4e..f9ef52131e74 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -15,12 +15,14 @@ * @oversampling_avail pointer to the array which stores the available * oversampling ratios. * @oversampling_num number of elements stored in oversampling_avail array + * @os_req_reset some devices require a reset to update oversampling */ struct ad7606_chip_info { const struct iio_chan_spec *channels; unsigned intnum_channels; const unsigned int *oversampling_avail; unsigned intoversampling_num; + boolos_req_reset; }; /** @@ -76,9 +78,9 @@ struct ad7606_state { /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. -* 8 * 16-bit samples + 64-bit timestamp +* 16 * 16-bit samples + 64-bit timestamp */ - unsigned short data[12] cacheline_aligned; + unsigned short data[20] cacheline_aligned; }; /**
[PATCH 1/3] iio: adc: ad7606: Move oversampling options in chip info and rework *_avail attributes
From: Stefan Popa Available oversampling ratios and scales can be shown by calling a common ad7606_show_avail function which takes as parameters the array which stores the values, together with the size of the array. Oversampling options are now defined in chip info structure and they are loaded at probe. Has_Oversampling attribute was removed because oversampling_num was added and it is not needed anymore. The purpose of this patch is to deal with the scale_avail and oversampling_avail arrays in a generic way. This makes it easier to add support for new devices which will work with different scales and oversampling ratios. It is also an intermediate step for adding support for ad7616 which has different oversampling sampling ratios available. Signed-off-by: Stefan Popa Signed-off-by: Beniamin Bia --- drivers/iio/adc/ad7606.c | 74 drivers/iio/adc/ad7606.h | 16 +++-- 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index ebb8de03bbce..6b87ed410c93 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -31,7 +31,7 @@ * Scales are computed as 5000/32768 and 1/32768 respectively, * so that when applied to the raw values they provide mV values */ -static const unsigned int scale_avail[2] = { +static const unsigned int ad7606_scale_avail[2] = { 152588, 305176 }; @@ -154,7 +154,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - *val2 = scale_avail[st->range]; + *val2 = st->scale_avail[st->range]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = st->oversampling; @@ -163,21 +163,31 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, return -EINVAL; } -static ssize_t in_voltage_scale_available_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t ad7606_show_avail(char *buf, const unsigned int *vals, +unsigned int n, bool micros) { - int i, len = 0; - - for (i = 0; i < ARRAY_SIZE(scale_avail); i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", -scale_avail[i]); + size_t len = 0; + int i; + for (i = 0; i < n; i++) { + len += scnprintf(buf + len, PAGE_SIZE - len, + micros ? "0.%06u " : "%u ", vals[i]); + } buf[len - 1] = '\n'; return len; } +static ssize_t in_voltage_scale_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_show_avail(buf, st->scale_avail, st->num_scales, true); +} + static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); static int ad7606_write_raw(struct iio_dev *indio_dev, @@ -193,7 +203,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SCALE: mutex_lock(&st->lock); - i = find_closest(val2, scale_avail, ARRAY_SIZE(scale_avail)); + i = find_closest(val2, st->scale_avail, st->num_scales); gpiod_set_value(st->gpio_range, i); st->range = i; mutex_unlock(&st->lock); @@ -202,15 +212,15 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_OVERSAMPLING_RATIO: if (val2) return -EINVAL; - i = find_closest(val, ad7606_oversampling_avail, -ARRAY_SIZE(ad7606_oversampling_avail)); + i = find_closest(val, st->oversampling_avail, +st->num_os_ratios); values[0] = i; mutex_lock(&st->lock); gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, st->gpio_os->info, values); - st->oversampling = ad7606_oversampling_avail[i]; + st->oversampling = st->oversampling_avail[i]; mutex_unlock(&st->lock); return 0; @@ -219,11 +229,23 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, } } -static IIO_CONST_ATTR(oversampling_ratio_available, "1 2 4 8 16 32 64"); +static ssize_t ad7606_oversampling_ratio_avail(struct device *dev, +
[PATCH 4/4] dt-bindings: iio: adc: Add AD7606B ADC documentation
Documentation for AD7606B Analog to Digital Converter and software mode was added. Signed-off-by: Beniamin Bia --- Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt | 8 Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt index d8652460198e..9cc7ea19eca6 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt @@ -7,6 +7,7 @@ Required properties for the AD7606: * "adi,ad7606-8" * "adi,ad7606-6" * "adi,ad7606-4" + * "adi,ad7606b" * "adi,ad7616" - reg: SPI chip select number for the device - spi-max-frequency: Max SPI frequency to use @@ -42,6 +43,12 @@ Optional properties: - adi,oversampling-ratio-gpios: must be the device tree identifier of the over-sampling mode pins. As the line is active high, it should be marked GPIO_ACTIVE_HIGH. +- adi,sw-mode: Boolean, software mode of operation, so far available only for ad7606b. + Software mode is enabled when all three oversampling mode pins are connected to + high level. The AD7606B is configured by the corresponding registers. If the + adi,oversampling-ratio-gpios property is defined, then the driver will set the + oversampling gpios to high. Otherwise, it is assumed that the pins are hardwired + to VDD. Example: @@ -63,4 +70,5 @@ Example: &gpio 23 GPIO_ACTIVE_HIGH &gpio 26 GPIO_ACTIVE_HIGH>; standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>; + adi,sw-mode; }; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml index 509dbe9c84d2..2afe31747a70 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -13,6 +13,7 @@ maintainers: description: | Analog Devices AD7606 Simultaneous Sampling ADC https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf properties: @@ -22,6 +23,7 @@ properties: - adi,ad7606-8 - adi,ad7606-6 - adi,ad7606-4 + - adi,ad7606b - adi,ad7616 reg: @@ -87,7 +89,7 @@ properties: adi,sw-mode: description: - Software mode of operation, so far available only for ad7616. + Software mode of operation, so far available only for ad7616 and ad7606B. It is enabled when all three oversampling mode pins are connected to high level. The device is configured by the corresponding registers. If the adi,oversampling-ratio-gpios property is defined, then the driver will set the -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 3/4] dt-bindings: iio: adc: Migrate AD7606 documentation to yaml
The documentation for ad7606 was migrated to yaml, the new Linux Kernel standard. Signed-off-by: Beniamin Bia --- .../bindings/iio/adc/adi,ad7606.yaml | 134 ++ MAINTAINERS | 2 +- 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml new file mode 100644 index ..509dbe9c84d2 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7606.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7606 Simultaneous Sampling ADC + +maintainers: + - Beniamin Bia + - Stefan Popa + +description: | + Analog Devices AD7606 Simultaneous Sampling ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf + +properties: + compatible: +enum: + - adi,ad7605-4 + - adi,ad7606-8 + - adi,ad7606-6 + - adi,ad7606-4 + - adi,ad7616 + + reg: +maxItems: 1 + + spi-cpha: true + + avcc-supply: +description: + Phandle to the Avcc power supply +maxItems: 1 + + interrupts: +maxItems: 1 + + adi,conversion-start-gpios: +description: + Must be the device tree identifier of the CONVST pin. + This logic input is used to initiate conversions on the analog + input channels. As the line is active high, it should be marked + GPIO_ACTIVE_HIGH. +maxItems: 1 + + reset-gpios: +description: + Must be the device tree identifier of the RESET pin. If specified, + it will be asserted during driver probe. As the line is active high, + it should be marked GPIO_ACTIVE_HIGH. +maxItems: 1 + + standby-gpios: +description: + Must be the device tree identifier of the STBY pin. This pin is used + to place the AD7606 into one of two power-down modes, Standby mode or + Shutdown mode. As the line is active low, it should be marked + GPIO_ACTIVE_LOW. +maxItems: 1 + + adi,first-data-gpios: +description: + Must be the device tree identifier of the FRSTDATA pin. + The FRSTDATA output indicates when the first channel, V1, is + being read back on either the parallel, byte or serial interface. + As the line is active high, it should be marked GPIO_ACTIVE_HIGH. +maxItems: 1 + + adi,range-gpios: +description: + Must be the device tree identifier of the RANGE pin. The polarity on + this pin determines the input range of the analog input channels. If + this pin is tied to a logic high, the analog input range is ±10V for + all channels. If this pin is tied to a logic low, the analog input range + is ±5V for all channels. As the line is active high, it should be marked + GPIO_ACTIVE_HIGH. +maxItems: 1 + + adi,oversampling-ratio-gpios: +description: + Must be the device tree identifier of the over-sampling + mode pins. As the line is active high, it should be marked + GPIO_ACTIVE_HIGH. +maxItems: 1 + + adi,sw-mode: +description: + Software mode of operation, so far available only for ad7616. + It is enabled when all three oversampling mode pins are connected to + high level. The device is configured by the corresponding registers. If the + adi,oversampling-ratio-gpios property is defined, then the driver will set the + oversampling gpios to high. Otherwise, it is assumed that the pins are hardwired + to VDD. +maxItems: 1 +type: boolean + +required: + - compatible + - reg + - spi-cpha + - avcc-supply + - interrupts + - adi,conversion-start-gpios + +examples: + - | +spi0 { +#address-cells = <1>; +#size-cells = <0>; + +adc@0 { +compatible = "adi,ad7606-8"; +reg = <0>; +spi-max-frequency = <100>; +spi-cpol; + +avcc-supply = <&adc_vref>; + +interrupts = <25 IRQ_TYPE_EDGE_FALLING>; +interrupt-parent = <&gpio>; + +adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; +reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; +adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; +adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH +&gpio 23 GPIO_ACTIVE_HIGH +&gpio 26 GPIO_ACTIVE_HIGH>; +standby-gpios = <&gpio
[PATCH 2/4] MAINTAINERS: Add Beniamin Bia for AD7606 driver
Add Beniamin Bia as maintainer for AD7606 driver. Signed-off-by: Beniamin Bia --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ad498428b38c..052d7a8591fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -895,6 +895,7 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt ANALOG DEVICES INC AD7606 DRIVER M: Stefan Popa +M: Beniamin Bia L: linux-...@vger.kernel.org W: http://ez.analog.com/community/linux-device-drivers S: Supported -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 1/4] iio: adc: ad7606: Add support for AD7606B ADC
From: Stefan Popa The AD7606B is a 16-bit ADC that supports simultaneous sampling of 8 channels. It is pin compatible to AD7606, but adds extra modes by writing to the register map. The AD7606B can be configured to work in software mode by setting all oversampling pins to high. This mode is selected by default. The oversampling ratio is configured from the OS_MODE register (address 0x08) with the addition of OS=128 and OS=256 that were not available in hardware mode. The device is configured to output data on a single spi channel, but this configuration must be done right after restart. That is why the delay was removed for devices which doesn't require it. Moreover, in software mode, the range gpio has no longer its function. Instead, the scale can be configured individually for each channel from the RANGE_CH registers (address 0x03 to 0x06). Besides the already supported ±10 V and ±5 V ranges, software mode can also accommodate the ±2.5 V range. Signed-off-by: Stefan Popa Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- drivers/iio/adc/ad7606.c | 13 - drivers/iio/adc/ad7606.h | 4 ++ drivers/iio/adc/ad7606_spi.c | 107 +++ 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index ed2d08437e5d..f5ba94c03a8d 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -410,12 +410,19 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), }, + [ID_AD7606B] = { + .channels = ad7606_channels, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + }, [ID_AD7616] = { .channels = ad7616_channels, .num_channels = 17, .oversampling_avail = ad7616_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), .os_req_reset = true, + .init_delay_ms = 15, }, }; @@ -631,8 +638,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); /* AD7616 requires al least 15ms to reconfigure after a reset */ - if (msleep_interruptible(15)) - return -ERESTARTSYS; + if (st->chip_info->init_delay_ms) { + if (msleep_interruptible(st->chip_info->init_delay_ms)) + return -ERESTARTSYS; + } st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index eeaaa8b905db..9350ef1f63b5 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -46,6 +46,8 @@ * oversampling ratios. * @oversampling_num number of elements stored in oversampling_avail array * @os_req_reset some devices require a reset to update oversampling + * @init_delay_ms required delay in miliseconds for initialization + * after a restart */ struct ad7606_chip_info { const struct iio_chan_spec *channels; @@ -53,6 +55,7 @@ struct ad7606_chip_info { const unsigned int *oversampling_avail; unsigned intoversampling_num; boolos_req_reset; + unsigned long init_delay_ms; }; /** @@ -155,6 +158,7 @@ enum ad7606_supported_device_ids { ID_AD7606_8, ID_AD7606_6, ID_AD7606_4, + ID_AD7606B, ID_AD7616, }; diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index 98ed52b74507..070ee7e31e2c 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -31,6 +31,20 @@ /* The range of the channel is stored on 2 bits*/ #define AD7616_RANGE_CH_MSK(ch)(0b11 << (((ch) & 0b11) * 2)) #define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << ch) & 0b11)) * 2)) + +#define AD7606_CONFIGURATION_REGISTER 0x02 +#define AD7606_SINGLE_DOUT 0x0 + +/* + * Range for AD7606B channels are stored in registers starting with address 0x3. + * Each register stores range for 2 channels(4 bits per channel). + */ +#define AD7606_RANGE_CH_MSK(ch)(GENMASK(3, 0) << (4 * ((ch) & 0x1))) +#define AD7606_RANGE_CH_MODE(ch, mode) \ + ((GENMASK(3, 0) & mode) << (4 * ((ch) & 0x1))) +#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1)) +#define AD7606_OS_MODE 0x08 + static const struct iio_chan_spec ad7616_sw_channels[] = { IIO_CHAN
[PATCH v2 1/4] iio: adc: ad7606: Add support for AD7606B ADC
From: Stefan Popa The AD7606B is a 16-bit ADC that supports simultaneous sampling of 8 channels. It is pin compatible to AD7606, but adds extra modes by writing to the register map. The AD7606B can be configured to work in software mode by setting all oversampling pins to high. This mode is selected by default. The oversampling ratio is configured from the OS_MODE register (address 0x08) with the addition of OS=128 and OS=256 that were not available in hardware mode. The device is configured to output data on a single spi channel, but this configuration must be done right after restart. That is why the delay was removed for devices which doesn't require it. Moreover, in software mode, the range gpio has no longer its function. Instead, the scale can be configured individually for each channel from the RANGE_CH registers (address 0x03 to 0x06). Besides the already supported ±10 V and ±5 V ranges, software mode can also accommodate the ±2.5 V range. Signed-off-by: Stefan Popa Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia Acked-by: Jonathan Cameron --- Changes in v2: -nothing changed drivers/iio/adc/ad7606.c | 13 - drivers/iio/adc/ad7606.h | 4 ++ drivers/iio/adc/ad7606_spi.c | 107 +++ 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index ed2d08437e5d..f5ba94c03a8d 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -410,12 +410,19 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), }, + [ID_AD7606B] = { + .channels = ad7606_channels, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + }, [ID_AD7616] = { .channels = ad7616_channels, .num_channels = 17, .oversampling_avail = ad7616_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), .os_req_reset = true, + .init_delay_ms = 15, }, }; @@ -631,8 +638,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); /* AD7616 requires al least 15ms to reconfigure after a reset */ - if (msleep_interruptible(15)) - return -ERESTARTSYS; + if (st->chip_info->init_delay_ms) { + if (msleep_interruptible(st->chip_info->init_delay_ms)) + return -ERESTARTSYS; + } st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index eeaaa8b905db..9350ef1f63b5 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -46,6 +46,8 @@ * oversampling ratios. * @oversampling_num number of elements stored in oversampling_avail array * @os_req_reset some devices require a reset to update oversampling + * @init_delay_ms required delay in miliseconds for initialization + * after a restart */ struct ad7606_chip_info { const struct iio_chan_spec *channels; @@ -53,6 +55,7 @@ struct ad7606_chip_info { const unsigned int *oversampling_avail; unsigned intoversampling_num; boolos_req_reset; + unsigned long init_delay_ms; }; /** @@ -155,6 +158,7 @@ enum ad7606_supported_device_ids { ID_AD7606_8, ID_AD7606_6, ID_AD7606_4, + ID_AD7606B, ID_AD7616, }; diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index 98ed52b74507..070ee7e31e2c 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -31,6 +31,20 @@ /* The range of the channel is stored on 2 bits*/ #define AD7616_RANGE_CH_MSK(ch)(0b11 << (((ch) & 0b11) * 2)) #define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << ch) & 0b11)) * 2)) + +#define AD7606_CONFIGURATION_REGISTER 0x02 +#define AD7606_SINGLE_DOUT 0x0 + +/* + * Range for AD7606B channels are stored in registers starting with address 0x3. + * Each register stores range for 2 channels(4 bits per channel). + */ +#define AD7606_RANGE_CH_MSK(ch)(GENMASK(3, 0) << (4 * ((ch) & 0x1))) +#define AD7606_RANGE_CH_MODE(ch, mode) \ + ((GENMASK(3, 0) & mode) << (4 * ((ch) & 0x1))) +#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1)) +#define AD7606_OS_MODE 0x08 + static
[PATCH v2 3/4] dt-bindings: iio: adc: Migrate AD7606 documentation to yaml
The documentation for ad7606 was migrated to yaml. Signed-off-by: Beniamin Bia --- Changes in v2: -old txt file was deleted .../bindings/iio/adc/adi,ad7606.txt | 66 - .../bindings/iio/adc/adi,ad7606.yaml | 134 ++ MAINTAINERS | 2 +- 3 files changed, 135 insertions(+), 67 deletions(-) delete mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt deleted file mode 100644 index d8652460198e.. --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt +++ /dev/null @@ -1,66 +0,0 @@ -Analog Devices AD7606 Simultaneous Sampling ADC - -Required properties for the AD7606: - -- compatible: Must be one of - * "adi,ad7605-4" - * "adi,ad7606-8" - * "adi,ad7606-6" - * "adi,ad7606-4" - * "adi,ad7616" -- reg: SPI chip select number for the device -- spi-max-frequency: Max SPI frequency to use - see: Documentation/devicetree/bindings/spi/spi-bus.txt -- spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt -- avcc-supply: phandle to the Avcc power supply -- interrupts: IRQ line for the ADC - see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt -- adi,conversion-start-gpios: must be the device tree identifier of the CONVST pin. - This logic input is used to initiate conversions on the analog - input channels. As the line is active high, it should be marked - GPIO_ACTIVE_HIGH. - -Optional properties: - -- reset-gpios: must be the device tree identifier of the RESET pin. If specified, - it will be asserted during driver probe. As the line is active high, - it should be marked GPIO_ACTIVE_HIGH. -- standby-gpios: must be the device tree identifier of the STBY pin. This pin is used - to place the AD7606 into one of two power-down modes, Standby mode or - Shutdown mode. As the line is active low, it should be marked - GPIO_ACTIVE_LOW. -- adi,first-data-gpios: must be the device tree identifier of the FRSTDATA pin. - The FRSTDATA output indicates when the first channel, V1, is - being read back on either the parallel, byte or serial interface. - As the line is active high, it should be marked GPIO_ACTIVE_HIGH. -- adi,range-gpios: must be the device tree identifier of the RANGE pin. The polarity on - this pin determines the input range of the analog input channels. If - this pin is tied to a logic high, the analog input range is ±10V for - all channels. If this pin is tied to a logic low, the analog input range - is ±5V for all channels. As the line is active high, it should be marked - GPIO_ACTIVE_HIGH. -- adi,oversampling-ratio-gpios: must be the device tree identifier of the over-sampling - mode pins. As the line is active high, it should be marked - GPIO_ACTIVE_HIGH. - -Example: - - adc@0 { - compatible = "adi,ad7606-8"; - reg = <0>; - spi-max-frequency = <100>; - spi-cpol; - - avcc-supply = <&adc_vref>; - - interrupts = <25 IRQ_TYPE_EDGE_FALLING>; - interrupt-parent = <&gpio>; - - adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; - adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; - adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH - &gpio 23 GPIO_ACTIVE_HIGH - &gpio 26 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>; - }; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml new file mode 100644 index ..509dbe9c84d2 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7606.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7606 Simultaneous Sampling ADC + +maintainers: + - Beniamin Bia + - Stefan Popa + +description: | + Analog Devices AD7606 Simultaneous Sampling ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_
[PATCH v2 2/4] MAINTAINERS: Add Beniamin Bia for AD7606 driver
Add Beniamin Bia as maintainer for AD7606 driver. Signed-off-by: Beniamin Bia --- Changes in v2: -nothing changed MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ad498428b38c..052d7a8591fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -895,6 +895,7 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt ANALOG DEVICES INC AD7606 DRIVER M: Stefan Popa +M: Beniamin Bia L: linux-...@vger.kernel.org W: http://ez.analog.com/community/linux-device-drivers S: Supported -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v2 4/4] dt-bindings: iio: adc: Add AD7606B ADC documentation
Documentation for AD7606B Analog to Digital Converter and software mode was added. Signed-off-by: Beniamin Bia --- Changes in v2: -nothing changed Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml index 509dbe9c84d2..2afe31747a70 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -13,6 +13,7 @@ maintainers: description: | Analog Devices AD7606 Simultaneous Sampling ADC https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf properties: @@ -22,6 +23,7 @@ properties: - adi,ad7606-8 - adi,ad7606-6 - adi,ad7606-4 + - adi,ad7606b - adi,ad7616 reg: @@ -87,7 +89,7 @@ properties: adi,sw-mode: description: - Software mode of operation, so far available only for ad7616. + Software mode of operation, so far available only for ad7616 and ad7606B. It is enabled when all three oversampling mode pins are connected to high level. The device is configured by the corresponding registers. If the adi,oversampling-ratio-gpios property is defined, then the driver will set the -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v3 1/4] iio: adc: ad7606: Add support for AD7606B ADC
From: Stefan Popa The AD7606B is a 16-bit ADC that supports simultaneous sampling of 8 channels. It is pin compatible to AD7606, but adds extra modes by writing to the register map. The AD7606B can be configured to work in software mode by setting all oversampling pins to high. This mode is selected by default. The oversampling ratio is configured from the OS_MODE register (address 0x08) with the addition of OS=128 and OS=256 that were not available in hardware mode. The device is configured to output data on a single spi channel, but this configuration must be done right after restart. That is why the delay was removed for devices which doesn't require it. Moreover, in software mode, the range gpio has no longer its function. Instead, the scale can be configured individually for each channel from the RANGE_CH registers (address 0x03 to 0x06). Besides the already supported ±10 V and ±5 V ranges, software mode can also accommodate the ±2.5 V range. Signed-off-by: Stefan Popa Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- Changes in v3: -comments reworked -isWriteOp renamed to is_write_op drivers/iio/adc/ad7606.c | 13 - drivers/iio/adc/ad7606.h | 4 ++ drivers/iio/adc/ad7606_spi.c | 109 ++- 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index ed2d08437e5d..f5ba94c03a8d 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -410,12 +410,19 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), }, + [ID_AD7606B] = { + .channels = ad7606_channels, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + }, [ID_AD7616] = { .channels = ad7616_channels, .num_channels = 17, .oversampling_avail = ad7616_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), .os_req_reset = true, + .init_delay_ms = 15, }, }; @@ -631,8 +638,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); /* AD7616 requires al least 15ms to reconfigure after a reset */ - if (msleep_interruptible(15)) - return -ERESTARTSYS; + if (st->chip_info->init_delay_ms) { + if (msleep_interruptible(st->chip_info->init_delay_ms)) + return -ERESTARTSYS; + } st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index eeaaa8b905db..9350ef1f63b5 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -46,6 +46,8 @@ * oversampling ratios. * @oversampling_num number of elements stored in oversampling_avail array * @os_req_reset some devices require a reset to update oversampling + * @init_delay_ms required delay in miliseconds for initialization + * after a restart */ struct ad7606_chip_info { const struct iio_chan_spec *channels; @@ -53,6 +55,7 @@ struct ad7606_chip_info { const unsigned int *oversampling_avail; unsigned intoversampling_num; boolos_req_reset; + unsigned long init_delay_ms; }; /** @@ -155,6 +158,7 @@ enum ad7606_supported_device_ids { ID_AD7606_8, ID_AD7606_6, ID_AD7606_4, + ID_AD7606B, ID_AD7616, }; diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index 98ed52b74507..29945ad07dca 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -28,9 +28,23 @@ * an offset of 2 for register address. */ #define AD7616_RANGE_CH_ADDR(ch) ((ch) >> 2) -/* The range of the channel is stored on 2 bits*/ +/* The range of the channel is stored in 2 bits */ #define AD7616_RANGE_CH_MSK(ch)(0b11 << (((ch) & 0b11) * 2)) #define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << ch) & 0b11)) * 2)) + +#define AD7606_CONFIGURATION_REGISTER 0x02 +#define AD7606_SINGLE_DOUT 0x00 + +/* + * Range for AD7606B channels are stored in registers starting with address 0x3. + * Each register stores range for 2 channels(4 bits per channel). + */ +#define AD7606_RANGE_CH_MSK(ch)(GENMASK(3, 0) << (4 * ((ch) & 0x1))) +#define AD7606_RANGE_CH_MODE(ch, mode) \ + ((GENMASK(3, 0) & mode)
[PATCH v3 3/4] dt-bindings: iio: adc: Migrate AD7606 documentation to yaml
The documentation for ad7606 was migrated to yaml. Signed-off-by: Beniamin Bia --- Changes in v3: -nothing changed .../bindings/iio/adc/adi,ad7606.txt | 66 - .../bindings/iio/adc/adi,ad7606.yaml | 134 ++ MAINTAINERS | 2 +- 3 files changed, 135 insertions(+), 67 deletions(-) delete mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt deleted file mode 100644 index d8652460198e.. --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt +++ /dev/null @@ -1,66 +0,0 @@ -Analog Devices AD7606 Simultaneous Sampling ADC - -Required properties for the AD7606: - -- compatible: Must be one of - * "adi,ad7605-4" - * "adi,ad7606-8" - * "adi,ad7606-6" - * "adi,ad7606-4" - * "adi,ad7616" -- reg: SPI chip select number for the device -- spi-max-frequency: Max SPI frequency to use - see: Documentation/devicetree/bindings/spi/spi-bus.txt -- spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt -- avcc-supply: phandle to the Avcc power supply -- interrupts: IRQ line for the ADC - see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt -- adi,conversion-start-gpios: must be the device tree identifier of the CONVST pin. - This logic input is used to initiate conversions on the analog - input channels. As the line is active high, it should be marked - GPIO_ACTIVE_HIGH. - -Optional properties: - -- reset-gpios: must be the device tree identifier of the RESET pin. If specified, - it will be asserted during driver probe. As the line is active high, - it should be marked GPIO_ACTIVE_HIGH. -- standby-gpios: must be the device tree identifier of the STBY pin. This pin is used - to place the AD7606 into one of two power-down modes, Standby mode or - Shutdown mode. As the line is active low, it should be marked - GPIO_ACTIVE_LOW. -- adi,first-data-gpios: must be the device tree identifier of the FRSTDATA pin. - The FRSTDATA output indicates when the first channel, V1, is - being read back on either the parallel, byte or serial interface. - As the line is active high, it should be marked GPIO_ACTIVE_HIGH. -- adi,range-gpios: must be the device tree identifier of the RANGE pin. The polarity on - this pin determines the input range of the analog input channels. If - this pin is tied to a logic high, the analog input range is ±10V for - all channels. If this pin is tied to a logic low, the analog input range - is ±5V for all channels. As the line is active high, it should be marked - GPIO_ACTIVE_HIGH. -- adi,oversampling-ratio-gpios: must be the device tree identifier of the over-sampling - mode pins. As the line is active high, it should be marked - GPIO_ACTIVE_HIGH. - -Example: - - adc@0 { - compatible = "adi,ad7606-8"; - reg = <0>; - spi-max-frequency = <100>; - spi-cpol; - - avcc-supply = <&adc_vref>; - - interrupts = <25 IRQ_TYPE_EDGE_FALLING>; - interrupt-parent = <&gpio>; - - adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; - adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; - adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH - &gpio 23 GPIO_ACTIVE_HIGH - &gpio 26 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>; - }; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml new file mode 100644 index ..509dbe9c84d2 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7606.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7606 Simultaneous Sampling ADC + +maintainers: + - Beniamin Bia + - Stefan Popa + +description: | + Analog Devices AD7606 Simultaneous Sampling ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf +
[PATCH v3 4/4] dt-bindings: iio: adc: Add AD7606B ADC documentation
Documentation for AD7606B Analog to Digital Converter and software mode was added. Signed-off-by: Beniamin Bia --- Changes in v3: -nothing changed Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml index 509dbe9c84d2..2afe31747a70 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -13,6 +13,7 @@ maintainers: description: | Analog Devices AD7606 Simultaneous Sampling ADC https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf properties: @@ -22,6 +23,7 @@ properties: - adi,ad7606-8 - adi,ad7606-6 - adi,ad7606-4 + - adi,ad7606b - adi,ad7616 reg: @@ -87,7 +89,7 @@ properties: adi,sw-mode: description: - Software mode of operation, so far available only for ad7616. + Software mode of operation, so far available only for ad7616 and ad7606B. It is enabled when all three oversampling mode pins are connected to high level. The device is configured by the corresponding registers. If the adi,oversampling-ratio-gpios property is defined, then the driver will set the -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v3 2/4] MAINTAINERS: Add Beniamin Bia for AD7606 driver
Add Beniamin Bia as maintainer for AD7606 driver. Signed-off-by: Beniamin Bia --- Changes in v3: -nothing changed MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ad498428b38c..052d7a8591fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -895,6 +895,7 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt ANALOG DEVICES INC AD7606 DRIVER M: Stefan Popa +M: Beniamin Bia L: linux-...@vger.kernel.org W: http://ez.analog.com/community/linux-device-drivers S: Supported -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH] drivers/staging/fbtft/fb_seps525: New driver for SEPS525 (Syncoam) LCD Controllers
From: Michael Hennerich The SEPS525 is a 160 RGB x 128 Dots, 262K Colors PM-OLED Display Driver and Controller. The controller can be found on the NHD-1.69-160128UGC3 (Newhaven Display International, Inc.). Datasheets: Link: https://www.newhavendisplay.com/appnotes/datasheets/OLEDs/SEPS525.pdf Signed-off-by: Michael Hennerich Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- MAINTAINERS| 8 ++ drivers/staging/fbtft/Kconfig | 7 + drivers/staging/fbtft/Makefile | 1 + drivers/staging/fbtft/fb_seps525.c | 213 + 4 files changed, 229 insertions(+) create mode 100644 drivers/staging/fbtft/fb_seps525.c diff --git a/MAINTAINERS b/MAINTAINERS index ef00d6210cff..d077d04f9bc5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15389,6 +15389,14 @@ L: linux-wirel...@vger.kernel.org S: Supported F: drivers/staging/wilc1000/ +STAGING - SEPS525 LCD CONTROLLER DRIVERS +M: Michael Hennerich +M: Beniamin Bia +L: linux-fb...@vger.kernel.org +S: Supported +F: drivers/staging/fbtft/fb_seps525.c +F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml + STAGING SUBSYSTEM M: Greg Kroah-Hartman T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig index 8ec524a95ec8..55af11ee2f5b 100644 --- a/drivers/staging/fbtft/Kconfig +++ b/drivers/staging/fbtft/Kconfig @@ -112,6 +112,13 @@ config FB_TFT_S6D1121 help Generic Framebuffer support for S6D1121 +config FB_TFT_SEPS525 + tristate "FB driver for the SEPS525 LCD Controller" + depends on FB_TFT + help + Generic Framebuffer support for SEPS525 + Say Y if you have such a display that utilizes this controller. + config FB_TFT_SH1106 tristate "FB driver for the SH1106 OLED Controller" depends on FB_TFT diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile index 6bc03311c9c7..e7a0cd9166e9 100644 --- a/drivers/staging/fbtft/Makefile +++ b/drivers/staging/fbtft/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o +obj-$(CONFIG_FB_TFT_SEPS525) += fb_seps525.o obj-$(CONFIG_FB_TFT_SH1106) += fb_sh1106.o obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o obj-$(CONFIG_FB_TFT_SSD1305) += fb_ssd1305.o diff --git a/drivers/staging/fbtft/fb_seps525.c b/drivers/staging/fbtft/fb_seps525.c new file mode 100644 index ..05882e2cde7f --- /dev/null +++ b/drivers/staging/fbtft/fb_seps525.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FB driver for the NHD-1.69-160128UGC3 (Newhaven Display International, Inc.) + * using the SEPS525 (Syncoam) LCD Controller + * + * Copyright (C) 2016 Analog Devices Inc. + * + * 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 +#include +#include +#include +#include + +#include "fbtft.h" + +#define DRVNAME"fb_seps525" +#define WIDTH 160 +#define HEIGHT 128 + +#define SEPS525_INDEX 0x00 +#define SEPS525_STATUS_RD 0x01 +#define SEPS525_OSC_CTL 0x02 +#define SEPS525_IREF 0x80 +#define SEPS525_CLOCK_DIV 0x03 +#define SEPS525_REDUCE_CURRENT 0x04 +#define SEPS525_SOFT_RST 0x05 +#define SEPS525_DISP_ONOFF 0x06 +#define SEPS525_PRECHARGE_TIME_R 0x08 +#define SEPS525_PRECHARGE_TIME_G 0x09 +#define SEPS525_PRECHARGE_TIME_B 0x0A +#define SEPS525_PRECHARGE_CURRENT_R 0x0B +#define SEPS525_PRECHARGE_CURRENT_G 0x0C +#define SEPS525_PRECHARGE_CURRENT_B 0x0D +#define SEPS525_DRIVING_CURRENT_R 0x10 +#define SEPS525_DRIVING_CURRENT_G 0x11 +#define SEPS525_DRIVING_CURRENT_B 0x12 +#define SEPS525_DISPLAYMODE_SET 0x13 +#define SEPS525_RGBIF 0x14 +#define SEPS525_RGB_POL 0x15 +#define SEPS525_MEMORY_WRITEMODE 0x16 +#define SEPS525_MX1_ADDR 0x17 +#define SEPS525_MX2_ADDR 0x18 +#define SEPS525_MY1_ADDR 0x19 +#define SEPS525_MY2_ADDR 0x1A +#define SEPS525_MEMORY_ACCESS_POINTER_X 0x20 +#define SEPS525_MEMORY_ACCESS_POINTER_Y 0x21 +#define SEPS525_DDRAM_DATA_ACCESS_PORT 0x22 +#define SEPS525_GRAY_SCALE_TABLE_INDEX 0x50 +#define SEPS525_GRAY_SCALE_TABLE_DATA 0x51 +#define SEPS525_DUTY 0x28 +#define SEPS525_DSL 0x29 +#define SEPS525_D1_DDRAM_FAC 0x2E +#define SEPS525_D1_DDRAM_FAR 0x2F +#define SEPS525_D2_DDRAM_SAC 0x31 +#d
[PATCH 1/4] iio: adc: Add support for AD7091R5 ADC
From: Paul Cercueil AD7091 is 4-Channel, I2C, Ultra Low Power,12-Bit ADC. Datasheet: Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- drivers/iio/adc/Kconfig| 7 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7091r-base.c | 273 + drivers/iio/adc/ad7091r-base.h | 30 drivers/iio/adc/ad7091r5.c | 108 + 5 files changed, 419 insertions(+) create mode 100644 drivers/iio/adc/ad7091r-base.c create mode 100644 drivers/iio/adc/ad7091r-base.h create mode 100644 drivers/iio/adc/ad7091r5.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7e3286265a38..80b1b9551749 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -22,6 +22,13 @@ config AD7124 To compile this driver as a module, choose M here: the module will be called ad7124. +config AD7091R5 + tristate "Analog Devices AD7091R5 ADC Driver" + depends on I2C + select REGMAP_I2C + help + Say yes here to build support for Analog Devices AD7091R-5 ADC. + config AD7266 tristate "Analog Devices AD7265/AD7266 ADC driver" depends on SPI_MASTER diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ef9cc485fb67..55e44735aaac 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7124) += ad7124.o +obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c new file mode 100644 index ..140413329754 --- /dev/null +++ b/drivers/iio/adc/ad7091r-base.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD7091RX Analog to Digital converter driver + * + * Copyright 2014 Analog Devices Inc. + * + */ + +#include "ad7091r-base.h" + +#include +#include +#include +#include +#include +#include + +#define AD7091R_REG_RESULT 0 +#define AD7091R_REG_CHANNEL 1 +#define AD7091R_REG_CONF2 +#define AD7091R_REG_ALERT 3 +#define AD7091R_REG_CH_LOW_LIMIT(ch) ((ch) * 3 + 4) +#define AD7091R_REG_CH_HIGH_LIMIT(ch) ((ch) * 3 + 5) +#define AD7091R_REG_CH_HYSTERESIS(ch) ((ch) * 3 + 6) + +/* AD7091R_REG_RESULT */ +#define REG_RESULT_CH_ID(x)(((x) >> 13) & 0x3) +#define REG_RESULT_CONV_RESULT(x) ((x) & 0xfff) + +/* AD7091R_REG_CONF */ +#define REG_CONF_AUTO BIT(8) +#define REG_CONF_CMDBIT(10) + +#define REG_CONF_MODE_MASK (REG_CONF_AUTO | REG_CONF_CMD) + +enum ad7091r_mode { + AD7091R_MODE_SAMPLE, + AD7091R_MODE_COMMAND, + AD7091R_MODE_AUTOCYCLE, +}; + +struct ad7091r_state { + struct device *dev; + struct regmap *map; + const struct ad7091r_chip_info *chip_info; + enum ad7091r_mode mode; +}; + +static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode) +{ + int ret; + + switch (mode) { + case AD7091R_MODE_SAMPLE: + ret = regmap_update_bits(st->map, AD7091R_REG_CONF, + REG_CONF_MODE_MASK, 0); + break; + case AD7091R_MODE_COMMAND: + ret = regmap_update_bits(st->map, AD7091R_REG_CONF, + REG_CONF_MODE_MASK, REG_CONF_CMD); + break; + case AD7091R_MODE_AUTOCYCLE: + ret = regmap_update_bits(st->map, AD7091R_REG_CONF, + REG_CONF_MODE_MASK, REG_CONF_AUTO); + break; + default: + ret = -EINVAL; + break; + } + + if (!ret) + st->mode = mode; + return ret; +} + +static int ad7091r_set_channel(struct ad7091r_state *st, unsigned int channel) +{ + unsigned int foo; + int ret; + + /* AD7091R_REG_CHANNEL is a 8-bit register */ + ret = regmap_write(st->map, AD7091R_REG_CHANNEL, + BIT(channel) | (BIT(channel) << 8)); + if (ret) + return ret; + + /* +* There is a latency of one conversion before the channel conversion +* sequence is updated +*/ + return regmap_read(st->map, AD7091R_REG_RESULT, &foo); +} + +static int ad7091r_read_one(struct iio_dev *iio_dev, + unsigned int channel, unsigned int *read_val) +{ + struct ad7091r_state *st = iio_priv(iio_dev); + unsigned int val; + int ret; + + /* TODO: locking */ + ret = ad7091r_set_channel(st, channel); + if (ret) + return ret; + + ret = regmap_read(st->map, AD7091R_REG_RESULT, &val);
[PATCH 3/4] dt-binding: iio: Add documentation for AD7091R5
Documentation for AD7091R5 ADC was added. Signed-off-by: Beniamin Bia --- .../bindings/iio/adc/adi,ad7091r5.yaml| 53 +++ 1 file changed, 53 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml new file mode 100644 index ..d041cd76804e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7091R5 4-Channel 12-Bit ADC + +maintainers: + - Beniamin Bia + +description: | + Analog Devices AD7091R5 4-Channel 12-Bit ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf + +properties: + compatible: +enum: + - adi,ad7091R5 + + reg: +maxItems: 1 + + avcc-supply: +description: + Phandle to the Avcc power supply +maxItems: 1 + + interrupts: +maxItems: 1 + + +required: + - compatible + - reg + +examples: + - | +#include +#include +i2c { +#address-cells = <1>; +#size-cells = <0>; + +adc@0 { +compatible = "adi,ad7091r5"; +reg = <0x2F>; + +interrupts = <25 IRQ_TYPE_EDGE_FALLING>; +interrupt-parent = <&gpio>; +}; +}; +... -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 4/4] MAINTAINERS: add entry for AD7091R5 driver
Add Beniamin Bia as a maintainer for AD7091R5 ADC. Signed-off-by: Beniamin Bia --- MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2e01d0f0b0e5..7f1e4b88688f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -893,6 +893,14 @@ S: Supported F: drivers/iio/dac/ad5758.c F: Documentation/devicetree/bindings/iio/dac/ad5758.txt +ANALOG DEVICES INC AD7091R5 DRIVER +M: Beniamin Bia +L: linux-...@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/iio/adc/ad7091r5.c +F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml + ANALOG DEVICES INC AD7124 DRIVER M: Stefan Popa L: linux-...@vger.kernel.org -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 2/4] iio: adc: ad7091r5: Add scale and external VREF support
From: Paul Cercueil The scale can now be obtained with the "in_voltage_scale" file. By default, the scale returned corresponds to the internal VREF of 2.5V. It is possible to use an external VREF (through the REFIN/REFOUT pin of the chip), by passing a regulator to the driver. The scale will then be calculated according to the voltage reported by the regulator. Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- drivers/iio/adc/ad7091r-base.c | 42 +- drivers/iio/adc/ad7091r-base.h | 1 + drivers/iio/adc/ad7091r5.c | 5 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index 140413329754..d416f0912531 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -14,6 +14,7 @@ #include #include #include +#include #define AD7091R_REG_RESULT 0 #define AD7091R_REG_CHANNEL 1 @@ -42,6 +43,7 @@ enum ad7091r_mode { struct ad7091r_state { struct device *dev; struct regmap *map; + struct regulator *reg; const struct ad7091r_chip_info *chip_info; enum ad7091r_mode mode; }; @@ -139,6 +141,21 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, ret = IIO_VAL_INT; break; + case IIO_CHAN_INFO_SCALE: + if (st->reg) { + ret = regulator_get_voltage(st->reg); + if (ret < 0) + goto unlock; + + *val = ret / 1000; + } else { + *val = st->chip_info->vref_mV; + } + + *val2 = chan->scan_type.realbits; + ret = IIO_VAL_FRACTIONAL_LOG2; + break; + default: ret = -EINVAL; break; @@ -215,6 +232,18 @@ int ad7091r_probe(struct device *dev, const char *name, return ret; } + st->reg = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(st->reg)) { + if (PTR_ERR(st->reg) == EPROBE_DEFER) + return -EPROBE_DEFER; + + st->reg = NULL; + } else { + ret = regulator_enable(st->reg); + if (ret) + return ret; + } + /* Use command mode by default */ ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND); if (ret < 0) @@ -222,18 +251,29 @@ int ad7091r_probe(struct device *dev, const char *name, ret = iio_device_register(iio_dev); if (ret) - return ret; + goto err_disable_reg; dev_dbg(dev, "Probed\n"); return 0; + +err_disable_reg: + if (st->reg) + regulator_disable(st->reg); + + return ret; } EXPORT_SYMBOL_GPL(ad7091r_probe); int ad7091r_remove(struct device *dev) { struct iio_dev *iio_dev = dev_get_drvdata(dev); + struct ad7091r_state *st = iio_priv(iio_dev); iio_device_unregister(iio_dev); + + if (st->reg) + regulator_disable(st->reg); + return 0; } EXPORT_SYMBOL_GPL(ad7091r_remove); diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h index 7a29f86ea82b..cec4fb75fecc 100644 --- a/drivers/iio/adc/ad7091r-base.h +++ b/drivers/iio/adc/ad7091r-base.h @@ -18,6 +18,7 @@ struct ad7091r_state; struct ad7091r_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; + unsigned int vref_mV; }; extern const struct regmap_config ad7091r_regmap_config; diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index 1ba838c58c31..65bcd8bb692a 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -35,10 +35,13 @@ static const struct iio_event_spec ad7091r5_events[] = { #define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .indexed = 1, \ .channel = idx, \ .event_spec = ev, \ .num_event_specs = num_ev, \ + .scan_type.storagebits = 16, \ + .scan_type.realbits = bits, \ } static const struct iio_chan_spec ad7091r5_channels_irq[] = { AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), @@ -58,11 +61,13 @@ static const struct iio_chan_spec ad7091r5_channels_noirq[] = { static const struct ad7091r_chip_info ad7091r5_chip_info_irq = { .channels = ad7091r5_channels_irq, .num_channels = ARRAY_SIZE(ad7091r5_channels_irq), + .vref_mV = 2500, }; static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = { .channels = ad7091r5_channels_noirq, .num_channels = ARRAY_SIZE(ad7091r5_channel
[PATCH v2 1/4] iio: adc: Add support for AD7091R5 ADC
From: Paul Cercueil AD7091 is 4-Channel, I2C, Ultra Low Power,12-Bit ADC. Datasheet: Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- Changes in v2: -blank lines removed -prefix added to macros -comments rework -error checking syntax changed -iio mutex replaced by a mutex -device remove function was removed and later replaced by devm_add_action -regmap include removed from header drivers/iio/adc/Kconfig| 7 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7091r-base.c | 264 + drivers/iio/adc/ad7091r-base.h | 25 drivers/iio/adc/ad7091r5.c | 102 + 5 files changed, 399 insertions(+) create mode 100644 drivers/iio/adc/ad7091r-base.c create mode 100644 drivers/iio/adc/ad7091r-base.h create mode 100644 drivers/iio/adc/ad7091r5.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7e3286265a38..80b1b9551749 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -22,6 +22,13 @@ config AD7124 To compile this driver as a module, choose M here: the module will be called ad7124. +config AD7091R5 + tristate "Analog Devices AD7091R5 ADC Driver" + depends on I2C + select REGMAP_I2C + help + Say yes here to build support for Analog Devices AD7091R-5 ADC. + config AD7266 tristate "Analog Devices AD7265/AD7266 ADC driver" depends on SPI_MASTER diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ef9cc485fb67..55e44735aaac 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7124) += ad7124.o +obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c new file mode 100644 index ..c2500f614d54 --- /dev/null +++ b/drivers/iio/adc/ad7091r-base.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD7091RX Analog to Digital converter driver + * + * Copyright 2014-2019 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "ad7091r-base.h" + +#define AD7091R_REG_RESULT 0 +#define AD7091R_REG_CHANNEL 1 +#define AD7091R_REG_CONF2 +#define AD7091R_REG_ALERT 3 +#define AD7091R_REG_CH_LOW_LIMIT(ch) ((ch) * 3 + 4) +#define AD7091R_REG_CH_HIGH_LIMIT(ch) ((ch) * 3 + 5) +#define AD7091R_REG_CH_HYSTERESIS(ch) ((ch) * 3 + 6) + +/* AD7091R_REG_RESULT */ +#define AD7091R_REG_RESULT_CH_ID(x)(((x) >> 13) & 0x3) +#define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff) + +/* AD7091R_REG_CONF */ +#define AD7091R_REG_CONF_AUTO BIT(8) +#define AD7091R_REG_CONF_CMDBIT(10) + +#define AD7091R_REG_CONF_MODE_MASK \ + (AD7091R_REG_CONF_AUTO | AD7091R_REG_CONF_CMD) + +enum ad7091r_mode { + AD7091R_MODE_SAMPLE, + AD7091R_MODE_COMMAND, + AD7091R_MODE_AUTOCYCLE, +}; + +struct ad7091r_state { + struct device *dev; + struct regmap *map; + const struct ad7091r_chip_info *chip_info; + enum ad7091r_mode mode; + struct mutex lock; +}; + +static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode) +{ + int ret; + + switch (mode) { + case AD7091R_MODE_SAMPLE: + ret = regmap_update_bits(st->map, AD7091R_REG_CONF, +AD7091R_REG_CONF_MODE_MASK, 0); + break; + case AD7091R_MODE_COMMAND: + ret = regmap_update_bits(st->map, AD7091R_REG_CONF, +AD7091R_REG_CONF_MODE_MASK, +AD7091R_REG_CONF_CMD); + break; + case AD7091R_MODE_AUTOCYCLE: + ret = regmap_update_bits(st->map, AD7091R_REG_CONF, +AD7091R_REG_CONF_MODE_MASK, +AD7091R_REG_CONF_AUTO); + break; + default: + ret = -EINVAL; + break; + } + + if (ret) + return ret; + + st->mode = mode; + + return ret; +} + +static int ad7091r_set_channel(struct ad7091r_state *st, unsigned int channel) +{ + unsigned int foo; + int ret; + + /* AD7091R_REG_CHANNEL specified which channels to be converted */ + ret = regmap_write(st->map, AD7091R_REG_CHANNEL, + BIT(channel) | (BIT(channel) << 8)); + if (ret) + return ret; + + /* +* There is a latency of one conversion before the channel con
[PATCH v2 2/4] iio: adc: ad7091r5: Add scale and external VREF support
From: Paul Cercueil The scale can now be obtained with the "in_voltage_scale" file. By default, the scale returned corresponds to the internal VREF of 2.5V. It is possible to use an external VREF (through the REFIN/REFOUT pin of the chip), by passing a regulator to the driver. The scale will then be calculated according to the voltage reported by the regulator. Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- Changes in v2: -device remove function replaced by devm_add_action_or_reset drivers/iio/adc/ad7091r-base.c | 41 ++ drivers/iio/adc/ad7091r-base.h | 1 + drivers/iio/adc/ad7091r5.c | 5 + 3 files changed, 47 insertions(+) diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index c2500f614d54..fda1112e7376 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "ad7091r-base.h" @@ -42,6 +43,7 @@ enum ad7091r_mode { struct ad7091r_state { struct device *dev; struct regmap *map; + struct regulator *reg; const struct ad7091r_chip_info *chip_info; enum ad7091r_mode mode; struct mutex lock; @@ -145,6 +147,21 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, ret = IIO_VAL_INT; break; + case IIO_CHAN_INFO_SCALE: + if (st->reg) { + ret = regulator_get_voltage(st->reg); + if (ret < 0) + goto unlock; + + *val = ret / 1000; + } else { + *val = st->chip_info->vref_mV; + } + + *val2 = chan->scan_type.realbits; + ret = IIO_VAL_FRACTIONAL_LOG2; + break; + default: ret = -EINVAL; break; @@ -187,6 +204,16 @@ static irqreturn_t ad7091r_event_handler(int irq, void *private) return IRQ_HANDLED; } +void ad7091r_remove(void *data) +{ + struct ad7091r_state *st; + + st = (struct ad7091r_state *)data; + + if (st->reg) + regulator_disable(st->reg); +} + int ad7091r_probe(struct device *dev, const char *name, const struct ad7091r_chip_info *chip_info, struct regmap *map, int irq) @@ -220,6 +247,20 @@ int ad7091r_probe(struct device *dev, const char *name, return ret; } + st->reg = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(st->reg)) { + if (PTR_ERR(st->reg) == EPROBE_DEFER) + return -EPROBE_DEFER; + + st->reg = NULL; + } else { + ret = regulator_enable(st->reg); + if (ret) + return ret; + } + + devm_add_action_or_reset(dev, ad7091r_remove, st); + /* Use command mode by default to convert only desired channels*/ ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND); if (ret < 0) diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h index 5f1147735953..76b76968d071 100644 --- a/drivers/iio/adc/ad7091r-base.h +++ b/drivers/iio/adc/ad7091r-base.h @@ -14,6 +14,7 @@ struct ad7091r_state; struct ad7091r_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; + unsigned int vref_mV; }; extern const struct regmap_config ad7091r_regmap_config; diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index 2c44dd02ba1a..7ee4a781cc01 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -35,10 +35,13 @@ static const struct iio_event_spec ad7091r5_events[] = { #define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .indexed = 1, \ .channel = idx, \ .event_spec = ev, \ .num_event_specs = num_ev, \ + .scan_type.storagebits = 16, \ + .scan_type.realbits = bits, \ } static const struct iio_chan_spec ad7091r5_channels_irq[] = { AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), @@ -58,11 +61,13 @@ static const struct iio_chan_spec ad7091r5_channels_noirq[] = { static const struct ad7091r_chip_info ad7091r5_chip_info_irq = { .channels = ad7091r5_channels_irq, .num_channels = ARRAY_SIZE(ad7091r5_channels_irq), + .vref_mV = 2500, }; static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = { .channels = ad7091r5_channels_noirq, .num_channels = ARRAY_SIZE(ad7091r5_channels_noirq), + .vref_mV = 2500, }; static int ad7091r5_i2c_probe(struct i2c_client *i2c, -- 2.17.
[PATCH v2 3/4] dt-binding: iio: Add documentation for AD7091R5
Documentation for AD7091R5 ADC was added. Signed-off-by: Beniamin Bia --- Changes in v2: -nothing changed .../bindings/iio/adc/adi,ad7091r5.yaml| 53 +++ 1 file changed, 53 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml new file mode 100644 index ..d041cd76804e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7091R5 4-Channel 12-Bit ADC + +maintainers: + - Beniamin Bia + +description: | + Analog Devices AD7091R5 4-Channel 12-Bit ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf + +properties: + compatible: +enum: + - adi,ad7091R5 + + reg: +maxItems: 1 + + avcc-supply: +description: + Phandle to the Avcc power supply +maxItems: 1 + + interrupts: +maxItems: 1 + + +required: + - compatible + - reg + +examples: + - | +#include +#include +i2c { +#address-cells = <1>; +#size-cells = <0>; + +adc@0 { +compatible = "adi,ad7091r5"; +reg = <0x2F>; + +interrupts = <25 IRQ_TYPE_EDGE_FALLING>; +interrupt-parent = <&gpio>; +}; +}; +... -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v2 4/4] MAINTAINERS: add entry for AD7091R5 driver
Add Beniamin Bia as a maintainer for AD7091R5 ADC. Signed-off-by: Beniamin Bia --- Changes in v2: -nothing changed MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2e01d0f0b0e5..7f1e4b88688f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -893,6 +893,14 @@ S: Supported F: drivers/iio/dac/ad5758.c F: Documentation/devicetree/bindings/iio/dac/ad5758.txt +ANALOG DEVICES INC AD7091R5 DRIVER +M: Beniamin Bia +L: linux-...@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/iio/adc/ad7091r5.c +F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml + ANALOG DEVICES INC AD7124 DRIVER M: Stefan Popa L: linux-...@vger.kernel.org -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v3 1/4] iio: adc: Add support for AD7091R5 ADC
From: Paul Cercueil AD7091 is 4-Channel, I2C, Ultra Low Power,12-Bit ADC. Datasheet: Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- Changes in v3: -parameters for functions calls were aligned -iio_device_register replaced by devm_iio_device_register -duplication of regmap_update_bits calls removed in set_mode drivers/iio/adc/Kconfig| 7 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7091r-base.c | 261 + drivers/iio/adc/ad7091r-base.h | 25 drivers/iio/adc/ad7091r5.c | 102 + 5 files changed, 396 insertions(+) create mode 100644 drivers/iio/adc/ad7091r-base.c create mode 100644 drivers/iio/adc/ad7091r-base.h create mode 100644 drivers/iio/adc/ad7091r5.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7e3286265a38..80b1b9551749 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -22,6 +22,13 @@ config AD7124 To compile this driver as a module, choose M here: the module will be called ad7124. +config AD7091R5 + tristate "Analog Devices AD7091R5 ADC Driver" + depends on I2C + select REGMAP_I2C + help + Say yes here to build support for Analog Devices AD7091R-5 ADC. + config AD7266 tristate "Analog Devices AD7265/AD7266 ADC driver" depends on SPI_MASTER diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ef9cc485fb67..55e44735aaac 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7124) += ad7124.o +obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c new file mode 100644 index ..2ebc40dfd927 --- /dev/null +++ b/drivers/iio/adc/ad7091r-base.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD7091RX Analog to Digital converter driver + * + * Copyright 2014-2019 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "ad7091r-base.h" + +#define AD7091R_REG_RESULT 0 +#define AD7091R_REG_CHANNEL 1 +#define AD7091R_REG_CONF2 +#define AD7091R_REG_ALERT 3 +#define AD7091R_REG_CH_LOW_LIMIT(ch) ((ch) * 3 + 4) +#define AD7091R_REG_CH_HIGH_LIMIT(ch) ((ch) * 3 + 5) +#define AD7091R_REG_CH_HYSTERESIS(ch) ((ch) * 3 + 6) + +/* AD7091R_REG_RESULT */ +#define AD7091R_REG_RESULT_CH_ID(x)(((x) >> 13) & 0x3) +#define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff) + +/* AD7091R_REG_CONF */ +#define AD7091R_REG_CONF_AUTO BIT(8) +#define AD7091R_REG_CONF_CMDBIT(10) + +#define AD7091R_REG_CONF_MODE_MASK \ + (AD7091R_REG_CONF_AUTO | AD7091R_REG_CONF_CMD) + +enum ad7091r_mode { + AD7091R_MODE_SAMPLE, + AD7091R_MODE_COMMAND, + AD7091R_MODE_AUTOCYCLE, +}; + +struct ad7091r_state { + struct device *dev; + struct regmap *map; + const struct ad7091r_chip_info *chip_info; + enum ad7091r_mode mode; + struct mutex lock; +}; + +static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode) +{ + int ret, conf; + + switch (mode) { + case AD7091R_MODE_SAMPLE: + conf = 0; + break; + case AD7091R_MODE_COMMAND: + conf = AD7091R_REG_CONF_CMD; + break; + case AD7091R_MODE_AUTOCYCLE: + conf = AD7091R_REG_CONF_AUTO; + break; + default: + ret = -EINVAL; + break; + } + + ret = regmap_update_bits(st->map, AD7091R_REG_CONF, +AD7091R_REG_CONF_MODE_MASK, conf); + if (ret) + return ret; + + st->mode = mode; + + return ret; +} + +static int ad7091r_set_channel(struct ad7091r_state *st, unsigned int channel) +{ + unsigned int foo; + int ret; + + /* AD7091R_REG_CHANNEL specified which channels to be converted */ + ret = regmap_write(st->map, AD7091R_REG_CHANNEL, + BIT(channel) | (BIT(channel) << 8)); + if (ret) + return ret; + + /* +* There is a latency of one conversion before the channel conversion +* sequence is updated +*/ + return regmap_read(st->map, AD7091R_REG_RESULT, &foo); +} + +static int ad7091r_read_one(struct iio_dev *iio_dev, + unsigned int channel, unsigned int *read_val) +{ + struct ad7091r_state *st = iio_priv(iio_dev); + unsigned int val; + int ret; + + ret = ad7091r_set
[PATCH v3 2/4] iio: adc: ad7091r5: Add scale and external VREF support
From: Paul Cercueil The scale can now be obtained with the "in_voltage_scale" file. By default, the scale returned corresponds to the internal VREF of 2.5V. It is possible to use an external VREF (through the REFIN/REFOUT pin of the chip), by passing a regulator to the driver. The scale will then be calculated according to the voltage reported by the regulator. Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- Changes in v3: -type cast from void* in remove function removed -error checking for devm_add_action_or_reset drivers/iio/adc/ad7091r-base.c | 41 ++ drivers/iio/adc/ad7091r-base.h | 1 + drivers/iio/adc/ad7091r5.c | 5 + 3 files changed, 47 insertions(+) diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index 2ebc40dfd927..abb0d9c2ea9c 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "ad7091r-base.h" @@ -42,6 +43,7 @@ enum ad7091r_mode { struct ad7091r_state { struct device *dev; struct regmap *map; + struct regulator *reg; const struct ad7091r_chip_info *chip_info; enum ad7091r_mode mode; struct mutex lock; @@ -142,6 +144,21 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, ret = IIO_VAL_INT; break; + case IIO_CHAN_INFO_SCALE: + if (st->reg) { + ret = regulator_get_voltage(st->reg); + if (ret < 0) + goto unlock; + + *val = ret / 1000; + } else { + *val = st->chip_info->vref_mV; + } + + *val2 = chan->scan_type.realbits; + ret = IIO_VAL_FRACTIONAL_LOG2; + break; + default: ret = -EINVAL; break; @@ -184,6 +201,14 @@ static irqreturn_t ad7091r_event_handler(int irq, void *private) return IRQ_HANDLED; } +static void ad7091r_remove(void *data) +{ + struct ad7091r_state *st = data; + + if (st->reg) + regulator_disable(st->reg); +} + int ad7091r_probe(struct device *dev, const char *name, const struct ad7091r_chip_info *chip_info, struct regmap *map, int irq) @@ -217,6 +242,22 @@ int ad7091r_probe(struct device *dev, const char *name, return ret; } + st->reg = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(st->reg)) { + if (PTR_ERR(st->reg) == EPROBE_DEFER) + return -EPROBE_DEFER; + + st->reg = NULL; + } else { + ret = regulator_enable(st->reg); + if (ret) + return ret; + } + + ret = devm_add_action_or_reset(dev, ad7091r_remove, st); + if (ret) + return ret; + /* Use command mode by default to convert only desired channels*/ ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND); if (ret) diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h index 5f1147735953..76b76968d071 100644 --- a/drivers/iio/adc/ad7091r-base.h +++ b/drivers/iio/adc/ad7091r-base.h @@ -14,6 +14,7 @@ struct ad7091r_state; struct ad7091r_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; + unsigned int vref_mV; }; extern const struct regmap_config ad7091r_regmap_config; diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index f7b3326032e8..73d18ddfd2c9 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -35,10 +35,13 @@ static const struct iio_event_spec ad7091r5_events[] = { #define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .indexed = 1, \ .channel = idx, \ .event_spec = ev, \ .num_event_specs = num_ev, \ + .scan_type.storagebits = 16, \ + .scan_type.realbits = bits, \ } static const struct iio_chan_spec ad7091r5_channels_irq[] = { AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), @@ -58,11 +61,13 @@ static const struct iio_chan_spec ad7091r5_channels_noirq[] = { static const struct ad7091r_chip_info ad7091r5_chip_info_irq = { .channels = ad7091r5_channels_irq, .num_channels = ARRAY_SIZE(ad7091r5_channels_irq), + .vref_mV = 2500, }; static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = { .channels = ad7091r5_channels_noirq, .num_channels = ARRAY_SIZE(ad7091r5_channels_noirq), + .vref_mV = 2500, }
[PATCH v3 4/4] MAINTAINERS: add entry for AD7091R5 driver
Add Beniamin Bia as a maintainer for AD7091R5 ADC. Signed-off-by: Beniamin Bia --- Changes in v3: -nothing changed MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2e01d0f0b0e5..7f1e4b88688f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -893,6 +893,14 @@ S: Supported F: drivers/iio/dac/ad5758.c F: Documentation/devicetree/bindings/iio/dac/ad5758.txt +ANALOG DEVICES INC AD7091R5 DRIVER +M: Beniamin Bia +L: linux-...@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/iio/adc/ad7091r5.c +F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml + ANALOG DEVICES INC AD7124 DRIVER M: Stefan Popa L: linux-...@vger.kernel.org -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v3 3/4] dt-binding: iio: Add documentation for AD7091R5
Documentation for AD7091R5 ADC was added. Signed-off-by: Beniamin Bia --- Changes in v3: -spdx identifier updated -compatible property with lower case -additionalProperties added -hex value with lower case .../bindings/iio/adc/adi,ad7091r5.yaml| 54 +++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml new file mode 100644 index ..bef84fe6212d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7091R5 4-Channel 12-Bit ADC + +maintainers: + - Beniamin Bia + +description: | + Analog Devices AD7091R5 4-Channel 12-Bit ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf + +properties: + compatible: +enum: + - adi,ad7091r5 + + reg: +maxItems: 1 + + avcc-supply: +description: + Phandle to the Avcc power supply + + interrupts: +maxItems: 1 + + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | +#include +#include +i2c { +#address-cells = <1>; +#size-cells = <0>; + +adc@2f { +compatible = "adi,ad7091r5"; +reg = <0x2f>; + +interrupts = <25 IRQ_TYPE_EDGE_FALLING>; +interrupt-parent = <&gpio>; +}; +}; +... -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 1/3] iio: Add ADM1177 Hot Swap Controller and Digital Power Monitor driver
From: Michael Hennerich ADM1177 is a Hot Swap Controller and Digital Power Monitor with Soft Start Pin. Datasheet: Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1177.pdf Signed-off-by: Michael Hennerich Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/adm1177.c | 257 ++ 3 files changed, 270 insertions(+) create mode 100644 drivers/iio/adc/adm1177.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 9554890a3200..4db8c6dcb595 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -228,6 +228,18 @@ config ASPEED_ADC To compile this driver as a module, choose M here: the module will be called aspeed_adc. +config ADM1177 + tristate "Analog Devices ADM1177 Digital Power Monitor driver" + depends on I2C + help + Say yes here to build support for Analog Devices: + ADM1177 Hot Swap Controller and Digital Power Monitor + with Soft Start Pin. Provides direct access + via sysfs. + + To compile this driver as a module, choose M here: the + module will be called adm1177. + config AT91_ADC tristate "Atmel AT91 ADC" depends on ARCH_AT91 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 5ecc481c2967..7899d6a158f3 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AD7949) += ad7949.o obj-$(CONFIG_AD799X) += ad799x.o obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o +obj-$(CONFIG_ADM1177) += adm1177.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o obj-$(CONFIG_AXP20X_ADC) += axp20x_adc.o diff --git a/drivers/iio/adc/adm1177.c b/drivers/iio/adc/adm1177.c new file mode 100644 index ..daec34566a65 --- /dev/null +++ b/drivers/iio/adc/adm1177.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ADM1177 Hot Swap Controller and Digital Power Monitor with Soft Start Pin + * + * Copyright 2015-2019 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Command Byte Operations */ +#define ADM1177_CMD_V_CONT BIT(0) +#define ADM1177_CMD_V_ONCE BIT(1) +#define ADM1177_CMD_I_CONT BIT(2) +#define ADM1177_CMD_I_ONCE BIT(3) +#define ADM1177_CMD_VRANGE BIT(4) +#define ADM1177_CMD_STATUS_RD BIT(6) + +/* Extended Register */ +#define ADM1177_REG_ALERT_EN 1 +#define ADM1177_REG_ALERT_TH 2 +#define ADM1177_REG_CONTROL3 + +/* ADM1177_REG_ALERT_EN */ +#define ADM1177_EN_ADC_OC1 BIT(0) +#define ADM1177_EN_ADC_OC4 BIT(1) +#define ADM1177_EN_HS_ALERTBIT(2) +#define ADM1177_EN_OFF_ALERT BIT(3) +#define ADM1177_CLEAR BIT(4) + +/* ADM1177_REG_CONTROL */ +#define ADM1177_SWOFF BIT(0) + +#define ADM1177_BITS 12 + +/** + * struct adm1177_state - driver instance specific data + * @client pointer to i2c client + * @regregulator info for the the power supply of the device + * @commandinternal control register + * @r_sense_uohm current sense resistor value + * @alert_threshold_ua current limit for shutdown + * @vrange_highinternal voltage divider + */ +struct adm1177_state { + struct i2c_client *client; + struct regulator*reg; + u8 command; + u32 r_sense_uohm; + u32 alert_threshold_ua; + boolvrange_high; +}; + +static int adm1177_read(struct adm1177_state *st, u8 num, u8 *data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_master_recv(client, data, num); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + return 0; +} + +static int adm1177_write_cmd(struct adm1177_state *st, u8 cmd) +{ + st->command = cmd; + return i2c_smbus_write_byte(st->client, cmd); +} + +static int adm1177_write_reg(struct adm1177_state *st, u8 reg, u8 val) +{ + return i2c_smbus_write_byte_data(st->client, reg, val); +} + +static int adm1177_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct adm1177_state *st = iio_priv(indio_dev); + u8 data[3]; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + adm1177_read(st, 3, data); + switch (chan->type) { + case IIO_VOLTAGE: + *val = (data[0]
[PATCH 2/3] dt-binding: iio: Add documentation for ADM1177
Documentation for ADM1177 was added. Signed-off-by: Beniamin Bia --- .../bindings/iio/adc/adi,adm1177.yaml | 60 +++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,adm1177.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,adm1177.yaml b/Documentation/devicetree/bindings/iio/adc/adi,adm1177.yaml new file mode 100644 index ..69a0230e59f5 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,adm1177.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,adm1177.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADM1177 Hot Swap Controller and Digital Power Monitor + +maintainers: + - Michael Hennerich + - Beniamin Bia + +description: | + Analog Devices ADM1177 Hot Swap Controller and Digital Power Monitor + https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1177.pdf + +properties: + compatible: +enum: + - adi,adm1177 + + reg: +maxItems: 1 + + avcc-supply: +description: + Phandle to the Avcc power supply + + adi,r-sense-micro-ohms: +description: + The value of curent sense resistor in microohms. + + adi,shutdown-threshold-microamp: +description: + Specifies the current level at which an over current alert occurs. +maximum: 255 + + adi,vrange-high-enable: +description: + Specifies which internal voltage divider to be used. A 1 selects + a 7:2 voltage divider while a 0 selects a 14:1 voltage divider. +type: boolean +required: + - compatible + - reg + +examples: + - | +#include +#include +i2c0 { +#address-cells = <1>; +#size-cells = <0>; + +adc@b4 { +compatible = "adi,adm1177"; +reg = <0xb4>; +}; +}; +... -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 3/3] MAINTAINERS: add entry for ADM1177 driver
Add Beniamin Bia and Michael Hennerich as a maintainer for ADM1177 ADC. Signed-off-by: Beniamin Bia --- MAINTAINERS | 9 + 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0fca3b055985..41a34d7a802c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -962,6 +962,15 @@ W: http://ez.analog.com/community/linux-device-drivers F: drivers/iio/imu/adis16460.c F: Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml +ANALOG DEVICES INC ADM1177 DRIVER +M: Beniamin Bia +M: Michael Hennerich +L: linux-...@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/iio/adc/adm1177.c +F: Documentation/devicetree/bindings/iio/adc/adi,adm1177.yaml + ANALOG DEVICES INC ADP5061 DRIVER M: Stefan Popa L: linux...@vger.kernel.org -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v4 2/4] iio: adc: ad7091r5: Add scale and external VREF support
From: Paul Cercueil The scale can now be obtained with the "in_voltage_scale" file. By default, the scale returned corresponds to the internal VREF of 2.5V. It is possible to use an external VREF (through the REFIN/REFOUT pin of the chip), by passing a regulator to the driver. The scale will then be calculated according to the voltage reported by the regulator. Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- Changes in v4: -reg renamed to vref -add ad7091r_remove only on successful reg enable drivers/iio/adc/ad7091r-base.c | 39 ++ drivers/iio/adc/ad7091r-base.h | 1 + drivers/iio/adc/ad7091r5.c | 5 + 3 files changed, 45 insertions(+) diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index 854de7c654c2..6e2b6d3f2aa9 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "ad7091r-base.h" @@ -42,6 +43,7 @@ enum ad7091r_mode { struct ad7091r_state { struct device *dev; struct regmap *map; + struct regulator *vref; const struct ad7091r_chip_info *chip_info; enum ad7091r_mode mode; struct mutex lock; /*lock to prevent concurent reads */ @@ -141,6 +143,21 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, ret = IIO_VAL_INT; break; + case IIO_CHAN_INFO_SCALE: + if (st->vref) { + ret = regulator_get_voltage(st->vref); + if (ret < 0) + goto unlock; + + *val = ret / 1000; + } else { + *val = st->chip_info->vref_mV; + } + + *val2 = chan->scan_type.realbits; + ret = IIO_VAL_FRACTIONAL_LOG2; + break; + default: ret = -EINVAL; break; @@ -183,6 +200,13 @@ static irqreturn_t ad7091r_event_handler(int irq, void *private) return IRQ_HANDLED; } +static void ad7091r_remove(void *data) +{ + struct ad7091r_state *st = data; + + regulator_disable(st->vref); +} + int ad7091r_probe(struct device *dev, const char *name, const struct ad7091r_chip_info *chip_info, struct regmap *map, int irq) @@ -216,6 +240,21 @@ int ad7091r_probe(struct device *dev, const char *name, return ret; } + st->vref = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(st->vref)) { + if (PTR_ERR(st->vref) == EPROBE_DEFER) + return -EPROBE_DEFER; + + st->vref = NULL; + } else { + ret = regulator_enable(st->vref); + if (ret) + return ret; + ret = devm_add_action_or_reset(dev, ad7091r_remove, st); + if (ret) + return ret; + } + /* Use command mode by default to convert only desired channels*/ ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND); if (ret) diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h index b0b4fe01a681..509748aef9b1 100644 --- a/drivers/iio/adc/ad7091r-base.h +++ b/drivers/iio/adc/ad7091r-base.h @@ -14,6 +14,7 @@ struct ad7091r_state; struct ad7091r_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; + unsigned int vref_mV; }; extern const struct regmap_config ad7091r_regmap_config; diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index 30ff0108a6ed..9665679c3ea6 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -35,10 +35,13 @@ static const struct iio_event_spec ad7091r5_events[] = { #define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .indexed = 1, \ .channel = idx, \ .event_spec = ev, \ .num_event_specs = num_ev, \ + .scan_type.storagebits = 16, \ + .scan_type.realbits = bits, \ } static const struct iio_chan_spec ad7091r5_channels_irq[] = { AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), @@ -57,11 +60,13 @@ static const struct iio_chan_spec ad7091r5_channels_noirq[] = { static const struct ad7091r_chip_info ad7091r5_chip_info_irq = { .channels = ad7091r5_channels_irq, .num_channels = ARRAY_SIZE(ad7091r5_channels_irq), + .vref_mV = 2500, }; static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = { .channels = ad7091r5_channels_noirq, .num_channels = ARRAY_SIZE(ad7091r5_channels_noirq), + .vref_mV = 2500, };
[PATCH v4 1/4] iio: adc: Add support for AD7091R5 ADC
From: Paul Cercueil AD7091R5 is 4-Channel, I2C, Ultra Low Power,12-Bit ADC. This driver will also support AD7091R2/4/8 in the future. Datasheet: Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- Changes in v4: -comment to specify mutex role -return on error in set_mode -int foo replaced by dummy -undef channel removed -device tree specific table added -comment matches endif drivers/iio/adc/Kconfig| 7 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7091r-base.c | 260 + drivers/iio/adc/ad7091r-base.h | 25 drivers/iio/adc/ad7091r5.c | 108 ++ 5 files changed, 401 insertions(+) create mode 100644 drivers/iio/adc/ad7091r-base.c create mode 100644 drivers/iio/adc/ad7091r-base.h create mode 100644 drivers/iio/adc/ad7091r5.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7e3286265a38..80b1b9551749 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -22,6 +22,13 @@ config AD7124 To compile this driver as a module, choose M here: the module will be called ad7124. +config AD7091R5 + tristate "Analog Devices AD7091R5 ADC Driver" + depends on I2C + select REGMAP_I2C + help + Say yes here to build support for Analog Devices AD7091R-5 ADC. + config AD7266 tristate "Analog Devices AD7265/AD7266 ADC driver" depends on SPI_MASTER diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ef9cc485fb67..55e44735aaac 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7124) += ad7124.o +obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c new file mode 100644 index ..854de7c654c2 --- /dev/null +++ b/drivers/iio/adc/ad7091r-base.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD7091RX Analog to Digital converter driver + * + * Copyright 2014-2019 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "ad7091r-base.h" + +#define AD7091R_REG_RESULT 0 +#define AD7091R_REG_CHANNEL 1 +#define AD7091R_REG_CONF2 +#define AD7091R_REG_ALERT 3 +#define AD7091R_REG_CH_LOW_LIMIT(ch) ((ch) * 3 + 4) +#define AD7091R_REG_CH_HIGH_LIMIT(ch) ((ch) * 3 + 5) +#define AD7091R_REG_CH_HYSTERESIS(ch) ((ch) * 3 + 6) + +/* AD7091R_REG_RESULT */ +#define AD7091R_REG_RESULT_CH_ID(x)(((x) >> 13) & 0x3) +#define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff) + +/* AD7091R_REG_CONF */ +#define AD7091R_REG_CONF_AUTO BIT(8) +#define AD7091R_REG_CONF_CMDBIT(10) + +#define AD7091R_REG_CONF_MODE_MASK \ + (AD7091R_REG_CONF_AUTO | AD7091R_REG_CONF_CMD) + +enum ad7091r_mode { + AD7091R_MODE_SAMPLE, + AD7091R_MODE_COMMAND, + AD7091R_MODE_AUTOCYCLE, +}; + +struct ad7091r_state { + struct device *dev; + struct regmap *map; + const struct ad7091r_chip_info *chip_info; + enum ad7091r_mode mode; + struct mutex lock; /*lock to prevent concurent reads */ +}; + +static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode) +{ + int ret, conf; + + switch (mode) { + case AD7091R_MODE_SAMPLE: + conf = 0; + break; + case AD7091R_MODE_COMMAND: + conf = AD7091R_REG_CONF_CMD; + break; + case AD7091R_MODE_AUTOCYCLE: + conf = AD7091R_REG_CONF_AUTO; + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(st->map, AD7091R_REG_CONF, +AD7091R_REG_CONF_MODE_MASK, conf); + if (ret) + return ret; + + st->mode = mode; + + return 0; +} + +static int ad7091r_set_channel(struct ad7091r_state *st, unsigned int channel) +{ + unsigned int dummy; + int ret; + + /* AD7091R_REG_CHANNEL specified which channels to be converted */ + ret = regmap_write(st->map, AD7091R_REG_CHANNEL, + BIT(channel) | (BIT(channel) << 8)); + if (ret) + return ret; + + /* +* There is a latency of one conversion before the channel conversion +* sequence is updated +*/ + return regmap_read(st->map, AD7091R_REG_RESULT, &dummy); +} + +static int ad7091r_read_one(struct iio_dev *iio_dev, + unsigned int channel, unsigned int *read_val) +{ + struct ad7091r_state *st = iio_priv(
[PATCH v4 3/4] dt-binding: iio: Add documentation for AD7091R5
Documentation for AD7091R5 ADC was added. Signed-off-by: Beniamin Bia Reviewed-by: Rob Herring --- Changes in v4: -nothing changed .../bindings/iio/adc/adi,ad7091r5.yaml| 54 +++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml new file mode 100644 index ..31ffa275f5fa --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7091R5 4-Channel 12-Bit ADC + +maintainers: + - Beniamin Bia + +description: | + Analog Devices AD7091R5 4-Channel 12-Bit ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf + +properties: + compatible: +enum: + - adi,ad7091r5 + + reg: +maxItems: 1 + + vref-supply: +description: + Phandle to the vref power supply + + interrupts: +maxItems: 1 + + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | +#include +#include +i2c { +#address-cells = <1>; +#size-cells = <0>; + +adc@2f { +compatible = "adi,ad7091r5"; +reg = <0x2f>; + +interrupts = <25 IRQ_TYPE_EDGE_FALLING>; +interrupt-parent = <&gpio>; +}; +}; +... -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v4 4/4] MAINTAINERS: add entry for AD7091R5 driver
Add Beniamin Bia as a maintainer for AD7091R5 ADC. Signed-off-by: Beniamin Bia --- Changes in v4: -nothing changed MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2e01d0f0b0e5..7f1e4b88688f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -893,6 +893,14 @@ S: Supported F: drivers/iio/dac/ad5758.c F: Documentation/devicetree/bindings/iio/dac/ad5758.txt +ANALOG DEVICES INC AD7091R5 DRIVER +M: Beniamin Bia +L: linux-...@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/iio/adc/ad7091r5.c +F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml + ANALOG DEVICES INC AD7124 DRIVER M: Stefan Popa L: linux-...@vger.kernel.org -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v5 1/4] iio: adc: Add support for AD7091R5 ADC
From: Paul Cercueil AD7091R5 is 4-Channel, I2C, Ultra Low Power,12-Bit ADC. This driver will also support AD7091R2/4/8 in the future. Datasheet: Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- Changes in v5: -nothing changed drivers/iio/adc/Kconfig| 7 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7091r-base.c | 260 + drivers/iio/adc/ad7091r-base.h | 25 drivers/iio/adc/ad7091r5.c | 108 ++ 5 files changed, 401 insertions(+) create mode 100644 drivers/iio/adc/ad7091r-base.c create mode 100644 drivers/iio/adc/ad7091r-base.h create mode 100644 drivers/iio/adc/ad7091r5.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7e3286265a38..80b1b9551749 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -22,6 +22,13 @@ config AD7124 To compile this driver as a module, choose M here: the module will be called ad7124. +config AD7091R5 + tristate "Analog Devices AD7091R5 ADC Driver" + depends on I2C + select REGMAP_I2C + help + Say yes here to build support for Analog Devices AD7091R-5 ADC. + config AD7266 tristate "Analog Devices AD7265/AD7266 ADC driver" depends on SPI_MASTER diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ef9cc485fb67..55e44735aaac 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7124) += ad7124.o +obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c new file mode 100644 index ..854de7c654c2 --- /dev/null +++ b/drivers/iio/adc/ad7091r-base.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD7091RX Analog to Digital converter driver + * + * Copyright 2014-2019 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "ad7091r-base.h" + +#define AD7091R_REG_RESULT 0 +#define AD7091R_REG_CHANNEL 1 +#define AD7091R_REG_CONF2 +#define AD7091R_REG_ALERT 3 +#define AD7091R_REG_CH_LOW_LIMIT(ch) ((ch) * 3 + 4) +#define AD7091R_REG_CH_HIGH_LIMIT(ch) ((ch) * 3 + 5) +#define AD7091R_REG_CH_HYSTERESIS(ch) ((ch) * 3 + 6) + +/* AD7091R_REG_RESULT */ +#define AD7091R_REG_RESULT_CH_ID(x)(((x) >> 13) & 0x3) +#define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff) + +/* AD7091R_REG_CONF */ +#define AD7091R_REG_CONF_AUTO BIT(8) +#define AD7091R_REG_CONF_CMDBIT(10) + +#define AD7091R_REG_CONF_MODE_MASK \ + (AD7091R_REG_CONF_AUTO | AD7091R_REG_CONF_CMD) + +enum ad7091r_mode { + AD7091R_MODE_SAMPLE, + AD7091R_MODE_COMMAND, + AD7091R_MODE_AUTOCYCLE, +}; + +struct ad7091r_state { + struct device *dev; + struct regmap *map; + const struct ad7091r_chip_info *chip_info; + enum ad7091r_mode mode; + struct mutex lock; /*lock to prevent concurent reads */ +}; + +static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode) +{ + int ret, conf; + + switch (mode) { + case AD7091R_MODE_SAMPLE: + conf = 0; + break; + case AD7091R_MODE_COMMAND: + conf = AD7091R_REG_CONF_CMD; + break; + case AD7091R_MODE_AUTOCYCLE: + conf = AD7091R_REG_CONF_AUTO; + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(st->map, AD7091R_REG_CONF, +AD7091R_REG_CONF_MODE_MASK, conf); + if (ret) + return ret; + + st->mode = mode; + + return 0; +} + +static int ad7091r_set_channel(struct ad7091r_state *st, unsigned int channel) +{ + unsigned int dummy; + int ret; + + /* AD7091R_REG_CHANNEL specified which channels to be converted */ + ret = regmap_write(st->map, AD7091R_REG_CHANNEL, + BIT(channel) | (BIT(channel) << 8)); + if (ret) + return ret; + + /* +* There is a latency of one conversion before the channel conversion +* sequence is updated +*/ + return regmap_read(st->map, AD7091R_REG_RESULT, &dummy); +} + +static int ad7091r_read_one(struct iio_dev *iio_dev, + unsigned int channel, unsigned int *read_val) +{ + struct ad7091r_state *st = iio_priv(iio_dev); + unsigned int val; + int ret; + + ret = ad7091r_set_channel(st, channel); + if (ret) + return
[PATCH v5 2/4] iio: adc: ad7091r5: Add scale and external VREF support
From: Paul Cercueil The scale can now be obtained with the "in_voltage_scale" file. By default, the scale returned corresponds to the internal VREF of 2.5V. It is possible to use an external VREF (through the REFIN/REFOUT pin of the chip), by passing a regulator to the driver. The scale will then be calculated according to the voltage reported by the regulator. Signed-off-by: Paul Cercueil Co-developed-by: Beniamin Bia Signed-off-by: Beniamin Bia --- Changes in v5: -check if error is -eprobe instead of eprobe -one bracket aligned drivers/iio/adc/ad7091r-base.c | 38 ++ drivers/iio/adc/ad7091r-base.h | 1 + drivers/iio/adc/ad7091r5.c | 5 + 3 files changed, 44 insertions(+) diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index 854de7c654c2..58fcf1ff8c76 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "ad7091r-base.h" @@ -42,6 +43,7 @@ enum ad7091r_mode { struct ad7091r_state { struct device *dev; struct regmap *map; + struct regulator *vref; const struct ad7091r_chip_info *chip_info; enum ad7091r_mode mode; struct mutex lock; /*lock to prevent concurent reads */ @@ -141,6 +143,21 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, ret = IIO_VAL_INT; break; + case IIO_CHAN_INFO_SCALE: + if (st->vref) { + ret = regulator_get_voltage(st->vref); + if (ret < 0) + goto unlock; + + *val = ret / 1000; + } else { + *val = st->chip_info->vref_mV; + } + + *val2 = chan->scan_type.realbits; + ret = IIO_VAL_FRACTIONAL_LOG2; + break; + default: ret = -EINVAL; break; @@ -183,6 +200,13 @@ static irqreturn_t ad7091r_event_handler(int irq, void *private) return IRQ_HANDLED; } +static void ad7091r_remove(void *data) +{ + struct ad7091r_state *st = data; + + regulator_disable(st->vref); +} + int ad7091r_probe(struct device *dev, const char *name, const struct ad7091r_chip_info *chip_info, struct regmap *map, int irq) @@ -216,6 +240,20 @@ int ad7091r_probe(struct device *dev, const char *name, return ret; } + st->vref = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(st->vref)) { + if (PTR_ERR(st->reg) == -EPROBE_DEFER) + return -EPROBE_DEFER; + st->vref = NULL; + } else { + ret = regulator_enable(st->vref); + if (ret) + return ret; + ret = devm_add_action_or_reset(dev, ad7091r_remove, st); + if (ret) + return ret; + } + /* Use command mode by default to convert only desired channels*/ ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND); if (ret) diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h index b0b4fe01a681..509748aef9b1 100644 --- a/drivers/iio/adc/ad7091r-base.h +++ b/drivers/iio/adc/ad7091r-base.h @@ -14,6 +14,7 @@ struct ad7091r_state; struct ad7091r_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; + unsigned int vref_mV; }; extern const struct regmap_config ad7091r_regmap_config; diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index 30ff0108a6ed..9665679c3ea6 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -35,10 +35,13 @@ static const struct iio_event_spec ad7091r5_events[] = { #define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .indexed = 1, \ .channel = idx, \ .event_spec = ev, \ .num_event_specs = num_ev, \ + .scan_type.storagebits = 16, \ + .scan_type.realbits = bits, \ } static const struct iio_chan_spec ad7091r5_channels_irq[] = { AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), @@ -57,11 +60,13 @@ static const struct iio_chan_spec ad7091r5_channels_noirq[] = { static const struct ad7091r_chip_info ad7091r5_chip_info_irq = { .channels = ad7091r5_channels_irq, .num_channels = ARRAY_SIZE(ad7091r5_channels_irq), + .vref_mV = 2500, }; static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = { .channels = ad7091r5_channels_noirq, .num_channels = ARRAY_SIZE(ad7091r5_channels_noirq), + .vref_mV = 2500, };
[PATCH v5 4/4] MAINTAINERS: add entry for AD7091R5 driver
Add Beniamin Bia as a maintainer for AD7091R5 ADC. Signed-off-by: Beniamin Bia --- Changes in v5: -nothing changed MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2e01d0f0b0e5..7f1e4b88688f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -893,6 +893,14 @@ S: Supported F: drivers/iio/dac/ad5758.c F: Documentation/devicetree/bindings/iio/dac/ad5758.txt +ANALOG DEVICES INC AD7091R5 DRIVER +M: Beniamin Bia +L: linux-...@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/iio/adc/ad7091r5.c +F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml + ANALOG DEVICES INC AD7124 DRIVER M: Stefan Popa L: linux-...@vger.kernel.org -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v5 3/4] dt-binding: iio: Add documentation for AD7091R5
Documentation for AD7091R5 ADC was added. Signed-off-by: Beniamin Bia Reviewed-by: Rob Herring --- Changes in v5: -nothing changed .../bindings/iio/adc/adi,ad7091r5.yaml| 54 +++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml new file mode 100644 index ..31ffa275f5fa --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7091R5 4-Channel 12-Bit ADC + +maintainers: + - Beniamin Bia + +description: | + Analog Devices AD7091R5 4-Channel 12-Bit ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf + +properties: + compatible: +enum: + - adi,ad7091r5 + + reg: +maxItems: 1 + + vref-supply: +description: + Phandle to the vref power supply + + interrupts: +maxItems: 1 + + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | +#include +#include +i2c { +#address-cells = <1>; +#size-cells = <0>; + +adc@2f { +compatible = "adi,ad7091r5"; +reg = <0x2f>; + +interrupts = <25 IRQ_TYPE_EDGE_FALLING>; +interrupt-parent = <&gpio>; +}; +}; +... -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 2/5] iio: adc: ad7606: Add software configuration
Because this driver will support multiple configurations for software, the software configuration was made generic. Signed-off-by: Beniamin Bia --- drivers/iio/adc/ad7606.c | 40 +--- drivers/iio/adc/ad7606.h | 2 ++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index c66ff22f32d2..aba0fd123a51 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -140,7 +140,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, int *val2, long m) { - int ret; + int ret, ch = 0; struct ad7606_state *st = iio_priv(indio_dev); switch (m) { @@ -157,8 +157,10 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, *val = (short)ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: + if (st->sw_mode_en) + ch = chan->address; *val = 0; - *val2 = st->scale_avail[st->range[0]]; + *val2 = st->scale_avail[st->range[ch]]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = st->oversampling; @@ -233,7 +235,9 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: mutex_lock(&st->lock); i = find_closest(val2, st->scale_avail, st->num_scales); - ret = st->write_scale(indio_dev, chan->address, i); + if (st->sw_mode_en) + ch = chan->address; + ret = st->write_scale(indio_dev, ch, i); if (ret < 0) { mutex_unlock(&st->lock); return ret; @@ -616,6 +620,36 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; + if (st->chip_info->sw_mode_config) + st->sw_mode_en = device_property_present(st->dev, +"adi,sw-mode"); + + if (st->sw_mode_en) { + /* After reset, in software mode, ±10 V is set by default */ + memset32(st->range, 2, ARRAY_SIZE(st->range)); + indio_dev->info = &ad7606_info_os_and_range; + + /* +* In software mode, the range gpio has no longer its function. +* Instead, the scale can be configured individually for each +* channel from the range registers. +*/ + if (st->chip_info->write_scale_sw) + st->write_scale = st->chip_info->write_scale_sw; + + /* +* In software mode, the oversampling is no longer configured +* with GPIO pins. Instead, the oversampling can be configured +* in configuratiion register. +*/ + if (st->chip_info->write_os_sw) + st->write_os = st->chip_info->write_os_sw; + + ret = st->chip_info->sw_mode_config(indio_dev); + if (ret < 0) + return ret; + } + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); if (!st->trig) diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index 143c30163df9..d8a509c2c428 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -43,6 +43,7 @@ struct ad7606_chip_info { * @range voltage range selection, selects which scale to apply * @oversampling oversampling selection * @base_address address from where to read data in parallel operation + * @sw_mode_en software mode enabled * @scale_availpointer to the array which stores the available scales * @num_scales number of elements stored in the scale_avail array * @oversampling_avail pointer to the array which stores the available @@ -71,6 +72,7 @@ struct ad7606_state { unsigned intrange[16]; unsigned intoversampling; void __iomem*base_address; + boolsw_mode_en; const unsigned int *scale_avail; unsigned intnum_scales; const unsigned int *oversampling_avail; -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 1/5] iio: adc: ad7606: Move oversampling and scale options to chip info
The device dependent options which are going to be different for devices which will be supported in the future by this driver, were moved in chip info for a more generic driver. This patch allows supporting more devices by the driver. Also, it is an intermediate step of adding support for ad7616 in software mode. Signed-off-by: Beniamin Bia --- drivers/iio/adc/ad7606.c | 61 +--- drivers/iio/adc/ad7606.h | 15 +- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 24c70c3cefb4..c66ff22f32d2 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -158,7 +158,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - *val2 = st->scale_avail[st->range]; + *val2 = st->scale_avail[st->range[0]]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = st->oversampling; @@ -194,6 +194,32 @@ static ssize_t in_voltage_scale_available_show(struct device *dev, static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); +static int ad7606_write_scale_hw(struct iio_dev *indio_dev, int ch, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + gpiod_set_value(st->gpio_range, val); + + return 0; +} + +static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + DECLARE_BITMAP(values, 3); + + values[0] = val; + + gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, + st->gpio_os->info, values); + + /* AD7616 requires a reset to update value */ + if (st->chip_info->os_req_reset) + ad7606_reset(st); + + return 0; +} + static int ad7606_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, @@ -201,15 +227,18 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, long mask) { struct ad7606_state *st = iio_priv(indio_dev); - DECLARE_BITMAP(values, 3); - int i; + int i, ret, ch = 0; switch (mask) { case IIO_CHAN_INFO_SCALE: mutex_lock(&st->lock); i = find_closest(val2, st->scale_avail, st->num_scales); - gpiod_set_value(st->gpio_range, i); - st->range = i; + ret = st->write_scale(indio_dev, chan->address, i); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + st->range[ch] = i; mutex_unlock(&st->lock); return 0; @@ -218,17 +247,12 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, return -EINVAL; i = find_closest(val, st->oversampling_avail, st->num_os_ratios); - - values[0] = i; - mutex_lock(&st->lock); - gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, - st->gpio_os->info, values); - - /* AD7616 requires a reset to update value */ - if (st->chip_info->os_req_reset) - ad7606_reset(st); - + ret = st->write_os(indio_dev, i); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } st->oversampling = st->oversampling_avail[i]; mutex_unlock(&st->lock); @@ -536,7 +560,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, st->bops = bops; st->base_address = base_address; /* tied to logic low, analog input range is +/- 5V */ - st->range = 0; + st->range[0] = 0; st->oversampling = 1; st->scale_avail = ad7606_scale_avail; st->num_scales = ARRAY_SIZE(ad7606_scale_avail); @@ -589,6 +613,9 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); + st->write_scale = ad7606_write_scale_hw; + st->write_os = ad7606_write_os_hw; + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); if (!st->trig) @@ -643,7 +670,7 @@ static int ad7606_resume(struct device *dev) struct ad7606_state *st = iio_priv(indio_dev);
[PATCH 5/5] iio: adc: ad7606: Add debug mode for ad7616
Support for register access was added for spi devices. Signed-off-by: Beniamin Bia --- drivers/iio/adc/ad7606.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index f77df3efe43f..b03bdce4fd4e 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -134,6 +134,30 @@ static int ad7606_spi_write_mask(struct ad7606_state *st, return ad7606_spi_reg_write(st, addr, readval); } +static int ad7606_reg_access(struct iio_dev *indio_dev, +unsigned int reg, +unsigned int writeval, +unsigned int *readval) +{ + struct ad7606_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + if (readval) { + ret = ad7606_spi_reg_read(st, reg); + if (ret < 0) + goto err_unlock; + *readval = ret; + ret = 0; + } else { + ret = ad7606_spi_reg_write(st, reg, writeval); + } +err_unlock: + mutex_unlock(&st->lock); + + return ret; +} + static int ad7606_read_samples(struct ad7606_state *st) { unsigned int num = st->chip_info->num_channels; @@ -645,6 +669,7 @@ static const struct iio_info ad7606_info_no_os_or_range = { static const struct iio_info ad7606_info_os_and_range = { .read_raw = &ad7606_read_raw, .write_raw = &ad7606_write_raw, + .debugfs_reg_access = &ad7606_reg_access, .attrs = &ad7606_attribute_group_os_and_range, .validate_trigger = &ad7606_validate_trigger, }; -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 3/5] iio: adc: ad7606: Make SPI register calculation generic and add spi support
In order to support AD7616 software mode, the spi register access must be added and the calculation of registers address must be generic. The length of address and bit which specifies the read/write operation is different for every device, that is why it was made generic. Signed-off-by: Beniamin Bia --- drivers/iio/adc/ad7606.c | 60 drivers/iio/adc/ad7606.h | 2 ++ 2 files changed, 62 insertions(+) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index aba0fd123a51..6df81117cacc 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -25,6 +25,8 @@ #include #include +#include + #include "ad7606.h" /* @@ -43,6 +45,11 @@ static const unsigned int ad7616_oversampling_avail[8] = { 1, 2, 4, 8, 16, 32, 64, 128, }; +static int ad7616_spi_rd_wr_cmd(int addr, char isWriteOp) +{ + return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7); +} + static int ad7606_reset(struct ad7606_state *st) { if (st->gpio_reset) { @@ -55,6 +62,59 @@ static int ad7606_reset(struct ad7606_state *st) return -ENODEV; } +static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr) +{ + struct spi_device *spi = to_spi_device(st->dev); + struct spi_transfer t[] = { + { + .tx_buf = &st->data[0], + .len = 2, + .cs_change = 0, + }, { + .rx_buf = &st->data[1], + .len = 2, + }, + }; + int ret; + + st->data[0] = cpu_to_be16(st->chip_info->spi_rd_wr_cmd(addr, 0) << 8); + + ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t)); + if (ret < 0) + return ret; + + return be16_to_cpu(st->data[1]); +} + +static int ad7606_spi_reg_write(struct ad7606_state *st, + unsigned int addr, + unsigned int val) +{ + struct spi_device *spi = to_spi_device(st->dev); + + st->data[0] = cpu_to_be16((st->chip_info->spi_rd_wr_cmd(addr, 1) << 8) | + (val & 0x1FF)); + + return spi_write(spi, &st->data[0], sizeof(st->data[0])); +} + +static int ad7606_spi_write_mask(struct ad7606_state *st, +unsigned int addr, +unsigned long mask, +unsigned int val) +{ + int readval; + + readval = ad7606_spi_reg_read(st, addr); + if (readval < 0) + return readval; + + readval &= ~mask; + readval |= val; + + return ad7606_spi_reg_write(st, addr, readval); +} + static int ad7606_read_samples(struct ad7606_state *st) { unsigned int num = st->chip_info->num_channels; diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index d8a509c2c428..dfc60af9b8ac 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -16,6 +16,7 @@ * oversampling ratios. * @oversampling_num number of elements stored in oversampling_avail array * @os_req_reset some devices require a reset to update oversampling + * @spi_rd_wr_cmd pointer to the function which calculates the spi address * @write_scale_sw pointer to the function which writes the scale via spi in software mode * @write_os_swpointer to the function which writes the os via spi @@ -29,6 +30,7 @@ struct ad7606_chip_info { const unsigned int *oversampling_avail; unsigned intoversampling_num; boolos_req_reset; + int (*spi_rd_wr_cmd)(int addr, char isWriteOp); int (*write_scale_sw)(struct iio_dev *indio_dev, int ch, int val); int (*write_os_sw)(struct iio_dev *indio_dev, int val); int (*sw_mode_config)(struct iio_dev *indio_dev); -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH 4/5] iio: adc: ad7606: Add support for software mode for ad7616
Support for ad7616 running in software was added. In order to activate the software mode, HW_RNGSEL pins must be pulled low. Oversampling and input ranges are now configured in corresponding registers. Ad7616 has multiple scale options when it is configured in software mode. Signed-off-by: Beniamin Bia --- drivers/iio/adc/ad7606.c | 111 --- 1 file changed, 103 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 6df81117cacc..f77df3efe43f 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -29,6 +29,20 @@ #include "ad7606.h" +#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1)) +#define AD7606_OS_MODE 0x08 + +#define AD7616_CONFIGURATION_REGISTER 0x02 +#define AD7616_OS_MASK GENMASK(4, 2) +#define AD7616_BURST_MODE BIT(6) +#define AD7616_SEQEN_MODE BIT(5) +#define AD7616_RANGE_CH_ADDR_OFF 0x04 +#define AD7616_RANGE_CH_ADDR(ch) ch) & 0x1) << 1) + ((ch) >> 3)) +#define AD7616_RANGE_CH_MSK(ch)(GENMASK(1, 0) << ((ch) & 0x6)) +#define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << (ch & GENMASK(2, 1))) + +static int ad7616_sw_mode_config(struct iio_dev *indio_dev); + /* * Scales are computed as 5000/32768 and 1/32768 respectively, * so that when applied to the raw values they provide mV values @@ -37,6 +51,11 @@ static const unsigned int ad7606_scale_avail[2] = { 152588, 305176 }; + +static const unsigned int ad7616_sw_scale_avail[3] = { + 76293, 152588, 305176 +}; + static const unsigned int ad7606_oversampling_avail[7] = { 1, 2, 4, 8, 16, 32, 64, }; @@ -282,6 +301,26 @@ static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val) return 0; } +static int ad7616_write_scale_sw(struct iio_dev *indio_dev, int ch, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned int ch_addr, mode; + + ch_addr = AD7616_RANGE_CH_ADDR_OFF + AD7616_RANGE_CH_ADDR(ch); + mode = AD7616_RANGE_CH_MODE(ch, ((val + 1) & 0x3)); + + return ad7606_spi_write_mask(st, ch_addr, AD7616_RANGE_CH_MSK(ch), +mode); +} + +static int ad7616_write_os_sw(struct iio_dev *indio_dev, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_spi_write_mask(st, AD7616_CONFIGURATION_REGISTER, +AD7616_OS_MASK, val << 2); +} + static int ad7606_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, @@ -368,14 +407,14 @@ static const struct attribute_group ad7606_attribute_group_range = { .attrs = ad7606_attributes_range, }; -#define AD760X_CHANNEL(num, mask) {\ +#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all) { \ .type = IIO_VOLTAGE,\ .indexed = 1, \ .channel = num, \ .address = num, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ - .info_mask_shared_by_all = mask,\ + .info_mask_separate = mask_sep, \ + .info_mask_shared_by_type = mask_type, \ + .info_mask_shared_by_all = mask_all,\ .scan_index = num, \ .scan_type = { \ .sign = 's',\ @@ -385,11 +424,18 @@ static const struct attribute_group ad7606_attribute_group_range = { }, \ } -#define AD7605_CHANNEL(num)\ - AD760X_CHANNEL(num, 0) +#define AD7605_CHANNEL(num)\ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ + BIT(IIO_CHAN_INFO_SCALE), 0) + +#define AD7606_CHANNEL(num)\ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ + BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) -#define AD7606_CHANNEL(num)\ - AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) +#define AD7616_CHANNEL(num)\ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),\ + 0, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) static const struct iio_chan_spec ad7605_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(4), @@ -441,6 +487,26 @@ static const struct iio_chan_spec ad7616_channels[] = { AD7606_
[PATCH v2 3/4] iio: adc: ad7606: Add support for software mode for ad7616
Support for ad7616 running in software was added. In order to activate the software mode, HW_RNGSEL pins must be pulled low. Oversampling and input ranges are now configured in corresponding registers. Ad7616 has multiple scale options when it is configured in software mode. Also, in order to support multiple devices in software mode, the spi the calculation of registers address must be generic. Because the length of address and bit which specifies the read/write operation is different for every device, calculation of address was made generic. Signed-off-by: Beniamin Bia --- Changes in v2: -squashed with the patch which introduces the reg access function. -some casting warnings were fixed. drivers/iio/adc/ad7606.c | 171 +-- drivers/iio/adc/ad7606.h | 4 + 2 files changed, 167 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index aba0fd123a51..8e09ad4bb72e 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -25,8 +25,24 @@ #include #include +#include + #include "ad7606.h" +#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1)) +#define AD7606_OS_MODE 0x08 + +#define AD7616_CONFIGURATION_REGISTER 0x02 +#define AD7616_OS_MASK GENMASK(4, 2) +#define AD7616_BURST_MODE BIT(6) +#define AD7616_SEQEN_MODE BIT(5) +#define AD7616_RANGE_CH_ADDR_OFF 0x04 +#define AD7616_RANGE_CH_ADDR(ch) ch) & 0x1) << 1) + ((ch) >> 3)) +#define AD7616_RANGE_CH_MSK(ch)(GENMASK(1, 0) << ((ch) & 0x6)) +#define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << (ch & GENMASK(2, 1))) + +static int ad7616_sw_mode_config(struct iio_dev *indio_dev); + /* * Scales are computed as 5000/32768 and 1/32768 respectively, * so that when applied to the raw values they provide mV values @@ -35,6 +51,11 @@ static const unsigned int ad7606_scale_avail[2] = { 152588, 305176 }; + +static const unsigned int ad7616_sw_scale_avail[3] = { + 76293, 152588, 305176 +}; + static const unsigned int ad7606_oversampling_avail[7] = { 1, 2, 4, 8, 16, 32, 64, }; @@ -43,6 +64,11 @@ static const unsigned int ad7616_oversampling_avail[8] = { 1, 2, 4, 8, 16, 32, 64, 128, }; +static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp) +{ + return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7); +} + static int ad7606_reset(struct ad7606_state *st) { if (st->gpio_reset) { @@ -55,6 +81,59 @@ static int ad7606_reset(struct ad7606_state *st) return -ENODEV; } +static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr) +{ + struct spi_device *spi = to_spi_device(st->dev); + struct spi_transfer t[] = { + { + .tx_buf = &st->d16[0], + .len = 2, + .cs_change = 0, + }, { + .rx_buf = &st->d16[1], + .len = 2, + }, + }; + int ret; + + st->d16[0] = cpu_to_be16(st->chip_info->spi_rd_wr_cmd(addr, 0) << 8); + + ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t)); + if (ret < 0) + return ret; + + return be16_to_cpu(st->d16[1]); +} + +static int ad7606_spi_reg_write(struct ad7606_state *st, + unsigned int addr, + unsigned int val) +{ + struct spi_device *spi = to_spi_device(st->dev); + + st->d16[0] = cpu_to_be16((st->chip_info->spi_rd_wr_cmd(addr, 1) << 8) | + (val & 0x1FF)); + + return spi_write(spi, &st->d16[0], sizeof(st->d16[0])); +} + +static int ad7606_spi_write_mask(struct ad7606_state *st, +unsigned int addr, +unsigned long mask, +unsigned int val) +{ + int readval; + + readval = ad7606_spi_reg_read(st, addr); + if (readval < 0) + return readval; + + readval &= ~mask; + readval |= val; + + return ad7606_spi_reg_write(st, addr, readval); +} + static int ad7606_read_samples(struct ad7606_state *st) { unsigned int num = st->chip_info->num_channels; @@ -222,6 +301,26 @@ static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val) return 0; } +static int ad7616_write_scale_sw(struct iio_dev *indio_dev, int ch, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned int ch_addr, mode; + + ch_addr = AD7616_RANGE_CH_ADDR_OFF + AD7616_RANGE_CH_ADDR(ch); + mode = AD7616_RANGE_CH_MODE(ch, ((val + 1) & 0x3)); + + return ad7606_spi_write_mask(st, ch_addr, AD7616_RANGE_CH_MSK(ch), +
[PATCH v2 4/4] iio: adc: ad7606: Add debug mode for ad7616
Support for register access was added for spi devices. Signed-off-by: Beniamin Bia Acked-by: Jonathan Cameron --- Changes in v2: -nothing changed drivers/iio/adc/ad7606.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 8e09ad4bb72e..0eccfc873802 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -134,6 +134,30 @@ static int ad7606_spi_write_mask(struct ad7606_state *st, return ad7606_spi_reg_write(st, addr, readval); } +static int ad7606_reg_access(struct iio_dev *indio_dev, +unsigned int reg, +unsigned int writeval, +unsigned int *readval) +{ + struct ad7606_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + if (readval) { + ret = ad7606_spi_reg_read(st, reg); + if (ret < 0) + goto err_unlock; + *readval = ret; + ret = 0; + } else { + ret = ad7606_spi_reg_write(st, reg, writeval); + } +err_unlock: + mutex_unlock(&st->lock); + + return ret; +} + static int ad7606_read_samples(struct ad7606_state *st) { unsigned int num = st->chip_info->num_channels; @@ -645,6 +669,7 @@ static const struct iio_info ad7606_info_no_os_or_range = { static const struct iio_info ad7606_info_os_and_range = { .read_raw = &ad7606_read_raw, .write_raw = &ad7606_write_raw, + .debugfs_reg_access = &ad7606_reg_access, .attrs = &ad7606_attribute_group_os_and_range, .validate_trigger = &ad7606_validate_trigger, }; -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
[PATCH v2 1/4] iio: adc: ad7606: Move oversampling and scale options to chip info
The device dependent options which are going to be different for devices which will be supported in the future by this driver, were moved in chip info for a more generic driver. This patch allows supporting more devices by the driver. Also, it is an intermediate step of adding support for ad7616 in software mode. Signed-off-by: Beniamin Bia Acked-by: Jonathan Cameron --- Changes in v2: -nothing changed drivers/iio/adc/ad7606.c | 61 +--- drivers/iio/adc/ad7606.h | 15 +- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 24c70c3cefb4..c66ff22f32d2 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -158,7 +158,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - *val2 = st->scale_avail[st->range]; + *val2 = st->scale_avail[st->range[0]]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = st->oversampling; @@ -194,6 +194,32 @@ static ssize_t in_voltage_scale_available_show(struct device *dev, static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); +static int ad7606_write_scale_hw(struct iio_dev *indio_dev, int ch, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + gpiod_set_value(st->gpio_range, val); + + return 0; +} + +static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + DECLARE_BITMAP(values, 3); + + values[0] = val; + + gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, + st->gpio_os->info, values); + + /* AD7616 requires a reset to update value */ + if (st->chip_info->os_req_reset) + ad7606_reset(st); + + return 0; +} + static int ad7606_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, @@ -201,15 +227,18 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, long mask) { struct ad7606_state *st = iio_priv(indio_dev); - DECLARE_BITMAP(values, 3); - int i; + int i, ret, ch = 0; switch (mask) { case IIO_CHAN_INFO_SCALE: mutex_lock(&st->lock); i = find_closest(val2, st->scale_avail, st->num_scales); - gpiod_set_value(st->gpio_range, i); - st->range = i; + ret = st->write_scale(indio_dev, chan->address, i); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + st->range[ch] = i; mutex_unlock(&st->lock); return 0; @@ -218,17 +247,12 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, return -EINVAL; i = find_closest(val, st->oversampling_avail, st->num_os_ratios); - - values[0] = i; - mutex_lock(&st->lock); - gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, - st->gpio_os->info, values); - - /* AD7616 requires a reset to update value */ - if (st->chip_info->os_req_reset) - ad7606_reset(st); - + ret = st->write_os(indio_dev, i); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } st->oversampling = st->oversampling_avail[i]; mutex_unlock(&st->lock); @@ -536,7 +560,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, st->bops = bops; st->base_address = base_address; /* tied to logic low, analog input range is +/- 5V */ - st->range = 0; + st->range[0] = 0; st->oversampling = 1; st->scale_avail = ad7606_scale_avail; st->num_scales = ARRAY_SIZE(ad7606_scale_avail); @@ -589,6 +613,9 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); + st->write_scale = ad7606_write_scale_hw; + st->write_os = ad7606_write_os_hw; + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); if (!st->trig) @@ -643,7 +670,7 @@ static int ad7606_resume(struct device *dev)
[PATCH v2 2/4] iio: adc: ad7606: Add software configuration
Because this driver will support multiple configurations for software, the software configuration was made generic. Signed-off-by: Beniamin Bia Acked-by: Jonathan Cameron --- Changes in v2: -nothing changed drivers/iio/adc/ad7606.c | 40 +--- drivers/iio/adc/ad7606.h | 2 ++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index c66ff22f32d2..aba0fd123a51 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -140,7 +140,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, int *val2, long m) { - int ret; + int ret, ch = 0; struct ad7606_state *st = iio_priv(indio_dev); switch (m) { @@ -157,8 +157,10 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, *val = (short)ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: + if (st->sw_mode_en) + ch = chan->address; *val = 0; - *val2 = st->scale_avail[st->range[0]]; + *val2 = st->scale_avail[st->range[ch]]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = st->oversampling; @@ -233,7 +235,9 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: mutex_lock(&st->lock); i = find_closest(val2, st->scale_avail, st->num_scales); - ret = st->write_scale(indio_dev, chan->address, i); + if (st->sw_mode_en) + ch = chan->address; + ret = st->write_scale(indio_dev, ch, i); if (ret < 0) { mutex_unlock(&st->lock); return ret; @@ -616,6 +620,36 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; + if (st->chip_info->sw_mode_config) + st->sw_mode_en = device_property_present(st->dev, +"adi,sw-mode"); + + if (st->sw_mode_en) { + /* After reset, in software mode, ±10 V is set by default */ + memset32(st->range, 2, ARRAY_SIZE(st->range)); + indio_dev->info = &ad7606_info_os_and_range; + + /* +* In software mode, the range gpio has no longer its function. +* Instead, the scale can be configured individually for each +* channel from the range registers. +*/ + if (st->chip_info->write_scale_sw) + st->write_scale = st->chip_info->write_scale_sw; + + /* +* In software mode, the oversampling is no longer configured +* with GPIO pins. Instead, the oversampling can be configured +* in configuratiion register. +*/ + if (st->chip_info->write_os_sw) + st->write_os = st->chip_info->write_os_sw; + + ret = st->chip_info->sw_mode_config(indio_dev); + if (ret < 0) + return ret; + } + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); if (!st->trig) diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index 143c30163df9..d8a509c2c428 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -43,6 +43,7 @@ struct ad7606_chip_info { * @range voltage range selection, selects which scale to apply * @oversampling oversampling selection * @base_address address from where to read data in parallel operation + * @sw_mode_en software mode enabled * @scale_availpointer to the array which stores the available scales * @num_scales number of elements stored in the scale_avail array * @oversampling_avail pointer to the array which stores the available @@ -71,6 +72,7 @@ struct ad7606_state { unsigned intrange[16]; unsigned intoversampling; void __iomem*base_address; + boolsw_mode_en; const unsigned int *scale_avail; unsigned intnum_scales; const unsigned int *oversampling_avail; -- 2.17.1 ___ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel