All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] iio: adc: ad7606: Move oversampling and scale options to chip info
@ 2019-05-16 14:32 ` Beniamin Bia
  0 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

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 <beniamin.bia@analog.com>
---
 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);
 
 	if (st->gpio_standby) {
-		gpiod_set_value(st->gpio_range, st->range);
+		gpiod_set_value(st->gpio_range, st->range[0]);
 		gpiod_set_value(st->gpio_standby, 1);
 		ad7606_reset(st);
 	}
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index f9ef52131e74..143c30163df9 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -16,6 +16,12 @@
  *			oversampling ratios.
  * @oversampling_num	number of elements stored in oversampling_avail array
  * @os_req_reset	some devices require a reset to update oversampling
+ * @write_scale_sw	pointer to the function which writes the scale via spi
+			in software mode
+ * @write_os_sw		pointer to the function which writes the os via spi
+			in software mode
+ * @sw_mode_config:	pointer to a function which configured the device
+ *			for software mode
  */
 struct ad7606_chip_info {
 	const struct iio_chan_spec	*channels;
@@ -23,6 +29,9 @@ struct ad7606_chip_info {
 	const unsigned int		*oversampling_avail;
 	unsigned int			oversampling_num;
 	bool				os_req_reset;
+	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);
 };
 
 /**
@@ -39,6 +48,8 @@ struct ad7606_chip_info {
  * @oversampling_avail	pointer to the array which stores the available
  *			oversampling ratios.
  * @num_os_ratios	number of elements stored in oversampling_avail array
+ * @write_scale		pointer to the function which writes the scale
+ * @write_os		pointer to the function which writes the os
  * @lock		protect sensor state from concurrent accesses to GPIOs
  * @gpio_convst	GPIO descriptor for conversion start signal (CONVST)
  * @gpio_reset		GPIO descriptor for device hard-reset
@@ -57,13 +68,15 @@ struct ad7606_state {
 	const struct ad7606_chip_info	*chip_info;
 	struct regulator		*reg;
 	const struct ad7606_bus_ops	*bops;
-	unsigned int			range;
+	unsigned int			range[16];
 	unsigned int			oversampling;
 	void __iomem			*base_address;
 	const unsigned int		*scale_avail;
 	unsigned int			num_scales;
 	const unsigned int		*oversampling_avail;
 	unsigned int			num_os_ratios;
+	int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
+	int (*write_os)(struct iio_dev *indio_dev, int val);
 
 	struct mutex			lock; /* protect sensor state */
 	struct gpio_desc		*gpio_convst;
-- 
2.17.1


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

* [PATCH 1/5] iio: adc: ad7606: Move oversampling and scale options to chip info
@ 2019-05-16 14:32 ` Beniamin Bia
  0 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

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 <beniamin.bia@analog.com>
---
 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);
 
 	if (st->gpio_standby) {
-		gpiod_set_value(st->gpio_range, st->range);
+		gpiod_set_value(st->gpio_range, st->range[0]);
 		gpiod_set_value(st->gpio_standby, 1);
 		ad7606_reset(st);
 	}
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index f9ef52131e74..143c30163df9 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -16,6 +16,12 @@
  *			oversampling ratios.
  * @oversampling_num	number of elements stored in oversampling_avail array
  * @os_req_reset	some devices require a reset to update oversampling
+ * @write_scale_sw	pointer to the function which writes the scale via spi
+			in software mode
+ * @write_os_sw		pointer to the function which writes the os via spi
+			in software mode
+ * @sw_mode_config:	pointer to a function which configured the device
+ *			for software mode
  */
 struct ad7606_chip_info {
 	const struct iio_chan_spec	*channels;
@@ -23,6 +29,9 @@ struct ad7606_chip_info {
 	const unsigned int		*oversampling_avail;
 	unsigned int			oversampling_num;
 	bool				os_req_reset;
+	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);
 };
 
 /**
@@ -39,6 +48,8 @@ struct ad7606_chip_info {
  * @oversampling_avail	pointer to the array which stores the available
  *			oversampling ratios.
  * @num_os_ratios	number of elements stored in oversampling_avail array
+ * @write_scale		pointer to the function which writes the scale
+ * @write_os		pointer to the function which writes the os
  * @lock		protect sensor state from concurrent accesses to GPIOs
  * @gpio_convst	GPIO descriptor for conversion start signal (CONVST)
  * @gpio_reset		GPIO descriptor for device hard-reset
@@ -57,13 +68,15 @@ struct ad7606_state {
 	const struct ad7606_chip_info	*chip_info;
 	struct regulator		*reg;
 	const struct ad7606_bus_ops	*bops;
-	unsigned int			range;
+	unsigned int			range[16];
 	unsigned int			oversampling;
 	void __iomem			*base_address;
 	const unsigned int		*scale_avail;
 	unsigned int			num_scales;
 	const unsigned int		*oversampling_avail;
 	unsigned int			num_os_ratios;
+	int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
+	int (*write_os)(struct iio_dev *indio_dev, int val);
 
 	struct mutex			lock; /* protect sensor state */
 	struct gpio_desc		*gpio_convst;
-- 
2.17.1

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

* [PATCH 2/5] iio: adc: ad7606: Add software configuration
  2019-05-16 14:32 ` Beniamin Bia
@ 2019-05-16 14:32   ` Beniamin Bia
  -1 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

Because this driver will support multiple configurations for software,
the software configuration was made generic.

Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
---
 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_avail		pointer 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 int			range[16];
 	unsigned int			oversampling;
 	void __iomem			*base_address;
