* [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document
@ 2019-11-11 21:40 Uwe Kleine-König
2019-11-11 21:40 ` [PATCH 2/3] iio: adc: ltc2497: split channel definition in a separate module Uwe Kleine-König
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Uwe Kleine-König @ 2019-11-11 21:40 UTC (permalink / raw)
To: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
Michael Hennerich, Stefan Popa
Cc: kernel, linux-iio, devicetree
The ADC only requires the standard stuff for spi devices and a reference
voltage.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
.../devicetree/bindings/iio/adc/ltc2496.txt | 15 +++++++++++++++
1 file changed, 15 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/adc/ltc2496.txt
diff --git a/Documentation/devicetree/bindings/iio/adc/ltc2496.txt b/Documentation/devicetree/bindings/iio/adc/ltc2496.txt
new file mode 100644
index 000000000000..d44ab45b26ea
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ltc2496.txt
@@ -0,0 +1,15 @@
+* Linear Technology / Analog Devices LTC2496 ADC
+
+Required properties:
+ - compatible: Must be "lltc,ltc2496"
+ - vref-supply: The regulator supply for ADC reference voltage
+ - further properties required for spi device nodes according to
+ Documentation/devicetree/bindings/spi/spi-controller.yaml
+
+Example:
+ ltc2497: adc@76 {
+ compatible = "lltc,ltc2496";
+ reg = <0>;
+ vref-supply = <<c249x_reg>;
+ spi-max-frequency = <2000000>;
+ };
--
2.24.0.rc1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/3] iio: adc: ltc2497: split channel definition in a separate module
2019-11-11 21:40 [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document Uwe Kleine-König
@ 2019-11-11 21:40 ` Uwe Kleine-König
2019-11-12 7:14 ` Ardelean, Alexandru
2019-11-11 21:40 ` [PATCH 3/3] iio: adc: new driver to support Linear technology's ltc2496 Uwe Kleine-König
2019-11-12 6:57 ` [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document Ardelean, Alexandru
2 siblings, 1 reply; 9+ messages in thread
From: Uwe Kleine-König @ 2019-11-11 21:40 UTC (permalink / raw)
To: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
Michael Hennerich, Stefan Popa
Cc: kernel, linux-iio, devicetree
This allows to share the data for the ltc2496 driver added in
the next commit that is an SPI variant of the ltc2497.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
drivers/iio/adc/Makefile | 2 +-
drivers/iio/adc/ltc2497.c | 81 +++++----------------------------------
drivers/iio/adc/ltc249x.c | 72 ++++++++++++++++++++++++++++++++++
drivers/iio/adc/ltc249x.h | 10 +++++
4 files changed, 93 insertions(+), 72 deletions(-)
create mode 100644 drivers/iio/adc/ltc249x.c
create mode 100644 drivers/iio/adc/ltc249x.h
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index ef9cc485fb67..660242c2cca7 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -47,7 +47,7 @@ obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
obj-$(CONFIG_LTC2471) += ltc2471.o
obj-$(CONFIG_LTC2485) += ltc2485.o
-obj-$(CONFIG_LTC2497) += ltc2497.o
+obj-$(CONFIG_LTC2497) += ltc2497.o ltc249x.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1118) += max1118.o
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index 470406032720..e86fe42f1598 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -16,12 +16,7 @@
#include <linux/of.h>
#include <linux/regulator/consumer.h>
-#define LTC2497_ENABLE 0xA0
-#define LTC2497_SGL BIT(4)
-#define LTC2497_DIFF 0
-#define LTC2497_SIGN BIT(3)
-#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE
-#define LTC2497_CONVERSION_TIME_MS 150ULL
+#include "ltc249x.h"
struct ltc2497_st {
struct i2c_client *client;
@@ -41,18 +36,18 @@ static int ltc2497_wait_conv(struct ltc2497_st *st)
time_elapsed = ktime_ms_delta(ktime_get(), st->time_prev);
- if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {
+ if (time_elapsed < LTC249X_CONVERSION_TIME_MS) {
/* delay if conversion time not passed
* since last read or write
*/
if (msleep_interruptible(
- LTC2497_CONVERSION_TIME_MS - time_elapsed))
+ LTC249X_CONVERSION_TIME_MS - time_elapsed))
return -ERESTARTSYS;
return 0;
}
- if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {
+ if (time_elapsed - LTC249X_CONVERSION_TIME_MS <= 0) {
/* We're in automatic mode -
* so the last reading is stil not outdated
*/
@@ -73,11 +68,11 @@ static int ltc2497_read(struct ltc2497_st *st, u8 address, int *val)
if (ret || st->addr_prev != address) {
ret = i2c_smbus_write_byte(st->client,
- LTC2497_ENABLE | address);
+ LTC249X_ENABLE | address);
if (ret < 0)
return ret;
st->addr_prev = address;
- if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))
+ if (msleep_interruptible(LTC249X_CONVERSION_TIME_MS))
return -ERESTARTSYS;
}
ret = i2c_master_recv(client, (char *)&st->buf, 3);
@@ -127,62 +122,6 @@ static int ltc2497_read_raw(struct iio_dev *indio_dev,
}
}
-#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .channel = (_chan), \
- .address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .datasheet_name = (_ds_name), \
-}
-
-#define LTC2497_CHAN_DIFF(_chan, _addr) { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \
- .channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\
- .address = (_addr | _chan), \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .differential = 1, \
-}
-
-static const struct iio_chan_spec ltc2497_channel[] = {
- LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
- LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
- LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
- LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
- LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
- LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
- LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
- LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
- LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
- LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
- LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
- LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
- LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
- LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
- LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
- LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
- LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(3, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(4, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(5, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(6, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(7, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),
-};
-
static const struct iio_info ltc2497_info = {
.read_raw = ltc2497_read_raw,
};
@@ -211,8 +150,8 @@ static int ltc2497_probe(struct i2c_client *client,
indio_dev->name = id->name;
indio_dev->info = <c2497_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = ltc2497_channel;
- indio_dev->num_channels = ARRAY_SIZE(ltc2497_channel);
+ indio_dev->channels = ltc249x_channel;
+ indio_dev->num_channels = ltc249x_num_channels;
st->ref = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(st->ref))
@@ -231,11 +170,11 @@ static int ltc2497_probe(struct i2c_client *client,
}
}
- ret = i2c_smbus_write_byte(st->client, LTC2497_CONFIG_DEFAULT);
+ ret = i2c_smbus_write_byte(st->client, LTC249X_CONFIG_DEFAULT);
if (ret < 0)
goto err_array_unregister;
- st->addr_prev = LTC2497_CONFIG_DEFAULT;
+ st->addr_prev = LTC249X_CONFIG_DEFAULT;
st->time_prev = ktime_get();
ret = iio_device_register(indio_dev);
diff --git a/drivers/iio/adc/ltc249x.c b/drivers/iio/adc/ltc249x.c
new file mode 100644
index 000000000000..571fce7cc808
--- /dev/null
+++ b/drivers/iio/adc/ltc249x.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/module.h>
+
+#define LTC249X_SGL BIT(4)
+#define LTC249X_DIFF 0
+#define LTC249X_SIGN BIT(3)
+
+#define LTC249X_CHAN(_chan, _addr, _ds_name) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_chan), \
+ .address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC249X_SIGN : 0)), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = (_ds_name), \
+}
+
+#define LTC249X_CHAN_DIFF(_chan, _addr) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_chan) * 2 + ((_addr) & LTC249X_SIGN ? 1 : 0), \
+ .channel2 = (_chan) * 2 + ((_addr) & LTC249X_SIGN ? 0 : 1),\
+ .address = (_addr | _chan), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .differential = 1, \
+}
+
+const struct iio_chan_spec ltc249x_channel[] = {
+ LTC249X_CHAN(0, LTC249X_SGL, "CH0"),
+ LTC249X_CHAN(1, LTC249X_SGL, "CH1"),
+ LTC249X_CHAN(2, LTC249X_SGL, "CH2"),
+ LTC249X_CHAN(3, LTC249X_SGL, "CH3"),
+ LTC249X_CHAN(4, LTC249X_SGL, "CH4"),
+ LTC249X_CHAN(5, LTC249X_SGL, "CH5"),
+ LTC249X_CHAN(6, LTC249X_SGL, "CH6"),
+ LTC249X_CHAN(7, LTC249X_SGL, "CH7"),
+ LTC249X_CHAN(8, LTC249X_SGL, "CH8"),
+ LTC249X_CHAN(9, LTC249X_SGL, "CH9"),
+ LTC249X_CHAN(10, LTC249X_SGL, "CH10"),
+ LTC249X_CHAN(11, LTC249X_SGL, "CH11"),
+ LTC249X_CHAN(12, LTC249X_SGL, "CH12"),
+ LTC249X_CHAN(13, LTC249X_SGL, "CH13"),
+ LTC249X_CHAN(14, LTC249X_SGL, "CH14"),
+ LTC249X_CHAN(15, LTC249X_SGL, "CH15"),
+ LTC249X_CHAN_DIFF(0, LTC249X_DIFF),
+ LTC249X_CHAN_DIFF(1, LTC249X_DIFF),
+ LTC249X_CHAN_DIFF(2, LTC249X_DIFF),
+ LTC249X_CHAN_DIFF(3, LTC249X_DIFF),
+ LTC249X_CHAN_DIFF(4, LTC249X_DIFF),
+ LTC249X_CHAN_DIFF(5, LTC249X_DIFF),
+ LTC249X_CHAN_DIFF(6, LTC249X_DIFF),
+ LTC249X_CHAN_DIFF(7, LTC249X_DIFF),
+ LTC249X_CHAN_DIFF(0, LTC249X_DIFF | LTC249X_SIGN),
+ LTC249X_CHAN_DIFF(1, LTC249X_DIFF | LTC249X_SIGN),
+ LTC249X_CHAN_DIFF(2, LTC249X_DIFF | LTC249X_SIGN),
+ LTC249X_CHAN_DIFF(3, LTC249X_DIFF | LTC249X_SIGN),
+ LTC249X_CHAN_DIFF(4, LTC249X_DIFF | LTC249X_SIGN),
+ LTC249X_CHAN_DIFF(5, LTC249X_DIFF | LTC249X_SIGN),
+ LTC249X_CHAN_DIFF(6, LTC249X_DIFF | LTC249X_SIGN),
+ LTC249X_CHAN_DIFF(7, LTC249X_DIFF | LTC249X_SIGN),
+};
+EXPORT_SYMBOL_NS_GPL(ltc249x_channel, LTC249X);
+
+const int ltc249x_num_channels = ARRAY_SIZE(ltc249x_channel);
+EXPORT_SYMBOL_NS_GPL(ltc249x_num_channels, LTC249X);
+
+MODULE_DESCRIPTION("common code for LTC2496/LTC2497 drivers");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ltc249x.h b/drivers/iio/adc/ltc249x.h
new file mode 100644
index 000000000000..dac8b5ed0ecf
--- /dev/null
+++ b/drivers/iio/adc/ltc249x.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#define LTC249X_ENABLE 0xA0
+#define LTC249X_CONFIG_DEFAULT LTC249X_ENABLE
+#define LTC249X_CONVERSION_TIME_MS 150ULL
+
+extern const struct iio_chan_spec ltc249x_channel[];
+extern const int ltc249x_num_channels;
+
+MODULE_IMPORT_NS(LTC249X);
--
2.24.0.rc1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/3] iio: adc: new driver to support Linear technology's ltc2496
2019-11-11 21:40 [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document Uwe Kleine-König
2019-11-11 21:40 ` [PATCH 2/3] iio: adc: ltc2497: split channel definition in a separate module Uwe Kleine-König
@ 2019-11-11 21:40 ` Uwe Kleine-König
2019-11-12 7:54 ` Ardelean, Alexandru
2019-11-12 6:57 ` [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document Ardelean, Alexandru
2 siblings, 1 reply; 9+ messages in thread
From: Uwe Kleine-König @ 2019-11-11 21:40 UTC (permalink / raw)
To: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
Michael Hennerich, Stefan Popa
Cc: kernel, linux-iio, devicetree
This chip is similar to the LTC2497 ADC, it just uses SPI instead of I2C
and so has a slightly different protocol. The channel definitions are
shared between the two drivers.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
drivers/iio/adc/Kconfig | 10 ++
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/ltc2496.c | 208 ++++++++++++++++++++++++++++++++++++++
3 files changed, 219 insertions(+)
create mode 100644 drivers/iio/adc/ltc2496.c
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index f0af3a42f53c..deb86f6039b3 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -492,6 +492,16 @@ config LTC2485
To compile this driver as a module, choose M here: the module will be
called ltc2485.
+config LTC2496
+ tristate "Linear Technology LTC2496 ADC driver"
+ depends on SPI
+ help
+ Say yes here to build support for Linear Technology LTC2496
+ 16-Bit 8-/16-Channel Delta Sigma ADC.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ltc2496.
+
config LTC2497
tristate "Linear Technology LTC2497 ADC driver"
depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 660242c2cca7..afe2b6db4a5e 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
obj-$(CONFIG_LTC2471) += ltc2471.o
obj-$(CONFIG_LTC2485) += ltc2485.o
+obj-$(CONFIG_LTC2496) += ltc2496.o ltc249x.o
obj-$(CONFIG_LTC2497) += ltc2497.o ltc249x.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX11100) += max11100.o
diff --git a/drivers/iio/adc/ltc2496.c b/drivers/iio/adc/ltc2496.c
new file mode 100644
index 000000000000..0b0a7aa8987f
--- /dev/null
+++ b/drivers/iio/adc/ltc2496.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ltc2496.c - Driver for Analog Devices/Linear Technology LTC2496 ADC
+ *
+ * Based on ltc2497.c which has
+ * Copyright (C) 2017 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ *
+ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2496fc.pdf
+ */
+
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include "ltc249x.h"
+
+struct ltc2496_st {
+ struct spi_device *spi;
+ struct regulator *ref;
+ ktime_t time_prev;
+ u8 addr_prev;
+};
+
+static int ltc2496_wait_conv(struct ltc2496_st *st)
+{
+ s64 time_elapsed;
+
+ time_elapsed = ktime_ms_delta(ktime_get(), st->time_prev);
+
+ if (time_elapsed < LTC249X_CONVERSION_TIME_MS) {
+ /* delay if conversion time not passed
+ * since last read or write
+ */
+ if (msleep_interruptible(
+ LTC249X_CONVERSION_TIME_MS - time_elapsed))
+ return -ERESTARTSYS;
+
+ return 0;
+ }
+
+ if (time_elapsed - LTC249X_CONVERSION_TIME_MS <= 0) {
+ /* We're in automatic mode -
+ * so the last reading is still not outdated
+ */
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ltc2496_read(struct ltc2496_st *st, u8 address, int *val)
+{
+ struct spi_device *spi = st->spi;
+ int ret;
+ unsigned char txbuf[3] = { LTC249X_ENABLE | address, };
+ unsigned char rxbuf[3];
+ struct spi_transfer t = {
+ .tx_buf = txbuf,
+ .rx_buf = rxbuf,
+ .len = sizeof(txbuf),
+ };
+
+ ret = ltc2496_wait_conv(st);
+ if (ret < 0)
+ return ret;
+
+ if (ret || st->addr_prev != address) {
+ ret = spi_sync_transfer(spi, &t, 1);
+ if (ret < 0)
+ return ret;
+ st->addr_prev = address;
+ if (msleep_interruptible(LTC249X_CONVERSION_TIME_MS))
+ return -ERESTARTSYS;
+ }
+
+ ret = spi_sync_transfer(spi, &t, 1);
+ if (ret < 0) {
+ dev_err(&spi->dev, "spi_sync_transfer failed\n");
+ return ret;
+ }
+ st->time_prev = ktime_get();
+
+ /* convert and shift the result,
+ * and finally convert from offset binary to signed integer
+ */
+ *val = ((rxbuf[0] & 0x3f) << 12 | rxbuf[1] << 4 | rxbuf[2] >> 4)
+ - (1 << 17);
+
+ return ret;
+}
+
+static int ltc2496_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ltc2496_st *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ ret = ltc2496_read(st, chan->address, val);
+ mutex_unlock(&indio_dev->mlock);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = regulator_get_voltage(st->ref);
+ if (ret < 0)
+ return ret;
+
+ *val = ret / 1000;
+ *val2 = 17;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ltc2496_info = {
+ .read_raw = ltc2496_read_raw,
+};
+
+static int ltc2496_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ltc2496_st *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ spi_set_drvdata(spi, indio_dev);
+ st->spi = spi;
+
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = "ltc2496";
+ indio_dev->info = <c2496_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ltc249x_channel;
+ indio_dev->num_channels = ltc249x_num_channels;
+
+ st->ref = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->ref))
+ return PTR_ERR(st->ref);
+
+ ret = regulator_enable(st->ref);
+ if (ret < 0)
+ return ret;
+
+ st->addr_prev = 0;
+ st->time_prev = ktime_get();
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ goto err_regulator_disable;
+
+ return 0;
+
+err_regulator_disable:
+ regulator_disable(st->ref);
+
+ return ret;
+}
+
+static int ltc2496_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ltc2496_st *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ regulator_disable(st->ref);
+
+ return 0;
+}
+
+static const struct of_device_id ltc2496_of_match[] = {
+ { .compatible = "lltc,ltc2496", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ltc2496_of_match);
+
+static struct spi_driver ltc2496_driver = {
+ .driver = {
+ .name = "ltc2496",
+ .of_match_table = of_match_ptr(ltc2496_of_match),
+ },
+ .probe = ltc2496_probe,
+ .remove = ltc2496_remove,
+};
+module_spi_driver(ltc2496_driver);
+
+MODULE_AUTHOR("Uwe Kleine-König <u.kleine-könig@pengutronix.de>");
+MODULE_DESCRIPTION("Linear Technology LTC2496 ADC driver");
+MODULE_LICENSE("GPL v2");
--
2.24.0.rc1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document
2019-11-11 21:40 [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document Uwe Kleine-König
2019-11-11 21:40 ` [PATCH 2/3] iio: adc: ltc2497: split channel definition in a separate module Uwe Kleine-König
2019-11-11 21:40 ` [PATCH 3/3] iio: adc: new driver to support Linear technology's ltc2496 Uwe Kleine-König
@ 2019-11-12 6:57 ` Ardelean, Alexandru
2019-11-12 7:04 ` Uwe Kleine-König
2 siblings, 1 reply; 9+ messages in thread
From: Ardelean, Alexandru @ 2019-11-12 6:57 UTC (permalink / raw)
To: Popa, Stefan Serban, mark.rutland, u.kleine-koenig, jic23, lars,
Hennerich, Michael, pmeerw, knaack.h, robh+dt
Cc: kernel, devicetree, linux-iio
On Mon, 2019-11-11 at 22:40 +0100, Uwe Kleine-König wrote:
> The ADC only requires the standard stuff for spi devices and a reference
> voltage.
>
Hey,
Thanks for the patch.
DT bindings must be in YAML format.
But in this case, you can probably extend the existing
"Documentation/devicetree/bindings/iio/adc/ltc2497.txt".
You don't need to create new file altogether.
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
> .../devicetree/bindings/iio/adc/ltc2496.txt | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/adc/ltc2496.txt
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/ltc2496.txt
> b/Documentation/devicetree/bindings/iio/adc/ltc2496.txt
> new file mode 100644
> index 000000000000..d44ab45b26ea
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/ltc2496.txt
> @@ -0,0 +1,15 @@
> +* Linear Technology / Analog Devices LTC2496 ADC
> +
> +Required properties:
> + - compatible: Must be "lltc,ltc2496"
> + - vref-supply: The regulator supply for ADC reference voltage
> + - further properties required for spi device nodes according to
> + Documentation/devicetree/bindings/spi/spi-controller.yaml
> +
> +Example:
> + ltc2497: adc@76 {
> + compatible = "lltc,ltc2496";
> + reg = <0>;
> + vref-supply = <<c249x_reg>;
> + spi-max-frequency = <2000000>;
> + };
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document
2019-11-12 6:57 ` [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document Ardelean, Alexandru
@ 2019-11-12 7:04 ` Uwe Kleine-König
2019-11-12 11:56 ` Ardelean, Alexandru
0 siblings, 1 reply; 9+ messages in thread
From: Uwe Kleine-König @ 2019-11-12 7:04 UTC (permalink / raw)
To: Ardelean, Alexandru
Cc: Popa, Stefan Serban, mark.rutland, jic23, lars, Hennerich,
Michael, pmeerw, knaack.h, robh+dt, kernel, devicetree,
linux-iio
Hello Alexandru,
On Tue, Nov 12, 2019 at 06:57:49AM +0000, Ardelean, Alexandru wrote:
> On Mon, 2019-11-11 at 22:40 +0100, Uwe Kleine-König wrote:
> > The ADC only requires the standard stuff for spi devices and a reference
> > voltage.
>
> DT bindings must be in YAML format.
Yeah, I noticed this trend. But given that I only saw .txt files for
iio, I thought I'd stick to that.
> But in this case, you can probably extend the existing
> "Documentation/devicetree/bindings/iio/adc/ltc2497.txt".
I considered that shortly, but as the ltc2497 is an i2c device and the
ltc2496 uses spi I chose to create another simple document instead of
complicating the existing one by describing two nearly orthogonal sets
of properties.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | https://www.pengutronix.de/ |
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/3] iio: adc: ltc2497: split channel definition in a separate module
2019-11-11 21:40 ` [PATCH 2/3] iio: adc: ltc2497: split channel definition in a separate module Uwe Kleine-König
@ 2019-11-12 7:14 ` Ardelean, Alexandru
0 siblings, 0 replies; 9+ messages in thread
From: Ardelean, Alexandru @ 2019-11-12 7:14 UTC (permalink / raw)
To: Popa, Stefan Serban, mark.rutland, u.kleine-koenig, jic23, lars,
Hennerich, Michael, pmeerw, knaack.h, robh+dt
Cc: kernel, devicetree, linux-iio
On Mon, 2019-11-11 at 22:40 +0100, Uwe Kleine-König wrote:
> This allows to share the data for the ltc2496 driver added in
> the next commit that is an SPI variant of the ltc2497.
>
Hey,
For this split, maybe take a look at adxl372-i2c.c & adxl372-spi.c.
I think that one is similar to how this split could be.
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
> drivers/iio/adc/Makefile | 2 +-
> drivers/iio/adc/ltc2497.c | 81 +++++----------------------------------
> drivers/iio/adc/ltc249x.c | 72 ++++++++++++++++++++++++++++++++++
> drivers/iio/adc/ltc249x.h | 10 +++++
> 4 files changed, 93 insertions(+), 72 deletions(-)
> create mode 100644 drivers/iio/adc/ltc249x.c
> create mode 100644 drivers/iio/adc/ltc249x.h
>
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index ef9cc485fb67..660242c2cca7 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -47,7 +47,7 @@ obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
> obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
> obj-$(CONFIG_LTC2471) += ltc2471.o
> obj-$(CONFIG_LTC2485) += ltc2485.o
> -obj-$(CONFIG_LTC2497) += ltc2497.o
> +obj-$(CONFIG_LTC2497) += ltc2497.o ltc249x.o
Typically, we name the common/core files "ltc2497-core.o".
Or you can leave this unchanged and just add a new "ltc2497-i2c.o"
In this case, you also need some new Kconfig symbols. [patch2-note1]
And this would be
obj-$(CONFIG_LTC2497) += ltc2497.o
+obj-$(CONFIG_LTC2497_I2C) += ltc2497-i2c.o
Because, the new driver would be:
obj-$(CONFIG_LTC2497) += ltc2497.o
+obj-$(CONFIG_LTC2497_I2C) += ltc2497-
i2c.o
+obj-$(CONFIG_LTC2497_SPI) += ltc2497-spi.o
So, LTC2496 would go into "ltc2497-spi."
> obj-$(CONFIG_MAX1027) += max1027.o
> obj-$(CONFIG_MAX11100) += max11100.o
> obj-$(CONFIG_MAX1118) += max1118.o
> diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
> index 470406032720..e86fe42f1598 100644
> --- a/drivers/iio/adc/ltc2497.c
> +++ b/drivers/iio/adc/ltc2497.c
> @@ -16,12 +16,7 @@
> #include <linux/of.h>
> #include <linux/regulator/consumer.h>
>
> -#define LTC2497_ENABLE 0xA0
> -#define LTC2497_SGL BIT(4)
> -#define LTC2497_DIFF 0
> -#define LTC2497_SIGN BIT(3)
> -#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE
> -#define LTC2497_CONVERSION_TIME_MS 150ULL
> +#include "ltc249x.h"
>
> struct ltc2497_st {
> struct i2c_client *client;
> @@ -41,18 +36,18 @@ static int ltc2497_wait_conv(struct ltc2497_st *st)
>
> time_elapsed = ktime_ms_delta(ktime_get(), st->time_prev);
>
> - if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {
> + if (time_elapsed < LTC249X_CONVERSION_TIME_MS) {
You can leave all LTC2497_xxx macros/definitions unchanged.
If LTC2496 has something new, you can add a new LTC2496_specific_xxx
definition and use it.
> /* delay if conversion time not passed
> * since last read or write
> */
> if (msleep_interruptible(
> - LTC2497_CONVERSION_TIME_MS - time_elapsed))
> + LTC249X_CONVERSION_TIME_MS - time_elapsed))
> return -ERESTARTSYS;
>
> return 0;
> }
>
> - if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {
> + if (time_elapsed - LTC249X_CONVERSION_TIME_MS <= 0) {
> /* We're in automatic mode -
> * so the last reading is stil not outdated
> */
> @@ -73,11 +68,11 @@ static int ltc2497_read(struct ltc2497_st *st, u8
> address, int *val)
>
> if (ret || st->addr_prev != address) {
> ret = i2c_smbus_write_byte(st->client,
> - LTC2497_ENABLE | address);
> + LTC249X_ENABLE | address);
> if (ret < 0)
> return ret;
> st->addr_prev = address;
> - if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))
> + if (msleep_interruptible(LTC249X_CONVERSION_TIME_MS))
> return -ERESTARTSYS;
> }
> ret = i2c_master_recv(client, (char *)&st->buf, 3);
> @@ -127,62 +122,6 @@ static int ltc2497_read_raw(struct iio_dev
> *indio_dev,
> }
> }
>
> -#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
> - .type = IIO_VOLTAGE, \
> - .indexed = 1, \
> - .channel = (_chan), \
> - .address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN :
> 0)), \
> - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> - .datasheet_name = (_ds_name), \
> -}
> -
> -#define LTC2497_CHAN_DIFF(_chan, _addr) { \
> - .type = IIO_VOLTAGE, \
> - .indexed = 1, \
> - .channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \
> - .channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\
> - .address = (_addr | _chan), \
> - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> - .differential = 1, \
> -}
> -
> -static const struct iio_chan_spec ltc2497_channel[] = {
> - LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
> - LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
> - LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
> - LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
> - LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
> - LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
> - LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
> - LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
> - LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
> - LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
> - LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
> - LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
> - LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
> - LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
> - LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
> - LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
> - LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
> - LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
> - LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
> - LTC2497_CHAN_DIFF(3, LTC2497_DIFF),
> - LTC2497_CHAN_DIFF(4, LTC2497_DIFF),
> - LTC2497_CHAN_DIFF(5, LTC2497_DIFF),
> - LTC2497_CHAN_DIFF(6, LTC2497_DIFF),
> - LTC2497_CHAN_DIFF(7, LTC2497_DIFF),
> - LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),
> - LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),
> - LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),
> - LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),
> - LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),
> - LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),
> - LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),
> - LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),
> -};
> -
> static const struct iio_info ltc2497_info = {
> .read_raw = ltc2497_read_raw,
> };
> @@ -211,8 +150,8 @@ static int ltc2497_probe(struct i2c_client *client,
> indio_dev->name = id->name;
> indio_dev->info = <c2497_info;
> indio_dev->modes = INDIO_DIRECT_MODE;
> - indio_dev->channels = ltc2497_channel;
> - indio_dev->num_channels = ARRAY_SIZE(ltc2497_channel);
> + indio_dev->channels = ltc249x_channel;
> + indio_dev->num_channels = ltc249x_num_channels;
>
> st->ref = devm_regulator_get(&client->dev, "vref");
> if (IS_ERR(st->ref))
> @@ -231,11 +170,11 @@ static int ltc2497_probe(struct i2c_client *client,
> }
> }
>
> - ret = i2c_smbus_write_byte(st->client, LTC2497_CONFIG_DEFAULT);
> + ret = i2c_smbus_write_byte(st->client, LTC249X_CONFIG_DEFAULT);
> if (ret < 0)
> goto err_array_unregister;
>
> - st->addr_prev = LTC2497_CONFIG_DEFAULT;
> + st->addr_prev = LTC249X_CONFIG_DEFAULT;
> st->time_prev = ktime_get();
>
> ret = iio_device_register(indio_dev);
> diff --git a/drivers/iio/adc/ltc249x.c b/drivers/iio/adc/ltc249x.c
> new file mode 100644
> index 000000000000..571fce7cc808
> --- /dev/null
> +++ b/drivers/iio/adc/ltc249x.c
> @@ -0,0 +1,72 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/driver.h>
> +#include <linux/module.h>
> +
> +#define LTC249X_SGL BIT(4)
> +#define LTC249X_DIFF 0
> +#define LTC249X_SIGN BIT(3)
> +
> +#define LTC249X_CHAN(_chan, _addr, _ds_name) { \
> + .type = IIO_VOLTAGE, \
> + .indexed = 1, \
> + .channel = (_chan), \
> + .address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC249X_SIGN :
> 0)), \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> + .datasheet_name = (_ds_name), \
> +}
> +
> +#define LTC249X_CHAN_DIFF(_chan, _addr) { \
> + .type = IIO_VOLTAGE, \
> + .indexed = 1, \
> + .channel = (_chan) * 2 + ((_addr) & LTC249X_SIGN ? 1 : 0), \
> + .channel2 = (_chan) * 2 + ((_addr) & LTC249X_SIGN ? 0 : 1),\
> + .address = (_addr | _chan), \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> + .differential = 1, \
> +}
> +
> +const struct iio_chan_spec ltc249x_channel[] = {
> + LTC249X_CHAN(0, LTC249X_SGL, "CH0"),
> + LTC249X_CHAN(1, LTC249X_SGL, "CH1"),
> + LTC249X_CHAN(2, LTC249X_SGL, "CH2"),
> + LTC249X_CHAN(3, LTC249X_SGL, "CH3"),
> + LTC249X_CHAN(4, LTC249X_SGL, "CH4"),
> + LTC249X_CHAN(5, LTC249X_SGL, "CH5"),
> + LTC249X_CHAN(6, LTC249X_SGL, "CH6"),
> + LTC249X_CHAN(7, LTC249X_SGL, "CH7"),
> + LTC249X_CHAN(8, LTC249X_SGL, "CH8"),
> + LTC249X_CHAN(9, LTC249X_SGL, "CH9"),
> + LTC249X_CHAN(10, LTC249X_SGL, "CH10"),
> + LTC249X_CHAN(11, LTC249X_SGL, "CH11"),
> + LTC249X_CHAN(12, LTC249X_SGL, "CH12"),
> + LTC249X_CHAN(13, LTC249X_SGL, "CH13"),
> + LTC249X_CHAN(14, LTC249X_SGL, "CH14"),
> + LTC249X_CHAN(15, LTC249X_SGL, "CH15"),
> + LTC249X_CHAN_DIFF(0, LTC249X_DIFF),
> + LTC249X_CHAN_DIFF(1, LTC249X_DIFF),
> + LTC249X_CHAN_DIFF(2, LTC249X_DIFF),
> + LTC249X_CHAN_DIFF(3, LTC249X_DIFF),
> + LTC249X_CHAN_DIFF(4, LTC249X_DIFF),
> + LTC249X_CHAN_DIFF(5, LTC249X_DIFF),
> + LTC249X_CHAN_DIFF(6, LTC249X_DIFF),
> + LTC249X_CHAN_DIFF(7, LTC249X_DIFF),
> + LTC249X_CHAN_DIFF(0, LTC249X_DIFF | LTC249X_SIGN),
> + LTC249X_CHAN_DIFF(1, LTC249X_DIFF | LTC249X_SIGN),
> + LTC249X_CHAN_DIFF(2, LTC249X_DIFF | LTC249X_SIGN),
> + LTC249X_CHAN_DIFF(3, LTC249X_DIFF | LTC249X_SIGN),
> + LTC249X_CHAN_DIFF(4, LTC249X_DIFF | LTC249X_SIGN),
> + LTC249X_CHAN_DIFF(5, LTC249X_DIFF | LTC249X_SIGN),
> + LTC249X_CHAN_DIFF(6, LTC249X_DIFF | LTC249X_SIGN),
> + LTC249X_CHAN_DIFF(7, LTC249X_DIFF | LTC249X_SIGN),
> +};
> +EXPORT_SYMBOL_NS_GPL(ltc249x_channel, LTC249X);
Maybe leave these channel definitions in "ltc2497.o" file [which can be
the common one].
Instead of exporting these, maybe create a
"int ltc2497_core_probe(struct device *dev)" function.
and add it in the "ltc2497.h" file.
You can call it with "ltc2497_core_probe(&spi->dev)" and
"ltc2497_core_probe(&client->dev)"
The beauty of this approach is that you also allocate the IIO device in the
common code.
> +
> +const int ltc249x_num_channels = ARRAY_SIZE(ltc249x_channel);
> +EXPORT_SYMBOL_NS_GPL(ltc249x_num_channels, LTC249X);
> +
> +MODULE_DESCRIPTION("common code for LTC2496/LTC2497 drivers");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iio/adc/ltc249x.h b/drivers/iio/adc/ltc249x.h
> new file mode 100644
> index 000000000000..dac8b5ed0ecf
> --- /dev/null
> +++ b/drivers/iio/adc/ltc249x.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#define LTC249X_ENABLE 0xA0
> +#define LTC249X_CONFIG_DEFAULT LTC249X_ENABLE
> +#define LTC249X_CONVERSION_TIME_MS 150ULL
> +
> +extern const struct iio_chan_spec ltc249x_channel[];
> +extern const int ltc249x_num_channels;
> +
> +MODULE_IMPORT_NS(LTC249X);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] iio: adc: new driver to support Linear technology's ltc2496
2019-11-11 21:40 ` [PATCH 3/3] iio: adc: new driver to support Linear technology's ltc2496 Uwe Kleine-König
@ 2019-11-12 7:54 ` Ardelean, Alexandru
0 siblings, 0 replies; 9+ messages in thread
From: Ardelean, Alexandru @ 2019-11-12 7:54 UTC (permalink / raw)
To: Popa, Stefan Serban, mark.rutland, u.kleine-koenig, jic23, lars,
Hennerich, Michael, pmeerw, knaack.h, robh+dt
Cc: kernel, devicetree, linux-iio
On Mon, 2019-11-11 at 22:40 +0100, Uwe Kleine-König wrote:
> This chip is similar to the LTC2497 ADC, it just uses SPI instead of I2C
> and so has a slightly different protocol. The channel definitions are
> shared between the two drivers.
Much of this code is duplicated from the i2c/base ltc2497.o driver.
I would leave most of this code in the base/common driver and export the
i2c/spi read hooks.
You can check [as an example] the ad7606 driver.
That one passes some bus_ops struct from the SPI & Parallel drivers to
the common probe.
I agree that regmap isn't usable here, but a bus_ops struct [that is
defined in ltc2497.h] should be doable.
Thanks
Alex
>
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
> drivers/iio/adc/Kconfig | 10 ++
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/ltc2496.c | 208 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 219 insertions(+)
> create mode 100644 drivers/iio/adc/ltc2496.c
>
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index f0af3a42f53c..deb86f6039b3 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -492,6 +492,16 @@ config LTC2485
> To compile this driver as a module, choose M here: the module
> will be
> called ltc2485.
>
> +config LTC2496
> + tristate "Linear Technology LTC2496 ADC driver"
> + depends on SPI
Regarding [patch2-note1], this Kconfig symbols would be LTC2497_SPI
> + help
> + Say yes here to build support for Linear Technology LTC2496
> + 16-Bit 8-/16-Channel Delta Sigma ADC.
> +
> + To compile this driver as a module, choose M here: the module
> will be
> + called ltc2496.
> +
> config LTC2497
Regarding [patch2-note1], this Kconfig symbols would become LTC2497_I2C.
And a new config LTC2497 could be added, but without any title, so that it
cannot be selected in menuconfig.
> tristate "Linear Technology LTC2497 ADC driver"
> depends on I2C
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 660242c2cca7..afe2b6db4a5e 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -47,6 +47,7 @@ obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
> obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
> obj-$(CONFIG_LTC2471) += ltc2471.o
> obj-$(CONFIG_LTC2485) += ltc2485.o
> +obj-$(CONFIG_LTC2496) += ltc2496.o ltc249x.o
> obj-$(CONFIG_LTC2497) += ltc2497.o ltc249x.o
> obj-$(CONFIG_MAX1027) += max1027.o
> obj-$(CONFIG_MAX11100) += max11100.o
> diff --git a/drivers/iio/adc/ltc2496.c b/drivers/iio/adc/ltc2496.c
> new file mode 100644
> index 000000000000..0b0a7aa8987f
> --- /dev/null
> +++ b/drivers/iio/adc/ltc2496.c
> @@ -0,0 +1,208 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * ltc2496.c - Driver for Analog Devices/Linear Technology LTC2496 ADC
> + *
> + * Based on ltc2497.c which has
> + * Copyright (C) 2017 Analog Devices Inc.
> + *
> + * Licensed under the GPL-2.
> + *
> + * Datasheet:
> https://www.analog.com/media/en/technical-documentation/data-sheets/2496fc.pdf
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/spi/spi.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/driver.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include "ltc249x.h"
> +
> +struct ltc2496_st {
> + struct spi_device *spi;
> + struct regulator *ref;
> + ktime_t time_prev;
> + u8 addr_prev;
> +};
> +
> +static int ltc2496_wait_conv(struct ltc2496_st *st)
> +{
> + s64 time_elapsed;
> +
> + time_elapsed = ktime_ms_delta(ktime_get(), st->time_prev);
> +
> + if (time_elapsed < LTC249X_CONVERSION_TIME_MS) {
> + /* delay if conversion time not passed
> + * since last read or write
> + */
> + if (msleep_interruptible(
> + LTC249X_CONVERSION_TIME_MS - time_elapsed))
> + return -ERESTARTSYS;
> +
> + return 0;
> + }
> +
> + if (time_elapsed - LTC249X_CONVERSION_TIME_MS <= 0) {
> + /* We're in automatic mode -
> + * so the last reading is still not outdated
> + */
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> +static int ltc2496_read(struct ltc2496_st *st, u8 address, int *val)
> +{
> + struct spi_device *spi = st->spi;
> + int ret;
> + unsigned char txbuf[3] = { LTC249X_ENABLE | address, };
> + unsigned char rxbuf[3];
> + struct spi_transfer t = {
> + .tx_buf = txbuf,
> + .rx_buf = rxbuf,
> + .len = sizeof(txbuf),
> + };
> +
> + ret = ltc2496_wait_conv(st);
> + if (ret < 0)
> + return ret;
> +
> + if (ret || st->addr_prev != address) {
> + ret = spi_sync_transfer(spi, &t, 1);
> + if (ret < 0)
> + return ret;
> + st->addr_prev = address;
> + if (msleep_interruptible(LTC249X_CONVERSION_TIME_MS))
> + return -ERESTARTSYS;
> + }
> +
> + ret = spi_sync_transfer(spi, &t, 1);
> + if (ret < 0) {
> + dev_err(&spi->dev, "spi_sync_transfer failed\n");
> + return ret;
> + }
> + st->time_prev = ktime_get();
> +
> + /* convert and shift the result,
> + * and finally convert from offset binary to signed integer
> + */
> + *val = ((rxbuf[0] & 0x3f) << 12 | rxbuf[1] << 4 | rxbuf[2] >> 4)
> + - (1 << 17);
> +
> + return ret;
> +}
> + int *val, int *val2, long mask)
> +{
> + struct ltc2496_st *st = iio_priv(indio_dev);
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + mutex_lock(&indio_dev->mlock);
> + ret = ltc2496_read(st, chan->address, val);
> + mutex_unlock(&indio_dev->mlock);
> + if (ret < 0)
> + return ret;
> +
> + return IIO_VAL_INT;
> +
> + case IIO_CHAN_INFO_SCALE:
> + ret = regulator_get_voltage(st->ref);
> + if (ret < 0)
> + return ret;
> +
> + *val = ret / 1000;
> + *val2 = 17;
> +
> + return IIO_VAL_FRACTIONAL_LOG2;
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static const struct iio_info ltc2496_info = {
> + .read_raw = ltc2496_read_raw,
> +};
> +
> +static int ltc2496_probe(struct spi_device *spi)
> +{
> + struct iio_dev *indio_dev;
> + struct ltc2496_st *st;
> + int ret;
> +
> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + st = iio_priv(indio_dev);
> + spi_set_drvdata(spi, indio_dev);
> + st->spi = spi;
> +
> + indio_dev->dev.parent = &spi->dev;
> + indio_dev->name = "ltc2496";
> + indio_dev->info = <c2496_info;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->channels = ltc249x_channel;
> + indio_dev->num_channels = ltc249x_num_channels;
> +
> + st->ref = devm_regulator_get(&spi->dev, "vref");
> + if (IS_ERR(st->ref))
> + return PTR_ERR(st->ref);
> +
> + ret = regulator_enable(st->ref);
> + if (ret < 0)
> + return ret;
> +
> + st->addr_prev = 0;
> + st->time_prev = ktime_get();
> +
> + ret = iio_device_register(indio_dev);
> + if (ret < 0)
> + goto err_regulator_disable;
> +
> + return 0;
> +
> +err_regulator_disable:
> + regulator_disable(st->ref);
> +
> + return ret;
> +}
> +
> +static int ltc2496_remove(struct spi_device *spi)
> +{
> + struct iio_dev *indio_dev = spi_get_drvdata(spi);
> + struct ltc2496_st *st = iio_priv(indio_dev);
> +
> + iio_device_unregister(indio_dev);
> + regulator_disable(st->ref);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id ltc2496_of_match[] = {
> + { .compatible = "lltc,ltc2496", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, ltc2496_of_match);
> +
> +static struct spi_driver ltc2496_driver = {
> + .driver = {
> + .name = "ltc2496",
> + .of_match_table = of_match_ptr(ltc2496_of_match),
> + },
> + .probe = ltc2496_probe,
> + .remove = ltc2496_remove,
> +};
> +module_spi_driver(ltc2496_driver);
> +
> +MODULE_AUTHOR("Uwe Kleine-König <u.kleine-könig@pengutronix.de>");
> +MODULE_DESCRIPTION("Linear Technology LTC2496 ADC driver");
> +MODULE_LICENSE("GPL v2");
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document
2019-11-12 7:04 ` Uwe Kleine-König
@ 2019-11-12 11:56 ` Ardelean, Alexandru
2019-11-16 15:25 ` Jonathan Cameron
0 siblings, 1 reply; 9+ messages in thread
From: Ardelean, Alexandru @ 2019-11-12 11:56 UTC (permalink / raw)
To: u.kleine-koenig
Cc: kernel, linux-iio, mark.rutland, devicetree, pmeerw, knaack.h,
Hennerich, Michael, jic23, Popa, Stefan Serban, robh+dt, lars
On Tue, 2019-11-12 at 08:04 +0100, Uwe Kleine-König wrote:
> [External]
>
> Hello Alexandru,
>
> On Tue, Nov 12, 2019 at 06:57:49AM +0000, Ardelean, Alexandru wrote:
> > On Mon, 2019-11-11 at 22:40 +0100, Uwe Kleine-König wrote:
> > > The ADC only requires the standard stuff for spi devices and a
> > > reference
> > > voltage.
> >
> > DT bindings must be in YAML format.
>
> Yeah, I noticed this trend. But given that I only saw .txt files for
> iio, I thought I'd stick to that.
>
> > But in this case, you can probably extend the existing
> > "Documentation/devicetree/bindings/iio/adc/ltc2497.txt".
>
> I considered that shortly, but as the ltc2497 is an i2c device and the
> ltc2496 uses spi I chose to create another simple document instead of
> complicating the existing one by describing two nearly orthogonal sets
> of properties.
There are dt-bindings that cover both SPI & I2C.
I think ADXL372 does that too.
>
> Best regards
> Uwe
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document
2019-11-12 11:56 ` Ardelean, Alexandru
@ 2019-11-16 15:25 ` Jonathan Cameron
0 siblings, 0 replies; 9+ messages in thread
From: Jonathan Cameron @ 2019-11-16 15:25 UTC (permalink / raw)
To: Ardelean, Alexandru
Cc: u.kleine-koenig, kernel, linux-iio, mark.rutland, devicetree,
pmeerw, knaack.h, Hennerich, Michael, Popa, Stefan Serban,
robh+dt, lars
On Tue, 12 Nov 2019 11:56:52 +0000
"Ardelean, Alexandru" <alexandru.Ardelean@analog.com> wrote:
> On Tue, 2019-11-12 at 08:04 +0100, Uwe Kleine-König wrote:
> > [External]
> >
> > Hello Alexandru,
> >
> > On Tue, Nov 12, 2019 at 06:57:49AM +0000, Ardelean, Alexandru wrote:
> > > On Mon, 2019-11-11 at 22:40 +0100, Uwe Kleine-König wrote:
> > > > The ADC only requires the standard stuff for spi devices and a
> > > > reference
> > > > voltage.
> > >
> > > DT bindings must be in YAML format.
> >
> > Yeah, I noticed this trend. But given that I only saw .txt files for
> > iio, I thought I'd stick to that.
> >
> > > But in this case, you can probably extend the existing
> > > "Documentation/devicetree/bindings/iio/adc/ltc2497.txt".
> >
> > I considered that shortly, but as the ltc2497 is an i2c device and the
> > ltc2496 uses spi I chose to create another simple document instead of
> > complicating the existing one by describing two nearly orthogonal sets
> > of properties.
>
> There are dt-bindings that cover both SPI & I2C.
> I think ADXL372 does that too.
True, but in that case no real choice as the same part does both
bus types. Here it's probably cleaner to just have a second document.
Thanks,
Jonathan
>
>
> >
> > Best regards
> > Uwe
> >
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2019-11-16 15:25 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-11 21:40 [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document Uwe Kleine-König
2019-11-11 21:40 ` [PATCH 2/3] iio: adc: ltc2497: split channel definition in a separate module Uwe Kleine-König
2019-11-12 7:14 ` Ardelean, Alexandru
2019-11-11 21:40 ` [PATCH 3/3] iio: adc: new driver to support Linear technology's ltc2496 Uwe Kleine-König
2019-11-12 7:54 ` Ardelean, Alexandru
2019-11-12 6:57 ` [PATCH 1/3] iio: adc: ltc2496: provide device tree binding document Ardelean, Alexandru
2019-11-12 7:04 ` Uwe Kleine-König
2019-11-12 11:56 ` Ardelean, Alexandru
2019-11-16 15:25 ` Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).