diff options
Diffstat (limited to 'drivers/iio/adc/ad7380.c')
-rw-r--r-- | drivers/iio/adc/ad7380.c | 917 |
1 files changed, 825 insertions, 92 deletions
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index 4f32cb22f140..4fcb49fdf566 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -15,6 +15,10 @@ * ad7386/7/8-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7386-4-7387-4-7388-4.pdf * adaq4370-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4370-4.pdf * adaq4380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4380-4.pdf + * adaq4381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4381-4.pdf + * + * HDL ad738x_fmc: https://analogdevicesinc.github.io/hdl/projects/ad738x_fmc/index.html + * */ #include <linux/align.h> @@ -29,11 +33,14 @@ #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/spi/offload/consumer.h> #include <linux/spi/spi.h> #include <linux/units.h> #include <linux/util_macros.h> #include <linux/iio/buffer.h> +#include <linux/iio/buffer-dmaengine.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> @@ -91,6 +98,12 @@ #define AD7380_NUM_SDO_LINES 1 #define AD7380_DEFAULT_GAIN_MILLI 1000 +/* + * Using SPI offload, storagebits is always 32, so can't be used to compute struct + * spi_transfer.len. Using realbits instead. + */ +#define AD7380_SPI_BYTES(scan_type) ((scan_type)->realbits > 16 ? 4 : 2) + struct ad7380_timing_specs { const unsigned int t_csh_ns; /* CS minimum high time */ }; @@ -98,6 +111,7 @@ struct ad7380_timing_specs { struct ad7380_chip_info { const char *name; const struct iio_chan_spec *channels; + const struct iio_chan_spec *offload_channels; unsigned int num_channels; unsigned int num_simult_channels; bool has_hardware_gain; @@ -110,6 +124,25 @@ struct ad7380_chip_info { unsigned int num_vcm_supplies; const unsigned long *available_scan_masks; const struct ad7380_timing_specs *timing_specs; + u32 max_conversion_rate_hz; +}; + +static const struct iio_event_spec ad7380_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_dir = BIT(IIO_EV_INFO_VALUE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_shared_by_dir = BIT(IIO_EV_INFO_VALUE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_shared_by_all = BIT(IIO_EV_INFO_ENABLE), + }, }; enum { @@ -197,6 +230,91 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = { }, }; +/* + * Defining here scan types for offload mode, since with current available HDL + * only a value of 32 for storagebits is supported. + */ + +/* Extended scan types for 12-bit unsigned chips, offload support. */ +static const struct iio_scan_type ad7380_scan_type_12_u_offload[] = { + [AD7380_SCAN_TYPE_NORMAL] = { + .sign = 'u', + .realbits = 12, + .storagebits = 32, + .endianness = IIO_CPU, + }, + [AD7380_SCAN_TYPE_RESOLUTION_BOOST] = { + .sign = 'u', + .realbits = 14, + .storagebits = 32, + .endianness = IIO_CPU, + }, +}; + +/* Extended scan types for 14-bit signed chips, offload support. */ +static const struct iio_scan_type ad7380_scan_type_14_s_offload[] = { + [AD7380_SCAN_TYPE_NORMAL] = { + .sign = 's', + .realbits = 14, + .storagebits = 32, + .endianness = IIO_CPU, + }, + [AD7380_SCAN_TYPE_RESOLUTION_BOOST] = { + .sign = 's', + .realbits = 16, + .storagebits = 32, + .endianness = IIO_CPU, + }, +}; + +/* Extended scan types for 14-bit unsigned chips, offload support. */ +static const struct iio_scan_type ad7380_scan_type_14_u_offload[] = { + [AD7380_SCAN_TYPE_NORMAL] = { + .sign = 'u', + .realbits = 14, + .storagebits = 32, + .endianness = IIO_CPU, + }, + [AD7380_SCAN_TYPE_RESOLUTION_BOOST] = { + .sign = 'u', + .realbits = 16, + .storagebits = 32, + .endianness = IIO_CPU, + }, +}; + +/* Extended scan types for 16-bit signed_chips, offload support. */ +static const struct iio_scan_type ad7380_scan_type_16_s_offload[] = { + [AD7380_SCAN_TYPE_NORMAL] = { + .sign = 's', + .realbits = 16, + .storagebits = 32, + .endianness = IIO_CPU, + }, + [AD7380_SCAN_TYPE_RESOLUTION_BOOST] = { + .sign = 's', + .realbits = 18, + .storagebits = 32, + .endianness = IIO_CPU, + }, +}; + +/* Extended scan types for 16-bit unsigned chips, offload support. */ +static const struct iio_scan_type ad7380_scan_type_16_u_offload[] = { + [AD7380_SCAN_TYPE_NORMAL] = { + .sign = 'u', + .realbits = 16, + .storagebits = 32, + .endianness = IIO_CPU, + }, + [AD7380_SCAN_TYPE_RESOLUTION_BOOST] = { + .sign = 'u', + .realbits = 18, + .storagebits = 32, + .endianness = IIO_CPU, + }, +}; + #define _AD7380_CHANNEL(index, bits, diff, sign, gain) { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ @@ -214,50 +332,127 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = { .has_ext_scan_type = 1, \ .ext_scan_type = ad7380_scan_type_##bits##_##sign, \ .num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits##_##sign), \ + .event_spec = ad7380_events, \ + .num_event_specs = ARRAY_SIZE(ad7380_events), \ +} + +#define _AD7380_OFFLOAD_CHANNEL(index, bits, diff, sign, gain) { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + ((gain) ? BIT(IIO_CHAN_INFO_SCALE) : 0) | \ + ((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \ + .info_mask_shared_by_type = ((gain) ? 0 : BIT(IIO_CHAN_INFO_SCALE)) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .indexed = 1, \ + .differential = (diff), \ + .channel = (diff) ? (2 * (index)) : (index), \ + .channel2 = (diff) ? (2 * (index) + 1) : 0, \ + .scan_index = (index), \ + .has_ext_scan_type = 1, \ + .ext_scan_type = ad7380_scan_type_##bits##_##sign##_offload, \ + .num_ext_scan_type = \ + ARRAY_SIZE(ad7380_scan_type_##bits##_##sign##_offload), \ + .event_spec = ad7380_events, \ + .num_event_specs = ARRAY_SIZE(ad7380_events), \ } +/* + * Notes on the offload channels: + * - There is no soft timestamp since everything is done in hardware. + * - There is a sampling frequency attribute added. This controls the SPI + * offload trigger. + * - The storagebits value depends on the SPI offload provider. Currently there + * is only one supported provider, namely the ADI PULSAR ADC HDL project, + * which always uses 32-bit words for data values, even for <= 16-bit ADCs. + * So the value is just hardcoded to 32 for now. + */ + #define AD7380_CHANNEL(index, bits, diff, sign) \ _AD7380_CHANNEL(index, bits, diff, sign, false) #define ADAQ4380_CHANNEL(index, bits, diff, sign) \ _AD7380_CHANNEL(index, bits, diff, sign, true) -#define DEFINE_AD7380_2_CHANNEL(name, bits, diff, sign) \ +#define DEFINE_AD7380_2_CHANNEL(name, bits, diff, sign) \ +static const struct iio_chan_spec name[] = { \ + AD7380_CHANNEL(0, bits, diff, sign), \ + AD7380_CHANNEL(1, bits, diff, sign), \ + IIO_CHAN_SOFT_TIMESTAMP(2), \ +} + +#define DEFINE_AD7380_4_CHANNEL(name, bits, diff, sign) \ +static const struct iio_chan_spec name[] = { \ + AD7380_CHANNEL(0, bits, diff, sign), \ + AD7380_CHANNEL(1, bits, diff, sign), \ + AD7380_CHANNEL(2, bits, diff, sign), \ + AD7380_CHANNEL(3, bits, diff, sign), \ + IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + +#define DEFINE_ADAQ4380_4_CHANNEL(name, bits, diff, sign) \ +static const struct iio_chan_spec name[] = { \ + ADAQ4380_CHANNEL(0, bits, diff, sign), \ + ADAQ4380_CHANNEL(1, bits, diff, sign), \ + ADAQ4380_CHANNEL(2, bits, diff, sign), \ + ADAQ4380_CHANNEL(3, bits, diff, sign), \ + IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + +#define DEFINE_AD7380_8_CHANNEL(name, bits, diff, sign) \ +static const struct iio_chan_spec name[] = { \ + AD7380_CHANNEL(0, bits, diff, sign), \ + AD7380_CHANNEL(1, bits, diff, sign), \ + AD7380_CHANNEL(2, bits, diff, sign), \ + AD7380_CHANNEL(3, bits, diff, sign), \ + AD7380_CHANNEL(4, bits, diff, sign), \ + AD7380_CHANNEL(5, bits, diff, sign), \ + AD7380_CHANNEL(6, bits, diff, sign), \ + AD7380_CHANNEL(7, bits, diff, sign), \ + IIO_CHAN_SOFT_TIMESTAMP(8), \ +} + +#define AD7380_OFFLOAD_CHANNEL(index, bits, diff, sign) \ +_AD7380_OFFLOAD_CHANNEL(index, bits, diff, sign, false) + +#define ADAQ4380_OFFLOAD_CHANNEL(index, bits, diff, sign) \ +_AD7380_OFFLOAD_CHANNEL(index, bits, diff, sign, true) + +#define DEFINE_AD7380_2_OFFLOAD_CHANNEL(name, bits, diff, sign) \ static const struct iio_chan_spec name[] = { \ - AD7380_CHANNEL(0, bits, diff, sign), \ - AD7380_CHANNEL(1, bits, diff, sign), \ - IIO_CHAN_SOFT_TIMESTAMP(2), \ + AD7380_OFFLOAD_CHANNEL(0, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(1, bits, diff, sign), \ } -#define DEFINE_AD7380_4_CHANNEL(name, bits, diff, sign) \ +#define DEFINE_AD7380_4_OFFLOAD_CHANNEL(name, bits, diff, sign) \ static const struct iio_chan_spec name[] = { \ - AD7380_CHANNEL(0, bits, diff, sign), \ - AD7380_CHANNEL(1, bits, diff, sign), \ - AD7380_CHANNEL(2, bits, diff, sign), \ - AD7380_CHANNEL(3, bits, diff, sign), \ - IIO_CHAN_SOFT_TIMESTAMP(4), \ + AD7380_OFFLOAD_CHANNEL(0, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(1, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(2, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(3, bits, diff, sign), \ } -#define DEFINE_ADAQ4380_4_CHANNEL(name, bits, diff, sign) \ -static const struct iio_chan_spec name[] = { \ - ADAQ4380_CHANNEL(0, bits, diff, sign), \ - ADAQ4380_CHANNEL(1, bits, diff, sign), \ - ADAQ4380_CHANNEL(2, bits, diff, sign), \ - ADAQ4380_CHANNEL(3, bits, diff, sign), \ - IIO_CHAN_SOFT_TIMESTAMP(4), \ +#define DEFINE_ADAQ4380_4_OFFLOAD_CHANNEL(name, bits, diff, sign) \ +static const struct iio_chan_spec name[] = { \ + AD7380_OFFLOAD_CHANNEL(0, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(1, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(2, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(3, bits, diff, sign), \ } -#define DEFINE_AD7380_8_CHANNEL(name, bits, diff, sign) \ +#define DEFINE_AD7380_8_OFFLOAD_CHANNEL(name, bits, diff, sign) \ static const struct iio_chan_spec name[] = { \ - AD7380_CHANNEL(0, bits, diff, sign), \ - AD7380_CHANNEL(1, bits, diff, sign), \ - AD7380_CHANNEL(2, bits, diff, sign), \ - AD7380_CHANNEL(3, bits, diff, sign), \ - AD7380_CHANNEL(4, bits, diff, sign), \ - AD7380_CHANNEL(5, bits, diff, sign), \ - AD7380_CHANNEL(6, bits, diff, sign), \ - AD7380_CHANNEL(7, bits, diff, sign), \ - IIO_CHAN_SOFT_TIMESTAMP(8), \ + AD7380_OFFLOAD_CHANNEL(0, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(1, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(2, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(3, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(4, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(5, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(6, bits, diff, sign), \ + AD7380_OFFLOAD_CHANNEL(7, bits, diff, sign), \ } /* fully differential */ @@ -266,6 +461,7 @@ DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1, s); DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1, s); DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1, s); DEFINE_ADAQ4380_4_CHANNEL(adaq4380_4_channels, 16, 1, s); +DEFINE_ADAQ4380_4_CHANNEL(adaq4381_4_channels, 14, 1, s); /* pseudo differential */ DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0, s); DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0, s); @@ -280,6 +476,28 @@ DEFINE_AD7380_8_CHANNEL(ad7386_4_channels, 16, 0, u); DEFINE_AD7380_8_CHANNEL(ad7387_4_channels, 14, 0, u); DEFINE_AD7380_8_CHANNEL(ad7388_4_channels, 12, 0, u); +/* offload channels */ +DEFINE_AD7380_2_OFFLOAD_CHANNEL(ad7380_offload_channels, 16, 1, s); +DEFINE_AD7380_2_OFFLOAD_CHANNEL(ad7381_offload_channels, 14, 1, s); +DEFINE_AD7380_4_OFFLOAD_CHANNEL(ad7380_4_offload_channels, 16, 1, s); +DEFINE_AD7380_4_OFFLOAD_CHANNEL(ad7381_4_offload_channels, 14, 1, s); +DEFINE_ADAQ4380_4_OFFLOAD_CHANNEL(adaq4380_4_offload_channels, 16, 1, s); +DEFINE_ADAQ4380_4_OFFLOAD_CHANNEL(adaq4381_4_offload_channels, 14, 1, s); + +/* pseudo differential */ +DEFINE_AD7380_2_OFFLOAD_CHANNEL(ad7383_offload_channels, 16, 0, s); +DEFINE_AD7380_2_OFFLOAD_CHANNEL(ad7384_offload_channels, 14, 0, s); +DEFINE_AD7380_4_OFFLOAD_CHANNEL(ad7383_4_offload_channels, 16, 0, s); +DEFINE_AD7380_4_OFFLOAD_CHANNEL(ad7384_4_offload_channels, 14, 0, s); + +/* Single ended */ +DEFINE_AD7380_4_OFFLOAD_CHANNEL(ad7386_offload_channels, 16, 0, u); +DEFINE_AD7380_4_OFFLOAD_CHANNEL(ad7387_offload_channels, 14, 0, u); +DEFINE_AD7380_4_OFFLOAD_CHANNEL(ad7388_offload_channels, 12, 0, u); +DEFINE_AD7380_8_OFFLOAD_CHANNEL(ad7386_4_offload_channels, 16, 0, u); +DEFINE_AD7380_8_OFFLOAD_CHANNEL(ad7387_4_offload_channels, 14, 0, u); +DEFINE_AD7380_8_OFFLOAD_CHANNEL(ad7388_4_offload_channels, 12, 0, u); + static const char * const ad7380_supplies[] = { "vcc", "vlogic", }; @@ -386,28 +604,33 @@ static const int ad7380_gains[] = { static const struct ad7380_chip_info ad7380_chip_info = { .name = "ad7380", .channels = ad7380_channels, + .offload_channels = ad7380_offload_channels, .num_channels = ARRAY_SIZE(ad7380_channels), .num_simult_channels = 2, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), .available_scan_masks = ad7380_2_channel_scan_masks, .timing_specs = &ad7380_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7381_chip_info = { .name = "ad7381", .channels = ad7381_channels, + .offload_channels = ad7381_offload_channels, .num_channels = ARRAY_SIZE(ad7381_channels), .num_simult_channels = 2, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), .available_scan_masks = ad7380_2_channel_scan_masks, .timing_specs = &ad7380_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7383_chip_info = { .name = "ad7383", .channels = ad7383_channels, + .offload_channels = ad7383_offload_channels, .num_channels = ARRAY_SIZE(ad7383_channels), .num_simult_channels = 2, .supplies = ad7380_supplies, @@ -416,11 +639,13 @@ static const struct ad7380_chip_info ad7383_chip_info = { .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies), .available_scan_masks = ad7380_2_channel_scan_masks, .timing_specs = &ad7380_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7384_chip_info = { .name = "ad7384", .channels = ad7384_channels, + .offload_channels = ad7384_offload_channels, .num_channels = ARRAY_SIZE(ad7384_channels), .num_simult_channels = 2, .supplies = ad7380_supplies, @@ -429,11 +654,13 @@ static const struct ad7380_chip_info ad7384_chip_info = { .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies), .available_scan_masks = ad7380_2_channel_scan_masks, .timing_specs = &ad7380_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7386_chip_info = { .name = "ad7386", .channels = ad7386_channels, + .offload_channels = ad7386_offload_channels, .num_channels = ARRAY_SIZE(ad7386_channels), .num_simult_channels = 2, .supplies = ad7380_supplies, @@ -441,11 +668,13 @@ static const struct ad7380_chip_info ad7386_chip_info = { .has_mux = true, .available_scan_masks = ad7380_2x2_channel_scan_masks, .timing_specs = &ad7380_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7387_chip_info = { .name = "ad7387", .channels = ad7387_channels, + .offload_channels = ad7387_offload_channels, .num_channels = ARRAY_SIZE(ad7387_channels), .num_simult_channels = 2, .supplies = ad7380_supplies, @@ -453,11 +682,13 @@ static const struct ad7380_chip_info ad7387_chip_info = { .has_mux = true, .available_scan_masks = ad7380_2x2_channel_scan_masks, .timing_specs = &ad7380_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7388_chip_info = { .name = "ad7388", .channels = ad7388_channels, + .offload_channels = ad7388_offload_channels, .num_channels = ARRAY_SIZE(ad7388_channels), .num_simult_channels = 2, .supplies = ad7380_supplies, @@ -465,11 +696,13 @@ static const struct ad7380_chip_info ad7388_chip_info = { .has_mux = true, .available_scan_masks = ad7380_2x2_channel_scan_masks, .timing_specs = &ad7380_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7380_4_chip_info = { .name = "ad7380-4", .channels = ad7380_4_channels, + .offload_channels = ad7380_4_offload_channels, .num_channels = ARRAY_SIZE(ad7380_4_channels), .num_simult_channels = 4, .supplies = ad7380_supplies, @@ -477,22 +710,26 @@ static const struct ad7380_chip_info ad7380_4_chip_info = { .external_ref_only = true, .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7381_4_chip_info = { .name = "ad7381-4", .channels = ad7381_4_channels, + .offload_channels = ad7381_4_offload_channels, .num_channels = ARRAY_SIZE(ad7381_4_channels), .num_simult_channels = 4, .supplies = ad7380_supplies, .num_supplies = ARRAY_SIZE(ad7380_supplies), .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7383_4_chip_info = { .name = "ad7383-4", .channels = ad7383_4_channels, + .offload_channels = ad7383_4_offload_channels, .num_channels = ARRAY_SIZE(ad7383_4_channels), .num_simult_channels = 4, .supplies = ad7380_supplies, @@ -501,11 +738,13 @@ static const struct ad7380_chip_info ad7383_4_chip_info = { .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies), .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7384_4_chip_info = { .name = "ad7384-4", .channels = ad7384_4_channels, + .offload_channels = ad7384_4_offload_channels, .num_channels = ARRAY_SIZE(ad7384_4_channels), .num_simult_channels = 4, .supplies = ad7380_supplies, @@ -514,11 +753,13 @@ static const struct ad7380_chip_info ad7384_4_chip_info = { .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies), .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7386_4_chip_info = { .name = "ad7386-4", .channels = ad7386_4_channels, + .offload_channels = ad7386_4_offload_channels, .num_channels = ARRAY_SIZE(ad7386_4_channels), .num_simult_channels = 4, .supplies = ad7380_supplies, @@ -526,11 +767,13 @@ static const struct ad7380_chip_info ad7386_4_chip_info = { .has_mux = true, .available_scan_masks = ad7380_2x4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7387_4_chip_info = { .name = "ad7387-4", .channels = ad7387_4_channels, + .offload_channels = ad7387_4_offload_channels, .num_channels = ARRAY_SIZE(ad7387_4_channels), .num_simult_channels = 4, .supplies = ad7380_supplies, @@ -538,11 +781,13 @@ static const struct ad7380_chip_info ad7387_4_chip_info = { .has_mux = true, .available_scan_masks = ad7380_2x4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info ad7388_4_chip_info = { .name = "ad7388-4", .channels = ad7388_4_channels, + .offload_channels = ad7388_4_offload_channels, .num_channels = ARRAY_SIZE(ad7388_4_channels), .num_simult_channels = 4, .supplies = ad7380_supplies, @@ -550,11 +795,13 @@ static const struct ad7380_chip_info ad7388_4_chip_info = { .has_mux = true, .available_scan_masks = ad7380_2x4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct ad7380_chip_info adaq4370_4_chip_info = { .name = "adaq4370-4", .channels = adaq4380_4_channels, + .offload_channels = adaq4380_4_offload_channels, .num_channels = ARRAY_SIZE(adaq4380_4_channels), .num_simult_channels = 4, .supplies = adaq4380_supplies, @@ -563,11 +810,13 @@ static const struct ad7380_chip_info adaq4370_4_chip_info = { .has_hardware_gain = true, .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 2 * MEGA, }; static const struct ad7380_chip_info adaq4380_4_chip_info = { .name = "adaq4380-4", .channels = adaq4380_4_channels, + .offload_channels = adaq4380_4_offload_channels, .num_channels = ARRAY_SIZE(adaq4380_4_channels), .num_simult_channels = 4, .supplies = adaq4380_supplies, @@ -576,13 +825,32 @@ static const struct ad7380_chip_info adaq4380_4_chip_info = { .has_hardware_gain = true, .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, +}; + +static const struct ad7380_chip_info adaq4381_4_chip_info = { + .name = "adaq4381-4", + .channels = adaq4381_4_channels, + .offload_channels = adaq4381_4_offload_channels, + .num_channels = ARRAY_SIZE(adaq4381_4_channels), + .num_simult_channels = 4, + .supplies = adaq4380_supplies, + .num_supplies = ARRAY_SIZE(adaq4380_supplies), + .adaq_internal_ref_only = true, + .has_hardware_gain = true, + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, +}; + +static const struct spi_offload_config ad7380_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | + SPI_OFFLOAD_CAP_RX_STREAM_DMA, }; struct ad7380_state { const struct ad7380_chip_info *chip_info; struct spi_device *spi; struct regmap *regmap; - unsigned int oversampling_ratio; bool resolution_boost_enabled; unsigned int ch; bool seq; @@ -594,6 +862,13 @@ struct ad7380_state { struct spi_message normal_msg; struct spi_transfer seq_xfer[4]; struct spi_message seq_msg; + struct spi_transfer offload_xfer; + struct spi_message offload_msg; + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + unsigned long offload_trigger_hz; + + int sample_freq_range[3]; /* * DMA (thus cache coherency maintenance) requires the transfer buffers * to live in their own cache lines. @@ -663,6 +938,20 @@ static int ad7380_regmap_reg_read(void *context, unsigned int reg, return 0; } +static const struct reg_default ad7380_reg_defaults[] = { + { AD7380_REG_ADDR_ALERT_LOW_TH, 0x800 }, + { AD7380_REG_ADDR_ALERT_HIGH_TH, 0x7FF }, +}; + +static const struct regmap_range ad7380_volatile_reg_ranges[] = { + regmap_reg_range(AD7380_REG_ADDR_CONFIG2, AD7380_REG_ADDR_ALERT), +}; + +static const struct regmap_access_table ad7380_volatile_regs = { + .yes_ranges = ad7380_volatile_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(ad7380_volatile_reg_ranges), +}; + static const struct regmap_config ad7380_regmap_config = { .reg_bits = 3, .val_bits = 12, @@ -670,20 +959,59 @@ static const struct regmap_config ad7380_regmap_config = { .reg_write = ad7380_regmap_reg_write, .max_register = AD7380_REG_ADDR_ALERT_HIGH_TH, .can_sleep = true, + .reg_defaults = ad7380_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ad7380_reg_defaults), + .volatile_table = &ad7380_volatile_regs, + .cache_type = REGCACHE_MAPLE, }; static int ad7380_debugfs_reg_access(struct iio_dev *indio_dev, u32 reg, u32 writeval, u32 *readval) { - iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - struct ad7380_state *st = iio_priv(indio_dev); + struct ad7380_state *st = iio_priv(indio_dev); + int ret; - if (readval) - return regmap_read(st->regmap, reg, readval); - else - return regmap_write(st->regmap, reg, writeval); - } - unreachable(); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + if (readval) + ret = regmap_read(st->regmap, reg, readval); + else + ret = regmap_write(st->regmap, reg, writeval); + + iio_device_release_direct(indio_dev); + + return ret; +} + +/** + * ad7380_regval_to_osr - convert OSR register value to ratio + * @regval: register value to check + * + * Returns: the ratio corresponding to the OSR register. If regval is not in + * bound, return 1 (oversampling disabled) + * + */ +static int ad7380_regval_to_osr(unsigned int regval) +{ + if (regval >= ARRAY_SIZE(ad7380_oversampling_ratios)) + return 1; + + return ad7380_oversampling_ratios[regval]; +} + +static int ad7380_get_osr(struct ad7380_state *st, int *val) +{ + u32 tmp; + int ret; + + ret = regmap_read(st->regmap, AD7380_REG_ADDR_CONFIG1, &tmp); + if (ret) + return ret; + + *val = ad7380_regval_to_osr(FIELD_GET(AD7380_CONFIG1_OSR, tmp)); + + return 0; } /* @@ -701,11 +1029,15 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch) .unit = SPI_DELAY_UNIT_NSECS, } }; - int ret; + int oversampling_ratio, ret; if (st->ch == ch) return 0; + ret = ad7380_get_osr(st, &oversampling_ratio); + if (ret) + return ret; + ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG1, AD7380_CONFIG1_CH, @@ -716,9 +1048,9 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch) st->ch = ch; - if (st->oversampling_ratio > 1) + if (oversampling_ratio > 1) xfer.delay.value = T_CONVERT_0_NS + - T_CONVERT_X_NS * (st->oversampling_ratio - 1) * + T_CONVERT_X_NS * (oversampling_ratio - 1) * st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES; return spi_sync_transfer(st->spi, &xfer, 1); @@ -729,20 +1061,25 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch) * @st: device instance specific state * @scan_type: current scan type */ -static void ad7380_update_xfers(struct ad7380_state *st, +static int ad7380_update_xfers(struct ad7380_state *st, const struct iio_scan_type *scan_type) { struct spi_transfer *xfer = st->seq ? st->seq_xfer : st->normal_xfer; unsigned int t_convert = T_CONVERT_NS; + int oversampling_ratio, ret; /* * In the case of oversampling, conversion time is higher than in normal * mode. Technically T_CONVERT_X_NS is lower for some chips, but we use * the maximum value for simplicity for now. */ - if (st->oversampling_ratio > 1) + ret = ad7380_get_osr(st, &oversampling_ratio); + if (ret) + return ret; + + if (oversampling_ratio > 1) t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS * - (st->oversampling_ratio - 1) * + (oversampling_ratio - 1) * st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES; if (st->seq) { @@ -751,11 +1088,11 @@ static void ad7380_update_xfers(struct ad7380_state *st, xfer[2].bits_per_word = xfer[3].bits_per_word = scan_type->realbits; xfer[2].len = xfer[3].len = - BITS_TO_BYTES(scan_type->storagebits) * + AD7380_SPI_BYTES(scan_type) * st->chip_info->num_simult_channels; xfer[3].rx_buf = xfer[2].rx_buf + xfer[2].len; /* Additional delay required here when oversampling is enabled */ - if (st->oversampling_ratio > 1) + if (oversampling_ratio > 1) xfer[2].delay.value = t_convert; else xfer[2].delay.value = 0; @@ -764,16 +1101,145 @@ static void ad7380_update_xfers(struct ad7380_state *st, xfer[0].delay.value = t_convert; xfer[0].delay.unit = SPI_DELAY_UNIT_NSECS; xfer[1].bits_per_word = scan_type->realbits; - xfer[1].len = BITS_TO_BYTES(scan_type->storagebits) * + xfer[1].len = AD7380_SPI_BYTES(scan_type) * st->chip_info->num_simult_channels; } + + return 0; } +static int ad7380_set_sample_freq(struct ad7380_state *st, int val) +{ + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + .periodic = { + .frequency_hz = val, + }, + }; + int ret; + + ret = spi_offload_trigger_validate(st->offload_trigger, &config); + if (ret) + return ret; + + st->offload_trigger_hz = config.periodic.frequency_hz; + + return 0; +} + +static int ad7380_init_offload_msg(struct ad7380_state *st, + struct iio_dev *indio_dev) +{ + struct spi_transfer *xfer = &st->offload_xfer; + struct device *dev = &st->spi->dev; + const struct iio_scan_type *scan_type; + int oversampling_ratio; + int ret; + + scan_type = iio_get_current_scan_type(indio_dev, + &indio_dev->channels[0]); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + if (st->chip_info->has_mux) { + int index; + + ret = iio_active_scan_mask_index(indio_dev); + if (ret < 0) + return ret; + + index = ret; + if (index == AD7380_SCAN_MASK_SEQ) { + ret = regmap_set_bits(st->regmap, AD7380_REG_ADDR_CONFIG1, + AD7380_CONFIG1_SEQ); + if (ret) + return ret; + + st->seq = true; + } else { + ret = ad7380_set_ch(st, index); + if (ret) + return ret; + } + } + + ret = ad7380_get_osr(st, &oversampling_ratio); + if (ret) + return ret; + + xfer->bits_per_word = scan_type->realbits; + xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + xfer->len = AD7380_SPI_BYTES(scan_type) * st->chip_info->num_simult_channels; + + spi_message_init_with_transfers(&st->offload_msg, xfer, 1); + st->offload_msg.offload = st->offload; + + ret = spi_optimize_message(st->spi, &st->offload_msg); + if (ret) { + dev_err(dev, "failed to prepare offload msg, err: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ad7380_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad7380_state *st = iio_priv(indio_dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + .periodic = { + .frequency_hz = st->offload_trigger_hz, + }, + }; + int ret; + + ret = ad7380_init_offload_msg(st, indio_dev); + if (ret) + return ret; + + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, &config); + if (ret) + spi_unoptimize_message(&st->offload_msg); + + return ret; +} + +static int ad7380_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad7380_state *st = iio_priv(indio_dev); + int ret; + + if (st->seq) { + ret = regmap_update_bits(st->regmap, + AD7380_REG_ADDR_CONFIG1, + AD7380_CONFIG1_SEQ, + FIELD_PREP(AD7380_CONFIG1_SEQ, 0)); + if (ret) + return ret; + + st->seq = false; + } + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + + spi_unoptimize_message(&st->offload_msg); + + return 0; +} + +static const struct iio_buffer_setup_ops ad7380_offload_buffer_setup_ops = { + .postenable = ad7380_offload_buffer_postenable, + .predisable = ad7380_offload_buffer_predisable, +}; + static int ad7380_triggered_buffer_preenable(struct iio_dev *indio_dev) { struct ad7380_state *st = iio_priv(indio_dev); const struct iio_scan_type *scan_type; struct spi_message *msg = &st->normal_msg; + int ret; /* * Currently, we always read all channels at the same time. The scan_type @@ -785,7 +1251,6 @@ static int ad7380_triggered_buffer_preenable(struct iio_dev *indio_dev) if (st->chip_info->has_mux) { unsigned int index; - int ret; /* * Depending on the requested scan_mask and current state, @@ -816,7 +1281,9 @@ static int ad7380_triggered_buffer_preenable(struct iio_dev *indio_dev) } - ad7380_update_xfers(st, scan_type); + ret = ad7380_update_xfers(st, scan_type); + if (ret) + return ret; return spi_optimize_message(st->spi, msg); } @@ -889,13 +1356,15 @@ static int ad7380_read_direct(struct ad7380_state *st, unsigned int scan_index, return ret; } - ad7380_update_xfers(st, scan_type); + ret = ad7380_update_xfers(st, scan_type); + if (ret) + return ret; ret = spi_sync(st->spi, &st->normal_msg); if (ret < 0) return ret; - if (scan_type->storagebits > 16) { + if (scan_type->realbits > 16) { if (scan_type->sign == 's') *val = sign_extend32(*(u32 *)(st->scan_data + 4 * index), scan_type->realbits - 1); @@ -920,6 +1389,7 @@ static int ad7380_read_raw(struct iio_dev *indio_dev, { struct ad7380_state *st = iio_priv(indio_dev); const struct iio_scan_type *scan_type; + int ret; scan_type = iio_get_current_scan_type(indio_dev, chan); @@ -928,11 +1398,15 @@ static int ad7380_read_raw(struct iio_dev *indio_dev, switch (info) { case IIO_CHAN_INFO_RAW: - iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - return ad7380_read_direct(st, chan->scan_index, - scan_type, val); - } - unreachable(); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = ad7380_read_direct(st, chan->scan_index, + scan_type, val); + + iio_device_release_direct(indio_dev); + + return ret; case IIO_CHAN_INFO_SCALE: /* * According to the datasheet, the LSB size is: @@ -961,8 +1435,19 @@ static int ad7380_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - *val = st->oversampling_ratio; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = ad7380_get_osr(st, val); + + iio_device_release_direct(indio_dev); + + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->offload_trigger_hz; return IIO_VAL_INT; default: return -EINVAL; @@ -974,6 +1459,8 @@ static int ad7380_read_avail(struct iio_dev *indio_dev, const int **vals, int *type, int *length, long mask) { + struct ad7380_state *st = iio_priv(indio_dev); + switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *vals = ad7380_oversampling_ratios; @@ -981,6 +1468,10 @@ static int ad7380_read_avail(struct iio_dev *indio_dev, *type = IIO_VAL_INT; return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = st->sample_freq_range; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; default: return -EINVAL; } @@ -1008,47 +1499,61 @@ static int ad7380_osr_to_regval(int ratio) return -EINVAL; } +static int ad7380_set_oversampling_ratio(struct ad7380_state *st, int val) +{ + int ret, osr, boost; + + osr = ad7380_osr_to_regval(val); + if (osr < 0) + return osr; + + /* always enable resolution boost when oversampling is enabled */ + boost = osr > 0 ? 1 : 0; + + ret = regmap_update_bits(st->regmap, + AD7380_REG_ADDR_CONFIG1, + AD7380_CONFIG1_OSR | AD7380_CONFIG1_RES, + FIELD_PREP(AD7380_CONFIG1_OSR, osr) | + FIELD_PREP(AD7380_CONFIG1_RES, boost)); + + if (ret) + return ret; + + st->resolution_boost_enabled = boost; + + /* + * Perform a soft reset. This will flush the oversampling + * block and FIFO but will maintain the content of the + * configurable registers. + */ + ret = regmap_update_bits(st->regmap, + AD7380_REG_ADDR_CONFIG2, + AD7380_CONFIG2_RESET, + FIELD_PREP(AD7380_CONFIG2_RESET, + AD7380_CONFIG2_RESET_SOFT)); + return ret; +} static int ad7380_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct ad7380_state *st = iio_priv(indio_dev); - int ret, osr, boost; + int ret; switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val < 1) + return -EINVAL; + return ad7380_set_sample_freq(st, val); case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - osr = ad7380_osr_to_regval(val); - if (osr < 0) - return osr; - - /* always enable resolution boost when oversampling is enabled */ - boost = osr > 0 ? 1 : 0; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; - iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - ret = regmap_update_bits(st->regmap, - AD7380_REG_ADDR_CONFIG1, - AD7380_CONFIG1_OSR | AD7380_CONFIG1_RES, - FIELD_PREP(AD7380_CONFIG1_OSR, osr) | - FIELD_PREP(AD7380_CONFIG1_RES, boost)); + ret = ad7380_set_oversampling_ratio(st, val); - if (ret) - return ret; + iio_device_release_direct(indio_dev); - st->oversampling_ratio = val; - st->resolution_boost_enabled = boost; - - /* - * Perform a soft reset. This will flush the oversampling - * block and FIFO but will maintain the content of the - * configurable registers. - */ - return regmap_update_bits(st->regmap, - AD7380_REG_ADDR_CONFIG2, - AD7380_CONFIG2_RESET, - FIELD_PREP(AD7380_CONFIG2_RESET, - AD7380_CONFIG2_RESET_SOFT)); - } - unreachable(); + return ret; default: return -EINVAL; } @@ -1063,12 +1568,179 @@ static int ad7380_get_current_scan_type(const struct iio_dev *indio_dev, : AD7380_SCAN_TYPE_NORMAL; } +static int ad7380_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct ad7380_state *st = iio_priv(indio_dev); + int tmp, ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_read(st->regmap, AD7380_REG_ADDR_CONFIG1, &tmp); + + iio_device_release_direct(indio_dev); + + if (ret) + return ret; + + return FIELD_GET(AD7380_CONFIG1_ALERTEN, tmp); +} + +static int ad7380_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct ad7380_state *st = iio_priv(indio_dev); + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_update_bits(st->regmap, + AD7380_REG_ADDR_CONFIG1, + AD7380_CONFIG1_ALERTEN, + FIELD_PREP(AD7380_CONFIG1_ALERTEN, state)); + + iio_device_release_direct(indio_dev); + + return ret; +} + +static int ad7380_get_alert_th(struct ad7380_state *st, + enum iio_event_direction dir, + int *val) +{ + int ret, tmp; + + switch (dir) { + case IIO_EV_DIR_RISING: + ret = regmap_read(st->regmap, + AD7380_REG_ADDR_ALERT_HIGH_TH, + &tmp); + if (ret) + return ret; + + *val = FIELD_GET(AD7380_ALERT_HIGH_TH, tmp); + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + ret = regmap_read(st->regmap, + AD7380_REG_ADDR_ALERT_LOW_TH, + &tmp); + if (ret) + return ret; + + *val = FIELD_GET(AD7380_ALERT_LOW_TH, tmp); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ad7380_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct ad7380_state *st = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_EV_INFO_VALUE: + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = ad7380_get_alert_th(st, dir, val); + + iio_device_release_direct(indio_dev); + return ret; + default: + return -EINVAL; + } +} + +static int ad7380_set_alert_th(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_direction dir, + int val) +{ + struct ad7380_state *st = iio_priv(indio_dev); + const struct iio_scan_type *scan_type; + u16 th; + + /* + * According to the datasheet, + * AD7380_REG_ADDR_ALERT_HIGH_TH[11:0] are the 12 MSB of the + * 16-bits internal alert high register. LSB are set to 0xf. + * AD7380_REG_ADDR_ALERT_LOW_TH[11:0] are the 12 MSB of the + * 16 bits internal alert low register. LSB are set to 0x0. + * + * When alert is enabled the conversion from the adc is compared + * immediately to the alert high/low thresholds, before any + * oversampling. This means that the thresholds are the same for + * normal mode and oversampling mode. + */ + + /* Extract the 12 MSB of val */ + scan_type = iio_get_current_scan_type(indio_dev, chan); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + th = val >> (scan_type->realbits - 12); + + switch (dir) { + case IIO_EV_DIR_RISING: + return regmap_write(st->regmap, + AD7380_REG_ADDR_ALERT_HIGH_TH, + th); + case IIO_EV_DIR_FALLING: + return regmap_write(st->regmap, + AD7380_REG_ADDR_ALERT_LOW_TH, + th); + default: + return -EINVAL; + } +} + +static int ad7380_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + int ret; + + switch (info) { + case IIO_EV_INFO_VALUE: + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = ad7380_set_alert_th(indio_dev, chan, dir, val); + + iio_device_release_direct(indio_dev); + return ret; + default: + return -EINVAL; + } +} + static const struct iio_info ad7380_info = { .read_raw = &ad7380_read_raw, .read_avail = &ad7380_read_avail, .write_raw = &ad7380_write_raw, .get_current_scan_type = &ad7380_get_current_scan_type, .debugfs_reg_access = &ad7380_debugfs_reg_access, + .read_event_config = &ad7380_read_event_config, + .write_event_config = &ad7380_write_event_config, + .read_event_value = &ad7380_read_event_value, + .write_event_value = &ad7380_write_event_value, }; static int ad7380_init(struct ad7380_state *st, bool external_ref_en) @@ -1092,7 +1764,6 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en) } /* This is the default value after reset. */ - st->oversampling_ratio = 1; st->ch = 0; st->seq = false; @@ -1103,6 +1774,53 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en) AD7380_NUM_SDO_LINES)); } +static int ad7380_probe_spi_offload(struct iio_dev *indio_dev, + struct ad7380_state *st) +{ + struct spi_device *spi = st->spi; + struct device *dev = &spi->dev; + struct dma_chan *rx_dma; + int sample_rate, ret; + + indio_dev->setup_ops = &ad7380_offload_buffer_setup_ops; + indio_dev->channels = st->chip_info->offload_channels; + /* Just removing the timestamp channel. */ + indio_dev->num_channels--; + + st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_PERIODIC); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "failed to get offload trigger\n"); + + sample_rate = st->chip_info->max_conversion_rate_hz * + AD7380_NUM_SDO_LINES / st->chip_info->num_simult_channels; + + st->sample_freq_range[0] = 1; /* min */ + st->sample_freq_range[1] = 1; /* step */ + st->sample_freq_range[2] = sample_rate; /* max */ + + /* + * Starting with a quite low frequency, to allow oversampling x32, + * user is then reponsible to adjust the frequency for the specific case. + */ + ret = ad7380_set_sample_freq(st, sample_rate / 32); + if (ret) + return ret; + + rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), + "failed to get offload RX DMA\n"); + + ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, + rx_dma, IIO_BUFFER_DIRECTION_IN); + if (ret) + return dev_err_probe(dev, ret, "cannot setup dma buffer\n"); + + return 0; +} + static int ad7380_probe(struct spi_device *spi) { struct device *dev = &spi->dev; @@ -1274,12 +1992,24 @@ static int ad7380_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->available_scan_masks = st->chip_info->available_scan_masks; - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, - iio_pollfunc_store_time, - ad7380_trigger_handler, - &ad7380_buffer_setup_ops); - if (ret) - return ret; + st->offload = devm_spi_offload_get(dev, spi, &ad7380_offload_config); + ret = PTR_ERR_OR_ZERO(st->offload); + if (ret && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to get offload\n"); + + /* If no SPI offload, fall back to low speed usage. */ + if (ret == -ENODEV) { + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ad7380_trigger_handler, + &ad7380_buffer_setup_ops); + if (ret) + return ret; + } else { + ret = ad7380_probe_spi_offload(indio_dev, st); + if (ret) + return ret; + } ret = ad7380_init(st, external_ref_en); if (ret) @@ -1305,6 +2035,7 @@ static const struct of_device_id ad7380_of_match_table[] = { { .compatible = "adi,ad7388-4", .data = &ad7388_4_chip_info }, { .compatible = "adi,adaq4370-4", .data = &adaq4370_4_chip_info }, { .compatible = "adi,adaq4380-4", .data = &adaq4380_4_chip_info }, + { .compatible = "adi,adaq4381-4", .data = &adaq4381_4_chip_info }, { } }; @@ -1325,6 +2056,7 @@ static const struct spi_device_id ad7380_id_table[] = { { "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info }, { "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info }, { "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info }, + { "adaq4381-4", (kernel_ulong_t)&adaq4381_4_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7380_id_table); @@ -1342,3 +2074,4 @@ module_spi_driver(ad7380_driver); MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); MODULE_DESCRIPTION("Analog Devices AD738x ADC driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); |