+	bool				sw_mode_en;
 	const unsigned int		*scale_avail;
 	unsigned int			num_scales;
 	const unsigned int		*oversampling_avail;
-- 
2.17.1


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

* [PATCH 2/5] iio: adc: ad7606: Add software configuration
@ 2019-05-16 14:32   ` Beniamin Bia
  0 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

Because this driver will support multiple configurations for software,
the software configuration was made generic.

Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
---
 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_avail		pointer 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 int			range[16];
 	unsigned int			oversampling;
 	void __iomem			*base_address;
+	bool				sw_mode_en;
 	const unsigned int		*scale_avail;
 	unsigned int			num_scales;
 	const unsigned int		*oversampling_avail;
-- 
2.17.1

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

* [PATCH 3/5] iio: adc: ad7606: Make SPI register calculation generic and add spi support
  2019-05-16 14:32 ` Beniamin Bia
@ 2019-05-16 14:32   ` Beniamin Bia
  -1 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

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 <beniamin.bia@analog.com>
---
 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 <linux/iio/triggered_buffer.h>
 #include <linux/iio/trigger_consumer.h>
 
+#include <linux/spi/spi.h>
+
 #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_sw		pointer to the function which writes the os via spi
@@ -29,6 +30,7 @@ struct ad7606_chip_info {
 	const unsigned int		*oversampling_avail;
 	unsigned int			oversampling_num;
 	bool				os_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


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

* [PATCH 3/5] iio: adc: ad7606: Make SPI register calculation generic and add spi support
@ 2019-05-16 14:32   ` Beniamin Bia
  0 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

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 <beniamin.bia@analog.com>
---
 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 <linux/iio/triggered_buffer.h>
 #include <linux/iio/trigger_consumer.h>
 
+#include <linux/spi/spi.h>
+
 #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_sw		pointer to the function which writes the os via spi
@@ -29,6 +30,7 @@ struct ad7606_chip_info {
 	const unsigned int		*oversampling_avail;
 	unsigned int			oversampling_num;
 	bool				os_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

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

* [PATCH 4/5] iio: adc: ad7606: Add support for software mode for ad7616
  2019-05-16 14:32 ` Beniamin Bia
@ 2019-05-16 14:32   ` Beniamin Bia
  -1 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

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 <beniamin.bia@analog.com>
---
 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 10000/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_CHANNEL(15),
 };
 
+static const struct iio_chan_spec ad7616_sw_channels[] = {
+	IIO_CHAN_SOFT_TIMESTAMP(16),
+	AD7616_CHANNEL(0),
+	AD7616_CHANNEL(1),
+	AD7616_CHANNEL(2),
+	AD7616_CHANNEL(3),
+	AD7616_CHANNEL(4),
+	AD7616_CHANNEL(5),
+	AD7616_CHANNEL(6),
+	AD7616_CHANNEL(7),
+	AD7616_CHANNEL(8),
+	AD7616_CHANNEL(9),
+	AD7616_CHANNEL(10),
+	AD7616_CHANNEL(11),
+	AD7616_CHANNEL(12),
+	AD7616_CHANNEL(13),
+	AD7616_CHANNEL(14),
+	AD7616_CHANNEL(15),
+};
+
 static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
 	/* More devices added in future */
 	[ID_AD7605_4] = {
@@ -468,9 +534,13 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
 	[ID_AD7616] = {
 		.channels = ad7616_channels,
 		.num_channels = 17,
+		.sw_mode_config = ad7616_sw_mode_config,
 		.oversampling_avail = ad7616_oversampling_avail,
 		.oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
 		.os_req_reset = true,
+		.spi_rd_wr_cmd = ad7616_spi_rd_wr_cmd,
+		.write_scale_sw = ad7616_write_scale_sw,
+		.write_os_sw = ad7616_write_os_sw,
 	},
 };
 
@@ -604,6 +674,23 @@ static void ad7606_regulator_disable(void *data)
 	regulator_disable(st->reg);
 }
 
+static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
+{
+	struct ad7606_state *st = iio_priv(indio_dev);
+
+	/*
+	 * Scale can be configured individually for each channel
+	 * in software mode.
+	 */
+	indio_dev->channels = ad7616_sw_channels;
+
+	/* Activate Burst mode and SEQEN MODE */
+	return ad7606_spi_write_mask(st,
+			      AD7616_CONFIGURATION_REGISTER,
+			      AD7616_BURST_MODE | AD7616_SEQEN_MODE,
+			      AD7616_BURST_MODE | AD7616_SEQEN_MODE);
+}
+
 int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
 		 const char *name, unsigned int id,
 		 const struct ad7606_bus_ops *bops)
@@ -677,6 +764,10 @@ 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");
 
+	/* AD7616 requires al least 15ms to reconfigure after a reset */
+	if (msleep_interruptible(15))
+		return -ERESTARTSYS;
+
 	st->write_scale = ad7606_write_scale_hw;
 	st->write_os = ad7606_write_os_hw;
 
