* [PATCH v6 0/7] Add support for AD4000 series of ADCs
@ 2024-06-29 19:04 Marcelo Schmitt
2024-06-29 19:04 ` [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration Marcelo Schmitt
` (7 more replies)
0 siblings, 8 replies; 23+ messages in thread
From: Marcelo Schmitt @ 2024-06-29 19:04 UTC (permalink / raw)
To: broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
This patch series extends the SPI bitbang, gpio, and spi-engine controllers to
support configurable MOSI line idle states.
It then introduces the ad4000 driver which uses the MOSI idle configuration to
provide improved support for the AD4000 series of ADCs.
Documentation is added describing the new extension to the SPI protocol.
The currently supported wiring modes for AD4000 devices were documented under
IIO documentation directory.
To apply this series, it requires the patches for SPI-Engine SPI_CS_HIGH feature
and the patches for devm_spi_optimize_message() helper.
89c2657429c4822a2697077bbb3a8d126d826ced "spi: axi-spi-engine: remove platform_set_drvdata()"
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git/commit/?h=for-6.11&id=89c2657429c4822a2697077bbb3a8d126d826ced
7e74a45c7afdd8a9f82d14fd79ae0383bbaaed1e "spi: add EXPORT_SYMBOL_GPL(devm_spi_optimize_message)"
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git/commit/?h=for-6.11&id=7e74a45c7afdd8a9f82d14fd79ae0383bbaaed1e
d4a0055fdc22381fa256e345095e88d134e354c5 "spi: add devm_spi_optimize_message() helper"
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git/commit/?h=for-6.11&id=d4a0055fdc22381fa256e345095e88d134e354c5
6ecdb0aa4dca62d236a659426e11e6cf302e8f18 "spi: axi-spi-engine: Add SPI_CS_HIGH support"
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git/commit/?h=for-6.11&id=6ecdb0aa4dca62d236a659426e11e6cf302e8f18
Change log v5 -> v6:
[SPI]
spi.h: Removed unused SPI_CONTROLLER_MOSI_IDLE_LOW and SPI_CONTROLLER_MOSI_IDLE_HIGH
spi-summay: Minor nit: inactive -> not asserted
spi-engine: Moved MOSI idle support check to IP core version check section
[IIO]
ad4000: Fixed ad4000_read_reg(). *val = st->tx_buf[1]; -> *val = st->rx_buf[1];
ad4000: Use devm_regulator_bulk_get_enable()
ad4000: Use iio_device_claim_direct_scoped() and guard() to protect scale update
ad4000: Fail probe if ad4000_config() fail
ad4000: Moved ad4000_prepare_..._message() closer to probe to reduce scope
ad4000: Added AD4000_SDI_GND and switch case for more accurate error msg
ad4000: Removed unused st->turbo_mode
ad4000: Removed old misleading comments in enum ad4000_sdi
ad4000: A few minor readability and code style nits
Link to v5: https://lore.kernel.org/linux-iio/cover.1719351923.git.marcelo.schmitt@analog.com/
Link to v4: https://lore.kernel.org/linux-iio/cover.1718749981.git.marcelo.schmitt@analog.com/
Link to v3: https://lore.kernel.org/linux-iio/cover.1717539384.git.marcelo.schmitt@analog.com/
Link to v2: https://lore.kernel.org/linux-iio/cover.1712585500.git.marcelo.schmitt@analog.com/
Link to v1: https://lore.kernel.org/linux-iio/cover.1711131830.git.marcelo.schmitt@analog.com/
Regard using spi_w8r8(), I tried it again and it doesn't work for ad4000.
Looks like the smallest transfer size for these devices is 16-bit.
From datasheets:
"The AD4000/AD4004/AD4008 configuration register is read from and written to
with a 16-bit SPI instruction."
Regarding the sample buffer size, I'm keeping it 32-bits long following
suggestion from Nuno and due to a bit of laziness from my side to re-test it.
Will change if required.
Thank you to everybody who reviewed these patches. I appreciate your support.
Thanks,
Marcelo
Marcelo Schmitt (7):
spi: Enable controllers to extend the SPI protocol with MOSI idle
configuration
spi: bitbang: Implement support for MOSI idle state configuration
spi: spi-gpio: Add support for MOSI idle state configuration
spi: spi-axi-spi-engine: Add support for MOSI idle configuration
dt-bindings: iio: adc: Add AD4000
iio: adc: Add support for AD4000
docs: iio: Add documentation for AD4000
.../bindings/iio/adc/adi,ad4000.yaml | 197 +++++
Documentation/iio/ad4000.rst | 131 ++++
Documentation/iio/index.rst | 1 +
Documentation/spi/spi-summary.rst | 83 ++
MAINTAINERS | 9 +
drivers/iio/adc/Kconfig | 12 +
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/ad4000.c | 708 ++++++++++++++++++
drivers/spi/spi-axi-spi-engine.c | 15 +-
drivers/spi/spi-bitbang.c | 24 +
drivers/spi/spi-gpio.c | 12 +-
drivers/spi/spi.c | 7 +
include/linux/spi/spi_bitbang.h | 1 +
include/uapi/linux/spi/spi.h | 5 +-
14 files changed, 1200 insertions(+), 6 deletions(-)
create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
create mode 100644 Documentation/iio/ad4000.rst
create mode 100644 drivers/iio/adc/ad4000.c
--
2.43.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration
2024-06-29 19:04 [PATCH v6 0/7] Add support for AD4000 series of ADCs Marcelo Schmitt
@ 2024-06-29 19:04 ` Marcelo Schmitt
2024-06-30 10:47 ` Jonathan Cameron
2024-07-08 21:15 ` David Lechner
2024-06-29 19:05 ` [PATCH v6 2/7] spi: bitbang: Implement support for MOSI idle state configuration Marcelo Schmitt
` (6 subsequent siblings)
7 siblings, 2 replies; 23+ messages in thread
From: Marcelo Schmitt @ 2024-06-29 19:04 UTC (permalink / raw)
To: broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
The behavior of an SPI controller data output line (SDO or MOSI or COPI
(Controller Output Peripheral Input) for disambiguation) is usually not
specified when the controller is not clocking out data on SCLK edges.
However, there do exist SPI peripherals that require specific MOSI line
state when data is not being clocked out of the controller.
Conventional SPI controllers may set the MOSI line on SCLK edges then bring
it low when no data is going out or leave the line the state of the last
transfer bit. More elaborated controllers are capable to set the MOSI idle
state according to different configurable levels and thus are more suitable
for interfacing with demanding peripherals.
Add SPI mode bits to allow peripherals to request explicit MOSI idle state
when needed.
When supporting a particular MOSI idle configuration, the data output line
state is expected to remain at the configured level when the controller is
not clocking out data. When a device that needs a specific MOSI idle state
is identified, its driver should request the MOSI idle configuration by
setting the proper SPI mode bit.
Acked-by: Nuno Sa <nuno.sa@analog.com>
Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
---
Documentation/spi/spi-summary.rst | 83 +++++++++++++++++++++++++++++++
drivers/spi/spi.c | 7 +++
include/uapi/linux/spi/spi.h | 5 +-
3 files changed, 93 insertions(+), 2 deletions(-)
diff --git a/Documentation/spi/spi-summary.rst b/Documentation/spi/spi-summary.rst
index 7f8accfae6f9..6e21e6f86912 100644
--- a/Documentation/spi/spi-summary.rst
+++ b/Documentation/spi/spi-summary.rst
@@ -614,6 +614,89 @@ queue, and then start some asynchronous transfer engine (unless it's
already running).
+Extensions to the SPI protocol
+------------------------------
+The fact that SPI doesn't have a formal specification or standard permits chip
+manufacturers to implement the SPI protocol in slightly different ways. In most
+cases, SPI protocol implementations from different vendors are compatible among
+each other. For example, in SPI mode 0 (CPOL=0, CPHA=0) the bus lines may behave
+like the following:
+
+::
+
+ nCSx ___ ___
+ \_________________________________________________________________/
+ • •
+ • •
+ SCLK ___ ___ ___ ___ ___ ___ ___ ___
+ _______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____
+ • : ; : ; : ; : ; : ; : ; : ; : ; •
+ • : ; : ; : ; : ; : ; : ; : ; : ; •
+ MOSI XXX__________ _______ _______ ________XXX
+ 0xA5 XXX__/ 1 \_0_____/ 1 \_0_______0_____/ 1 \_0_____/ 1 \_XXX
+ • ; ; ; ; ; ; ; ; •
+ • ; ; ; ; ; ; ; ; •
+ MISO XXX__________ _______________________ _______ XXX
+ 0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX
+
+Legend::
+
+ • marks the start/end of transmission;
+ : marks when data is clocked into the peripheral;
+ ; marks when data is clocked into the controller;
+ X marks when line states are not specified.
+
+In some few cases, chips extend the SPI protocol by specifying line behaviors
+that other SPI protocols don't (e.g. data line state for when CS is not
+asserted). Those distinct SPI protocols, modes, and configurations are supported
+by different SPI mode flags.
+
+MOSI idle state configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Common SPI protocol implementations don't specify any state or behavior for the
+MOSI line when the controller is not clocking out data. However, there do exist
+peripherals that require specific MOSI line state when data is not being clocked
+out. For example, if the peripheral expects the MOSI line to be high when the
+controller is not clocking out data (``SPI_MOSI_IDLE_HIGH``), then a transfer in
+SPI mode 0 would look like the following:
+
+::
+
+ nCSx ___ ___
+ \_________________________________________________________________/
+ • •
+ • •
+ SCLK ___ ___ ___ ___ ___ ___ ___ ___
+ _______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____
+ • : ; : ; : ; : ; : ; : ; : ; : ; •
+ • : ; : ; : ; : ; : ; : ; : ; : ; •
+ MOSI _____ _______ _______ _______________ ___
+ 0x56 \_0_____/ 1 \_0_____/ 1 \_0_____/ 1 1 \_0_____/
+ • ; ; ; ; ; ; ; ; •
+ • ; ; ; ; ; ; ; ; •
+ MISO XXX__________ _______________________ _______ XXX
+ 0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX
+
+Legend::
+
+ • marks the start/end of transmission;
+ : marks when data is clocked into the peripheral;
+ ; marks when data is clocked into the controller;
+ X marks when line states are not specified.
+
+In this extension to the usual SPI protocol, the MOSI line state is specified to
+be kept high when CS is asserted but the controller is not clocking out data to
+the peripheral and also when CS is not asserted.
+
+Peripherals that require this extension must request it by setting the
+``SPI_MOSI_IDLE_HIGH`` bit into the mode attribute of their ``struct
+spi_device`` and call spi_setup(). Controllers that support this extension
+should indicate it by setting ``SPI_MOSI_IDLE_HIGH`` in the mode_bits attribute
+of their ``struct spi_controller``. The configuration to idle MOSI low is
+analogous but uses the ``SPI_MOSI_IDLE_LOW`` mode bit.
+
+
THANKS TO
---------
Contributors to Linux-SPI discussions include (in alphabetical order,
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 93f59ebb5b79..c8ba5e490850 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -3942,6 +3942,12 @@ int spi_setup(struct spi_device *spi)
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
return -EINVAL;
+ /* Check against conflicting MOSI idle configuration */
+ if ((spi->mode & SPI_MOSI_IDLE_LOW) && (spi->mode & SPI_MOSI_IDLE_HIGH)) {
+ dev_err(&spi->dev,
+ "setup: MOSI configured to idle low and high at the same time.\n");
+ return -EINVAL;
+ }
/*
* Help drivers fail *cleanly* when they need options
* that aren't supported with their current controller.
@@ -3950,6 +3956,7 @@ int spi_setup(struct spi_device *spi)
*/
bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD |
SPI_NO_TX | SPI_NO_RX);
+
ugly_bits = bad_bits &
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL);
diff --git a/include/uapi/linux/spi/spi.h b/include/uapi/linux/spi/spi.h
index ca56e477d161..ee4ac812b8f8 100644
--- a/include/uapi/linux/spi/spi.h
+++ b/include/uapi/linux/spi/spi.h
@@ -28,7 +28,8 @@
#define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */
#define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */
#define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */
-#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave mosi line low when idle */
+#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave MOSI line low when idle */
+#define SPI_MOSI_IDLE_HIGH _BITUL(18) /* leave MOSI line high when idle */
/*
* All the bits defined above should be covered by SPI_MODE_USER_MASK.
@@ -38,6 +39,6 @@
* These bits must not overlap. A static assert check should make sure of that.
* If adding extra bits, make sure to increase the bit index below as well.
*/
-#define SPI_MODE_USER_MASK (_BITUL(18) - 1)
+#define SPI_MODE_USER_MASK (_BITUL(19) - 1)
#endif /* _UAPI_SPI_H */
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v6 2/7] spi: bitbang: Implement support for MOSI idle state configuration
2024-06-29 19:04 [PATCH v6 0/7] Add support for AD4000 series of ADCs Marcelo Schmitt
2024-06-29 19:04 ` [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration Marcelo Schmitt
@ 2024-06-29 19:05 ` Marcelo Schmitt
2024-06-30 10:52 ` Jonathan Cameron
2024-07-08 21:19 ` David Lechner
2024-06-29 19:05 ` [PATCH v6 3/7] spi: spi-gpio: Add " Marcelo Schmitt
` (5 subsequent siblings)
7 siblings, 2 replies; 23+ messages in thread
From: Marcelo Schmitt @ 2024-06-29 19:05 UTC (permalink / raw)
To: broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
Some SPI peripherals may require strict MOSI line state when the controller
is not clocking out data.
Implement support for MOSI idle state configuration (low or high) by
setting the data output line level on controller setup and after transfers.
Bitbang operations now call controller specific set_mosi_idle() call back
to set MOSI to its idle state.
The MOSI line is kept at its idle state if no tx buffer is provided.
Acked-by: Nuno Sa <nuno.sa@analog.com>
Reviewed-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
---
drivers/spi/spi-bitbang.c | 24 ++++++++++++++++++++++++
include/linux/spi/spi_bitbang.h | 1 +
2 files changed, 25 insertions(+)
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index ca5cc67555c5..8cc522bf444c 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -63,21 +63,28 @@ static unsigned bitbang_txrx_8(
unsigned flags
)
{
+ struct spi_bitbang *bitbang;
unsigned bits = t->bits_per_word;
unsigned count = t->len;
const u8 *tx = t->tx_buf;
u8 *rx = t->rx_buf;
+ bitbang = spi_controller_get_devdata(spi->controller);
while (likely(count > 0)) {
u8 word = 0;
if (tx)
word = *tx++;
+ else
+ word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFF : 0;
word = txrx_word(spi, ns, word, bits, flags);
if (rx)
*rx++ = word;
count -= 1;
}
+ if (bitbang->set_mosi_idle)
+ bitbang->set_mosi_idle(spi);
+
return t->len - count;
}
@@ -92,21 +99,28 @@ static unsigned bitbang_txrx_16(
unsigned flags
)
{
+ struct spi_bitbang *bitbang;
unsigned bits = t->bits_per_word;
unsigned count = t->len;
const u16 *tx = t->tx_buf;
u16 *rx = t->rx_buf;
+ bitbang = spi_controller_get_devdata(spi->controller);
while (likely(count > 1)) {
u16 word = 0;
if (tx)
word = *tx++;
+ else
+ word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFF : 0;
word = txrx_word(spi, ns, word, bits, flags);
if (rx)
*rx++ = word;
count -= 2;
}
+ if (bitbang->set_mosi_idle)
+ bitbang->set_mosi_idle(spi);
+
return t->len - count;
}
@@ -121,21 +135,28 @@ static unsigned bitbang_txrx_32(
unsigned flags
)
{
+ struct spi_bitbang *bitbang;
unsigned bits = t->bits_per_word;
unsigned count = t->len;
const u32 *tx = t->tx_buf;
u32 *rx = t->rx_buf;
+ bitbang = spi_controller_get_devdata(spi->controller);
while (likely(count > 3)) {
u32 word = 0;
if (tx)
word = *tx++;
+ else
+ word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFFFFFF : 0;
word = txrx_word(spi, ns, word, bits, flags);
if (rx)
*rx++ = word;
count -= 4;
}
+ if (bitbang->set_mosi_idle)
+ bitbang->set_mosi_idle(spi);
+
return t->len - count;
}
@@ -211,6 +232,9 @@ int spi_bitbang_setup(struct spi_device *spi)
goto err_free;
}
+ if (bitbang->set_mosi_idle)
+ bitbang->set_mosi_idle(spi);
+
dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);
return 0;
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
index b930eca2ef7b..1a54b593c691 100644
--- a/include/linux/spi/spi_bitbang.h
+++ b/include/linux/spi/spi_bitbang.h
@@ -22,6 +22,7 @@ struct spi_bitbang {
#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
#define BITBANG_CS_INACTIVE 0
+ void (*set_mosi_idle)(struct spi_device *spi);
/* txrx_bufs() may handle dma mapping for transfers that don't
* already have one (transfer.{tx,rx}_dma is zero), or use PIO
*/
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v6 3/7] spi: spi-gpio: Add support for MOSI idle state configuration
2024-06-29 19:04 [PATCH v6 0/7] Add support for AD4000 series of ADCs Marcelo Schmitt
2024-06-29 19:04 ` [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration Marcelo Schmitt
2024-06-29 19:05 ` [PATCH v6 2/7] spi: bitbang: Implement support for MOSI idle state configuration Marcelo Schmitt
@ 2024-06-29 19:05 ` Marcelo Schmitt
2024-06-30 10:53 ` Jonathan Cameron
2024-06-29 19:06 ` [PATCH v6 4/7] spi: spi-axi-spi-engine: Add support for MOSI idle configuration Marcelo Schmitt
` (4 subsequent siblings)
7 siblings, 1 reply; 23+ messages in thread
From: Marcelo Schmitt @ 2024-06-29 19:05 UTC (permalink / raw)
To: broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
Implement MOSI idle low and MOSI idle high to better support peripherals
that request specific MOSI behavior.
Acked-by: Nuno Sa <nuno.sa@analog.com>
Reviewed-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
---
drivers/spi/spi-gpio.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 909cce109bba..d3b8c99f0cb4 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -236,6 +236,14 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
}
}
+static void spi_gpio_set_mosi_idle(struct spi_device *spi)
+{
+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+
+ gpiod_set_value_cansleep(spi_gpio->mosi,
+ !!(spi->mode & SPI_MOSI_IDLE_HIGH));
+}
+
static int spi_gpio_setup(struct spi_device *spi)
{
struct gpio_desc *cs;
@@ -411,7 +419,8 @@ static int spi_gpio_probe(struct platform_device *pdev)
host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
host->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL |
- SPI_CS_HIGH | SPI_LSB_FIRST;
+ SPI_CS_HIGH | SPI_LSB_FIRST | SPI_MOSI_IDLE_LOW |
+ SPI_MOSI_IDLE_HIGH;
if (!spi_gpio->mosi) {
/* HW configuration without MOSI pin
*
@@ -436,6 +445,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
host->flags |= SPI_CONTROLLER_GPIO_SS;
bb->chipselect = spi_gpio_chipselect;
bb->set_line_direction = spi_gpio_set_direction;
+ bb->set_mosi_idle = spi_gpio_set_mosi_idle;
if (host->flags & SPI_CONTROLLER_NO_TX) {
bb->txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v6 4/7] spi: spi-axi-spi-engine: Add support for MOSI idle configuration
2024-06-29 19:04 [PATCH v6 0/7] Add support for AD4000 series of ADCs Marcelo Schmitt
` (2 preceding siblings ...)
2024-06-29 19:05 ` [PATCH v6 3/7] spi: spi-gpio: Add " Marcelo Schmitt
@ 2024-06-29 19:06 ` Marcelo Schmitt
2024-06-29 19:06 ` [PATCH v6 5/7] dt-bindings: iio: adc: Add AD4000 Marcelo Schmitt
` (3 subsequent siblings)
7 siblings, 0 replies; 23+ messages in thread
From: Marcelo Schmitt @ 2024-06-29 19:06 UTC (permalink / raw)
To: broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
Implement MOSI idle low and MOSI idle high to better support peripherals
that request specific MOSI behavior.
Acked-by: Nuno Sa <nuno.sa@analog.com>
Reviewed-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
---
drivers/spi/spi-axi-spi-engine.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index 03588fac9215..9e8f2108e279 100644
--- a/drivers/spi/spi-axi-spi-engine.c
+++ b/drivers/spi/spi-axi-spi-engine.c
@@ -41,6 +41,7 @@
#define SPI_ENGINE_CONFIG_CPHA BIT(0)
#define SPI_ENGINE_CONFIG_CPOL BIT(1)
#define SPI_ENGINE_CONFIG_3WIRE BIT(2)
+#define SPI_ENGINE_CONFIG_SDO_IDLE_HIGH BIT(3)
#define SPI_ENGINE_INST_TRANSFER 0x0
#define SPI_ENGINE_INST_ASSERT 0x1
@@ -137,6 +138,10 @@ static unsigned int spi_engine_get_config(struct spi_device *spi)
config |= SPI_ENGINE_CONFIG_CPHA;
if (spi->mode & SPI_3WIRE)
config |= SPI_ENGINE_CONFIG_3WIRE;
+ if (spi->mode & SPI_MOSI_IDLE_HIGH)
+ config |= SPI_ENGINE_CONFIG_SDO_IDLE_HIGH;
+ if (spi->mode & SPI_MOSI_IDLE_LOW)
+ config &= ~SPI_ENGINE_CONFIG_SDO_IDLE_HIGH;
return config;
}
@@ -682,9 +687,13 @@ static int spi_engine_probe(struct platform_device *pdev)
host->num_chipselect = 8;
/* Some features depend of the IP core version. */
- if (ADI_AXI_PCORE_VER_MINOR(version) >= 2) {
- host->mode_bits |= SPI_CS_HIGH;
- host->setup = spi_engine_setup;
+ if (ADI_AXI_PCORE_VER_MAJOR(version) >= 1) {
+ if (ADI_AXI_PCORE_VER_MINOR(version) >= 2) {
+ host->mode_bits |= SPI_CS_HIGH;
+ host->setup = spi_engine_setup;
+ }
+ if (ADI_AXI_PCORE_VER_MINOR(version) >= 3)
+ host->mode_bits |= SPI_MOSI_IDLE_LOW | SPI_MOSI_IDLE_HIGH;
}
if (host->max_speed_hz == 0)
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v6 5/7] dt-bindings: iio: adc: Add AD4000
2024-06-29 19:04 [PATCH v6 0/7] Add support for AD4000 series of ADCs Marcelo Schmitt
` (3 preceding siblings ...)
2024-06-29 19:06 ` [PATCH v6 4/7] spi: spi-axi-spi-engine: Add support for MOSI idle configuration Marcelo Schmitt
@ 2024-06-29 19:06 ` Marcelo Schmitt
2024-06-29 19:06 ` [PATCH v6 6/7] iio: adc: Add support for AD4000 Marcelo Schmitt
` (2 subsequent siblings)
7 siblings, 0 replies; 23+ messages in thread
From: Marcelo Schmitt @ 2024-06-29 19:06 UTC (permalink / raw)
To: broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel,
Conor Dooley
Add device tree documentation for AD4000 series of ADC devices.
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
---
.../bindings/iio/adc/adi,ad4000.yaml | 197 ++++++++++++++++++
MAINTAINERS | 7 +
2 files changed, 204 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
new file mode 100644
index 000000000000..e413a9d8d2a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
@@ -0,0 +1,197 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,ad4000.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD4000 and similar Analog to Digital Converters
+
+maintainers:
+ - Marcelo Schmitt <marcelo.schmitt@analog.com>
+
+description: |
+ Analog Devices AD4000 family of Analog to Digital Converters with SPI support.
+ Specifications can be found at:
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad4000-4004-4008.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad4001-4005.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad4002-4006-4010.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad4003-4007-4011.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad4020-4021-4022.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4001.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4003.pdf
+
+$ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - const: adi,ad4000
+ - items:
+ - enum:
+ - adi,ad4004
+ - adi,ad4008
+ - const: adi,ad4000
+
+ - const: adi,ad4001
+ - items:
+ - enum:
+ - adi,ad4005
+ - const: adi,ad4001
+
+ - const: adi,ad4002
+ - items:
+ - enum:
+ - adi,ad4006
+ - adi,ad4010
+ - const: adi,ad4002
+
+ - const: adi,ad4003
+ - items:
+ - enum:
+ - adi,ad4007
+ - adi,ad4011
+ - const: adi,ad4003
+
+ - const: adi,ad4020
+ - items:
+ - enum:
+ - adi,ad4021
+ - adi,ad4022
+ - const: adi,ad4020
+
+ - const: adi,adaq4001
+
+ - const: adi,adaq4003
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 102040816 # for VIO > 2.7 V, 81300813 for VIO > 1.7 V
+
+ adi,sdi-pin:
+ $ref: /schemas/types.yaml#/definitions/string
+ enum: [ high, low, cs, sdi ]
+ default: sdi
+ description:
+ Describes how the ADC SDI pin is wired. A value of "sdi" indicates that
+ the ADC SDI is connected to host SDO. "high" indicates that the ADC SDI
+ pin is hard-wired to logic high (VIO). "low" indicates that it is
+ hard-wired low (GND). "cs" indicates that the ADC SDI pin is connected to
+ the host CS line.
+
+ '#daisy-chained-devices': true
+
+ vdd-supply:
+ description: A 1.8V supply that powers the chip (VDD).
+
+ vio-supply:
+ description:
+ A 1.8V to 5.5V supply for the digital inputs and outputs (VIO).
+
+ ref-supply:
+ description:
+ A 2.5 to 5V supply for the external reference voltage (REF).
+
+ cnv-gpios:
+ description:
+ When provided, this property indicates the GPIO that is connected to the
+ CNV pin.
+ maxItems: 1
+
+ adi,high-z-input:
+ type: boolean
+ description:
+ High-Z mode allows the amplifier and RC filter in front of the ADC to be
+ chosen based on the signal bandwidth of interest, rather than the settling
+ requirements of the switched capacitor SAR ADC inputs.
+
+ adi,gain-milli:
+ description: |
+ The hardware gain applied to the ADC input (in milli units).
+ The gain provided by the ADC input scaler is defined by the hardware
+ connections between chip pins OUT+, R1K-, R1K1-, R1K+, R1K1+, and OUT-.
+ If not present, default to 1000 (no actual gain applied).
+ $ref: /schemas/types.yaml#/definitions/uint16
+ enum: [454, 909, 1000, 1900]
+ default: 1000
+
+ interrupts:
+ description:
+ The SDO pin can also function as a busy indicator. This node should be
+ connected to an interrupt that is triggered when the SDO line goes low
+ while the SDI line is high and the CNV line is low ("3-wire" mode) or the
+ SDI line is low and the CNV line is high ("4-wire" mode); or when the SDO
+ line goes high while the SDI and CNV lines are high (chain mode),
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - vio-supply
+ - ref-supply
+
+allOf:
+ # The configuration register can only be accessed if SDI is connected to MOSI
+ - if:
+ required:
+ - adi,sdi-pin
+ then:
+ properties:
+ adi,high-z-input: false
+ # chain mode has lower SCLK max rate
+ - if:
+ required:
+ - '#daisy-chained-devices'
+ then:
+ properties:
+ spi-max-frequency:
+ maximum: 50000000 # for VIO > 2.7 V, 40000000 for VIO > 1.7 V
+ # Gain property only applies to ADAQ devices
+ - if:
+ properties:
+ compatible:
+ not:
+ contains:
+ enum:
+ - adi,adaq4001
+ - adi,adaq4003
+ then:
+ properties:
+ adi,gain-milli: false
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ adc@0 {
+ compatible = "adi,ad4020";
+ reg = <0>;
+ spi-max-frequency = <71000000>;
+ vdd-supply = <&supply_1_8V>;
+ vio-supply = <&supply_1_8V>;
+ ref-supply = <&supply_5V>;
+ adi,sdi-pin = "cs";
+ cnv-gpios = <&gpio0 88 GPIO_ACTIVE_HIGH>;
+ };
+ };
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ adc@0 {
+ compatible = "adi,adaq4003";
+ reg = <0>;
+ spi-max-frequency = <80000000>;
+ vdd-supply = <&supply_1_8V>;
+ vio-supply = <&supply_1_8V>;
+ ref-supply = <&supply_5V>;
+ adi,high-z-input;
+ adi,gain-milli = /bits/ 16 <454>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 9517093d889d..9aa6531f7cf2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1199,6 +1199,13 @@ W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
F: drivers/iio/dac/ad3552r.c
+ANALOG DEVICES INC AD4000 DRIVER
+M: Marcelo Schmitt <marcelo.schmitt@analog.com>
+L: linux-iio@vger.kernel.org
+S: Supported
+W: https://ez.analog.com/linux-software-drivers
+F: Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
+
ANALOG DEVICES INC AD4130 DRIVER
M: Cosmin Tanislav <cosmin.tanislav@analog.com>
L: linux-iio@vger.kernel.org
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v6 6/7] iio: adc: Add support for AD4000
2024-06-29 19:04 [PATCH v6 0/7] Add support for AD4000 series of ADCs Marcelo Schmitt
` (4 preceding siblings ...)
2024-06-29 19:06 ` [PATCH v6 5/7] dt-bindings: iio: adc: Add AD4000 Marcelo Schmitt
@ 2024-06-29 19:06 ` Marcelo Schmitt
2024-06-30 11:17 ` Jonathan Cameron
` (2 more replies)
2024-06-29 19:07 ` [PATCH v6 7/7] docs: iio: Add documentation " Marcelo Schmitt
2024-07-29 18:02 ` (subset) [PATCH v6 0/7] Add support for AD4000 series of ADCs Mark Brown
7 siblings, 3 replies; 23+ messages in thread
From: Marcelo Schmitt @ 2024-06-29 19:06 UTC (permalink / raw)
To: broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
Add support for AD4000 series of low noise, low power, high speed,
successive approximation register (SAR) ADCs.
Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
---
MAINTAINERS | 1 +
drivers/iio/adc/Kconfig | 12 +
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/ad4000.c | 708 +++++++++++++++++++++++++++++++++++++++
4 files changed, 722 insertions(+)
create mode 100644 drivers/iio/adc/ad4000.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 9aa6531f7cf2..f4ffedada8ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1205,6 +1205,7 @@ L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
+F: drivers/iio/adc/ad4000.c
ANALOG DEVICES INC AD4130 DRIVER
M: Cosmin Tanislav <cosmin.tanislav@analog.com>
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index b8184706c7d1..5bbe843916a3 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -21,6 +21,18 @@ config AD_SIGMA_DELTA
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
+config AD4000
+ tristate "Analog Devices AD4000 ADC Driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Analog Devices AD4000 high speed
+ SPI analog to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad4000.
+
config AD4130
tristate "Analog Device AD4130 ADC Driver"
depends on SPI
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 51298c52b223..f4361df40cca 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -6,6 +6,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
+obj-$(CONFIG_AD4000) += ad4000.o
obj-$(CONFIG_AD4130) += ad4130.o
obj-$(CONFIG_AD7091R) += ad7091r-base.o
obj-$(CONFIG_AD7091R5) += ad7091r5.o
diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c
new file mode 100644
index 000000000000..6e08466d479c
--- /dev/null
+++ b/drivers/iio/adc/ad4000.c
@@ -0,0 +1,708 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AD4000 SPI ADC driver
+ *
+ * Copyright 2024 Analog Devices Inc.
+ */
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/byteorder/generic.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+#include <linux/util_macros.h>
+#include <linux/iio/iio.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define AD4000_READ_COMMAND 0x54
+#define AD4000_WRITE_COMMAND 0x14
+
+#define AD4000_CONFIG_REG_DEFAULT 0xE1
+
+/* AD4000 Configuration Register programmable bits */
+#define AD4000_CFG_SPAN_COMP BIT(3) /* Input span compression */
+#define AD4000_CFG_HIGHZ BIT(2) /* High impedance mode */
+
+#define AD4000_SCALE_OPTIONS 2
+
+#define AD4000_TQUIET1_NS 190
+#define AD4000_TQUIET2_NS 60
+#define AD4000_TCONV_NS 320
+
+#define __AD4000_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .differential = 1, \
+ .channel = 0, \
+ .channel2 = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\
+ .scan_type = { \
+ .sign = _sign, \
+ .realbits = _real_bits, \
+ .storagebits = _storage_bits, \
+ .shift = _storage_bits - _real_bits, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access) \
+ __AD4000_DIFF_CHANNEL((_sign), (_real_bits), \
+ ((_real_bits) > 16 ? 32 : 16), (_reg_access))
+
+#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access)\
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = 0, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\
+ .scan_type = { \
+ .sign = _sign, \
+ .realbits = _real_bits, \
+ .storagebits = _storage_bits, \
+ .shift = _storage_bits - _real_bits, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access) \
+ __AD4000_PSEUDO_DIFF_CHANNEL((_sign), (_real_bits), \
+ ((_real_bits) > 16 ? 32 : 16), (_reg_access))
+
+static const char * const ad4000_power_supplies[] = {
+ "vdd", "vio"
+};
+
+enum ad4000_sdi {
+ AD4000_SDI_MOSI,
+ AD4000_SDI_VIO,
+ AD4000_SDI_CS,
+ AD4000_SDI_GND,
+};
+
+/* maps adi,sdi-pin property value to enum */
+static const char * const ad4000_sdi_pin[] = {
+ [AD4000_SDI_MOSI] = "sdi",
+ [AD4000_SDI_VIO] = "high",
+ [AD4000_SDI_CS] = "cs",
+ [AD4000_SDI_GND] = "low",
+};
+
+struct ad4000_chip_info {
+ const char *dev_name;
+ struct iio_chan_spec chan_spec;
+ struct iio_chan_spec reg_access_chan_spec;
+ bool has_hardware_gain;
+};
+
+static const struct ad4000_chip_info ad4000_chip_info = {
+ .dev_name = "ad4000",
+ .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0),
+ .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1),
+};
+
+static const struct ad4000_chip_info ad4001_chip_info = {
+ .dev_name = "ad4001",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1),
+};
+
+static const struct ad4000_chip_info ad4002_chip_info = {
+ .dev_name = "ad4002",
+ .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0),
+ .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1),
+};
+
+static const struct ad4000_chip_info ad4003_chip_info = {
+ .dev_name = "ad4003",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
+};
+
+static const struct ad4000_chip_info ad4004_chip_info = {
+ .dev_name = "ad4004",
+ .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0),
+ .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1),
+};
+
+static const struct ad4000_chip_info ad4005_chip_info = {
+ .dev_name = "ad4005",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1),
+};
+
+static const struct ad4000_chip_info ad4006_chip_info = {
+ .dev_name = "ad4006",
+ .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0),
+ .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1),
+};
+
+static const struct ad4000_chip_info ad4007_chip_info = {
+ .dev_name = "ad4007",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
+};
+
+static const struct ad4000_chip_info ad4008_chip_info = {
+ .dev_name = "ad4008",
+ .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0),
+ .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1),
+};
+
+static const struct ad4000_chip_info ad4010_chip_info = {
+ .dev_name = "ad4010",
+ .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0),
+ .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1),
+};
+
+static const struct ad4000_chip_info ad4011_chip_info = {
+ .dev_name = "ad4011",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
+};
+
+static const struct ad4000_chip_info ad4020_chip_info = {
+ .dev_name = "ad4020",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1),
+};
+
+static const struct ad4000_chip_info ad4021_chip_info = {
+ .dev_name = "ad4021",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1),
+};
+
+static const struct ad4000_chip_info ad4022_chip_info = {
+ .dev_name = "ad4022",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1),
+};
+
+static const struct ad4000_chip_info adaq4001_chip_info = {
+ .dev_name = "adaq4001",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1),
+ .has_hardware_gain = true,
+};
+
+static const struct ad4000_chip_info adaq4003_chip_info = {
+ .dev_name = "adaq4003",
+ .chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
+ .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
+ .has_hardware_gain = true,
+};
+
+struct ad4000_state {
+ struct spi_device *spi;
+ struct gpio_desc *cnv_gpio;
+ struct spi_transfer xfers[2];
+ struct spi_message msg;
+ struct mutex lock; /* Protect read modify write cycle */
+ int vref_mv;
+ enum ad4000_sdi sdi_pin;
+ bool span_comp;
+ u16 gain_milli;
+ int scale_tbl[AD4000_SCALE_OPTIONS][2];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the transfer buffers
+ * to live in their own cache lines.
+ */
+ struct {
+ union {
+ __be16 sample_buf16;
+ __be32 sample_buf32;
+ } data;
+ s64 timestamp __aligned(8);
+ } scan __aligned(IIO_DMA_MINALIGN);
+ u8 tx_buf[2];
+ u8 rx_buf[2];
+};
+
+static void ad4000_fill_scale_tbl(struct ad4000_state *st,
+ struct iio_chan_spec const *chan)
+{
+ int val, tmp0, tmp1;
+ int scale_bits;
+ u64 tmp2;
+
+ /*
+ * ADCs that output two's complement code have one less bit to express
+ * voltage magnitude.
+ */
+ if (chan->scan_type.sign == 's')
+ scale_bits = chan->scan_type.realbits - 1;
+ else
+ scale_bits = chan->scan_type.realbits;
+
+ /*
+ * The gain is stored as a fraction of 1000 and, as we need to
+ * divide vref_mv by the gain, we invert the gain/1000 fraction.
+ * Also multiply by an extra MILLI to preserve precision.
+ * Thus, we have MILLI * MILLI equals MICRO as fraction numerator.
+ */
+ val = mult_frac(st->vref_mv, MICRO, st->gain_milli);
+ /* Would multiply by NANO here but we multiplied by extra MILLI */
+ tmp2 = shift_right((u64)val * MICRO, scale_bits);
+ tmp0 = div_s64_rem(tmp2, NANO, &tmp1);
+ /* Store scale for when span compression is disabled */
+ st->scale_tbl[0][0] = tmp0; /* Integer part */
+ st->scale_tbl[0][1] = abs(tmp1); /* Fractional part */
+ /* Store scale for when span compression is enabled */
+ st->scale_tbl[1][0] = tmp0;
+ /* The integer part is always zero so don't bother to divide it. */
+ if (chan->differential)
+ st->scale_tbl[1][1] = DIV_ROUND_CLOSEST(abs(tmp1) * 4, 5);
+ else
+ st->scale_tbl[1][1] = DIV_ROUND_CLOSEST(abs(tmp1) * 9, 10);
+}
+
+static int ad4000_write_reg(struct ad4000_state *st, uint8_t val)
+{
+ st->tx_buf[0] = AD4000_WRITE_COMMAND;
+ st->tx_buf[1] = val;
+ return spi_write(st->spi, st->tx_buf, ARRAY_SIZE(st->tx_buf));
+}
+
+static int ad4000_read_reg(struct ad4000_state *st, unsigned int *val)
+{
+ struct spi_transfer t = {
+ .tx_buf = st->tx_buf,
+ .rx_buf = st->rx_buf,
+ .len = 2,
+ };
+ int ret;
+
+ st->tx_buf[0] = AD4000_READ_COMMAND;
+ ret = spi_sync_transfer(st->spi, &t, 1);
+ if (ret < 0)
+ return ret;
+
+ *val = st->rx_buf[1];
+ return ret;
+}
+
+static int ad4000_convert_and_acquire(struct ad4000_state *st)
+{
+ int ret;
+
+ /*
+ * In 4-wire mode, the CNV line is held high for the entire conversion
+ * and acquisition process. In other modes, the CNV GPIO is optional
+ * and, if provided, replaces controller CS. If CNV GPIO is not defined
+ * gpiod_set_value_cansleep() has no effect.
+ */
+ gpiod_set_value_cansleep(st->cnv_gpio, 1);
+ ret = spi_sync(st->spi, &st->msg);
+ gpiod_set_value_cansleep(st->cnv_gpio, 0);
+
+ return ret;
+}
+
+static int ad4000_single_conversion(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val)
+{
+ struct ad4000_state *st = iio_priv(indio_dev);
+ u32 sample;
+ int ret;
+
+ ret = ad4000_convert_and_acquire(st);
+ if (ret < 0)
+ return ret;
+
+ if (chan->scan_type.storagebits > 16)
+ sample = be32_to_cpu(st->scan.data.sample_buf32);
+ else
+ sample = be16_to_cpu(st->scan.data.sample_buf16);
+
+ sample >>= chan->scan_type.shift;
+
+ if (chan->scan_type.sign == 's')
+ *val = sign_extend32(sample, chan->scan_type.realbits - 1);
+
+ return IIO_VAL_INT;
+}
+
+static int ad4000_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long info)
+{
+ struct ad4000_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return ad4000_single_conversion(indio_dev, chan, val);
+ unreachable();
+ case IIO_CHAN_INFO_SCALE:
+ *val = st->scale_tbl[st->span_comp][0];
+ *val2 = st->scale_tbl[st->span_comp][1];
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = 0;
+ if (st->span_comp)
+ *val = mult_frac(st->vref_mv, 1, 10);
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4000_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct ad4000_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (int *)st->scale_tbl;
+ *length = AD4000_SCALE_OPTIONS * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4000_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+}
+
+static int ad4000_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
+{
+ struct ad4000_state *st = iio_priv(indio_dev);
+ unsigned int reg_val;
+ bool span_comp_en;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ guard(mutex)(&st->lock);
+
+ ret = ad4000_read_reg(st, ®_val);
+ if (ret < 0)
+ return ret;
+
+ span_comp_en = val2 == st->scale_tbl[1][1];
+ reg_val &= ~AD4000_CFG_SPAN_COMP;
+ reg_val |= FIELD_PREP(AD4000_CFG_SPAN_COMP, span_comp_en);
+
+ ret = ad4000_write_reg(st, reg_val);
+ if (ret < 0)
+ return ret;
+
+ st->span_comp = span_comp_en;
+ return ret;
+ }
+ unreachable();
+ default:
+ return -EINVAL;
+ }
+}
+
+static irqreturn_t ad4000_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad4000_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = ad4000_convert_and_acquire(st);
+ if (ret < 0)
+ goto err_out;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp);
+
+err_out:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static const struct iio_info ad4000_reg_access_info = {
+ .read_raw = &ad4000_read_raw,
+ .read_avail = &ad4000_read_avail,
+ .write_raw = &ad4000_write_raw,
+ .write_raw_get_fmt = &ad4000_write_raw_get_fmt,
+};
+
+static const struct iio_info ad4000_info = {
+ .read_raw = &ad4000_read_raw,
+};
+
+/*
+ * This executes a data sample transfer for when the device connections are
+ * in "3-wire" mode, selected when the adi,sdi-pin device tree property is
+ * absent or set to "high". In this connection mode, the ADC SDI pin is
+ * connected to MOSI or to VIO and ADC CNV pin is connected either to a SPI
+ * controller CS or to a GPIO.
+ * AD4000 series of devices initiate conversions on the rising edge of CNV pin.
+ *
+ * If the CNV pin is connected to an SPI controller CS line (which is by default
+ * active low), the ADC readings would have a latency (delay) of one read.
+ * Moreover, since we also do ADC sampling for filling the buffer on triggered
+ * buffer mode, the timestamps of buffer readings would be disarranged.
+ * To prevent the read latency and reduce the time discrepancy between the
+ * sample read request and the time of actual sampling by the ADC, do a
+ * preparatory transfer to pulse the CS/CNV line.
+ */
+static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st,
+ const struct iio_chan_spec *chan)
+{
+ unsigned int cnv_pulse_time = AD4000_TCONV_NS;
+ struct spi_transfer *xfers = st->xfers;
+
+ xfers[0].cs_change = 1;
+ xfers[0].cs_change_delay.value = cnv_pulse_time;
+ xfers[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
+
+ xfers[1].rx_buf = &st->scan.data;
+ xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits);
+ xfers[1].delay.value = AD4000_TQUIET2_NS;
+ xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS;
+
+ spi_message_init_with_transfers(&st->msg, st->xfers, 2);
+
+ return devm_spi_optimize_message(&st->spi->dev, st->spi, &st->msg);
+}
+
+/*
+ * This executes a data sample transfer for when the device connections are
+ * in "4-wire" mode, selected when the adi,sdi-pin device tree property is
+ * set to "cs". In this connection mode, the controller CS pin is connected to
+ * ADC SDI pin and a GPIO is connected to ADC CNV pin.
+ * The GPIO connected to ADC CNV pin is set outside of the SPI transfer.
+ */
+static int ad4000_prepare_4wire_mode_message(struct ad4000_state *st,
+ const struct iio_chan_spec *chan)
+{
+ unsigned int cnv_to_sdi_time = AD4000_TCONV_NS;
+ struct spi_transfer *xfers = st->xfers;
+
+ /*
+ * Dummy transfer to cause enough delay between CNV going high and SDI
+ * going low.
+ */
+ xfers[0].cs_off = 1;
+ xfers[0].delay.value = cnv_to_sdi_time;
+ xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS;
+
+ xfers[1].rx_buf = &st->scan.data;
+ xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits);
+
+ spi_message_init_with_transfers(&st->msg, st->xfers, 2);
+
+ return devm_spi_optimize_message(&st->spi->dev, st->spi, &st->msg);
+}
+
+static int ad4000_config(struct ad4000_state *st)
+{
+ unsigned int reg_val = AD4000_CONFIG_REG_DEFAULT;
+
+ if (device_property_present(&st->spi->dev, "adi,high-z-input"))
+ reg_val |= FIELD_PREP(AD4000_CFG_HIGHZ, 1);
+
+ return ad4000_write_reg(st, reg_val);
+}
+
+static int ad4000_probe(struct spi_device *spi)
+{
+ const struct ad4000_chip_info *chip;
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ad4000_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ chip = spi_get_device_match_data(spi);
+ if (!chip)
+ return -EINVAL;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4000_power_supplies),
+ ad4000_power_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable power supplies\n");
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "ref");
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to get ref regulator reference\n");
+ st->vref_mv = ret / 1000;
+
+ st->cnv_gpio = devm_gpiod_get_optional(dev, "cnv", GPIOD_OUT_HIGH);
+ if (IS_ERR(st->cnv_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->cnv_gpio),
+ "Failed to get CNV GPIO");
+
+ ret = device_property_match_property_string(dev, "adi,sdi-pin",
+ ad4000_sdi_pin,
+ ARRAY_SIZE(ad4000_sdi_pin));
+ if (ret < 0 && ret != -EINVAL)
+ return dev_err_probe(dev, ret,
+ "getting adi,sdi-pin property failed\n");
+
+ /* Default to usual SPI connections if pin properties are not present */
+ st->sdi_pin = ret == -EINVAL ? AD4000_SDI_MOSI : ret;
+ switch (st->sdi_pin) {
+ case AD4000_SDI_MOSI:
+ indio_dev->info = &ad4000_reg_access_info;
+ indio_dev->channels = &chip->reg_access_chan_spec;
+
+ /*
+ * In "3-wire mode", the ADC SDI line must be kept high when
+ * data is not being clocked out of the controller.
+ * Request the SPI controller to make MOSI idle high.
+ */
+ spi->mode |= SPI_MOSI_IDLE_HIGH;
+ ret = spi_setup(spi);
+ if (ret < 0)
+ return ret;
+
+ ret = ad4000_prepare_3wire_mode_message(st, indio_dev->channels);
+ if (ret)
+ return ret;
+
+ ret = ad4000_config(st);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to config device\n");
+
+ break;
+ case AD4000_SDI_VIO:
+ indio_dev->info = &ad4000_info;
+ indio_dev->channels = &chip->chan_spec;
+ ret = ad4000_prepare_3wire_mode_message(st, indio_dev->channels);
+ if (ret)
+ return ret;
+
+ break;
+ case AD4000_SDI_CS:
+ indio_dev->info = &ad4000_info;
+ indio_dev->channels = &chip->chan_spec;
+ ret = ad4000_prepare_4wire_mode_message(st, indio_dev->channels);
+ if (ret)
+ return ret;
+
+ break;
+ case AD4000_SDI_GND:
+ return dev_err_probe(dev, -EPROTONOSUPPORT,
+ "Unsupported connection mode\n");
+
+ default:
+ return dev_err_probe(dev, -EINVAL, "Unrecognized connection mode\n");
+ }
+
+ indio_dev->name = chip->dev_name;
+ indio_dev->num_channels = 1;
+
+ devm_mutex_init(dev, &st->lock);
+
+ st->gain_milli = 1000;
+ if (chip->has_hardware_gain &&
+ device_property_present(dev, "adi,gain-milli")) {
+ ret = device_property_read_u16(dev, "adi,gain-milli",
+ &st->gain_milli);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read gain property\n");
+ }
+
+ ad4000_fill_scale_tbl(st, indio_dev->channels);
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad4000_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct spi_device_id ad4000_id[] = {
+ { "ad4000", (kernel_ulong_t)&ad4000_chip_info },
+ { "ad4001", (kernel_ulong_t)&ad4001_chip_info },
+ { "ad4002", (kernel_ulong_t)&ad4002_chip_info },
+ { "ad4003", (kernel_ulong_t)&ad4003_chip_info },
+ { "ad4004", (kernel_ulong_t)&ad4004_chip_info },
+ { "ad4005", (kernel_ulong_t)&ad4005_chip_info },
+ { "ad4006", (kernel_ulong_t)&ad4006_chip_info },
+ { "ad4007", (kernel_ulong_t)&ad4007_chip_info },
+ { "ad4008", (kernel_ulong_t)&ad4008_chip_info },
+ { "ad4010", (kernel_ulong_t)&ad4010_chip_info },
+ { "ad4011", (kernel_ulong_t)&ad4011_chip_info },
+ { "ad4020", (kernel_ulong_t)&ad4020_chip_info },
+ { "ad4021", (kernel_ulong_t)&ad4021_chip_info },
+ { "ad4022", (kernel_ulong_t)&ad4022_chip_info },
+ { "adaq4001", (kernel_ulong_t)&adaq4001_chip_info },
+ { "adaq4003", (kernel_ulong_t)&adaq4003_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad4000_id);
+
+static const struct of_device_id ad4000_of_match[] = {
+ { .compatible = "adi,ad4000", .data = &ad4000_chip_info },
+ { .compatible = "adi,ad4001", .data = &ad4001_chip_info },
+ { .compatible = "adi,ad4002", .data = &ad4002_chip_info },
+ { .compatible = "adi,ad4003", .data = &ad4003_chip_info },
+ { .compatible = "adi,ad4004", .data = &ad4004_chip_info },
+ { .compatible = "adi,ad4005", .data = &ad4005_chip_info },
+ { .compatible = "adi,ad4006", .data = &ad4006_chip_info },
+ { .compatible = "adi,ad4007", .data = &ad4007_chip_info },
+ { .compatible = "adi,ad4008", .data = &ad4008_chip_info },
+ { .compatible = "adi,ad4010", .data = &ad4010_chip_info },
+ { .compatible = "adi,ad4011", .data = &ad4011_chip_info },
+ { .compatible = "adi,ad4020", .data = &ad4020_chip_info },
+ { .compatible = "adi,ad4021", .data = &ad4021_chip_info },
+ { .compatible = "adi,ad4022", .data = &ad4022_chip_info },
+ { .compatible = "adi,adaq4001", .data = &adaq4001_chip_info },
+ { .compatible = "adi,adaq4003", .data = &adaq4003_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad4000_of_match);
+
+static struct spi_driver ad4000_driver = {
+ .driver = {
+ .name = "ad4000",
+ .of_match_table = ad4000_of_match,
+ },
+ .probe = ad4000_probe,
+ .id_table = ad4000_id,
+};
+module_spi_driver(ad4000_driver);
+
+MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD4000 ADC driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH v6 7/7] docs: iio: Add documentation for AD4000
2024-06-29 19:04 [PATCH v6 0/7] Add support for AD4000 series of ADCs Marcelo Schmitt
` (5 preceding siblings ...)
2024-06-29 19:06 ` [PATCH v6 6/7] iio: adc: Add support for AD4000 Marcelo Schmitt
@ 2024-06-29 19:07 ` Marcelo Schmitt
2024-07-08 21:25 ` David Lechner
2024-07-29 18:02 ` (subset) [PATCH v6 0/7] Add support for AD4000 series of ADCs Mark Brown
7 siblings, 1 reply; 23+ messages in thread
From: Marcelo Schmitt @ 2024-06-29 19:07 UTC (permalink / raw)
To: broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
Document wiring configurations for the AD4000 series of ADCs.
Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
---
Documentation/iio/ad4000.rst | 131 +++++++++++++++++++++++++++++++++++
Documentation/iio/index.rst | 1 +
MAINTAINERS | 1 +
3 files changed, 133 insertions(+)
create mode 100644 Documentation/iio/ad4000.rst
diff --git a/Documentation/iio/ad4000.rst b/Documentation/iio/ad4000.rst
new file mode 100644
index 000000000000..de8fd3ae6e62
--- /dev/null
+++ b/Documentation/iio/ad4000.rst
@@ -0,0 +1,131 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+=============
+AD4000 driver
+=============
+
+Device driver for Analog Devices Inc. AD4000 series of ADCs.
+
+Supported devices
+=================
+
+* `AD4000 <https://www.analog.com/AD4000>`_
+* `AD4001 <https://www.analog.com/AD4001>`_
+* `AD4002 <https://www.analog.com/AD4002>`_
+* `AD4003 <https://www.analog.com/AD4003>`_
+* `AD4004 <https://www.analog.com/AD4004>`_
+* `AD4005 <https://www.analog.com/AD4005>`_
+* `AD4006 <https://www.analog.com/AD4006>`_
+* `AD4007 <https://www.analog.com/AD4007>`_
+* `AD4008 <https://www.analog.com/AD4008>`_
+* `AD4010 <https://www.analog.com/AD4010>`_
+* `AD4011 <https://www.analog.com/AD4011>`_
+* `AD4020 <https://www.analog.com/AD4020>`_
+* `AD4021 <https://www.analog.com/AD4021>`_
+* `AD4022 <https://www.analog.com/AD4022>`_
+* `ADAQ4001 <https://www.analog.com/ADAQ4001>`_
+* `ADAQ4003 <https://www.analog.com/ADAQ4003>`_
+
+Wiring connections
+------------------
+
+Devices of the AD4000 series can be connected to the SPI host controller in a
+few different modes.
+
+CS mode, 3-wire turbo mode
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Datasheet "3-wire" mode is what most resembles standard SPI connection which,
+for these devices, comprises of connecting the controller CS line to device CNV
+pin and other SPI lines as usual. This configuration is (misleadingly) called
+"CS Mode, 3-Wire Turbo Mode" connection in datasheets.
+NOTE: The datasheet definition of 3-wire mode for the AD4000 series is NOT the
+same of standard spi-3wire mode.
+This is the only connection mode that allows configuration register access but
+it requires the SPI controller to support the ``SPI_MOSI_IDLE_HIGH`` feature.
+
+Omit the ``adi,sdi-pin`` property in device tree to select this mode.
+
+::
+
+ +-------------+
+ + ----------------------------------| SDO |
+ | | |
+ | +-------------------| CS |
+ | v | |
+ | +--------------------+ | HOST |
+ | | CNV | | |
+ +--->| SDI AD4000 SDO |-------->| SDI |
+ | SCK | | |
+ +--------------------+ | |
+ ^ | |
+ +--------------------| SCLK |
+ +-------------+
+
+CS mode, 3-wire, without busy indicator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Another wiring configuration supported as "3-wire" mode has the SDI pin
+hard-wired to digital input/output interface supply (VIO). In this setup, the
+controller is not required to support ``SPI_MOSI_IDLE_HIGH`` but register access
+is not possible. This connection mode saves one wire and works with any SPI
+controller.
+
+Set the ``adi,sdi-pin`` device tree property to ``"high"`` to select this mode.
+
+::
+
+ +-------------+
+ +--------------------| CS |
+ v | |
+ VIO +--------------------+ | HOST |
+ | | CNV | | |
+ +--->| SDI AD4000 SDO |-------->| SDI |
+ | SCK | | |
+ +--------------------+ | |
+ ^ | |
+ +--------------------| SCLK |
+ +-------------+
+
+Alternatively, a GPIO may be connected to the device CNV pin. This is similar to
+the previous wiring configuration but saves the use of a CS line.
+
+::
+
+ +-------------+
+ +--------------------| GPIO |
+ v | |
+ VIO +--------------------+ | HOST |
+ | | CNV | | |
+ +--->| SDI AD4000 SDO |-------->| SDI |
+ | SCK | | |
+ +--------------------+ | |
+ ^ | |
+ +--------------------| SCLK |
+ +-------------+
+
+CS mode, 4-wire without busy indicator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In datasheet "4-wire" mode, the controller CS line is connected to the ADC SDI
+pin and a GPIO is connected to the ADC CNV pin. This connection mode may better
+suit scenarios where multiple ADCs can share one CNV trigger.
+
+Set ``adi,sdi-pin`` to ``"cs"`` to select this mode.
+
+
+::
+
+ +-------------+
+ + ----------------------------------| CS |
+ | | |
+ | +-------------------| GPIO |
+ | v | |
+ | +--------------------+ | HOST |
+ | | CNV | | |
+ +--->| SDI AD4000 SDO |-------->| SDI |
+ | SCK | | |
+ +--------------------+ | |
+ ^ | |
+ +--------------------| SCLK |
+ +-------------+
diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst
index 4c13bfa2865c..5df157a44923 100644
--- a/Documentation/iio/index.rst
+++ b/Documentation/iio/index.rst
@@ -17,6 +17,7 @@ Industrial I/O Kernel Drivers
.. toctree::
:maxdepth: 1
+ ad4000
ad7944
adis16475
adis16480
diff --git a/MAINTAINERS b/MAINTAINERS
index f4ffedada8ea..a03b3db9157c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1205,6 +1205,7 @@ L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
+F: Documentation/iio/ad4000.rst
F: drivers/iio/adc/ad4000.c
ANALOG DEVICES INC AD4130 DRIVER
--
2.43.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration
2024-06-29 19:04 ` [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration Marcelo Schmitt
@ 2024-06-30 10:47 ` Jonathan Cameron
2024-07-01 17:30 ` Marcelo Schmitt
2024-07-08 21:15 ` David Lechner
1 sibling, 1 reply; 23+ messages in thread
From: Jonathan Cameron @ 2024-06-30 10:47 UTC (permalink / raw)
To: Marcelo Schmitt
Cc: broonie, lars, Michael.Hennerich, robh+dt, krzysztof.kozlowski+dt,
conor+dt, nuno.sa, dlechner, corbet, marcelo.schmitt1, linux-iio,
devicetree, linux-spi, linux-doc, linux-kernel
On Sat, 29 Jun 2024 16:04:40 -0300
Marcelo Schmitt <marcelo.schmitt@analog.com> wrote:
> The behavior of an SPI controller data output line (SDO or MOSI or COPI
> (Controller Output Peripheral Input) for disambiguation) is usually not
> specified when the controller is not clocking out data on SCLK edges.
> However, there do exist SPI peripherals that require specific MOSI line
> state when data is not being clocked out of the controller.
>
> Conventional SPI controllers may set the MOSI line on SCLK edges then bring
> it low when no data is going out or leave the line the state of the last
> transfer bit. More elaborated controllers are capable to set the MOSI idle
> state according to different configurable levels and thus are more suitable
> for interfacing with demanding peripherals.
>
> Add SPI mode bits to allow peripherals to request explicit MOSI idle state
> when needed.
>
> When supporting a particular MOSI idle configuration, the data output line
> state is expected to remain at the configured level when the controller is
> not clocking out data. When a device that needs a specific MOSI idle state
> is identified, its driver should request the MOSI idle configuration by
> setting the proper SPI mode bit.
>
> Acked-by: Nuno Sa <nuno.sa@analog.com>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
I always like to see some nice ascii art. Very nice documentation.
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index 93f59ebb5b79..c8ba5e490850 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -3950,6 +3956,7 @@ int spi_setup(struct spi_device *spi)
> */
> bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD |
> SPI_NO_TX | SPI_NO_RX);
> +
Trivial grumpy comment. Don't touch white space in unrelated code!
> ugly_bits = bad_bits &
> (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
> SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL);
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 2/7] spi: bitbang: Implement support for MOSI idle state configuration
2024-06-29 19:05 ` [PATCH v6 2/7] spi: bitbang: Implement support for MOSI idle state configuration Marcelo Schmitt
@ 2024-06-30 10:52 ` Jonathan Cameron
2024-07-08 21:19 ` David Lechner
1 sibling, 0 replies; 23+ messages in thread
From: Jonathan Cameron @ 2024-06-30 10:52 UTC (permalink / raw)
To: Marcelo Schmitt
Cc: broonie, lars, Michael.Hennerich, robh+dt, krzysztof.kozlowski+dt,
conor+dt, nuno.sa, dlechner, corbet, marcelo.schmitt1, linux-iio,
devicetree, linux-spi, linux-doc, linux-kernel
On Sat, 29 Jun 2024 16:05:05 -0300
Marcelo Schmitt <marcelo.schmitt@analog.com> wrote:
> Some SPI peripherals may require strict MOSI line state when the controller
> is not clocking out data.
> Implement support for MOSI idle state configuration (low or high) by
> setting the data output line level on controller setup and after transfers.
> Bitbang operations now call controller specific set_mosi_idle() call back
> to set MOSI to its idle state.
> The MOSI line is kept at its idle state if no tx buffer is provided.
Slightly odd wrapping - this doesn't warrant 3 paragraphs, so I'd just
reflow it into one.
I'm not a fan of counting F's, so would have gone with GENMASK for those
but it's not the local style, so fair enough to hard code them.
FWIW given it's been a long time since I messed around in SPI controller
drivers...
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>
> Acked-by: Nuno Sa <nuno.sa@analog.com>
> Reviewed-by: David Lechner <dlechner@baylibre.com>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 3/7] spi: spi-gpio: Add support for MOSI idle state configuration
2024-06-29 19:05 ` [PATCH v6 3/7] spi: spi-gpio: Add " Marcelo Schmitt
@ 2024-06-30 10:53 ` Jonathan Cameron
0 siblings, 0 replies; 23+ messages in thread
From: Jonathan Cameron @ 2024-06-30 10:53 UTC (permalink / raw)
To: Marcelo Schmitt
Cc: broonie, lars, Michael.Hennerich, robh+dt, krzysztof.kozlowski+dt,
conor+dt, nuno.sa, dlechner, corbet, marcelo.schmitt1, linux-iio,
devicetree, linux-spi, linux-doc, linux-kernel
On Sat, 29 Jun 2024 16:05:33 -0300
Marcelo Schmitt <marcelo.schmitt@analog.com> wrote:
> Implement MOSI idle low and MOSI idle high to better support peripherals
> that request specific MOSI behavior.
>
> Acked-by: Nuno Sa <nuno.sa@analog.com>
> Reviewed-by: David Lechner <dlechner@baylibre.com>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
LGTM
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 6/7] iio: adc: Add support for AD4000
2024-06-29 19:06 ` [PATCH v6 6/7] iio: adc: Add support for AD4000 Marcelo Schmitt
@ 2024-06-30 11:17 ` Jonathan Cameron
2024-07-01 18:10 ` Marcelo Schmitt
2024-07-08 21:34 ` David Lechner
2024-07-09 7:41 ` Nuno Sá
2 siblings, 1 reply; 23+ messages in thread
From: Jonathan Cameron @ 2024-06-30 11:17 UTC (permalink / raw)
To: Marcelo Schmitt
Cc: broonie, lars, Michael.Hennerich, robh+dt, krzysztof.kozlowski+dt,
conor+dt, nuno.sa, dlechner, corbet, marcelo.schmitt1, linux-iio,
devicetree, linux-spi, linux-doc, linux-kernel
On Sat, 29 Jun 2024 16:06:59 -0300
Marcelo Schmitt <marcelo.schmitt@analog.com> wrote:
> Add support for AD4000 series of low noise, low power, high speed,
> successive approximation register (SAR) ADCs.
>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
Hi Marcelo
A few comments inline. However, the spi_w8r8 etc can easily be a follow up
optimization patch (if you agree it's a good improvement) and the
other changes are so trivial I could tweak whilst applying.
So unless you have to do a v7 for some other reason this is fine for
merging as is - subject to the fact it's not been on list long enough yet
and I need Mark to pick up the SPI parts and throw me a tag to pull.
Thanks,
Jonathan
> --- /dev/null
> +++ b/drivers/iio/adc/ad4000.c
> @@ -0,0 +1,708 @@
> +
> +struct ad4000_state {
> + struct spi_device *spi;
> + struct gpio_desc *cnv_gpio;
> + struct spi_transfer xfers[2];
> + struct spi_message msg;
> + struct mutex lock; /* Protect read modify write cycle */
> + int vref_mv;
> + enum ad4000_sdi sdi_pin;
> + bool span_comp;
> + u16 gain_milli;
> + int scale_tbl[AD4000_SCALE_OPTIONS][2];
> +
> + /*
> + * DMA (thus cache coherency maintenance) requires the transfer buffers
> + * to live in their own cache lines.
> + */
> + struct {
> + union {
> + __be16 sample_buf16;
> + __be32 sample_buf32;
> + } data;
> + s64 timestamp __aligned(8);
> + } scan __aligned(IIO_DMA_MINALIGN);
> + u8 tx_buf[2];
> + u8 rx_buf[2];
If you made the spi_w8r8() change suggested below (which uses a bounce buffer
in the spi core), rx_buf would be unused and can go away.
Given I think registers accesses on this device are all off the fast path
you could even use spi_write_then_read() with zero read size for the
register writes and rely on the spi core bounce buffers.
That way tx_buf goes away as well leaving you with the dma
safe buffer for only the fast path reads.
> +};
> +
> +static void ad4000_fill_scale_tbl(struct ad4000_state *st,
> + struct iio_chan_spec const *chan)
> +{
> + int val, tmp0, tmp1;
> + int scale_bits;
> + u64 tmp2;
> +
> + /*
> + * ADCs that output two's complement code have one less bit to express
> + * voltage magnitude.
> + */
> + if (chan->scan_type.sign == 's')
> + scale_bits = chan->scan_type.realbits - 1;
> + else
> + scale_bits = chan->scan_type.realbits;
> +
> + /*
> + * The gain is stored as a fraction of 1000 and, as we need to
> + * divide vref_mv by the gain, we invert the gain/1000 fraction.
> + * Also multiply by an extra MILLI to preserve precision.
> + * Thus, we have MILLI * MILLI equals MICRO as fraction numerator.
> + */
> + val = mult_frac(st->vref_mv, MICRO, st->gain_milli);
If you are rolling a v7 for other reasons, stick some line breaks in here!
It's a bit of a mass of text that is hard for my eyes to parse!
> + /* Would multiply by NANO here but we multiplied by extra MILLI */
> + tmp2 = shift_right((u64)val * MICRO, scale_bits);
> + tmp0 = div_s64_rem(tmp2, NANO, &tmp1);
> + /* Store scale for when span compression is disabled */
> + st->scale_tbl[0][0] = tmp0; /* Integer part */
> + st->scale_tbl[0][1] = abs(tmp1); /* Fractional part */
> + /* Store scale for when span compression is enabled */
> + st->scale_tbl[1][0] = tmp0;
> + /* The integer part is always zero so don't bother to divide it. */
> + if (chan->differential)
> + st->scale_tbl[1][1] = DIV_ROUND_CLOSEST(abs(tmp1) * 4, 5);
> + else
> + st->scale_tbl[1][1] = DIV_ROUND_CLOSEST(abs(tmp1) * 9, 10);
> +}
> +static int ad4000_read_reg(struct ad4000_state *st, unsigned int *val)
> +{
> + struct spi_transfer t = {
> + .tx_buf = st->tx_buf,
> + .rx_buf = st->rx_buf,
> + .len = 2,
> + };
> + int ret;
> +
> + st->tx_buf[0] = AD4000_READ_COMMAND;
> + ret = spi_sync_transfer(st->spi, &t, 1);
> + if (ret < 0)
> + return ret;
> +
> + *val = st->rx_buf[1];
> + return ret;
I'd be tempted to do
ssize_t ret;
ret = spi_w8r8(AD4000_READ_COMMAND);
if (ret < 0)
return ret;
*val = ret;
return 0;
> +}
> +static int ad4000_write_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int val, int val2,
> + long mask)
> +{
> + struct ad4000_state *st = iio_priv(indio_dev);
> + unsigned int reg_val;
> + bool span_comp_en;
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_SCALE:
> + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
> + guard(mutex)(&st->lock);
> +
> + ret = ad4000_read_reg(st, ®_val);
> + if (ret < 0)
> + return ret;
> +
> + span_comp_en = val2 == st->scale_tbl[1][1];
> + reg_val &= ~AD4000_CFG_SPAN_COMP;
> + reg_val |= FIELD_PREP(AD4000_CFG_SPAN_COMP, span_comp_en);
> +
> + ret = ad4000_write_reg(st, reg_val);
> + if (ret < 0)
> + return ret;
> +
> + st->span_comp = span_comp_en;
> + return ret;
If you are spinning for another reason, make it clear this is always good.
The spi_write() never returns positive so current code is correct but I had
to go check which this would have avoided.
return 0;
If nothing else comes up, I'll probably tweak whilst applying.
J
> + }
> + unreachable();
> + default:
> + return -EINVAL;
> + }
> +}
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration
2024-06-30 10:47 ` Jonathan Cameron
@ 2024-07-01 17:30 ` Marcelo Schmitt
0 siblings, 0 replies; 23+ messages in thread
From: Marcelo Schmitt @ 2024-07-01 17:30 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Marcelo Schmitt, broonie, lars, Michael.Hennerich, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
On 06/30, Jonathan Cameron wrote:
> On Sat, 29 Jun 2024 16:04:40 -0300
> Marcelo Schmitt <marcelo.schmitt@analog.com> wrote:
>
> > The behavior of an SPI controller data output line (SDO or MOSI or COPI
> > (Controller Output Peripheral Input) for disambiguation) is usually not
> > specified when the controller is not clocking out data on SCLK edges.
> > However, there do exist SPI peripherals that require specific MOSI line
> > state when data is not being clocked out of the controller.
> >
> > Conventional SPI controllers may set the MOSI line on SCLK edges then bring
> > it low when no data is going out or leave the line the state of the last
> > transfer bit. More elaborated controllers are capable to set the MOSI idle
> > state according to different configurable levels and thus are more suitable
> > for interfacing with demanding peripherals.
> >
> > Add SPI mode bits to allow peripherals to request explicit MOSI idle state
> > when needed.
> >
> > When supporting a particular MOSI idle configuration, the data output line
> > state is expected to remain at the configured level when the controller is
> > not clocking out data. When a device that needs a specific MOSI idle state
> > is identified, its driver should request the MOSI idle configuration by
> > setting the proper SPI mode bit.
> >
> > Acked-by: Nuno Sa <nuno.sa@analog.com>
> > Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
>
> I always like to see some nice ascii art. Very nice documentation.
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>
> > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> > index 93f59ebb5b79..c8ba5e490850 100644
> > --- a/drivers/spi/spi.c
> > +++ b/drivers/spi/spi.c
>
> > @@ -3950,6 +3956,7 @@ int spi_setup(struct spi_device *spi)
> > */
> > bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD |
> > SPI_NO_TX | SPI_NO_RX);
> > +
>
> Trivial grumpy comment. Don't touch white space in unrelated code!
Ouf, must have slipped through after messing around with spi_setup().
Didn't intend to add that. Fine if that can be removed when applying the patch.
>
> > ugly_bits = bad_bits &
> > (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
> > SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL);
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 6/7] iio: adc: Add support for AD4000
2024-06-30 11:17 ` Jonathan Cameron
@ 2024-07-01 18:10 ` Marcelo Schmitt
2024-07-01 18:38 ` Mark Brown
2024-07-01 18:47 ` Jonathan Cameron
0 siblings, 2 replies; 23+ messages in thread
From: Marcelo Schmitt @ 2024-07-01 18:10 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Marcelo Schmitt, broonie, lars, Michael.Hennerich, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
On 06/30, Jonathan Cameron wrote:
> On Sat, 29 Jun 2024 16:06:59 -0300
> Marcelo Schmitt <marcelo.schmitt@analog.com> wrote:
>
> > Add support for AD4000 series of low noise, low power, high speed,
> > successive approximation register (SAR) ADCs.
> >
> > Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
>
> Hi Marcelo
>
> A few comments inline. However, the spi_w8r8 etc can easily be a follow up
> optimization patch (if you agree it's a good improvement) and the
> other changes are so trivial I could tweak whilst applying.
>
...
> > + /*
> > + * The gain is stored as a fraction of 1000 and, as we need to
> > + * divide vref_mv by the gain, we invert the gain/1000 fraction.
> > + * Also multiply by an extra MILLI to preserve precision.
> > + * Thus, we have MILLI * MILLI equals MICRO as fraction numerator.
> > + */
> > + val = mult_frac(st->vref_mv, MICRO, st->gain_milli);
>
> If you are rolling a v7 for other reasons, stick some line breaks in here!
> It's a bit of a mass of text that is hard for my eyes to parse!
>
Ack
...
>
> > +static int ad4000_read_reg(struct ad4000_state *st, unsigned int *val)
> > +{
> > + struct spi_transfer t = {
> > + .tx_buf = st->tx_buf,
> > + .rx_buf = st->rx_buf,
> > + .len = 2,
> > + };
> > + int ret;
> > +
> > + st->tx_buf[0] = AD4000_READ_COMMAND;
> > + ret = spi_sync_transfer(st->spi, &t, 1);
> > + if (ret < 0)
> > + return ret;
> > +
> > + *val = st->rx_buf[1];
> > + return ret;
>
> I'd be tempted to do
>
> ssize_t ret;
>
> ret = spi_w8r8(AD4000_READ_COMMAND);
> if (ret < 0)
> return ret;
> *val = ret;
>
> return 0;
>
I tried this when working on v6. Only difference was I had declared ret as int.
Then reg values were not read correctly with spi_w8r8().
I'm either missing something or reg access must be 16-bit transfer.
Datasheet sais:
"The AD4000/AD4004/AD4008 configuration register is read from and written to
with a 16-bit SPI instruction."
Yet, besides possible delay between first and last 8 SCLK pulses, I don't see
any transfer level differences between current and spi_w8r8() versions.
>
>
...
> > + ret = ad4000_write_reg(st, reg_val);
> > + if (ret < 0)
> > + return ret;
> > +
> > + st->span_comp = span_comp_en;
> > + return ret;
>
> If you are spinning for another reason, make it clear this is always good.
> The spi_write() never returns positive so current code is correct but I had
> to go check which this would have avoided.
>
> return 0;
Ack
>
> If nothing else comes up, I'll probably tweak whilst applying.
>
> J
>
> > + }
> > + unreachable();
> > + default:
> > + return -EINVAL;
> > + }
> > +}
>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 6/7] iio: adc: Add support for AD4000
2024-07-01 18:10 ` Marcelo Schmitt
@ 2024-07-01 18:38 ` Mark Brown
2024-07-01 18:47 ` Jonathan Cameron
1 sibling, 0 replies; 23+ messages in thread
From: Mark Brown @ 2024-07-01 18:38 UTC (permalink / raw)
To: Marcelo Schmitt
Cc: Jonathan Cameron, Marcelo Schmitt, lars, Michael.Hennerich,
robh+dt, krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner,
corbet, linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1668 bytes --]
On Mon, Jul 01, 2024 at 03:10:54PM -0300, Marcelo Schmitt wrote:
> On 06/30, Jonathan Cameron wrote:
> > Marcelo Schmitt <marcelo.schmitt@analog.com> wrote:
> > > + struct spi_transfer t = {
> > > + .tx_buf = st->tx_buf,
> > > + .rx_buf = st->rx_buf,
> > > + .len = 2,
> > > + };
> > I'd be tempted to do
> > ssize_t ret;
> >
> > ret = spi_w8r8(AD4000_READ_COMMAND);
> I tried this when working on v6. Only difference was I had declared ret as int.
> Then reg values were not read correctly with spi_w8r8().
> I'm either missing something or reg access must be 16-bit transfer.
> Datasheet sais:
> "The AD4000/AD4004/AD4008 configuration register is read from and written to
> with a 16-bit SPI instruction."
> Yet, besides possible delay between first and last 8 SCLK pulses, I don't see
> any transfer level differences between current and spi_w8r8() versions.
It is possible the chip gets upset with the state of the idle line
during the RX only or TX only portion of the transfer.
>
> >
> >
> ...
> > > + ret = ad4000_write_reg(st, reg_val);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + st->span_comp = span_comp_en;
> > > + return ret;
> >
> > If you are spinning for another reason, make it clear this is always good.
> > The spi_write() never returns positive so current code is correct but I had
> > to go check which this would have avoided.
> >
> > return 0;
>
> Ack
> >
> > If nothing else comes up, I'll probably tweak whilst applying.
> >
> > J
> >
> > > + }
> > > + unreachable();
> > > + default:
> > > + return -EINVAL;
> > > + }
> > > +}
> >
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 6/7] iio: adc: Add support for AD4000
2024-07-01 18:10 ` Marcelo Schmitt
2024-07-01 18:38 ` Mark Brown
@ 2024-07-01 18:47 ` Jonathan Cameron
1 sibling, 0 replies; 23+ messages in thread
From: Jonathan Cameron @ 2024-07-01 18:47 UTC (permalink / raw)
To: Marcelo Schmitt
Cc: Marcelo Schmitt, broonie, lars, Michael.Hennerich, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
On Mon, 1 Jul 2024 15:10:54 -0300
Marcelo Schmitt <marcelo.schmitt1@gmail.com> wrote:
> On 06/30, Jonathan Cameron wrote:
> > On Sat, 29 Jun 2024 16:06:59 -0300
> > Marcelo Schmitt <marcelo.schmitt@analog.com> wrote:
> >
> > > Add support for AD4000 series of low noise, low power, high speed,
> > > successive approximation register (SAR) ADCs.
> > >
> > > Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> >
> > Hi Marcelo
> >
> > A few comments inline. However, the spi_w8r8 etc can easily be a follow up
> > optimization patch (if you agree it's a good improvement) and the
> > other changes are so trivial I could tweak whilst applying.
> >
> ...
> > > + /*
> > > + * The gain is stored as a fraction of 1000 and, as we need to
> > > + * divide vref_mv by the gain, we invert the gain/1000 fraction.
> > > + * Also multiply by an extra MILLI to preserve precision.
> > > + * Thus, we have MILLI * MILLI equals MICRO as fraction numerator.
> > > + */
> > > + val = mult_frac(st->vref_mv, MICRO, st->gain_milli);
> >
> > If you are rolling a v7 for other reasons, stick some line breaks in here!
> > It's a bit of a mass of text that is hard for my eyes to parse!
> >
> Ack
>
> ...
>
> >
> > > +static int ad4000_read_reg(struct ad4000_state *st, unsigned int *val)
> > > +{
> > > + struct spi_transfer t = {
> > > + .tx_buf = st->tx_buf,
> > > + .rx_buf = st->rx_buf,
> > > + .len = 2,
> > > + };
> > > + int ret;
> > > +
> > > + st->tx_buf[0] = AD4000_READ_COMMAND;
> > > + ret = spi_sync_transfer(st->spi, &t, 1);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + *val = st->rx_buf[1];
> > > + return ret;
> >
> > I'd be tempted to do
> >
> > ssize_t ret;
> >
> > ret = spi_w8r8(AD4000_READ_COMMAND);
> > if (ret < 0)
> > return ret;
> > *val = ret;
> >
> > return 0;
> >
> I tried this when working on v6. Only difference was I had declared ret as int.
> Then reg values were not read correctly with spi_w8r8().
> I'm either missing something or reg access must be 16-bit transfer.
> Datasheet sais:
> "The AD4000/AD4004/AD4008 configuration register is read from and written to
> with a 16-bit SPI instruction."
> Yet, besides possible delay between first and last 8 SCLK pulses, I don't see
> any transfer level differences between current and spi_w8r8() versions.
Ah. If you go around again, throw in a comment so we don't 'fix' it in
the future!
>
> >
> >
> ...
> > > + ret = ad4000_write_reg(st, reg_val);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + st->span_comp = span_comp_en;
> > > + return ret;
> >
> > If you are spinning for another reason, make it clear this is always good.
> > The spi_write() never returns positive so current code is correct but I had
> > to go check which this would have avoided.
> >
> > return 0;
>
> Ack
> >
> > If nothing else comes up, I'll probably tweak whilst applying.
> >
> > J
> >
> > > + }
> > > + unreachable();
> > > + default:
> > > + return -EINVAL;
> > > + }
> > > +}
> >
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration
2024-06-29 19:04 ` [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration Marcelo Schmitt
2024-06-30 10:47 ` Jonathan Cameron
@ 2024-07-08 21:15 ` David Lechner
1 sibling, 0 replies; 23+ messages in thread
From: David Lechner @ 2024-07-08 21:15 UTC (permalink / raw)
To: Marcelo Schmitt, broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
On 6/29/24 2:04 PM, Marcelo Schmitt wrote:
> The behavior of an SPI controller data output line (SDO or MOSI or COPI
> (Controller Output Peripheral Input) for disambiguation) is usually not
> specified when the controller is not clocking out data on SCLK edges.
> However, there do exist SPI peripherals that require specific MOSI line
> state when data is not being clocked out of the controller.
>
> Conventional SPI controllers may set the MOSI line on SCLK edges then bring
> it low when no data is going out or leave the line the state of the last
> transfer bit. More elaborated controllers are capable to set the MOSI idle
> state according to different configurable levels and thus are more suitable
> for interfacing with demanding peripherals.
>
> Add SPI mode bits to allow peripherals to request explicit MOSI idle state
> when needed.
>
> When supporting a particular MOSI idle configuration, the data output line
> state is expected to remain at the configured level when the controller is
> not clocking out data. When a device that needs a specific MOSI idle state
> is identified, its driver should request the MOSI idle configuration by
> setting the proper SPI mode bit.
>
> Acked-by: Nuno Sa <nuno.sa@analog.com>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> ---
Tested both valid and invalid combinations of flags and saw expected
behavior/error messages in all cases.
Reviewed-by: David Lechner <dlechner@baylibre.com>
Tested-by: David Lechner <dlechner@baylibre.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 2/7] spi: bitbang: Implement support for MOSI idle state configuration
2024-06-29 19:05 ` [PATCH v6 2/7] spi: bitbang: Implement support for MOSI idle state configuration Marcelo Schmitt
2024-06-30 10:52 ` Jonathan Cameron
@ 2024-07-08 21:19 ` David Lechner
1 sibling, 0 replies; 23+ messages in thread
From: David Lechner @ 2024-07-08 21:19 UTC (permalink / raw)
To: Marcelo Schmitt, broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
On 6/29/24 2:05 PM, Marcelo Schmitt wrote:
> Some SPI peripherals may require strict MOSI line state when the controller
> is not clocking out data.
> Implement support for MOSI idle state configuration (low or high) by
> setting the data output line level on controller setup and after transfers.
> Bitbang operations now call controller specific set_mosi_idle() call back
> to set MOSI to its idle state.
> The MOSI line is kept at its idle state if no tx buffer is provided.
>
> Acked-by: Nuno Sa <nuno.sa@analog.com>
> Reviewed-by: David Lechner <dlechner@baylibre.com>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> ---
FYI, this doesn't apply cleanly to spi-next and needs to be rebased.
(conflicts with https://lore.kernel.org/all/20240517194104.747328-3-andriy.shevchenko@linux.intel.com/)
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 7/7] docs: iio: Add documentation for AD4000
2024-06-29 19:07 ` [PATCH v6 7/7] docs: iio: Add documentation " Marcelo Schmitt
@ 2024-07-08 21:25 ` David Lechner
0 siblings, 0 replies; 23+ messages in thread
From: David Lechner @ 2024-07-08 21:25 UTC (permalink / raw)
To: Marcelo Schmitt, broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
On 6/29/24 2:07 PM, Marcelo Schmitt wrote:
> Document wiring configurations for the AD4000 series of ADCs.
>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> ---
Reviewed-by: David Lechner <dlechner@baylibre.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 6/7] iio: adc: Add support for AD4000
2024-06-29 19:06 ` [PATCH v6 6/7] iio: adc: Add support for AD4000 Marcelo Schmitt
2024-06-30 11:17 ` Jonathan Cameron
@ 2024-07-08 21:34 ` David Lechner
2024-07-09 7:41 ` Nuno Sá
2 siblings, 0 replies; 23+ messages in thread
From: David Lechner @ 2024-07-08 21:34 UTC (permalink / raw)
To: Marcelo Schmitt, broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
On 6/29/24 2:06 PM, Marcelo Schmitt wrote:
> Add support for AD4000 series of low noise, low power, high speed,
> successive approximation register (SAR) ADCs.
>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> ---
Reviewed-by: David Lechner <dlechner@baylibre.com>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v6 6/7] iio: adc: Add support for AD4000
2024-06-29 19:06 ` [PATCH v6 6/7] iio: adc: Add support for AD4000 Marcelo Schmitt
2024-06-30 11:17 ` Jonathan Cameron
2024-07-08 21:34 ` David Lechner
@ 2024-07-09 7:41 ` Nuno Sá
2 siblings, 0 replies; 23+ messages in thread
From: Nuno Sá @ 2024-07-09 7:41 UTC (permalink / raw)
To: Marcelo Schmitt, broonie, lars, Michael.Hennerich, jic23, robh+dt,
krzysztof.kozlowski+dt, conor+dt, nuno.sa, dlechner, corbet,
marcelo.schmitt1
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
On Sat, 2024-06-29 at 16:06 -0300, Marcelo Schmitt wrote:
> Add support for AD4000 series of low noise, low power, high speed,
> successive approximation register (SAR) ADCs.
>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> ---
Hi Marcelo,
LGTM. Only one thing that needs to be addressed. With that,
Reviewed-by: Nuno Sa <nuno.sa@analog.com>
> MAINTAINERS | 1 +
> drivers/iio/adc/Kconfig | 12 +
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/ad4000.c | 708 +++++++++++++++++++++++++++++++++++++++
> 4 files changed, 722 insertions(+)
> create mode 100644 drivers/iio/adc/ad4000.c
>
...
>
> + st->gain_milli = 1000;
> + if (chip->has_hardware_gain &&
> + device_property_present(dev, "adi,gain-milli")) {
> + ret = device_property_read_u16(dev, "adi,gain-milli",
> + &st->gain_milli);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Failed to read gain
> property\n");
> + }
The above is odd. Why not reading directly device_property_read_u16()? Skip the
call to device_property_present().
But most importantly, you're not doing any validation on gain_milli which is an
enum (by looking at the bindings). So in theory even 0 would be accepted which
would lead to a divide by 0 later on. I would do:
if (chip->has_hardware_gain) {
ret = device_property_read_u16(...)
if (!ret) {
/* validate here for a proper value /*
}
}
You can also check for ret < 0 and -EINVAL to detect an invalid devicetree
parameter instead of completely ignoring return codes (but for non mandatory
properties one typically does not care much - up to you)
- Nuno Sá
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: (subset) [PATCH v6 0/7] Add support for AD4000 series of ADCs
2024-06-29 19:04 [PATCH v6 0/7] Add support for AD4000 series of ADCs Marcelo Schmitt
` (6 preceding siblings ...)
2024-06-29 19:07 ` [PATCH v6 7/7] docs: iio: Add documentation " Marcelo Schmitt
@ 2024-07-29 18:02 ` Mark Brown
2024-07-29 19:40 ` Jonathan Cameron
7 siblings, 1 reply; 23+ messages in thread
From: Mark Brown @ 2024-07-29 18:02 UTC (permalink / raw)
To: lars, Michael.Hennerich, jic23, robh+dt, krzysztof.kozlowski+dt,
conor+dt, nuno.sa, dlechner, corbet, marcelo.schmitt1,
Marcelo Schmitt
Cc: linux-iio, devicetree, linux-spi, linux-doc, linux-kernel
On Sat, 29 Jun 2024 16:04:00 -0300, Marcelo Schmitt wrote:
> This patch series extends the SPI bitbang, gpio, and spi-engine controllers to
> support configurable MOSI line idle states.
> It then introduces the ad4000 driver which uses the MOSI idle configuration to
> provide improved support for the AD4000 series of ADCs.
> Documentation is added describing the new extension to the SPI protocol.
> The currently supported wiring modes for AD4000 devices were documented under
> IIO documentation directory.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
Thanks!
[1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration
commit: f58872f45c36ded048bccc22701b0986019c24d8
[2/7] spi: bitbang: Implement support for MOSI idle state configuration
commit: 320f6693097bf89d67f9cabad24a2b911e23073f
[3/7] spi: spi-gpio: Add support for MOSI idle state configuration
commit: 927d382c7efbcc2206c31fa2f672fa264c0f1d5b
[4/7] spi: spi-axi-spi-engine: Add support for MOSI idle configuration
commit: a62073f4b2164028fc7c5ae45ceba10c9326cd91
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: (subset) [PATCH v6 0/7] Add support for AD4000 series of ADCs
2024-07-29 18:02 ` (subset) [PATCH v6 0/7] Add support for AD4000 series of ADCs Mark Brown
@ 2024-07-29 19:40 ` Jonathan Cameron
0 siblings, 0 replies; 23+ messages in thread
From: Jonathan Cameron @ 2024-07-29 19:40 UTC (permalink / raw)
To: Mark Brown
Cc: lars, Michael.Hennerich, robh+dt, krzysztof.kozlowski+dt,
conor+dt, nuno.sa, dlechner, corbet, marcelo.schmitt1,
Marcelo Schmitt, linux-iio, devicetree, linux-spi, linux-doc,
linux-kernel
On Mon, 29 Jul 2024 19:02:23 +0100
Mark Brown <broonie@kernel.org> wrote:
> On Sat, 29 Jun 2024 16:04:00 -0300, Marcelo Schmitt wrote:
> > This patch series extends the SPI bitbang, gpio, and spi-engine controllers to
> > support configurable MOSI line idle states.
> > It then introduces the ad4000 driver which uses the MOSI idle configuration to
> > provide improved support for the AD4000 series of ADCs.
> > Documentation is added describing the new extension to the SPI protocol.
> > The currently supported wiring modes for AD4000 devices were documented under
> > IIO documentation directory.
> >
> > [...]
>
> Applied to
>
> https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
>
> Thanks!
>
> [1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration
> commit: f58872f45c36ded048bccc22701b0986019c24d8
> [2/7] spi: bitbang: Implement support for MOSI idle state configuration
> commit: 320f6693097bf89d67f9cabad24a2b911e23073f
> [3/7] spi: spi-gpio: Add support for MOSI idle state configuration
> commit: 927d382c7efbcc2206c31fa2f672fa264c0f1d5b
> [4/7] spi: spi-axi-spi-engine: Add support for MOSI idle configuration
> commit: a62073f4b2164028fc7c5ae45ceba10c9326cd91
Hi Mark,
Any chance of a tag + you seem to have also picked up the ADC dt binding.
Patch 5/7. dt-bindings: iio: adc: Add AD4000
which I'm assuming was not intentional.
I think I only need the definition of SPI_MOSI_IDLE_HIGH
for 5-7 to build fine.
If needed, I can use a local value for that in the driver and
we can follow up with a patch using the main define once the trees
come together upstream.
Jonathan
>
> All being well this means that it will be integrated into the linux-next
> tree (usually sometime in the next 24 hours) and sent to Linus during
> the next merge window (or sooner if it is a bug fix), however if
> problems are discovered then the patch may be dropped or reverted.
>
> You may get further e-mails resulting from automated or manual testing
> and review of the tree, please engage with people reporting problems and
> send followup patches addressing any issues that are reported if needed.
>
> If any updates are required or you are submitting further changes they
> should be sent as incremental updates against current git, existing
> patches will not be replaced.
>
> Please add any relevant lists and maintainers to the CCs when replying
> to this mail.
>
> Thanks,
> Mark
>
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2024-07-29 19:40 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-29 19:04 [PATCH v6 0/7] Add support for AD4000 series of ADCs Marcelo Schmitt
2024-06-29 19:04 ` [PATCH v6 1/7] spi: Enable controllers to extend the SPI protocol with MOSI idle configuration Marcelo Schmitt
2024-06-30 10:47 ` Jonathan Cameron
2024-07-01 17:30 ` Marcelo Schmitt
2024-07-08 21:15 ` David Lechner
2024-06-29 19:05 ` [PATCH v6 2/7] spi: bitbang: Implement support for MOSI idle state configuration Marcelo Schmitt
2024-06-30 10:52 ` Jonathan Cameron
2024-07-08 21:19 ` David Lechner
2024-06-29 19:05 ` [PATCH v6 3/7] spi: spi-gpio: Add " Marcelo Schmitt
2024-06-30 10:53 ` Jonathan Cameron
2024-06-29 19:06 ` [PATCH v6 4/7] spi: spi-axi-spi-engine: Add support for MOSI idle configuration Marcelo Schmitt
2024-06-29 19:06 ` [PATCH v6 5/7] dt-bindings: iio: adc: Add AD4000 Marcelo Schmitt
2024-06-29 19:06 ` [PATCH v6 6/7] iio: adc: Add support for AD4000 Marcelo Schmitt
2024-06-30 11:17 ` Jonathan Cameron
2024-07-01 18:10 ` Marcelo Schmitt
2024-07-01 18:38 ` Mark Brown
2024-07-01 18:47 ` Jonathan Cameron
2024-07-08 21:34 ` David Lechner
2024-07-09 7:41 ` Nuno Sá
2024-06-29 19:07 ` [PATCH v6 7/7] docs: iio: Add documentation " Marcelo Schmitt
2024-07-08 21:25 ` David Lechner
2024-07-29 18:02 ` (subset) [PATCH v6 0/7] Add support for AD4000 series of ADCs Mark Brown
2024-07-29 19:40 ` 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).