2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00
linux/drivers/iio/adc/ad7606.c
Greg Kroah-Hartman 0ca7cb7089 IIO: New device support, features and cleanup for 6.16 - take 2
Note - last minute rebase was to drop a typo patch that I'd accidentally
 picked up (in the microblaze arch Kconfig)
 Take 2 is due to that rebase messing up some fixes tags that were
 referring to patches after that point.
 
 There is a known merge conflict due to changes in neighbouring lines.
 
 Stephen's resolution in linux-next is:
 https://lore.kernel.org/linux-next/20250506155728.65605bae@canb.auug.org.au/
 
 Added 3 named IIO reviewers to MAINTAINERS. This is a reflection of those
 who have been doing much of this work for some time. Lars-Peter is
 removed from the entry having moved on to other topics.  Thanks
 Nuno, David and Andy for stepping up and Lars-Peter for all your
 hard work in the past!
 
 Includes the usual mix of new device support, features and general
 cleanup.
 
 This time we also have some tree wide changes.
 
 - Rip out the iio_device_claim_direct_scoped() as it proved hard to work
   with.  This series includes quite a few related cleanups such as use
   of guard or factoring code out to allow direct returns.
 - Switch from iio_device_claim/release_direct_mode() to new
   iio_device_claim/release_direct() which is structured so that sparse
   can warn on failed releases. There were a few false positives but
   those were mostly in code that benefited from being cleaned up as part
   of this process.
 - Introduce iio_push_to_buffers_with_ts() to replace the _timestamp()
   version over time. This version takes the size of the supplied buffer
   which the core checks is at least as big as expected by calculation
   from channel descriptions of those channels enabled. Use this in
   an initial set of drivers.
 - Add macros for IIO_DECLARE_BUFFER_WITH_TS() and
   IIO_DECLARE_DMA_BUFFER_WITH_TS() to avoid lots of fiddly code to ensure
   correctly aligned buffers for timestamps being added onto the end of
   channel data.
 
 New device support
 ------------------
 
 adi,ad3530r
 - New driver for AD3530, AD3530R, AD3531 and AD3531R DACs with
   programmable gain controls. R variants have internal references.
 adi,ad7476
 - Add support (dt compatible only) for the Rohm BU79100G ADC which is
   fully compatible with the ti,ads7866.
 adi,ad7606
 - Support ad7606c-16 and ad7606c-18 devices. Includes switch to dynamic
   channel information allocation.
 adi,ad7380
 - Add support for the AD7389-4
 dfrobot,sen0322
 - New driver for this oxygen sensor.
 mediatek,mt2701-auxadc
 - Add binding for MT6893 which is fully compatible with already supported
   MT8173.
 meson-saradc
 - Support the GXLX SoCs.  Mostly this is a workaround for some unrelated
   clock control bits found in the ADC register map.
 nuvoton,nct7201
 - New driver for NCT7201 and NCT7202 I2C ADCs.
 rohm,bd79124
 - New driver for this 12-bit, 8-channel SAR ADC.
 - Switch to new set_rv etc gpio callbacks that were added in 6.15.
 rohm,bd79703
 - Add support for BD79700, BD79701 and BD79702 DACs that have subsets of
   functionality of the already supported bd79703.  Included making this
   driver suitable for support device variants.
 st,stm32-lptimer
 - Add support for stm32pm25 to this trigger.
 
 Features
 --------
 
 Beyond IIO
 - Property iterator for named children.
 core
 - Enable writes for 64 bit integers used for standard IIO ABI elements.
   Previously these could be read only.
 - Helper library that should avoid code duplication for simpler ADC
   bindings that have a child node per channel.
 - Enforce that IIO_DMA_MINALIGN is always at least 8 (almost always true
   and simplifies code on all significant architectures)
 core/backend
 - Add support to control source of data - useful when the HDL includes
   things like generated ramps for testing purposes. Enable this for
   adi-axi-dac
 adi,ad3552-hs
 - Add debugfs related callbacks to allow debug access to register contents.
 adi,ad4000
 - Support SPI offload with appropriate FPGA firmware along with improving
   documentation.
 adi,ad7293
 - Add support for external reference voltage.
 adi,ad7606
 - Support SPI offload.
 adi,ad7768-1
 - Support reset GPIO.
 adi,admv8818
 - Support filter frequencies beyond 2^32.
 adi,adxl345
 - Add single and double tap events.
 hid-sensor-prox
 - Support 16-bit report sizes as seen on some Intel platforms.
 invensense,icm42600
 - Enable use of named interrupts to avoid problems with some wiring choices.
   Get the interrupt by name, but fallback to previous assumption on the first
   being INT1 if no names are supplied.
 microchip,mcp3911
 - Add reset gpio support.
 rohm,bh7150
 - Add reset gpio support.
 st,stm32
 - Add support to control oversampling.
 ti,adc128s052
 - Add support for ROHM BD79104 which is early compatible with the TI
   parts already supported by this driver. Includes some general driver
   cleanup and a separate dt binding.
 - Simplify reference voltage handling by assuming it is fixed after enabling
   the supply.
 winsen,mhz19b
 - New driver for this C02 sensor.
 
 Cleanup and minor fixes
 -----------------------
 
 dt-bindings
 - Correct indentation and style for DTS examples.
 - Use unevalutateProperties for SPI devices instead of additionalProperties
   to allow generic SPI properties from spi-peripheral-props.yaml
 ABI Docs
 - Add missing docs for sampling_frequency when it applies only to events.
 Treewide
 - Various minor tweaks, comment fixes and similar.
 - Sort TI ADCs in Kconfig that had gotten out of order.
 - Switch various drives that provide GPIO chip functionality to the new
   callbacks with return values.
 - Standardize on { } formatting for all array sentinels.
 - Make use of aligned_s64 in a few places to replace either wrong types
   or manually defined equivalents.
 - Drop places where spi bits_per_word is set to 8 because that is the
   default anyway.
 
 adi,ad_sigma_delta library
 - Avoid a potential use of uninitialized data if reg_size has a value
   that is not supported (no drivers hit this but it is reasonable hardening)
 adi,ad4030
 - Add error checking for scan types and no longer store it in state.
 - Rework code to reduce duplication.
 - Move setting the mode from buffer preenable() to update_scan_mode(),
   better matching expected semantics of the two different callbacks.
 - Improve data marshalling comments.
 adi,ad4695
 - Use u16 for buffer elements as oversampling is not yet supported except
   with SPI offload (which doesn't use this path).
 adi,ad5592r
 - Clean up destruction of mutexes.
 - Use lock guards to simplify code (later patch fixes a missed unlock)
 adi,ad5933
 - Correct some incorrect settling times.
 adi,ad7091
 - Deduplicate handling of writable vs volatile registers as they are the
   inverse of each other for this device.
 adi,ad7124
 - Fix 3db Filter frequency.
 - Remove ability to directly write the filter frequency (which was broken)
 - Register naming improvements.
 adi,ad7606
 - Add a missing return value check.
 - Fill in max sampling rates for all chips.
 - Use devm_mutex_init()
 - Fix up some kernel-doc formatting issues.
 - Remove some camel case that snuck in.
 - Drop setting address field in channels as easily established from other
   fields.
 - Drop unnecessary parameter to ad76060_scale_setup_cb_t.
 adi,ad7768-1
 - Convert to regmap.
 - Factor out buffer allocation.
 - Tidy up headers.
 adi,ad7944
 - Stop setting bits_per_word in SPI xfers with no data.
 adi,ad9832
 - Add of_device_id table rather than just relying on fallbacks.
 - Use FIELD_PREP() to set values of fields.
 adi,admv1013
 - Cleanup a pointless ternary.
 adi,admv8818
 - Fix up LPF Band 5 frequency which was slightly wrong.
 - Fix an integer overflow.
 - Fix range calculation
 adi,adt7316
 - Replace irqd_get_trigger_type(irq_get_irq_data()) with simpler
   irq_get_trigger_type()
 adi,adxl345
 - Use regmap cache instead of various state variables that were there to
   reduce bus accesses.
 - Make regmap return value checking consistent across all call sites.
 adi,axi-dac
 - Add a check on number of channels (0 to 15 valid)
 allwinner,sun20i
 - Use new adc-helpers to replace local parsing code for channel nodes.
 bosch,bmp290
 - Move to local variables for sensor data marshalling removing the need
   for a messy definition that has to work for all supported parts.
   Follow up fix adds a missing initialization.
 dynaimage,al3010 and dynaimage,al3320a
 - Various minor cleanup to bring these drivers inline with reviewed feedback
   given on a new driver.
 - Fix an error path in which power down is not called when it should be.
 - Switch to regmap.
 google,cros_ec
 - Fix up a flexible array in middle of structure warning.
 - Flush fifo when changing the timeout to avoid potential long wait
   for samples.
 hid-sensor-rotation
 - Remove an __aligned(16) marking that doesn't seem to be justified.
 kionix,kxcjk-1013
 - Deduplicate code for setting up interrupts.
 microchip,mcp3911
 - Fix handling of conversion results register which differs across supported
   devices.
 idt,zopt2201
 - Avoid duplicating register lists as all volatile registers are the
   inverse of writeable registers on this device.
 renesas,rzg2l
 - Use new adc-helpers to replace local parsing code for channel nodes.
 ti,ads1298
 - Fix a missing Kconfig dependency.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmgt1EgRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0Foii3g//bZJT2/rHGIkU/MKUsYQCZGh5ux7X59Kk
 DT8R7i8RYg2dshbtkkHUn/S6yC3OX84q3Legzy8TtHkPvGMK1NSwWCrn2cqkCZdG
 4kksfq3P41FmRrpSfm4p+WSAD9nYzA/LToSLdwGIOa44lKxlCElBgsIDz/HxwXLB
 N08H5jniST+cmSWAkkxCj15jcKXGtuIUS3XSCffwlzQZNPHp7guk4u+5EiUaPwvy
 X75iZ6SthUo9GfE6QyhE4rdOceix6S5wsQrKVpGKB7ZuQbXYQxlvNVt/l5p6MGdY
 teoqB7CyUADD1yHZp9L85+JSqjbodxm5a/Y9b0wQKHV33dxphEVZeli9t+VZYg6K
 fSM5xq0Cmt0msXLGRgB1uvZcEfj+vlkn7SN9nyyfTN2nXoac1E/MYCEiCLMhOj6D
 jxwc1aQDwaT+f6U6mRyRab2+TPea7AOv81x0MyRclOArqY4NCOPIG+XvC2nouYXk
 9MSyK4FIysbINjenFCZdpdibp3HKWGqc8rTv3NWrx7CejAYQoEkYW5WA9qyzy/I8
 8gDbcQskcYcehrI8ztc1ratfKl5k0QJPCgcLvuTpxK3PkQCgX+dGnL1EXW7D4BRx
 7Gl6O7gW7JR6kVx7LidJAxUSykoCdtPyiDxfEU8ypERiype2E6EJN/Bn11o1P8zr
 VZ/PdGti5gg=
 =vLKV
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-6.16a-take2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next

Jonathan writes:

IIO: New device support, features and cleanup for 6.16 - take 2

Note - last minute rebase was to drop a typo patch that I'd accidentally
picked up (in the microblaze arch Kconfig)
Take 2 is due to that rebase messing up some fixes tags that were
referring to patches after that point.

There is a known merge conflict due to changes in neighbouring lines.

Stephen's resolution in linux-next is:
https://lore.kernel.org/linux-next/20250506155728.65605bae@canb.auug.org.au/

Added 3 named IIO reviewers to MAINTAINERS. This is a reflection of those
who have been doing much of this work for some time. Lars-Peter is
removed from the entry having moved on to other topics.  Thanks
Nuno, David and Andy for stepping up and Lars-Peter for all your
hard work in the past!

Includes the usual mix of new device support, features and general
cleanup.

This time we also have some tree wide changes.

- Rip out the iio_device_claim_direct_scoped() as it proved hard to work
  with.  This series includes quite a few related cleanups such as use
  of guard or factoring code out to allow direct returns.
- Switch from iio_device_claim/release_direct_mode() to new
  iio_device_claim/release_direct() which is structured so that sparse
  can warn on failed releases. There were a few false positives but
  those were mostly in code that benefited from being cleaned up as part
  of this process.
- Introduce iio_push_to_buffers_with_ts() to replace the _timestamp()
  version over time. This version takes the size of the supplied buffer
  which the core checks is at least as big as expected by calculation
  from channel descriptions of those channels enabled. Use this in
  an initial set of drivers.
- Add macros for IIO_DECLARE_BUFFER_WITH_TS() and
  IIO_DECLARE_DMA_BUFFER_WITH_TS() to avoid lots of fiddly code to ensure
  correctly aligned buffers for timestamps being added onto the end of
  channel data.

New device support
------------------

adi,ad3530r
- New driver for AD3530, AD3530R, AD3531 and AD3531R DACs with
  programmable gain controls. R variants have internal references.
adi,ad7476
- Add support (dt compatible only) for the Rohm BU79100G ADC which is
  fully compatible with the ti,ads7866.
adi,ad7606
- Support ad7606c-16 and ad7606c-18 devices. Includes switch to dynamic
  channel information allocation.
adi,ad7380
- Add support for the AD7389-4
dfrobot,sen0322
- New driver for this oxygen sensor.
mediatek,mt2701-auxadc
- Add binding for MT6893 which is fully compatible with already supported
  MT8173.
meson-saradc
- Support the GXLX SoCs.  Mostly this is a workaround for some unrelated
  clock control bits found in the ADC register map.
nuvoton,nct7201
- New driver for NCT7201 and NCT7202 I2C ADCs.
rohm,bd79124
- New driver for this 12-bit, 8-channel SAR ADC.
- Switch to new set_rv etc gpio callbacks that were added in 6.15.
rohm,bd79703
- Add support for BD79700, BD79701 and BD79702 DACs that have subsets of
  functionality of the already supported bd79703.  Included making this
  driver suitable for support device variants.
st,stm32-lptimer
- Add support for stm32pm25 to this trigger.

Features
--------

Beyond IIO
- Property iterator for named children.
core
- Enable writes for 64 bit integers used for standard IIO ABI elements.
  Previously these could be read only.
- Helper library that should avoid code duplication for simpler ADC
  bindings that have a child node per channel.
- Enforce that IIO_DMA_MINALIGN is always at least 8 (almost always true
  and simplifies code on all significant architectures)
core/backend
- Add support to control source of data - useful when the HDL includes
  things like generated ramps for testing purposes. Enable this for
  adi-axi-dac
adi,ad3552-hs
- Add debugfs related callbacks to allow debug access to register contents.
adi,ad4000
- Support SPI offload with appropriate FPGA firmware along with improving
  documentation.
adi,ad7293
- Add support for external reference voltage.
adi,ad7606
- Support SPI offload.
adi,ad7768-1
- Support reset GPIO.
adi,admv8818
- Support filter frequencies beyond 2^32.
adi,adxl345
- Add single and double tap events.
hid-sensor-prox
- Support 16-bit report sizes as seen on some Intel platforms.
invensense,icm42600
- Enable use of named interrupts to avoid problems with some wiring choices.
  Get the interrupt by name, but fallback to previous assumption on the first
  being INT1 if no names are supplied.
microchip,mcp3911
- Add reset gpio support.
rohm,bh7150
- Add reset gpio support.
st,stm32
- Add support to control oversampling.
ti,adc128s052
- Add support for ROHM BD79104 which is early compatible with the TI
  parts already supported by this driver. Includes some general driver
  cleanup and a separate dt binding.
- Simplify reference voltage handling by assuming it is fixed after enabling
  the supply.
winsen,mhz19b
- New driver for this C02 sensor.

Cleanup and minor fixes
-----------------------

dt-bindings
- Correct indentation and style for DTS examples.
- Use unevalutateProperties for SPI devices instead of additionalProperties
  to allow generic SPI properties from spi-peripheral-props.yaml
ABI Docs
- Add missing docs for sampling_frequency when it applies only to events.
Treewide
- Various minor tweaks, comment fixes and similar.
- Sort TI ADCs in Kconfig that had gotten out of order.
- Switch various drives that provide GPIO chip functionality to the new
  callbacks with return values.
- Standardize on { } formatting for all array sentinels.
- Make use of aligned_s64 in a few places to replace either wrong types
  or manually defined equivalents.
- Drop places where spi bits_per_word is set to 8 because that is the
  default anyway.

adi,ad_sigma_delta library
- Avoid a potential use of uninitialized data if reg_size has a value
  that is not supported (no drivers hit this but it is reasonable hardening)
adi,ad4030
- Add error checking for scan types and no longer store it in state.
- Rework code to reduce duplication.
- Move setting the mode from buffer preenable() to update_scan_mode(),
  better matching expected semantics of the two different callbacks.
- Improve data marshalling comments.
adi,ad4695
- Use u16 for buffer elements as oversampling is not yet supported except
  with SPI offload (which doesn't use this path).
adi,ad5592r
- Clean up destruction of mutexes.
- Use lock guards to simplify code (later patch fixes a missed unlock)
adi,ad5933
- Correct some incorrect settling times.
adi,ad7091
- Deduplicate handling of writable vs volatile registers as they are the
  inverse of each other for this device.
adi,ad7124
- Fix 3db Filter frequency.
- Remove ability to directly write the filter frequency (which was broken)
- Register naming improvements.
adi,ad7606
- Add a missing return value check.
- Fill in max sampling rates for all chips.
- Use devm_mutex_init()
- Fix up some kernel-doc formatting issues.
- Remove some camel case that snuck in.
- Drop setting address field in channels as easily established from other
  fields.
- Drop unnecessary parameter to ad76060_scale_setup_cb_t.
adi,ad7768-1
- Convert to regmap.
- Factor out buffer allocation.
- Tidy up headers.
adi,ad7944
- Stop setting bits_per_word in SPI xfers with no data.
adi,ad9832
- Add of_device_id table rather than just relying on fallbacks.
- Use FIELD_PREP() to set values of fields.
adi,admv1013
- Cleanup a pointless ternary.
adi,admv8818
- Fix up LPF Band 5 frequency which was slightly wrong.
- Fix an integer overflow.
- Fix range calculation
adi,adt7316
- Replace irqd_get_trigger_type(irq_get_irq_data()) with simpler
  irq_get_trigger_type()
adi,adxl345
- Use regmap cache instead of various state variables that were there to
  reduce bus accesses.
- Make regmap return value checking consistent across all call sites.
adi,axi-dac
- Add a check on number of channels (0 to 15 valid)
allwinner,sun20i
- Use new adc-helpers to replace local parsing code for channel nodes.
bosch,bmp290
- Move to local variables for sensor data marshalling removing the need
  for a messy definition that has to work for all supported parts.
  Follow up fix adds a missing initialization.
dynaimage,al3010 and dynaimage,al3320a
- Various minor cleanup to bring these drivers inline with reviewed feedback
  given on a new driver.
- Fix an error path in which power down is not called when it should be.
- Switch to regmap.
google,cros_ec
- Fix up a flexible array in middle of structure warning.
- Flush fifo when changing the timeout to avoid potential long wait
  for samples.
hid-sensor-rotation
- Remove an __aligned(16) marking that doesn't seem to be justified.
kionix,kxcjk-1013
- Deduplicate code for setting up interrupts.
microchip,mcp3911
- Fix handling of conversion results register which differs across supported
  devices.
idt,zopt2201
- Avoid duplicating register lists as all volatile registers are the
  inverse of writeable registers on this device.
renesas,rzg2l
- Use new adc-helpers to replace local parsing code for channel nodes.
ti,ads1298
- Fix a missing Kconfig dependency.

* tag 'iio-for-6.16a-take2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (260 commits)
  dt-bindings: iio: adc: Add ROHM BD79100G
  iio: adc: add support for Nuvoton NCT7201
  dt-bindings: iio: adc: add NCT7201 ADCs
  iio: chemical: Add driver for SEN0322
  dt-bindings: trivial-devices: Document SEN0322
  iio: adc: ad7768-1: reorganize driver headers
  iio: bmp280: zero-init buffer
  iio: ssp_sensors: optimalize -> optimize
  HID: sensor-hub: Fix typo and improve documentation
  iio: admv1013: replace redundant ternary operator with just len
  iio: chemical: mhz19b: Fix error code in probe()
  iio: adc: at91-sama5d2: use IIO_DECLARE_BUFFER_WITH_TS
  iio: accel: sca3300: use IIO_DECLARE_BUFFER_WITH_TS
  iio: adc: ad7380: use IIO_DECLARE_DMA_BUFFER_WITH_TS
  iio: adc: ad4695: rename AD4695_MAX_VIN_CHANNELS
  iio: adc: ad4695: use IIO_DECLARE_DMA_BUFFER_WITH_TS
  iio: introduce IIO_DECLARE_BUFFER_WITH_TS macros
  iio: make IIO_DMA_MINALIGN minimum of 8 bytes
  iio: pressure: zpa2326_spi: remove bits_per_word = 8
  iio: pressure: ms5611_spi: remove bits_per_word = 8
  ...
2025-05-22 15:54:52 +02:00

1506 lines
39 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* AD7606 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc.
*/
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/regulator/consumer.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/units.h>
#include <linux/util_macros.h>
#include <linux/iio/backend.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include "ad7606.h"
/*
* Scales are computed as 5000/32768 and 10000/32768 respectively,
* so that when applied to the raw values they provide mV values.
* The scale arrays are kept as IIO_VAL_INT_PLUS_MICRO, so index
* X is the integer part and X + 1 is the fractional part.
*/
static const unsigned int ad7606_16bit_hw_scale_avail[2][2] = {
{ 0, 152588 }, { 0, 305176 }
};
static const unsigned int ad7606_18bit_hw_scale_avail[2][2] = {
{ 0, 38147 }, { 0, 76294 }
};
static const unsigned int ad7606c_16bit_single_ended_unipolar_scale_avail[3][2] = {
{ 0, 76294 }, { 0, 152588 }, { 0, 190735 }
};
static const unsigned int ad7606c_16bit_single_ended_bipolar_scale_avail[5][2] = {
{ 0, 76294 }, { 0, 152588 }, { 0, 190735 }, { 0, 305176 }, { 0, 381470 }
};
static const unsigned int ad7606c_16bit_differential_bipolar_scale_avail[4][2] = {
{ 0, 152588 }, { 0, 305176 }, { 0, 381470 }, { 0, 610352 }
};
static const unsigned int ad7606c_18bit_single_ended_unipolar_scale_avail[3][2] = {
{ 0, 19073 }, { 0, 38147 }, { 0, 47684 }
};
static const unsigned int ad7606c_18bit_single_ended_bipolar_scale_avail[5][2] = {
{ 0, 19073 }, { 0, 38147 }, { 0, 47684 }, { 0, 76294 }, { 0, 95367 }
};
static const unsigned int ad7606c_18bit_differential_bipolar_scale_avail[4][2] = {
{ 0, 38147 }, { 0, 76294 }, { 0, 95367 }, { 0, 152588 }
};
static const unsigned int ad7606_16bit_sw_scale_avail[3][2] = {
{ 0, 76293 }, { 0, 152588 }, { 0, 305176 }
};
static const unsigned int ad7607_hw_scale_avail[2][2] = {
{ 0, 610352 }, { 1, 220703 }
};
static const unsigned int ad7609_hw_scale_avail[2][2] = {
{ 0, 152588 }, { 0, 305176 }
};
static const unsigned int ad7606_oversampling_avail[7] = {
1, 2, 4, 8, 16, 32, 64,
};
static const unsigned int ad7606b_oversampling_avail[9] = {
1, 2, 4, 8, 16, 32, 64, 128, 256,
};
static const unsigned int ad7616_oversampling_avail[8] = {
1, 2, 4, 8, 16, 32, 64, 128,
};
static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan);
static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan);
static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan);
static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan);
static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan);
static int ad7609_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan);
static int ad7616_sw_mode_setup(struct iio_dev *indio_dev);
static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev);
const struct ad7606_chip_info ad7605_4_info = {
.max_samplerate = 300 * KILO,
.name = "ad7605-4",
.bits = 16,
.num_adc_channels = 4,
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
};
EXPORT_SYMBOL_NS_GPL(ad7605_4_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606_8_info = {
.max_samplerate = 200 * KILO,
.name = "ad7606-8",
.bits = 16,
.num_adc_channels = 8,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
};
EXPORT_SYMBOL_NS_GPL(ad7606_8_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606_6_info = {
.max_samplerate = 200 * KILO,
.name = "ad7606-6",
.bits = 16,
.num_adc_channels = 6,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606_6_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606_4_info = {
.max_samplerate = 200 * KILO,
.name = "ad7606-4",
.bits = 16,
.num_adc_channels = 4,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606_4_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606b_info = {
.max_samplerate = 800 * KILO,
.name = "ad7606b",
.bits = 16,
.num_adc_channels = 8,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606c_16_info = {
.max_samplerate = 1 * MEGA,
.name = "ad7606c16",
.bits = 16,
.num_adc_channels = 8,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606c_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606");
const struct ad7606_chip_info ad7607_info = {
.max_samplerate = 200 * KILO,
.name = "ad7607",
.bits = 14,
.num_adc_channels = 8,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7607_chan_scale_setup,
.offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7607_info, "IIO_AD7606");
const struct ad7606_chip_info ad7608_info = {
.max_samplerate = 200 * KILO,
.name = "ad7608",
.bits = 18,
.num_adc_channels = 8,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7608_chan_scale_setup,
.offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7608_info, "IIO_AD7606");
const struct ad7606_chip_info ad7609_info = {
.max_samplerate = 200 * KILO,
.name = "ad7609",
.bits = 18,
.num_adc_channels = 8,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7609_chan_scale_setup,
.offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7609_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606c_18_info = {
.max_samplerate = 1 * MEGA,
.name = "ad7606c18",
.bits = 18,
.num_adc_channels = 8,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606c_18bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606");
const struct ad7606_chip_info ad7616_info = {
.max_samplerate = 1 * MEGA,
.init_delay_ms = 15,
.name = "ad7616",
.bits = 16,
.num_adc_channels = 16,
.oversampling_avail = ad7616_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
.os_req_reset = true,
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.sw_setup_cb = ad7616_sw_mode_setup,
.offload_storagebits = 16,
};
EXPORT_SYMBOL_NS_GPL(ad7616_info, "IIO_AD7606");
int ad7606_reset(struct ad7606_state *st)
{
if (st->gpio_reset) {
gpiod_set_value(st->gpio_reset, 1);
ndelay(100); /* t_reset >= 100ns */
gpiod_set_value(st->gpio_reset, 0);
return 0;
}
return -ENODEV;
}
EXPORT_SYMBOL_NS_GPL(ad7606_reset, "IIO_AD7606");
static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
if (!st->sw_mode_en) {
/* tied to logic low, analog input range is +/- 5V */
cs->range = 0;
cs->scale_avail = ad7606_16bit_hw_scale_avail;
cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
return 0;
}
/* Scale of 0.076293 is only available in sw mode */
/* After reset, in software mode, ±10 V is set by default */
cs->range = 2;
cs->scale_avail = ad7606_16bit_sw_scale_avail;
cs->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail);
return 0;
}
static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
bool *bipolar, bool *differential)
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned int num_channels = st->chip_info->num_adc_channels;
struct device *dev = st->dev;
int ret;
*bipolar = false;
*differential = false;
device_for_each_child_node_scoped(dev, child) {
u32 pins[2];
int reg;
ret = fwnode_property_read_u32(child, "reg", &reg);
if (ret)
continue;
/* channel number (here) is from 1 to num_channels */
if (reg < 1 || reg > num_channels) {
dev_warn(dev,
"Invalid channel number (ignoring): %d\n", reg);
continue;
}
if (reg != (ch + 1))
continue;
*bipolar = fwnode_property_read_bool(child, "bipolar");
ret = fwnode_property_read_u32_array(child, "diff-channels",
pins, ARRAY_SIZE(pins));
/* Channel is differential, if pins are the same as 'reg' */
if (ret == 0 && (pins[0] != reg || pins[1] != reg)) {
dev_err(dev,
"Differential pins must be the same as 'reg'");
return -EINVAL;
}
*differential = (ret == 0);
if (*differential && !*bipolar) {
dev_err(dev,
"'bipolar' must be added for diff channel %d\n",
reg);
return -EINVAL;
}
return 0;
}
return 0;
}
static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
bool bipolar, differential;
int ret;
if (!st->sw_mode_en) {
cs->range = 0;
cs->scale_avail = ad7606_18bit_hw_scale_avail;
cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
return 0;
}
ret = ad7606_get_chan_config(indio_dev, chan->scan_index, &bipolar,
&differential);
if (ret)
return ret;
if (differential) {
cs->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail;
cs->num_scales =
ARRAY_SIZE(ad7606c_18bit_differential_bipolar_scale_avail);
/* Bipolar differential ranges start at 8 (b1000) */
cs->reg_offset = 8;
cs->range = 1;
chan->differential = 1;
chan->channel2 = chan->channel;
return 0;
}
chan->differential = 0;
if (bipolar) {
cs->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail;
cs->num_scales =
ARRAY_SIZE(ad7606c_18bit_single_ended_bipolar_scale_avail);
/* Bipolar single-ended ranges start at 0 (b0000) */
cs->reg_offset = 0;
cs->range = 3;
chan->scan_type.sign = 's';
return 0;
}
cs->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail;
cs->num_scales =
ARRAY_SIZE(ad7606c_18bit_single_ended_unipolar_scale_avail);
/* Unipolar single-ended ranges start at 5 (b0101) */
cs->reg_offset = 5;
cs->range = 1;
chan->scan_type.sign = 'u';
return 0;
}
static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
bool bipolar, differential;
int ret;
if (!st->sw_mode_en) {
cs->range = 0;
cs->scale_avail = ad7606_16bit_hw_scale_avail;
cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
return 0;
}
ret = ad7606_get_chan_config(indio_dev, chan->scan_index, &bipolar,
&differential);
if (ret)
return ret;
if (differential) {
cs->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail;
cs->num_scales =
ARRAY_SIZE(ad7606c_16bit_differential_bipolar_scale_avail);
/* Bipolar differential ranges start at 8 (b1000) */
cs->reg_offset = 8;
cs->range = 1;
chan->differential = 1;
chan->channel2 = chan->channel;
chan->scan_type.sign = 's';
return 0;
}
chan->differential = 0;
if (bipolar) {
cs->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail;
cs->num_scales =
ARRAY_SIZE(ad7606c_16bit_single_ended_bipolar_scale_avail);
/* Bipolar single-ended ranges start at 0 (b0000) */
cs->reg_offset = 0;
cs->range = 3;
chan->scan_type.sign = 's';
return 0;
}
cs->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail;
cs->num_scales =
ARRAY_SIZE(ad7606c_16bit_single_ended_unipolar_scale_avail);
/* Unipolar single-ended ranges start at 5 (b0101) */
cs->reg_offset = 5;
cs->range = 1;
chan->scan_type.sign = 'u';
return 0;
}
static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
cs->range = 0;
cs->scale_avail = ad7607_hw_scale_avail;
cs->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail);
return 0;
}
static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
cs->range = 0;
cs->scale_avail = ad7606_18bit_hw_scale_avail;
cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
return 0;
}
static int ad7609_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
cs->range = 0;
cs->scale_avail = ad7609_hw_scale_avail;
cs->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail);
return 0;
}
static int ad7606_reg_access(struct iio_dev *indio_dev,
unsigned int reg,
unsigned int writeval,
unsigned int *readval)
{
struct ad7606_state *st = iio_priv(indio_dev);
int ret;
guard(mutex)(&st->lock);
if (readval) {
ret = st->bops->reg_read(st, reg);
if (ret < 0)
return ret;
*readval = ret;
return 0;
} else {
return st->bops->reg_write(st, reg, writeval);
}
}
static int ad7606_pwm_set_high(struct ad7606_state *st)
{
struct pwm_state cnvst_pwm_state;
int ret;
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
cnvst_pwm_state.enabled = true;
cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period;
ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
return ret;
}
int ad7606_pwm_set_low(struct ad7606_state *st)
{
struct pwm_state cnvst_pwm_state;
int ret;
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
cnvst_pwm_state.enabled = true;
cnvst_pwm_state.duty_cycle = 0;
ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
return ret;
}
EXPORT_SYMBOL_NS_GPL(ad7606_pwm_set_low, "IIO_AD7606");
int ad7606_pwm_set_swing(struct ad7606_state *st)
{
struct pwm_state cnvst_pwm_state;
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
cnvst_pwm_state.enabled = true;
cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2;
return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
}
EXPORT_SYMBOL_NS_GPL(ad7606_pwm_set_swing, "IIO_AD7606");
static bool ad7606_pwm_is_swinging(struct ad7606_state *st)
{
struct pwm_state cnvst_pwm_state;
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
return cnvst_pwm_state.duty_cycle != cnvst_pwm_state.period &&
cnvst_pwm_state.duty_cycle != 0;
}
static int ad7606_set_sampling_freq(struct ad7606_state *st, unsigned long freq)
{
struct pwm_state cnvst_pwm_state;
bool is_swinging = ad7606_pwm_is_swinging(st);
bool is_high;
if (freq == 0)
return -EINVAL;
/* Retrieve the previous state. */
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
is_high = cnvst_pwm_state.duty_cycle == cnvst_pwm_state.period;
cnvst_pwm_state.period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, freq);
cnvst_pwm_state.polarity = PWM_POLARITY_NORMAL;
if (is_high)
cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period;
else if (is_swinging)
cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2;
else
cnvst_pwm_state.duty_cycle = 0;
return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
}
static int ad7606_read_samples(struct ad7606_state *st)
{
unsigned int num = st->chip_info->num_adc_channels;
return st->bops->read_block(st->dev, num, &st->data);
}
static irqreturn_t ad7606_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7606_state *st = iio_priv(indio_dev);
int ret;
guard(mutex)(&st->lock);
ret = ad7606_read_samples(st);
if (ret)
goto error_ret;
iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data),
iio_get_time_ns(indio_dev));
error_ret:
iio_trigger_notify_done(indio_dev->trig);
/* The rising edge of the CONVST signal starts a new conversion. */
gpiod_set_value(st->gpio_convst, 1);
return IRQ_HANDLED;
}
static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
int *val)
{
struct ad7606_state *st = iio_priv(indio_dev);
const struct iio_chan_spec *chan;
unsigned int realbits;
int ret;
if (st->gpio_convst) {
gpiod_set_value(st->gpio_convst, 1);
} else {
ret = ad7606_pwm_set_high(st);
if (ret < 0)
return ret;
}
/*
* If no backend, wait for the interruption on busy pin, otherwise just add
* a delay to leave time for the data to be available. For now, the latter
* will not happen because IIO_CHAN_INFO_RAW is not supported for the backend.
* TODO: Add support for reading a single value when the backend is used.
*/
if (st->trig) {
ret = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(1000));
if (!ret) {
ret = -ETIMEDOUT;
goto error_ret;
}
} else {
/*
* If the BUSY interrupt is not available, wait enough time for
* the longest possible conversion (max for the whole family is
* around 350us).
*/
fsleep(400);
}
ret = ad7606_read_samples(st);
if (ret)
goto error_ret;
chan = &indio_dev->channels[ch];
realbits = chan->scan_type.realbits;
if (realbits > 16)
*val = st->data.buf32[ch];
else
*val = st->data.buf16[ch];
*val &= GENMASK(realbits - 1, 0);
if (chan->scan_type.sign == 's')
*val = sign_extend32(*val, realbits - 1);
error_ret:
if (!st->gpio_convst) {
ret = ad7606_pwm_set_low(st);
if (ret < 0)
return ret;
}
gpiod_set_value(st->gpio_convst, 0);
return ret;
}
static int ad7606_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret, ch = 0;
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs;
struct pwm_state cnvst_pwm_state;
switch (m) {
case IIO_CHAN_INFO_RAW:
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = ad7606_scan_direct(indio_dev, chan->scan_index, val);
iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
ch = chan->scan_index;
cs = &st->chan_scales[ch];
*val = cs->scale_avail[cs->range][0];
*val2 = cs->scale_avail[cs->range][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = st->oversampling;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
*val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period);
return IIO_VAL_INT;
}
return -EINVAL;
}
static ssize_t in_voltage_scale_available_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs = &st->chan_scales[0];
const unsigned int (*vals)[2] = cs->scale_avail;
unsigned int i;
size_t len = 0;
for (i = 0; i < cs->num_scales; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
vals[i][0], vals[i][1]);
buf[len - 1] = '\n';
return len;
}
static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0);
static int ad7606_write_scale_hw(struct iio_dev *indio_dev, int ch, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
gpiod_set_value(st->gpio_range, val);
return 0;
}
static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
DECLARE_BITMAP(values, 3);
values[0] = val & GENMASK(2, 0);
gpiod_multi_set_value_cansleep(st->gpio_os, values);
/* AD7616 requires a reset to update value */
if (st->chip_info->os_req_reset)
ad7606_reset(st);
return 0;
}
static int ad7606_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned int scale_avail_uv[AD760X_MAX_SCALES];
struct ad7606_chan_scale *cs;
int i, ret, ch = 0;
guard(mutex)(&st->lock);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
ch = chan->scan_index;
cs = &st->chan_scales[ch];
for (i = 0; i < cs->num_scales; i++) {
scale_avail_uv[i] = cs->scale_avail[i][0] * MICRO +
cs->scale_avail[i][1];
}
val = (val * MICRO) + val2;
i = find_closest(val, scale_avail_uv, cs->num_scales);
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = st->write_scale(indio_dev, ch, i + cs->reg_offset);
iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
cs->range = i;
return 0;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
if (val2)
return -EINVAL;
i = find_closest(val, st->oversampling_avail,
st->num_os_ratios);
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = st->write_os(indio_dev, i);
iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
st->oversampling = st->oversampling_avail[i];
return 0;
case IIO_CHAN_INFO_SAMP_FREQ:
if (val < 0 && val2 != 0)
return -EINVAL;
return ad7606_set_sampling_freq(st, val);
default:
return -EINVAL;
}
}
static ssize_t ad7606_oversampling_ratio_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
const unsigned int *vals = st->oversampling_avail;
unsigned int i;
size_t len = 0;
for (i = 0; i < st->num_os_ratios; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "%u ", vals[i]);
buf[len - 1] = '\n';
return len;
}
static IIO_DEVICE_ATTR(oversampling_ratio_available, 0444,
ad7606_oversampling_ratio_avail, NULL, 0);
static struct attribute *ad7606_attributes_os_and_range[] = {
&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
&iio_dev_attr_oversampling_ratio_available.dev_attr.attr,
NULL,
};
static const struct attribute_group ad7606_attribute_group_os_and_range = {
.attrs = ad7606_attributes_os_and_range,
};
static struct attribute *ad7606_attributes_os[] = {
&iio_dev_attr_oversampling_ratio_available.dev_attr.attr,
NULL,
};
static const struct attribute_group ad7606_attribute_group_os = {
.attrs = ad7606_attributes_os,
};
static struct attribute *ad7606_attributes_range[] = {
&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group ad7606_attribute_group_range = {
.attrs = ad7606_attributes_range,
};
static int ad7606_request_gpios(struct ad7606_state *st)
{
struct device *dev = st->dev;
st->gpio_convst = devm_gpiod_get_optional(dev, "adi,conversion-start",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_convst))
return PTR_ERR(st->gpio_convst);
st->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_reset))
return PTR_ERR(st->gpio_reset);
st->gpio_range = devm_gpiod_get_optional(dev, "adi,range",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_range))
return PTR_ERR(st->gpio_range);
st->gpio_standby = devm_gpiod_get_optional(dev, "standby",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_standby))
return PTR_ERR(st->gpio_standby);
st->gpio_frstdata = devm_gpiod_get_optional(dev, "adi,first-data",
GPIOD_IN);
if (IS_ERR(st->gpio_frstdata))
return PTR_ERR(st->gpio_frstdata);
if (!st->chip_info->oversampling_num)
return 0;
st->gpio_os = devm_gpiod_get_array_optional(dev,
"adi,oversampling-ratio",
GPIOD_OUT_LOW);
return PTR_ERR_OR_ZERO(st->gpio_os);
}
/*
* The BUSY signal indicates when conversions are in progress, so when a rising
* edge of CONVST is applied, BUSY goes logic high and transitions low at the
* end of the entire conversion process. The falling edge of the BUSY signal
* triggers this interrupt.
*/
static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
{
struct iio_dev *indio_dev = dev_id;
struct ad7606_state *st = iio_priv(indio_dev);
int ret;
if (iio_buffer_enabled(indio_dev)) {
if (st->gpio_convst) {
gpiod_set_value(st->gpio_convst, 0);
} else {
ret = ad7606_pwm_set_low(st);
if (ret < 0) {
dev_err(st->dev, "PWM set low failed");
goto done;
}
}
iio_trigger_poll_nested(st->trig);
} else {
complete(&st->completion);
}
done:
return IRQ_HANDLED;
};
static int ad7606_validate_trigger(struct iio_dev *indio_dev,
struct iio_trigger *trig)
{
struct ad7606_state *st = iio_priv(indio_dev);
if (st->trig != trig)
return -EINVAL;
return 0;
}
static int ad7606_buffer_postenable(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
gpiod_set_value(st->gpio_convst, 1);
return 0;
}
static int ad7606_buffer_predisable(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
gpiod_set_value(st->gpio_convst, 0);
return 0;
}
static int ad7606_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long info)
{
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs;
unsigned int ch = 0;
switch (info) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*vals = st->oversampling_avail;
*length = st->num_os_ratios;
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
ch = chan->scan_index;
cs = &st->chan_scales[ch];
*vals = (int *)cs->scale_avail;
*length = cs->num_scales * 2;
*type = IIO_VAL_INT_PLUS_MICRO;
return IIO_AVAIL_LIST;
}
return -EINVAL;
}
static int ad7606_backend_buffer_postenable(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
return ad7606_pwm_set_swing(st);
}
static int ad7606_backend_buffer_predisable(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
return ad7606_pwm_set_low(st);
}
static int ad7606_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct ad7606_state *st = iio_priv(indio_dev);
/*
* The update scan mode is only for iio backend compatible drivers.
* If the specific update_scan_mode is not defined in the bus ops,
* just do nothing and return 0.
*/
if (!st->bops->update_scan_mode)
return 0;
return st->bops->update_scan_mode(indio_dev, scan_mask);
}
static const struct iio_buffer_setup_ops ad7606_buffer_ops = {
.postenable = &ad7606_buffer_postenable,
.predisable = &ad7606_buffer_predisable,
};
static const struct iio_buffer_setup_ops ad7606_backend_buffer_ops = {
.postenable = &ad7606_backend_buffer_postenable,
.predisable = &ad7606_backend_buffer_predisable,
};
static const struct iio_info ad7606_info_no_os_or_range = {
.read_raw = &ad7606_read_raw,
.validate_trigger = &ad7606_validate_trigger,
.update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_info ad7606_info_os_and_range = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_os_and_range,
.validate_trigger = &ad7606_validate_trigger,
.update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_info ad7606_info_sw_mode = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.read_avail = &ad7606_read_avail,
.debugfs_reg_access = &ad7606_reg_access,
.validate_trigger = &ad7606_validate_trigger,
.update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_info ad7606_info_os = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_os,
.validate_trigger = &ad7606_validate_trigger,
.update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_info ad7606_info_range = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_range,
.validate_trigger = &ad7606_validate_trigger,
.update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_trigger_ops ad7606_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
};
static int ad7606_write_mask(struct ad7606_state *st, unsigned int addr,
unsigned long mask, unsigned int val)
{
int readval;
readval = st->bops->reg_read(st, addr);
if (readval < 0)
return readval;
readval &= ~mask;
readval |= val;
return st->bops->reg_write(st, addr, readval);
}
static int ad7616_write_scale_sw(struct iio_dev *indio_dev, int ch, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned int ch_addr, mode, ch_index;
/*
* Ad7616 has 16 channels divided in group A and group B.
* The range of channels from A are stored in registers with address 4
* while channels from B are stored in register with address 6.
* The last bit from channels determines if it is from group A or B
* because the order of channels in iio is 0A, 0B, 1A, 1B...
*/
ch_index = ch >> 1;
ch_addr = AD7616_RANGE_CH_ADDR(ch_index);
if ((ch & 0x1) == 0) /* channel A */
ch_addr += AD7616_RANGE_CH_A_ADDR_OFF;
else /* channel B */
ch_addr += AD7616_RANGE_CH_B_ADDR_OFF;
/* 0b01 for 2.5v, 0b10 for 5v and 0b11 for 10v */
mode = AD7616_RANGE_CH_MODE(ch_index, ((val + 1) & 0b11));
return ad7606_write_mask(st, ch_addr, AD7616_RANGE_CH_MSK(ch_index),
mode);
}
static int ad7616_write_os_sw(struct iio_dev *indio_dev, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
return ad7606_write_mask(st, AD7616_CONFIGURATION_REGISTER,
AD7616_OS_MASK, val << 2);
}
static int ad7606_write_scale_sw(struct iio_dev *indio_dev, int ch, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
return ad7606_write_mask(st, AD7606_RANGE_CH_ADDR(ch),
AD7606_RANGE_CH_MSK(ch),
AD7606_RANGE_CH_MODE(ch, val));
}
static int ad7606_write_os_sw(struct iio_dev *indio_dev, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
return st->bops->reg_write(st, AD7606_OS_MODE, val);
}
static int ad7616_sw_mode_setup(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
int ret;
/*
* Scale can be configured individually for each channel
* in software mode.
*/
st->write_scale = ad7616_write_scale_sw;
st->write_os = &ad7616_write_os_sw;
if (st->bops->sw_mode_config) {
ret = st->bops->sw_mode_config(indio_dev);
if (ret)
return ret;
}
/* Activate Burst mode and SEQEN MODE */
return ad7606_write_mask(st, AD7616_CONFIGURATION_REGISTER,
AD7616_BURST_MODE | AD7616_SEQEN_MODE,
AD7616_BURST_MODE | AD7616_SEQEN_MODE);
}
static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
DECLARE_BITMAP(os, 3);
bitmap_fill(os, 3);
/*
* Software mode is enabled when all three oversampling
* pins are set to high. If oversampling gpios are defined
* in the device tree, then they need to be set to high,
* otherwise, they must be hardwired to VDD
*/
if (st->gpio_os)
gpiod_multi_set_value_cansleep(st->gpio_os, os);
/* OS of 128 and 256 are available only in software mode */
st->oversampling_avail = ad7606b_oversampling_avail;
st->num_os_ratios = ARRAY_SIZE(ad7606b_oversampling_avail);
st->write_scale = ad7606_write_scale_sw;
st->write_os = &ad7606_write_os_sw;
if (!st->bops->sw_mode_config)
return 0;
return st->bops->sw_mode_config(indio_dev);
}
static int ad7606_probe_channels(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
struct iio_chan_spec *channels;
bool slow_bus;
int ret, i;
slow_bus = !(st->bops->iio_backend_config || st->offload_en);
indio_dev->num_channels = st->chip_info->num_adc_channels;
/* Slow buses also get 1 more channel for soft timestamp */
if (slow_bus)
indio_dev->num_channels++;
channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels),
GFP_KERNEL);
if (!channels)
return -ENOMEM;
for (i = 0; i < st->chip_info->num_adc_channels; i++) {
struct iio_chan_spec *chan = &channels[i];
chan->type = IIO_VOLTAGE;
chan->indexed = 1;
chan->channel = i;
chan->scan_index = i;
chan->scan_type.sign = 's';
chan->scan_type.realbits = st->chip_info->bits;
/*
* If in SPI offload mode, storagebits are set based
* on the spi-engine hw implementation.
*/
chan->scan_type.storagebits = st->offload_en ?
st->chip_info->offload_storagebits :
(st->chip_info->bits > 16 ? 32 : 16);
chan->scan_type.endianness = IIO_CPU;
if (indio_dev->modes & INDIO_DIRECT_MODE)
chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
if (st->sw_mode_en) {
chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
chan->info_mask_separate_available |=
BIT(IIO_CHAN_INFO_SCALE);
/*
* All chips with software mode support oversampling,
* so we skip the oversampling_available check. And the
* shared_by_type instead of shared_by_all on slow
* buses is for backward compatibility.
*/
if (slow_bus)
chan->info_mask_shared_by_type |=
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
else
chan->info_mask_shared_by_all |=
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
chan->info_mask_shared_by_all_available |=
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
} else {
chan->info_mask_shared_by_type |=
BIT(IIO_CHAN_INFO_SCALE);
if (st->chip_info->oversampling_avail)
chan->info_mask_shared_by_all |=
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
}
if (!slow_bus)
chan->info_mask_shared_by_all |=
BIT(IIO_CHAN_INFO_SAMP_FREQ);
ret = st->chip_info->scale_setup_cb(indio_dev, chan);
if (ret)
return ret;
}
if (slow_bus)
channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i);
indio_dev->channels = channels;
return 0;
}
static void ad7606_pwm_disable(void *data)
{
pwm_disable(data);
}
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
const struct ad7606_chip_info *chip_info,
const struct ad7606_bus_ops *bops)
{
struct ad7606_state *st;
int ret;
struct iio_dev *indio_dev;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
ret = devm_mutex_init(dev, &st->lock);
if (ret)
return ret;
st->dev = dev;
st->bops = bops;
st->base_address = base_address;
st->oversampling = 1;
st->sw_mode_en = device_property_read_bool(dev, "adi,sw-mode");
if (st->sw_mode_en && !chip_info->sw_setup_cb)
return dev_err_probe(dev, -EINVAL,
"Software mode is not supported for this chip\n");
ret = devm_regulator_get_enable(dev, "avcc");
if (ret)
return dev_err_probe(dev, ret,
"Failed to enable specified AVcc supply\n");
st->chip_info = chip_info;
if (st->chip_info->oversampling_num) {
st->oversampling_avail = st->chip_info->oversampling_avail;
st->num_os_ratios = st->chip_info->oversampling_num;
}
ret = ad7606_request_gpios(st);
if (ret)
return ret;
if (st->gpio_os) {
if (st->gpio_range)
indio_dev->info = &ad7606_info_os_and_range;
else
indio_dev->info = &ad7606_info_os;
} else {
if (st->gpio_range)
indio_dev->info = &ad7606_info_range;
else
indio_dev->info = &ad7606_info_no_os_or_range;
}
/* AXI ADC backend doesn't support single read. */
indio_dev->modes = st->bops->iio_backend_config ? 0 : INDIO_DIRECT_MODE;
indio_dev->name = chip_info->name;
/* Using spi-engine with offload support ? */
if (st->bops->offload_config) {
ret = st->bops->offload_config(dev, indio_dev);
if (ret)
return ret;
}
ret = ad7606_probe_channels(indio_dev);
if (ret)
return ret;
ret = ad7606_reset(st);
if (ret)
dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
/* AD7616 requires al least 15ms to reconfigure after a reset */
if (st->chip_info->init_delay_ms) {
if (msleep_interruptible(st->chip_info->init_delay_ms))
return -ERESTARTSYS;
}
/* If convst pin is not defined, setup PWM. */
if (!st->gpio_convst || st->offload_en) {
st->cnvst_pwm = devm_pwm_get(dev, NULL);
if (IS_ERR(st->cnvst_pwm))
return PTR_ERR(st->cnvst_pwm);
/* The PWM is initialized at 1MHz to have a fast enough GPIO emulation. */
ret = ad7606_set_sampling_freq(st, 1 * MEGA);
if (ret)
return ret;
ret = ad7606_pwm_set_low(st);
if (ret)
return ret;
/*
* PWM is not disabled when sampling stops, but instead its duty cycle is set
* to 0% to be sure we have a "low" state. After we unload the driver, let's
* disable the PWM.
*/
ret = devm_add_action_or_reset(dev, ad7606_pwm_disable,
st->cnvst_pwm);
if (ret)
return ret;
}
if (st->bops->iio_backend_config) {
/*
* If there is a backend, the PWM should not overpass the maximum sampling
* frequency the chip supports.
*/
ret = ad7606_set_sampling_freq(st, chip_info->max_samplerate);
if (ret)
return ret;
ret = st->bops->iio_backend_config(dev, indio_dev);
if (ret)
return ret;
indio_dev->setup_ops = &ad7606_backend_buffer_ops;
} else if (!st->offload_en) {
/* Reserve the PWM use only for backend (force gpio_convst definition) */
if (!st->gpio_convst)
return dev_err_probe(dev, -EINVAL,
"No backend, connect convst to a GPIO");
init_completion(&st->completion);
st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
iio_device_id(indio_dev));
if (!st->trig)
return -ENOMEM;
st->trig->ops = &ad7606_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev);
ret = devm_iio_trigger_register(dev, st->trig);
if (ret)
return ret;
indio_dev->trig = iio_trigger_get(st->trig);
ret = devm_request_threaded_irq(dev, irq, NULL, &ad7606_interrupt,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
chip_info->name, indio_dev);
if (ret)
return ret;
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
&iio_pollfunc_store_time,
&ad7606_trigger_handler,
&ad7606_buffer_ops);
if (ret)
return ret;
}
st->write_scale = ad7606_write_scale_hw;
st->write_os = ad7606_write_os_hw;
/* Offload needs 1 DOUT line, applying this setting in sw_setup_cb. */
if (st->sw_mode_en || st->offload_en) {
indio_dev->info = &ad7606_info_sw_mode;
st->chip_info->sw_setup_cb(indio_dev);
}
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(ad7606_probe, "IIO_AD7606");
#ifdef CONFIG_PM_SLEEP
static int ad7606_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7606_state *st = iio_priv(indio_dev);
if (st->gpio_standby) {
gpiod_set_value(st->gpio_range, 1);
gpiod_set_value(st->gpio_standby, 1);
}
return 0;
}
static int ad7606_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7606_state *st = iio_priv(indio_dev);
if (st->gpio_standby) {
gpiod_set_value(st->gpio_range, st->chan_scales[0].range);
gpiod_set_value(st->gpio_standby, 1);
ad7606_reset(st);
}
return 0;
}
SIMPLE_DEV_PM_OPS(ad7606_pm_ops, ad7606_suspend, ad7606_resume);
EXPORT_SYMBOL_NS_GPL(ad7606_pm_ops, "IIO_AD7606");
#endif
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");