@@ -685,6 +776,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
 							 "adi,sw-mode");
 
 	if (st->sw_mode_en) {
+		/* Scale of 0.076293 is only available in sw mode */
+		st->scale_avail = ad7616_sw_scale_avail;
+		st->num_scales = ARRAY_SIZE(ad7616_sw_scale_avail);
+
 		/* 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;
-- 
2.17.1


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

* [PATCH 4/5] iio: adc: ad7606: Add support for software mode for ad7616
@ 2019-05-16 14:32   ` Beniamin Bia
  0 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

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 <beniamin.bia@analog.com>
---
 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 10000/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_CHANNEL(15),
 };
 
+static const struct iio_chan_spec ad7616_sw_channels[] = {
+	IIO_CHAN_SOFT_TIMESTAMP(16),
+	AD7616_CHANNEL(0),
+	AD7616_CHANNEL(1),
+	AD7616_CHANNEL(2),
+	AD7616_CHANNEL(3),
+	AD7616_CHANNEL(4),
+	AD7616_CHANNEL(5),
+	AD7616_CHANNEL(6),
+	AD7616_CHANNEL(7),
+	AD7616_CHANNEL(8),
+	AD7616_CHANNEL(9),
+	AD7616_CHANNEL(10),
+	AD7616_CHANNEL(11),
+	AD7616_CHANNEL(12),
+	AD7616_CHANNEL(13),
+	AD7616_CHANNEL(14),
+	AD7616_CHANNEL(15),
+};
+
 static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
 	/* More devices added in future */
 	[ID_AD7605_4] = {
@@ -468,9 +534,13 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
 	[ID_AD7616] = {
 		.channels = ad7616_channels,
 		.num_channels = 17,
+		.sw_mode_config = ad7616_sw_mode_config,
 		.oversampling_avail = ad7616_oversampling_avail,
 		.oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
 		.os_req_reset = true,
+		.spi_rd_wr_cmd = ad7616_spi_rd_wr_cmd,
+		.write_scale_sw = ad7616_write_scale_sw,
+		.write_os_sw = ad7616_write_os_sw,
 	},
 };
 
@@ -604,6 +674,23 @@ static void ad7606_regulator_disable(void *data)
 	regulator_disable(st->reg);
 }
 
+static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
+{
+	struct ad7606_state *st = iio_priv(indio_dev);
+
+	/*
+	 * Scale can be configured individually for each channel
+	 * in software mode.
+	 */
+	indio_dev->channels = ad7616_sw_channels;
+
+	/* Activate Burst mode and SEQEN MODE */
+	return ad7606_spi_write_mask(st,
+			      AD7616_CONFIGURATION_REGISTER,
+			      AD7616_BURST_MODE | AD7616_SEQEN_MODE,
+			      AD7616_BURST_MODE | AD7616_SEQEN_MODE);
+}
+
 int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
 		 const char *name, unsigned int id,
 		 const struct ad7606_bus_ops *bops)
@@ -677,6 +764,10 @@ 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");
 
+	/* AD7616 requires al least 15ms to reconfigure after a reset */
+	if (msleep_interruptible(15))
+		return -ERESTARTSYS;
+
 	st->write_scale = ad7606_write_scale_hw;
 	st->write_os = ad7606_write_os_hw;
 
