mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00

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 ...
1506 lines
39 KiB
C
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", ®);
|
|
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");
|