@@ -685,6 +776,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
 							 "adi,sw-mode");
 
 	if (st->sw_mode_en) {
+		/* Scale of 0.076293 is only available in sw mode */
+		st->scale_avail = ad7616_sw_scale_avail;
+		st->num_scales = ARRAY_SIZE(ad7616_sw_scale_avail);
+
 		/* 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;
-- 
2.17.1

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

* [PATCH 5/5] iio: adc: ad7606: Add debug mode for ad7616
  2019-05-16 14:32 ` Beniamin Bia
@ 2019-05-16 14:32   ` Beniamin Bia
  -1 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

Support for register access was added for spi devices.

Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
---
 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


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

* [PATCH 5/5] iio: adc: ad7606: Add debug mode for ad7616
@ 2019-05-16 14:32   ` Beniamin Bia
  0 siblings, 0 replies; 24+ messages in thread
From: Beniamin Bia @ 2019-05-16 14:32 UTC (permalink / raw)
  To: jic23
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin, Beniamin Bia

Support for register access was added for spi devices.

Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
---
 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

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

* Re: [PATCH 1/5] iio: adc: ad7606: Move oversampling and scale options to chip info
  2019-05-16 14:32 ` Beniamin Bia
@ 2019-05-18 10:04   ` Jonathan Cameron
  -1 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:04 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:04 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> 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 <beniamin.bia@analog.com>
Looks good to me.

Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to play with it.

Thanks,

Jonathan

> ---
>  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);
>  
>  	if (st->gpio_standby) {
> -		gpiod_set_value(st->gpio_range, st->range);
> +		gpiod_set_value(st->gpio_range, st->range[0]);
>  		gpiod_set_value(st->gpio_standby, 1);
>  		ad7606_reset(st);
>  	}
> diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
> index f9ef52131e74..143c30163df9 100644
> --- a/drivers/iio/adc/ad7606.h
> +++ b/drivers/iio/adc/ad7606.h
> @@ -16,6 +16,12 @@
>   *			oversampling ratios.
>   * @oversampling_num	number of elements stored in oversampling_avail array
>   * @os_req_reset	some devices require a reset to update oversampling
> + * @write_scale_sw	pointer to the function which writes the scale via spi
> +			in software mode
> + * @write_os_sw		pointer to the function which writes the os via spi
> +			in software mode
> + * @sw_mode_config:	pointer to a function which configured the device
> + *			for software mode
>   */
>  struct ad7606_chip_info {
>  	const struct iio_chan_spec	*channels;
> @@ -23,6 +29,9 @@ struct ad7606_chip_info {
>  	const unsigned int		*oversampling_avail;
>  	unsigned int			oversampling_num;
>  	bool				os_req_reset;
> +	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);
>  };
>  
>  /**
> @@ -39,6 +48,8 @@ struct ad7606_chip_info {
>   * @oversampling_avail	pointer to the array which stores the available
>   *			oversampling ratios.
>   * @num_os_ratios	number of elements stored in oversampling_avail array
> + * @write_scale		pointer to the function which writes the scale
> + * @write_os		pointer to the function which writes the os
>   * @lock		protect sensor state from concurrent accesses to GPIOs
>   * @gpio_convst	GPIO descriptor for conversion start signal (CONVST)
>   * @gpio_reset		GPIO descriptor for device hard-reset
> @@ -57,13 +68,15 @@ struct ad7606_state {
>  	const struct ad7606_chip_info	*chip_info;
>  	struct regulator		*reg;
>  	const struct ad7606_bus_ops	*bops;
> -	unsigned int			range;
> +	unsigned int			range[16];
>  	unsigned int			oversampling;
>  	void __iomem			*base_address;
>  	const unsigned int		*scale_avail;
>  	unsigned int			num_scales;
>  	const unsigned int		*oversampling_avail;
>  	unsigned int			num_os_ratios;
> +	int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
> +	int (*write_os)(struct iio_dev *indio_dev, int val);
>  
>  	struct mutex			lock; /* protect sensor state */
>  	struct gpio_desc		*gpio_convst;


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

* Re: [PATCH 1/5] iio: adc: ad7606: Move oversampling and scale options to chip info
@ 2019-05-18 10:04   ` Jonathan Cameron
  0 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:04 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:04 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> 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 <beniamin.bia@analog.com>
Looks good to me.

Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to play with it.

Thanks,

Jonathan

> ---
>  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);
>  
>  	if (st->gpio_standby) {
> -		gpiod_set_value(st->gpio_range, st->range);
> +		gpiod_set_value(st->gpio_range, st->range[0]);
>  		gpiod_set_value(st->gpio_standby, 1);
>  		ad7606_reset(st);
>  	}
> diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
> index f9ef52131e74..143c30163df9 100644
> --- a/drivers/iio/adc/ad7606.h
> +++ b/drivers/iio/adc/ad7606.h
> @@ -16,6 +16,12 @@
>   *			oversampling ratios.
>   * @oversampling_num	number of elements stored in oversampling_avail array
>   * @os_req_reset	some devices require a reset to update oversampling
> + * @write_scale_sw	pointer to the function which writes the scale via spi
> +			in software mode
> + * @write_os_sw		pointer to the function which writes the os via spi
> +			in software mode
> + * @sw_mode_config:	pointer to a function which configured the device
> + *			for software mode
>   */
>  struct ad7606_chip_info {
>  	const struct iio_chan_spec	*channels;
> @@ -23,6 +29,9 @@ struct ad7606_chip_info {
>  	const unsigned int		*oversampling_avail;
>  	unsigned int			oversampling_num;
>  	bool				os_req_reset;
> +	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);
>  };
>  
>  /**
> @@ -39,6 +48,8 @@ struct ad7606_chip_info {
>   * @oversampling_avail	pointer to the array which stores the available
>   *			oversampling ratios.
>   * @num_os_ratios	number of elements stored in oversampling_avail array
> + * @write_scale		pointer to the function which writes the scale
> + * @write_os		pointer to the function which writes the os
>   * @lock		protect sensor state from concurrent accesses to GPIOs
>   * @gpio_convst	GPIO descriptor for conversion start signal (CONVST)
>   * @gpio_reset		GPIO descriptor for device hard-reset
> @@ -57,13 +68,15 @@ struct ad7606_state {
>  	const struct ad7606_chip_info	*chip_info;
>  	struct regulator		*reg;
>  	const struct ad7606_bus_ops	*bops;
> -	unsigned int			range;
> +	unsigned int			range[16];
>  	unsigned int			oversampling;
>  	void __iomem			*base_address;
>  	const unsigned int		*scale_avail;
>  	unsigned int			num_scales;
>  	const unsigned int		*oversampling_avail;
>  	unsigned int			num_os_ratios;
> +	int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
> +	int (*write_os)(struct iio_dev *indio_dev, int val);
>  
>  	struct mutex			lock; /* protect sensor state */
>  	struct gpio_desc		*gpio_convst;

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

* Re: [PATCH 2/5] iio: adc: ad7606: Add software configuration
  2019-05-16 14:32   ` Beniamin Bia
@ 2019-05-18 10:07     ` Jonathan Cameron
  -1 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:07 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:05 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> Because this driver will support multiple configurations for software,
> the software configuration was made generic.
> 
> Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to play with it.

Thanks

Jonathan

> ---
>  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_avail		pointer 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 int			range[16];
>  	unsigned int			oversampling;
>  	void __iomem			*base_address;
> +	bool				sw_mode_en;
>  	const unsigned int		*scale_avail;
>  	unsigned int			num_scales;
>  	const unsigned int		*oversampling_avail;


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

* Re: [PATCH 2/5] iio: adc: ad7606: Add software configuration
@ 2019-05-18 10:07     ` Jonathan Cameron
  0 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:07 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:05 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> Because this driver will support multiple configurations for software,
> the software configuration was made generic.
> 
> Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to play with it.

Thanks

Jonathan

> ---
>  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_avail		pointer 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 int			range[16];
>  	unsigned int			oversampling;
>  	void __iomem			*base_address;
> +	bool				sw_mode_en;
>  	const unsigned int		*scale_avail;
>  	unsigned int			num_scales;
>  	const unsigned int		*oversampling_avail;

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

* Re: [PATCH 3/5] iio: adc: ad7606: Make SPI register calculation generic and add spi support
  2019-05-16 14:32   ` Beniamin Bia
@ 2019-05-18 10:20     ` Jonathan Cameron
  -1 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:20 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:06 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> 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 <beniamin.bia@analog.com>
The break up patches has ended up a little odd. This one introduced unused
functions for example. Probably best to merge this and the next patch.

As a potential follow up, could this driver just use a 16 bit word
length and avoid some of the endian handling? (this might also fix
the casting issues).

However, there are some nasty casts in here that sparse is unhappy about.
I would definitely like those cleaned up before we add more of them.

If changing to 16bit SPI words doesn't do the job, then perhaps
we have to have a be16 version of data (as a union to avoid more
space usage).

Thanks,

Jonathan

> ---
>  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 <linux/iio/triggered_buffer.h>
>  #include <linux/iio/trigger_consumer.h>
>  
> +#include <linux/spi/spi.h>
> +
>  #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_sw		pointer to the function which writes the os via spi
> @@ -29,6 +30,7 @@ struct ad7606_chip_info {
>  	const unsigned int		*oversampling_avail;
>  	unsigned int			oversampling_num;
>  	bool				os_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);


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

* Re: [PATCH 3/5] iio: adc: ad7606: Make SPI register calculation generic and add spi support
@ 2019-05-18 10:20     ` Jonathan Cameron
  0 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:20 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:06 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> 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 <beniamin.bia@analog.com>
The break up patches has ended up a little odd. This one introduced unused
functions for example. Probably best to merge this and the next patch.

As a potential follow up, could this driver just use a 16 bit word
length and avoid some of the endian handling? (this might also fix
the casting issues).

However, there are some nasty casts in here that sparse is unhappy about.
I would definitely like those cleaned up before we add more of them.

If changing to 16bit SPI words doesn't do the job, then perhaps
we have to have a be16 version of data (as a union to avoid more
space usage).

Thanks,

Jonathan

> ---
>  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 <linux/iio/triggered_buffer.h>
>  #include <linux/iio/trigger_consumer.h>
>  
> +#include <linux/spi/spi.h>
> +
>  #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_sw		pointer to the function which writes the os via spi
> @@ -29,6 +30,7 @@ struct ad7606_chip_info {
>  	const unsigned int		*oversampling_avail;
>  	unsigned int			oversampling_num;
>  	bool				os_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);

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

* Re: [PATCH 4/5] iio: adc: ad7606: Add support for software mode for ad7616
  2019-05-16 14:32   ` Beniamin Bia
@ 2019-05-18 10:20     ` Jonathan Cameron
  -1 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:20 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:07 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> 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 <beniamin.bia@analog.com>
Looks good subject to comments on the previous.

Thanks,

Jonathan

> ---
>  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 10000/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_CHANNEL(15),
>  };
>  
> +static const struct iio_chan_spec ad7616_sw_channels[] = {
> +	IIO_CHAN_SOFT_TIMESTAMP(16),
> +	AD7616_CHANNEL(0),
> +	AD7616_CHANNEL(1),
> +	AD7616_CHANNEL(2),
> +	AD7616_CHANNEL(3),
> +	AD7616_CHANNEL(4),
> +	AD7616_CHANNEL(5),
> +	AD7616_CHANNEL(6),
> +	AD7616_CHANNEL(7),
> +	AD7616_CHANNEL(8),
> +	AD7616_CHANNEL(9),
> +	AD7616_CHANNEL(10),
> +	AD7616_CHANNEL(11),
> +	AD7616_CHANNEL(12),
> +	AD7616_CHANNEL(13),
> +	AD7616_CHANNEL(14),
> +	AD7616_CHANNEL(15),
> +};
> +
>  static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
>  	/* More devices added in future */
>  	[ID_AD7605_4] = {
> @@ -468,9 +534,13 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
>  	[ID_AD7616] = {
>  		.channels = ad7616_channels,
>  		.num_channels = 17,
> +		.sw_mode_config = ad7616_sw_mode_config,
>  		.oversampling_avail = ad7616_oversampling_avail,
>  		.oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
>  		.os_req_reset = true,
> +		.spi_rd_wr_cmd = ad7616_spi_rd_wr_cmd,
> +		.write_scale_sw = ad7616_write_scale_sw,
> +		.write_os_sw = ad7616_write_os_sw,
>  	},
>  };
>  
> @@ -604,6 +674,23 @@ static void ad7606_regulator_disable(void *data)
>  	regulator_disable(st->reg);
>  }
>  
> +static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
> +{
> +	struct ad7606_state *st = iio_priv(indio_dev);
> +
> +	/*
> +	 * Scale can be configured individually for each channel
> +	 * in software mode.
> +	 */
> +	indio_dev->channels = ad7616_sw_channels;
> +
> +	/* Activate Burst mode and SEQEN MODE */
> +	return ad7606_spi_write_mask(st,
> +			      AD7616_CONFIGURATION_REGISTER,
> +			      AD7616_BURST_MODE | AD7616_SEQEN_MODE,
> +			      AD7616_BURST_MODE | AD7616_SEQEN_MODE);
> +}
> +
>  int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
>  		 const char *name, unsigned int id,
>  		 const struct ad7606_bus_ops *bops)
> @@ -677,6 +764,10 @@ 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");
>  
> +	/* AD7616 requires al least 15ms to reconfigure after a reset */
> +	if (msleep_interruptible(15))
> +		return -ERESTARTSYS;
> +
>  	st->write_scale = ad7606_write_scale_hw;
>  	st->write_os = ad7606_write_os_hw;
>  
> @@ -685,6 +776,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
>  							 "adi,sw-mode");
>  
>  	if (st->sw_mode_en) {
> +		/* Scale of 0.076293 is only available in sw mode */
> +		st->scale_avail = ad7616_sw_scale_avail;
> +		st->num_scales = ARRAY_SIZE(ad7616_sw_scale_avail);
> +
>  		/* 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;


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

* Re: [PATCH 4/5] iio: adc: ad7606: Add support for software mode for ad7616
@ 2019-05-18 10:20     ` Jonathan Cameron
  0 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:20 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:07 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> 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 <beniamin.bia@analog.com>
Looks good subject to comments on the previous.

Thanks,

Jonathan

> ---
>  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 10000/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_CHANNEL(15),
>  };
>  
> +static const struct iio_chan_spec ad7616_sw_channels[] = {
> +	IIO_CHAN_SOFT_TIMESTAMP(16),
> +	AD7616_CHANNEL(0),
> +	AD7616_CHANNEL(1),
> +	AD7616_CHANNEL(2),
> +	AD7616_CHANNEL(3),
> +	AD7616_CHANNEL(4),
> +	AD7616_CHANNEL(5),
> +	AD7616_CHANNEL(6),
> +	AD7616_CHANNEL(7),
> +	AD7616_CHANNEL(8),
> +	AD7616_CHANNEL(9),
> +	AD7616_CHANNEL(10),
> +	AD7616_CHANNEL(11),
> +	AD7616_CHANNEL(12),
> +	AD7616_CHANNEL(13),
> +	AD7616_CHANNEL(14),
> +	AD7616_CHANNEL(15),
> +};
> +
>  static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
>  	/* More devices added in future */
>  	[ID_AD7605_4] = {
> @@ -468,9 +534,13 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
>  	[ID_AD7616] = {
>  		.channels = ad7616_channels,
>  		.num_channels = 17,
> +		.sw_mode_config = ad7616_sw_mode_config,
>  		.oversampling_avail = ad7616_oversampling_avail,
>  		.oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
>  		.os_req_reset = true,
> +		.spi_rd_wr_cmd = ad7616_spi_rd_wr_cmd,
> +		.write_scale_sw = ad7616_write_scale_sw,
> +		.write_os_sw = ad7616_write_os_sw,
>  	},
>  };
>  
> @@ -604,6 +674,23 @@ static void ad7606_regulator_disable(void *data)
>  	regulator_disable(st->reg);
>  }
>  
> +static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
> +{
> +	struct ad7606_state *st = iio_priv(indio_dev);
> +
> +	/*
> +	 * Scale can be configured individually for each channel
> +	 * in software mode.
> +	 */
> +	indio_dev->channels = ad7616_sw_channels;
> +
> +	/* Activate Burst mode and SEQEN MODE */
> +	return ad7606_spi_write_mask(st,
> +			      AD7616_CONFIGURATION_REGISTER,
> +			      AD7616_BURST_MODE | AD7616_SEQEN_MODE,
> +			      AD7616_BURST_MODE | AD7616_SEQEN_MODE);
> +}
> +
>  int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
>  		 const char *name, unsigned int id,
>  		 const struct ad7606_bus_ops *bops)
> @@ -677,6 +764,10 @@ 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");
>  
> +	/* AD7616 requires al least 15ms to reconfigure after a reset */
> +	if (msleep_interruptible(15))
> +		return -ERESTARTSYS;
> +
>  	st->write_scale = ad7606_write_scale_hw;
>  	st->write_os = ad7606_write_os_hw;
>  
> @@ -685,6 +776,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
>  							 "adi,sw-mode");
>  
>  	if (st->sw_mode_en) {
> +		/* Scale of 0.076293 is only available in sw mode */
> +		st->scale_avail = ad7616_sw_scale_avail;
> +		st->num_scales = ARRAY_SIZE(ad7616_sw_scale_avail);
> +
>  		/* 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;

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

* Re: [PATCH 1/5] iio: adc: ad7606: Move oversampling and scale options to chip info
  2019-05-18 10:04   ` Jonathan Cameron
@ 2019-05-18 10:22     ` Jonathan Cameron
  -1 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:22 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Sat, 18 May 2019 11:04:49 +0100
Jonathan Cameron <jic23@kernel.org> wrote:

> On Thu, 16 May 2019 17:32:04 +0300
> Beniamin Bia <beniamin.bia@analog.com> wrote:
> 
> > 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 <beniamin.bia@analog.com>  
> Looks good to me.
> 
> Applied to the togreg branch of iio.git and pushed out as testing for
> the autobuilders to play with it.

Actually, as this only makes sense with the later patches, I'm going
to back this out until those are ready.

For reference though add
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
to v2. Thanks

Jonathan

> 
> Thanks,
> 
> Jonathan
> 
> > ---
> >  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);
> >  
> >  	if (st->gpio_standby) {
> > -		gpiod_set_value(st->gpio_range, st->range);
> > +		gpiod_set_value(st->gpio_range, st->range[0]);
> >  		gpiod_set_value(st->gpio_standby, 1);
> >  		ad7606_reset(st);
> >  	}
> > diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
> > index f9ef52131e74..143c30163df9 100644
> > --- a/drivers/iio/adc/ad7606.h
> > +++ b/drivers/iio/adc/ad7606.h
> > @@ -16,6 +16,12 @@
> >   *			oversampling ratios.
> >   * @oversampling_num	number of elements stored in oversampling_avail array
> >   * @os_req_reset	some devices require a reset to update oversampling
> > + * @write_scale_sw	pointer to the function which writes the scale via spi
> > +			in software mode
> > + * @write_os_sw		pointer to the function which writes the os via spi
> > +			in software mode
> > + * @sw_mode_config:	pointer to a function which configured the device
> > + *			for software mode
> >   */
> >  struct ad7606_chip_info {
> >  	const struct iio_chan_spec	*channels;
> > @@ -23,6 +29,9 @@ struct ad7606_chip_info {
> >  	const unsigned int		*oversampling_avail;
> >  	unsigned int			oversampling_num;
> >  	bool				os_req_reset;
> > +	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);
> >  };
> >  
> >  /**
> > @@ -39,6 +48,8 @@ struct ad7606_chip_info {
> >   * @oversampling_avail	pointer to the array which stores the available
> >   *			oversampling ratios.
> >   * @num_os_ratios	number of elements stored in oversampling_avail array
> > + * @write_scale		pointer to the function which writes the scale
> > + * @write_os		pointer to the function which writes the os
> >   * @lock		protect sensor state from concurrent accesses to GPIOs
> >   * @gpio_convst	GPIO descriptor for conversion start signal (CONVST)
> >   * @gpio_reset		GPIO descriptor for device hard-reset
> > @@ -57,13 +68,15 @@ struct ad7606_state {
> >  	const struct ad7606_chip_info	*chip_info;
> >  	struct regulator		*reg;
> >  	const struct ad7606_bus_ops	*bops;
> > -	unsigned int			range;
> > +	unsigned int			range[16];
> >  	unsigned int			oversampling;
> >  	void __iomem			*base_address;
> >  	const unsigned int		*scale_avail;
> >  	unsigned int			num_scales;
> >  	const unsigned int		*oversampling_avail;
> >  	unsigned int			num_os_ratios;
> > +	int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
> > +	int (*write_os)(struct iio_dev *indio_dev, int val);
> >  
> >  	struct mutex			lock; /* protect sensor state */
> >  	struct gpio_desc		*gpio_convst;  
> 


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

* Re: [PATCH 1/5] iio: adc: ad7606: Move oversampling and scale options to chip info
@ 2019-05-18 10:22     ` Jonathan Cameron
  0 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:22 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Sat, 18 May 2019 11:04:49 +0100
Jonathan Cameron <jic23@kernel.org> wrote:

> On Thu, 16 May 2019 17:32:04 +0300
> Beniamin Bia <beniamin.bia@analog.com> wrote:
> 
> > 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 <beniamin.bia@analog.com>  
> Looks good to me.
> 
> Applied to the togreg branch of iio.git and pushed out as testing for
> the autobuilders to play with it.

Actually, as this only makes sense with the later patches, I'm going
to back this out until those are ready.

For reference though add
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
to v2. Thanks

Jonathan

> 
> Thanks,
> 
> Jonathan
> 
> > ---
> >  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);
> >  
> >  	if (st->gpio_standby) {
> > -		gpiod_set_value(st->gpio_range, st->range);
> > +		gpiod_set_value(st->gpio_range, st->range[0]);
> >  		gpiod_set_value(st->gpio_standby, 1);
> >  		ad7606_reset(st);
> >  	}
> > diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
> > index f9ef52131e74..143c30163df9 100644
> > --- a/drivers/iio/adc/ad7606.h
> > +++ b/drivers/iio/adc/ad7606.h
> > @@ -16,6 +16,12 @@
> >   *			oversampling ratios.
> >   * @oversampling_num	number of elements stored in oversampling_avail array
> >   * @os_req_reset	some devices require a reset to update oversampling
> > + * @write_scale_sw	pointer to the function which writes the scale via spi
> > +			in software mode
> > + * @write_os_sw		pointer to the function which writes the os via spi
> > +			in software mode
> > + * @sw_mode_config:	pointer to a function which configured the device
> > + *			for software mode
> >   */
> >  struct ad7606_chip_info {
> >  	const struct iio_chan_spec	*channels;
> > @@ -23,6 +29,9 @@ struct ad7606_chip_info {
> >  	const unsigned int		*oversampling_avail;
> >  	unsigned int			oversampling_num;
> >  	bool				os_req_reset;
> > +	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);
> >  };
> >  
> >  /**
> > @@ -39,6 +48,8 @@ struct ad7606_chip_info {
> >   * @oversampling_avail	pointer to the array which stores the available
> >   *			oversampling ratios.
> >   * @num_os_ratios	number of elements stored in oversampling_avail array
> > + * @write_scale		pointer to the function which writes the scale
> > + * @write_os		pointer to the function which writes the os
> >   * @lock		protect sensor state from concurrent accesses to GPIOs
> >   * @gpio_convst	GPIO descriptor for conversion start signal (CONVST)
> >   * @gpio_reset		GPIO descriptor for device hard-reset
> > @@ -57,13 +68,15 @@ struct ad7606_state {
> >  	const struct ad7606_chip_info	*chip_info;
> >  	struct regulator		*reg;
> >  	const struct ad7606_bus_ops	*bops;
> > -	unsigned int			range;
> > +	unsigned int			range[16];
> >  	unsigned int			oversampling;
> >  	void __iomem			*base_address;
> >  	const unsigned int		*scale_avail;
> >  	unsigned int			num_scales;
> >  	const unsigned int		*oversampling_avail;
> >  	unsigned int			num_os_ratios;
> > +	int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
> > +	int (*write_os)(struct iio_dev *indio_dev, int val);
> >  
> >  	struct mutex			lock; /* protect sensor state */
> >  	struct gpio_desc		*gpio_convst;  
> 

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

* Re: [PATCH 2/5] iio: adc: ad7606: Add software configuration
  2019-05-18 10:07     ` Jonathan Cameron
@ 2019-05-18 10:23       ` Jonathan Cameron
  -1 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:23 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Sat, 18 May 2019 11:07:49 +0100
Jonathan Cameron <jic23@kernel.org> wrote:

> On Thu, 16 May 2019 17:32:05 +0300
> Beniamin Bia <beniamin.bia@analog.com> wrote:
> 
> > Because this driver will support multiple configurations for software,
> > the software configuration was made generic.
> > 
> > Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>  
> Applied to the togreg branch of iio.git and pushed out as testing for
> the autobuilders to play with it.
As with patch 1, I've backed this out for now as it doesn't make sense
with the later.  For reference please add.

Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

Thanks,

Jonathan

> 
> Thanks
> 
> Jonathan
> 
> > ---
> >  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_avail		pointer 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 int			range[16];
> >  	unsigned int			oversampling;
> >  	void __iomem			*base_address;
> > +	bool				sw_mode_en;
> >  	const unsigned int		*scale_avail;
> >  	unsigned int			num_scales;
> >  	const unsigned int		*oversampling_avail;  
> 


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

* Re: [PATCH 2/5] iio: adc: ad7606: Add software configuration
@ 2019-05-18 10:23       ` Jonathan Cameron
  0 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:23 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Sat, 18 May 2019 11:07:49 +0100
Jonathan Cameron <jic23@kernel.org> wrote:

> On Thu, 16 May 2019 17:32:05 +0300
> Beniamin Bia <beniamin.bia@analog.com> wrote:
> 
> > Because this driver will support multiple configurations for software,
> > the software configuration was made generic.
> > 
> > Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>  
> Applied to the togreg branch of iio.git and pushed out as testing for
> the autobuilders to play with it.
As with patch 1, I've backed this out for now as it doesn't make sense
with the later.  For reference please add.

Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

Thanks,

Jonathan

> 
> Thanks
> 
> Jonathan
> 
> > ---
> >  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_avail		pointer 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 int			range[16];
> >  	unsigned int			oversampling;
> >  	void __iomem			*base_address;
> > +	bool				sw_mode_en;
> >  	const unsigned int		*scale_avail;
> >  	unsigned int			num_scales;
> >  	const unsigned int		*oversampling_avail;  
> 

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

* Re: [PATCH 5/5] iio: adc: ad7606: Add debug mode for ad7616
  2019-05-16 14:32   ` Beniamin Bia
@ 2019-05-18 10:24     ` Jonathan Cameron
  -1 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:24 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:08 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> Support for register access was added for spi devices.
> 
> Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
Looks fine.  For my reference please add
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  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,
>  };


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

* Re: [PATCH 5/5] iio: adc: ad7606: Add debug mode for ad7616
@ 2019-05-18 10:24     ` Jonathan Cameron
  0 siblings, 0 replies; 24+ messages in thread
From: Jonathan Cameron @ 2019-05-18 10:24 UTC (permalink / raw)
  To: Beniamin Bia
  Cc: lars, Michael.Hennerich, knaack.h, pmeerw, gregkh, linux-iio,
	devel, linux-kernel, mark.rutland, robh+dt, devicetree,
	biabeniamin

On Thu, 16 May 2019 17:32:08 +0300
Beniamin Bia <beniamin.bia@analog.com> wrote:

> Support for register access was added for spi devices.
> 
> Signed-off-by: Beniamin Bia <beniamin.bia@analog.com>
Looks fine.  For my reference please add
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  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,
>  };

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

end of thread, other threads:[~2019-05-18 10:24 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-16 14:32 [PATCH 1/5] iio: adc: ad7606: Move oversampling and scale options to chip info Beniamin Bia
2019-05-16 14:32 ` Beniamin Bia
2019-05-16 14:32 ` [PATCH 2/5] iio: adc: ad7606: Add software configuration Beniamin Bia
2019-05-16 14:32   ` Beniamin Bia
2019-05-18 10:07   ` Jonathan Cameron
2019-05-18 10:07     ` Jonathan Cameron
2019-05-18 10:23     ` Jonathan Cameron
2019-05-18 10:23       ` Jonathan Cameron
2019-05-16 14:32 ` [PATCH 3/5] iio: adc: ad7606: Make SPI register calculation generic and add spi support Beniamin Bia
2019-05-16 14:32   ` Beniamin Bia
2019-05-18 10:20   ` Jonathan Cameron
2019-05-18 10:20     ` Jonathan Cameron
2019-05-16 14:32 ` [PATCH 4/5] iio: adc: ad7606: Add support for software mode for ad7616 Beniamin Bia
2019-05-16 14:32   ` Beniamin Bia
2019-05-18 10:20   ` Jonathan Cameron
2019-05-18 10:20     ` Jonathan Cameron
2019-05-16 14:32 ` [PATCH 5/5] iio: adc: ad7606: Add debug " Beniamin Bia
2019-05-16 14:32   ` Beniamin Bia
2019-05-18 10:24   ` Jonathan Cameron
2019-05-18 10:24     ` Jonathan Cameron
2019-05-18 10:04 ` [PATCH 1/5] iio: adc: ad7606: Move oversampling and scale options to chip info Jonathan Cameron
2019-05-18 10:04   ` Jonathan Cameron
2019-05-18 10:22   ` Jonathan Cameron
2019-05-18 10:22     ` Jonathan Cameron

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.