| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Analog Devices AD4851 DAS driver |
| * |
| * Copyright 2024 Analog Devices Inc. |
| */ |
| |
| #include <linux/array_size.h> |
| #include <linux/bitfield.h> |
| #include <linux/bits.h> |
| #include <linux/delay.h> |
| #include <linux/device.h> |
| #include <linux/err.h> |
| #include <linux/minmax.h> |
| #include <linux/mod_devicetable.h> |
| #include <linux/module.h> |
| #include <linux/mutex.h> |
| #include <linux/pwm.h> |
| #include <linux/regmap.h> |
| #include <linux/regulator/consumer.h> |
| #include <linux/spi/spi.h> |
| #include <linux/types.h> |
| #include <linux/unaligned.h> |
| #include <linux/units.h> |
| |
| #include <linux/iio/backend.h> |
| #include <linux/iio/iio.h> |
| |
| #define AD4851_REG_INTERFACE_CONFIG_A 0x00 |
| #define AD4851_REG_INTERFACE_CONFIG_B 0x01 |
| #define AD4851_REG_PRODUCT_ID_L 0x04 |
| #define AD4851_REG_PRODUCT_ID_H 0x05 |
| #define AD4851_REG_DEVICE_CTRL 0x25 |
| #define AD4851_REG_PACKET 0x26 |
| #define AD4851_REG_OVERSAMPLE 0x27 |
| |
| #define AD4851_REG_CH_CONFIG_BASE 0x2A |
| #define AD4851_REG_CHX_SOFTSPAN(ch) ((0x12 * (ch)) + AD4851_REG_CH_CONFIG_BASE) |
| #define AD4851_REG_CHX_OFFSET(ch) (AD4851_REG_CHX_SOFTSPAN(ch) + 0x01) |
| #define AD4851_REG_CHX_OFFSET_LSB(ch) AD4851_REG_CHX_OFFSET(ch) |
| #define AD4851_REG_CHX_OFFSET_MID(ch) (AD4851_REG_CHX_OFFSET_LSB(ch) + 0x01) |
| #define AD4851_REG_CHX_OFFSET_MSB(ch) (AD4851_REG_CHX_OFFSET_MID(ch) + 0x01) |
| #define AD4851_REG_CHX_GAIN(ch) (AD4851_REG_CHX_OFFSET(ch) + 0x03) |
| #define AD4851_REG_CHX_GAIN_LSB(ch) AD4851_REG_CHX_GAIN(ch) |
| #define AD4851_REG_CHX_GAIN_MSB(ch) (AD4851_REG_CHX_GAIN(ch) + 0x01) |
| #define AD4851_REG_CHX_PHASE(ch) (AD4851_REG_CHX_GAIN(ch) + 0x02) |
| #define AD4851_REG_CHX_PHASE_LSB(ch) AD4851_REG_CHX_PHASE(ch) |
| #define AD4851_REG_CHX_PHASE_MSB(ch) (AD4851_REG_CHX_PHASE_LSB(ch) + 0x01) |
| |
| #define AD4851_REG_TESTPAT_0(c) (0x38 + (c) * 0x12) |
| #define AD4851_REG_TESTPAT_1(c) (0x39 + (c) * 0x12) |
| #define AD4851_REG_TESTPAT_2(c) (0x3A + (c) * 0x12) |
| #define AD4851_REG_TESTPAT_3(c) (0x3B + (c) * 0x12) |
| |
| #define AD4851_SW_RESET (BIT(7) | BIT(0)) |
| #define AD4851_SDO_ENABLE BIT(4) |
| #define AD4851_SINGLE_INSTRUCTION BIT(7) |
| #define AD4851_REFBUF BIT(2) |
| #define AD4851_REFSEL BIT(1) |
| #define AD4851_ECHO_CLOCK_MODE BIT(0) |
| |
| #define AD4851_PACKET_FORMAT_0 0 |
| #define AD4851_PACKET_FORMAT_1 1 |
| #define AD4851_PACKET_FORMAT_MASK GENMASK(1, 0) |
| |
| #define AD4851_OS_EN_MSK BIT(7) |
| #define AD4851_OS_RATIO_MSK GENMASK(3, 0) |
| |
| #define AD4851_TEST_PAT BIT(2) |
| |
| #define AD4858_PACKET_SIZE_20 0 |
| #define AD4858_PACKET_SIZE_24 1 |
| #define AD4858_PACKET_SIZE_32 2 |
| |
| #define AD4857_PACKET_SIZE_16 0 |
| #define AD4857_PACKET_SIZE_24 1 |
| |
| #define AD4851_TESTPAT_0_DEFAULT 0x2A |
| #define AD4851_TESTPAT_1_DEFAULT 0x3C |
| #define AD4851_TESTPAT_2_DEFAULT 0xCE |
| #define AD4851_TESTPAT_3_DEFAULT(c) (0x0A + (0x10 * (c))) |
| |
| #define AD4851_SOFTSPAN_0V_2V5 0 |
| #define AD4851_SOFTSPAN_N2V5_2V5 1 |
| #define AD4851_SOFTSPAN_0V_5V 2 |
| #define AD4851_SOFTSPAN_N5V_5V 3 |
| #define AD4851_SOFTSPAN_0V_6V25 4 |
| #define AD4851_SOFTSPAN_N6V25_6V25 5 |
| #define AD4851_SOFTSPAN_0V_10V 6 |
| #define AD4851_SOFTSPAN_N10V_10V 7 |
| #define AD4851_SOFTSPAN_0V_12V5 8 |
| #define AD4851_SOFTSPAN_N12V5_12V5 9 |
| #define AD4851_SOFTSPAN_0V_20V 10 |
| #define AD4851_SOFTSPAN_N20V_20V 11 |
| #define AD4851_SOFTSPAN_0V_25V 12 |
| #define AD4851_SOFTSPAN_N25V_25V 13 |
| #define AD4851_SOFTSPAN_0V_40V 14 |
| #define AD4851_SOFTSPAN_N40V_40V 15 |
| |
| #define AD4851_MAX_LANES 8 |
| #define AD4851_MAX_IODELAY 32 |
| |
| #define AD4851_T_CNVH_NS 40 |
| #define AD4851_T_CNVH_NS_MARGIN 10 |
| |
| #define AD4841_MAX_SCALE_AVAIL 8 |
| |
| #define AD4851_MAX_CH_NR 8 |
| #define AD4851_CH_START 0 |
| |
| struct ad4851_scale { |
| unsigned int scale_val; |
| u8 reg_val; |
| }; |
| |
| static const struct ad4851_scale ad4851_scale_table_unipolar[] = { |
| { 2500, 0x0 }, |
| { 5000, 0x2 }, |
| { 6250, 0x4 }, |
| { 10000, 0x6 }, |
| { 12500, 0x8 }, |
| { 20000, 0xA }, |
| { 25000, 0xC }, |
| { 40000, 0xE }, |
| }; |
| |
| static const struct ad4851_scale ad4851_scale_table_bipolar[] = { |
| { 5000, 0x1 }, |
| { 10000, 0x3 }, |
| { 12500, 0x5 }, |
| { 20000, 0x7 }, |
| { 25000, 0x9 }, |
| { 40000, 0xB }, |
| { 50000, 0xD }, |
| { 80000, 0xF }, |
| }; |
| |
| static const unsigned int ad4851_scale_avail_unipolar[] = { |
| 2500, |
| 5000, |
| 6250, |
| 10000, |
| 12500, |
| 20000, |
| 25000, |
| 40000, |
| }; |
| |
| static const unsigned int ad4851_scale_avail_bipolar[] = { |
| 5000, |
| 10000, |
| 12500, |
| 20000, |
| 25000, |
| 40000, |
| 50000, |
| 80000, |
| }; |
| |
| struct ad4851_chip_info { |
| const char *name; |
| unsigned int product_id; |
| int num_scales; |
| unsigned long max_sample_rate_hz; |
| unsigned int resolution; |
| unsigned int max_channels; |
| int (*parse_channels)(struct iio_dev *indio_dev); |
| }; |
| |
| enum { |
| AD4851_SCAN_TYPE_NORMAL, |
| AD4851_SCAN_TYPE_RESOLUTION_BOOST, |
| }; |
| |
| struct ad4851_state { |
| struct spi_device *spi; |
| struct pwm_device *cnv; |
| struct iio_backend *back; |
| /* |
| * Synchronize access to members the of driver state, and ensure |
| * atomicity of consecutive regmap operations. |
| */ |
| struct mutex lock; |
| struct regmap *regmap; |
| const struct ad4851_chip_info *info; |
| struct gpio_desc *pd_gpio; |
| bool resolution_boost_enabled; |
| unsigned long cnv_trigger_rate_hz; |
| unsigned int osr; |
| bool vrefbuf_en; |
| bool vrefio_en; |
| bool bipolar_ch[AD4851_MAX_CH_NR]; |
| unsigned int scales_unipolar[AD4841_MAX_SCALE_AVAIL][2]; |
| unsigned int scales_bipolar[AD4841_MAX_SCALE_AVAIL][2]; |
| }; |
| |
| static int ad4851_reg_access(struct iio_dev *indio_dev, |
| unsigned int reg, |
| unsigned int writeval, |
| unsigned int *readval) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| |
| if (readval) |
| return regmap_read(st->regmap, reg, readval); |
| |
| return regmap_write(st->regmap, reg, writeval); |
| } |
| |
| static int ad4851_set_sampling_freq(struct ad4851_state *st, unsigned int freq) |
| { |
| struct pwm_state cnv_state = { |
| .duty_cycle = AD4851_T_CNVH_NS + AD4851_T_CNVH_NS_MARGIN, |
| .enabled = true, |
| }; |
| int ret; |
| |
| freq = clamp(freq, 1, st->info->max_sample_rate_hz); |
| |
| cnv_state.period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, freq); |
| |
| ret = pwm_apply_might_sleep(st->cnv, &cnv_state); |
| if (ret) |
| return ret; |
| |
| st->cnv_trigger_rate_hz = freq; |
| |
| return 0; |
| } |
| |
| static const int ad4851_oversampling_ratios[] = { |
| 1, 2, 4, 8, 16, 32, 64, 128, |
| 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, |
| 65536, |
| }; |
| |
| static int ad4851_osr_to_regval(unsigned int ratio) |
| { |
| int i; |
| |
| for (i = 1; i < ARRAY_SIZE(ad4851_oversampling_ratios); i++) |
| if (ratio == ad4851_oversampling_ratios[i]) |
| return i - 1; |
| |
| return -EINVAL; |
| } |
| |
| static int __ad4851_get_scale(struct iio_dev *indio_dev, int scale_tbl, |
| unsigned int *val, unsigned int *val2) |
| { |
| const struct iio_scan_type *scan_type; |
| unsigned int tmp; |
| |
| scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]); |
| if (IS_ERR(scan_type)) |
| return PTR_ERR(scan_type); |
| |
| tmp = ((u64)scale_tbl * MICRO) >> scan_type->realbits; |
| *val = tmp / MICRO; |
| *val2 = tmp % MICRO; |
| |
| return 0; |
| } |
| |
| static int ad4851_scale_fill(struct iio_dev *indio_dev) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| unsigned int i, val1, val2; |
| int ret; |
| |
| for (i = 0; i < ARRAY_SIZE(ad4851_scale_avail_unipolar); i++) { |
| ret = __ad4851_get_scale(indio_dev, |
| ad4851_scale_avail_unipolar[i], |
| &val1, &val2); |
| if (ret) |
| return ret; |
| |
| st->scales_unipolar[i][0] = val1; |
| st->scales_unipolar[i][1] = val2; |
| } |
| |
| for (i = 0; i < ARRAY_SIZE(ad4851_scale_avail_bipolar); i++) { |
| ret = __ad4851_get_scale(indio_dev, |
| ad4851_scale_avail_bipolar[i], |
| &val1, &val2); |
| if (ret) |
| return ret; |
| |
| st->scales_bipolar[i][0] = val1; |
| st->scales_bipolar[i][1] = val2; |
| } |
| |
| return 0; |
| } |
| |
| static int ad4851_set_oversampling_ratio(struct iio_dev *indio_dev, |
| unsigned int osr) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| int val, ret; |
| |
| guard(mutex)(&st->lock); |
| |
| if (osr == 1) { |
| ret = regmap_clear_bits(st->regmap, AD4851_REG_OVERSAMPLE, |
| AD4851_OS_EN_MSK); |
| if (ret) |
| return ret; |
| } else { |
| val = ad4851_osr_to_regval(osr); |
| if (val < 0) |
| return -EINVAL; |
| |
| ret = regmap_update_bits(st->regmap, AD4851_REG_OVERSAMPLE, |
| AD4851_OS_EN_MSK | |
| AD4851_OS_RATIO_MSK, |
| FIELD_PREP(AD4851_OS_EN_MSK, 1) | |
| FIELD_PREP(AD4851_OS_RATIO_MSK, val)); |
| if (ret) |
| return ret; |
| } |
| |
| /* Channel is ignored by the backend being used here */ |
| ret = iio_backend_oversampling_ratio_set(st->back, 0, osr); |
| if (ret) |
| return ret; |
| |
| switch (st->info->resolution) { |
| case 20: |
| switch (osr) { |
| case 0: |
| return -EINVAL; |
| case 1: |
| val = 20; |
| break; |
| default: |
| val = 24; |
| break; |
| } |
| break; |
| case 16: |
| val = 16; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| ret = iio_backend_data_size_set(st->back, val); |
| if (ret) |
| return ret; |
| |
| if (osr == 1 || st->info->resolution == 16) { |
| ret = regmap_clear_bits(st->regmap, AD4851_REG_PACKET, |
| AD4851_PACKET_FORMAT_MASK); |
| if (ret) |
| return ret; |
| |
| st->resolution_boost_enabled = false; |
| } else { |
| ret = regmap_update_bits(st->regmap, AD4851_REG_PACKET, |
| AD4851_PACKET_FORMAT_MASK, |
| FIELD_PREP(AD4851_PACKET_FORMAT_MASK, 1)); |
| if (ret) |
| return ret; |
| |
| st->resolution_boost_enabled = true; |
| } |
| |
| if (st->osr != osr) { |
| ret = ad4851_scale_fill(indio_dev); |
| if (ret) |
| return ret; |
| |
| st->osr = osr; |
| } |
| |
| return 0; |
| } |
| |
| static int ad4851_get_oversampling_ratio(struct ad4851_state *st, unsigned int *val) |
| { |
| unsigned int osr; |
| int ret; |
| |
| guard(mutex)(&st->lock); |
| |
| ret = regmap_read(st->regmap, AD4851_REG_OVERSAMPLE, &osr); |
| if (ret) |
| return ret; |
| |
| if (!FIELD_GET(AD4851_OS_EN_MSK, osr)) |
| *val = 1; |
| else |
| *val = ad4851_oversampling_ratios[FIELD_GET(AD4851_OS_RATIO_MSK, osr) + 1]; |
| |
| st->osr = *val; |
| |
| return IIO_VAL_INT; |
| } |
| |
| static void ad4851_pwm_disable(void *data) |
| { |
| pwm_disable(data); |
| } |
| |
| static int ad4851_setup(struct ad4851_state *st) |
| { |
| unsigned int product_id; |
| int ret; |
| |
| if (st->pd_gpio) { |
| /* To initiate a global reset, bring the PD pin high twice */ |
| gpiod_set_value(st->pd_gpio, 1); |
| fsleep(1); |
| gpiod_set_value(st->pd_gpio, 0); |
| fsleep(1); |
| gpiod_set_value(st->pd_gpio, 1); |
| fsleep(1); |
| gpiod_set_value(st->pd_gpio, 0); |
| fsleep(1000); |
| } else { |
| ret = regmap_set_bits(st->regmap, AD4851_REG_INTERFACE_CONFIG_A, |
| AD4851_SW_RESET); |
| if (ret) |
| return ret; |
| } |
| |
| if (st->vrefbuf_en) { |
| ret = regmap_set_bits(st->regmap, AD4851_REG_DEVICE_CTRL, |
| AD4851_REFBUF); |
| if (ret) |
| return ret; |
| } |
| |
| if (st->vrefio_en) { |
| ret = regmap_set_bits(st->regmap, AD4851_REG_DEVICE_CTRL, |
| AD4851_REFSEL); |
| if (ret) |
| return ret; |
| } |
| |
| ret = regmap_write(st->regmap, AD4851_REG_INTERFACE_CONFIG_B, |
| AD4851_SINGLE_INSTRUCTION); |
| if (ret) |
| return ret; |
| |
| if (!(st->spi->mode & SPI_3WIRE)) { |
| ret = regmap_write(st->regmap, AD4851_REG_INTERFACE_CONFIG_A, |
| AD4851_SDO_ENABLE); |
| if (ret) |
| return ret; |
| } |
| |
| ret = regmap_read(st->regmap, AD4851_REG_PRODUCT_ID_L, &product_id); |
| if (ret) |
| return ret; |
| |
| if (product_id != st->info->product_id) |
| dev_info(&st->spi->dev, "Unknown product ID: 0x%02X\n", |
| product_id); |
| |
| ret = regmap_set_bits(st->regmap, AD4851_REG_DEVICE_CTRL, |
| AD4851_ECHO_CLOCK_MODE); |
| if (ret) |
| return ret; |
| |
| return regmap_write(st->regmap, AD4851_REG_PACKET, 0); |
| } |
| |
| /* |
| * Find the longest consecutive sequence of false values from field |
| * and return starting index. |
| */ |
| static int ad4851_find_opt(const unsigned long *field, unsigned int start, |
| unsigned int nbits, unsigned int *val) |
| { |
| unsigned int bit = start, end, start_cnt, cnt = 0; |
| |
| for_each_clear_bitrange_from(bit, end, field, start + nbits) { |
| if (end - bit > cnt) { |
| cnt = end - bit; |
| start_cnt = bit - start; |
| } |
| } |
| |
| if (!cnt) |
| return -ENOENT; |
| |
| *val = start_cnt; |
| |
| return cnt; |
| } |
| |
| static int ad4851_calibrate(struct iio_dev *indio_dev) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| unsigned int opt_delay, num_lanes, delay, i, s; |
| enum iio_backend_interface_type interface_type; |
| DECLARE_BITMAP(pn_status, AD4851_MAX_LANES * AD4851_MAX_IODELAY); |
| bool status; |
| int c, ret; |
| |
| ret = iio_backend_interface_type_get(st->back, &interface_type); |
| if (ret) |
| return ret; |
| |
| switch (interface_type) { |
| case IIO_BACKEND_INTERFACE_SERIAL_CMOS: |
| num_lanes = indio_dev->num_channels; |
| break; |
| case IIO_BACKEND_INTERFACE_SERIAL_LVDS: |
| num_lanes = 1; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| if (st->info->resolution == 16) { |
| ret = iio_backend_data_size_set(st->back, 24); |
| if (ret) |
| return ret; |
| |
| ret = regmap_write(st->regmap, AD4851_REG_PACKET, |
| AD4851_TEST_PAT | AD4857_PACKET_SIZE_24); |
| if (ret) |
| return ret; |
| } else { |
| ret = iio_backend_data_size_set(st->back, 32); |
| if (ret) |
| return ret; |
| |
| ret = regmap_write(st->regmap, AD4851_REG_PACKET, |
| AD4851_TEST_PAT | AD4858_PACKET_SIZE_32); |
| if (ret) |
| return ret; |
| } |
| |
| for (i = 0; i < indio_dev->num_channels; i++) { |
| ret = regmap_write(st->regmap, AD4851_REG_TESTPAT_0(i), |
| AD4851_TESTPAT_0_DEFAULT); |
| if (ret) |
| return ret; |
| |
| ret = regmap_write(st->regmap, AD4851_REG_TESTPAT_1(i), |
| AD4851_TESTPAT_1_DEFAULT); |
| if (ret) |
| return ret; |
| |
| ret = regmap_write(st->regmap, AD4851_REG_TESTPAT_2(i), |
| AD4851_TESTPAT_2_DEFAULT); |
| if (ret) |
| return ret; |
| |
| ret = regmap_write(st->regmap, AD4851_REG_TESTPAT_3(i), |
| AD4851_TESTPAT_3_DEFAULT(i)); |
| if (ret) |
| return ret; |
| |
| ret = iio_backend_chan_enable(st->back, |
| indio_dev->channels[i].channel); |
| if (ret) |
| return ret; |
| } |
| |
| for (i = 0; i < num_lanes; i++) { |
| for (delay = 0; delay < AD4851_MAX_IODELAY; delay++) { |
| ret = iio_backend_iodelay_set(st->back, i, delay); |
| if (ret) |
| return ret; |
| |
| ret = iio_backend_chan_status(st->back, i, &status); |
| if (ret) |
| return ret; |
| |
| __assign_bit(i * AD4851_MAX_IODELAY + delay, pn_status, |
| status); |
| } |
| } |
| |
| for (i = 0; i < num_lanes; i++) { |
| c = ad4851_find_opt(pn_status, i * AD4851_MAX_IODELAY, |
| AD4851_MAX_IODELAY, &s); |
| if (c < 0) |
| return c; |
| |
| opt_delay = s + c / 2; |
| ret = iio_backend_iodelay_set(st->back, i, opt_delay); |
| if (ret) |
| return ret; |
| } |
| |
| for (i = 0; i < indio_dev->num_channels; i++) { |
| ret = iio_backend_chan_disable(st->back, i); |
| if (ret) |
| return ret; |
| } |
| |
| ret = iio_backend_data_size_set(st->back, 20); |
| if (ret) |
| return ret; |
| |
| return regmap_write(st->regmap, AD4851_REG_PACKET, 0); |
| } |
| |
| static int ad4851_get_calibscale(struct ad4851_state *st, int ch, int *val, int *val2) |
| { |
| unsigned int reg_val; |
| int gain; |
| int ret; |
| |
| guard(mutex)(&st->lock); |
| |
| ret = regmap_read(st->regmap, AD4851_REG_CHX_GAIN_MSB(ch), ®_val); |
| if (ret) |
| return ret; |
| |
| gain = reg_val << 8; |
| |
| ret = regmap_read(st->regmap, AD4851_REG_CHX_GAIN_LSB(ch), ®_val); |
| if (ret) |
| return ret; |
| |
| gain |= reg_val; |
| |
| *val = gain; |
| *val2 = 15; |
| |
| return IIO_VAL_FRACTIONAL_LOG2; |
| } |
| |
| static int ad4851_set_calibscale(struct ad4851_state *st, int ch, int val, |
| int val2) |
| { |
| u64 gain; |
| u8 buf[2]; |
| int ret; |
| |
| if (val < 0 || val2 < 0) |
| return -EINVAL; |
| |
| gain = val * MICRO + val2; |
| gain = DIV_U64_ROUND_CLOSEST(gain * 32768, MICRO); |
| |
| put_unaligned_be16(gain, buf); |
| |
| guard(mutex)(&st->lock); |
| |
| ret = regmap_write(st->regmap, AD4851_REG_CHX_GAIN_MSB(ch), buf[0]); |
| if (ret) |
| return ret; |
| |
| return regmap_write(st->regmap, AD4851_REG_CHX_GAIN_LSB(ch), buf[1]); |
| } |
| |
| static int ad4851_get_calibbias(struct ad4851_state *st, int ch, int *val) |
| { |
| unsigned int lsb, mid, msb; |
| int ret; |
| |
| guard(mutex)(&st->lock); |
| /* |
| * After testing, the bulk_write operations doesn't work as expected |
| * here since the cs needs to be raised after each byte transaction. |
| */ |
| ret = regmap_read(st->regmap, AD4851_REG_CHX_OFFSET_MSB(ch), &msb); |
| if (ret) |
| return ret; |
| |
| ret = regmap_read(st->regmap, AD4851_REG_CHX_OFFSET_MID(ch), &mid); |
| if (ret) |
| return ret; |
| |
| ret = regmap_read(st->regmap, AD4851_REG_CHX_OFFSET_LSB(ch), &lsb); |
| if (ret) |
| return ret; |
| |
| if (st->info->resolution == 16) { |
| *val = msb << 8; |
| *val |= mid; |
| *val = sign_extend32(*val, 15); |
| } else { |
| *val = msb << 12; |
| *val |= mid << 4; |
| *val |= lsb >> 4; |
| *val = sign_extend32(*val, 19); |
| } |
| |
| return IIO_VAL_INT; |
| } |
| |
| static int ad4851_set_calibbias(struct ad4851_state *st, int ch, int val) |
| { |
| u8 buf[3]; |
| int ret; |
| |
| if (val < 0) |
| return -EINVAL; |
| |
| if (st->info->resolution == 16) |
| put_unaligned_be16(val, buf); |
| else |
| put_unaligned_be24(val << 4, buf); |
| |
| guard(mutex)(&st->lock); |
| /* |
| * After testing, the bulk_write operations doesn't work as expected |
| * here since the cs needs to be raised after each byte transaction. |
| */ |
| ret = regmap_write(st->regmap, AD4851_REG_CHX_OFFSET_LSB(ch), buf[2]); |
| if (ret) |
| return ret; |
| |
| ret = regmap_write(st->regmap, AD4851_REG_CHX_OFFSET_MID(ch), buf[1]); |
| if (ret) |
| return ret; |
| |
| return regmap_write(st->regmap, AD4851_REG_CHX_OFFSET_MSB(ch), buf[0]); |
| } |
| |
| static int ad4851_set_scale(struct iio_dev *indio_dev, |
| const struct iio_chan_spec *chan, int val, int val2) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| unsigned int scale_val[2]; |
| unsigned int i; |
| const struct ad4851_scale *scale_table; |
| size_t table_size; |
| int ret; |
| |
| if (st->bipolar_ch[chan->channel]) { |
| scale_table = ad4851_scale_table_bipolar; |
| table_size = ARRAY_SIZE(ad4851_scale_table_bipolar); |
| } else { |
| scale_table = ad4851_scale_table_unipolar; |
| table_size = ARRAY_SIZE(ad4851_scale_table_unipolar); |
| } |
| |
| for (i = 0; i < table_size; i++) { |
| ret = __ad4851_get_scale(indio_dev, scale_table[i].scale_val, |
| &scale_val[0], &scale_val[1]); |
| if (ret) |
| return ret; |
| |
| if (scale_val[0] != val || scale_val[1] != val2) |
| continue; |
| |
| return regmap_write(st->regmap, |
| AD4851_REG_CHX_SOFTSPAN(chan->channel), |
| scale_table[i].reg_val); |
| } |
| |
| return -EINVAL; |
| } |
| |
| static int ad4851_get_scale(struct iio_dev *indio_dev, |
| const struct iio_chan_spec *chan, int *val, |
| int *val2) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| const struct ad4851_scale *scale_table; |
| size_t table_size; |
| u32 softspan_val; |
| int i, ret; |
| |
| if (st->bipolar_ch[chan->channel]) { |
| scale_table = ad4851_scale_table_bipolar; |
| table_size = ARRAY_SIZE(ad4851_scale_table_bipolar); |
| } else { |
| scale_table = ad4851_scale_table_unipolar; |
| table_size = ARRAY_SIZE(ad4851_scale_table_unipolar); |
| } |
| |
| ret = regmap_read(st->regmap, AD4851_REG_CHX_SOFTSPAN(chan->channel), |
| &softspan_val); |
| if (ret) |
| return ret; |
| |
| for (i = 0; i < table_size; i++) { |
| if (softspan_val == scale_table[i].reg_val) |
| break; |
| } |
| |
| if (i == table_size) |
| return -EIO; |
| |
| ret = __ad4851_get_scale(indio_dev, scale_table[i].scale_val, val, |
| val2); |
| if (ret) |
| return ret; |
| |
| return IIO_VAL_INT_PLUS_MICRO; |
| } |
| |
| static int ad4851_read_raw(struct iio_dev *indio_dev, |
| const struct iio_chan_spec *chan, |
| int *val, int *val2, long info) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| |
| switch (info) { |
| case IIO_CHAN_INFO_SAMP_FREQ: |
| *val = st->cnv_trigger_rate_hz; |
| *val2 = st->osr; |
| return IIO_VAL_FRACTIONAL; |
| case IIO_CHAN_INFO_CALIBSCALE: |
| return ad4851_get_calibscale(st, chan->channel, val, val2); |
| case IIO_CHAN_INFO_SCALE: |
| return ad4851_get_scale(indio_dev, chan, val, val2); |
| case IIO_CHAN_INFO_CALIBBIAS: |
| return ad4851_get_calibbias(st, chan->channel, val); |
| case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| return ad4851_get_oversampling_ratio(st, val); |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| static int ad4851_write_raw(struct iio_dev *indio_dev, |
| struct iio_chan_spec const *chan, |
| int val, int val2, long info) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| |
| switch (info) { |
| case IIO_CHAN_INFO_SAMP_FREQ: |
| if (val < 0 || val2 < 0) |
| return -EINVAL; |
| return ad4851_set_sampling_freq(st, val * st->osr + val2 * st->osr / MICRO); |
| case IIO_CHAN_INFO_SCALE: |
| return ad4851_set_scale(indio_dev, chan, val, val2); |
| case IIO_CHAN_INFO_CALIBSCALE: |
| return ad4851_set_calibscale(st, chan->channel, val, val2); |
| case IIO_CHAN_INFO_CALIBBIAS: |
| return ad4851_set_calibbias(st, chan->channel, val); |
| case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| return ad4851_set_oversampling_ratio(indio_dev, val); |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| static int ad4851_update_scan_mode(struct iio_dev *indio_dev, |
| const unsigned long *scan_mask) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| unsigned int c; |
| int ret; |
| |
| for (c = 0; c < indio_dev->num_channels; c++) { |
| if (test_bit(c, scan_mask)) |
| ret = iio_backend_chan_enable(st->back, c); |
| else |
| ret = iio_backend_chan_disable(st->back, c); |
| if (ret) |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int ad4851_read_avail(struct iio_dev *indio_dev, |
| struct iio_chan_spec const *chan, |
| const int **vals, int *type, int *length, |
| long mask) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| |
| switch (mask) { |
| case IIO_CHAN_INFO_SCALE: |
| if (st->bipolar_ch[chan->channel]) { |
| *vals = (const int *)st->scales_bipolar; |
| *type = IIO_VAL_INT_PLUS_MICRO; |
| /* Values are stored in a 2D matrix */ |
| *length = ARRAY_SIZE(ad4851_scale_avail_bipolar) * 2; |
| } else { |
| *vals = (const int *)st->scales_unipolar; |
| *type = IIO_VAL_INT_PLUS_MICRO; |
| /* Values are stored in a 2D matrix */ |
| *length = ARRAY_SIZE(ad4851_scale_avail_unipolar) * 2; |
| } |
| return IIO_AVAIL_LIST; |
| case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| *vals = ad4851_oversampling_ratios; |
| *length = ARRAY_SIZE(ad4851_oversampling_ratios); |
| *type = IIO_VAL_INT; |
| return IIO_AVAIL_LIST; |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| static const struct iio_scan_type ad4851_scan_type_20_u[] = { |
| [AD4851_SCAN_TYPE_NORMAL] = { |
| .sign = 'u', |
| .realbits = 20, |
| .storagebits = 32, |
| }, |
| [AD4851_SCAN_TYPE_RESOLUTION_BOOST] = { |
| .sign = 'u', |
| .realbits = 24, |
| .storagebits = 32, |
| }, |
| }; |
| |
| static const struct iio_scan_type ad4851_scan_type_20_b[] = { |
| [AD4851_SCAN_TYPE_NORMAL] = { |
| .sign = 's', |
| .realbits = 20, |
| .storagebits = 32, |
| }, |
| [AD4851_SCAN_TYPE_RESOLUTION_BOOST] = { |
| .sign = 's', |
| .realbits = 24, |
| .storagebits = 32, |
| }, |
| }; |
| |
| static int ad4851_get_current_scan_type(const struct iio_dev *indio_dev, |
| const struct iio_chan_spec *chan) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| |
| return st->resolution_boost_enabled ? AD4851_SCAN_TYPE_RESOLUTION_BOOST |
| : AD4851_SCAN_TYPE_NORMAL; |
| } |
| |
| #define AD4851_IIO_CHANNEL \ |
| .type = IIO_VOLTAGE, \ |
| .info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ |
| BIT(IIO_CHAN_INFO_CALIBBIAS) | \ |
| BIT(IIO_CHAN_INFO_SCALE), \ |
| .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE), \ |
| .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ |
| BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ |
| .info_mask_shared_by_all_available = \ |
| BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ |
| .indexed = 1 |
| |
| /* |
| * In case of AD4858_IIO_CHANNEL the scan_type is handled dynamically during the |
| * parse_channels function. |
| */ |
| #define AD4858_IIO_CHANNEL \ |
| { \ |
| AD4851_IIO_CHANNEL \ |
| } |
| |
| #define AD4857_IIO_CHANNEL \ |
| { \ |
| AD4851_IIO_CHANNEL, \ |
| .scan_type = { \ |
| .sign = 'u', \ |
| .realbits = 16, \ |
| .storagebits = 16, \ |
| }, \ |
| } |
| |
| static int ad4851_parse_channels_common(struct iio_dev *indio_dev, |
| struct iio_chan_spec **chans, |
| const struct iio_chan_spec ad4851_chan) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| struct device *dev = &st->spi->dev; |
| struct iio_chan_spec *channels, *chan_start; |
| unsigned int num_channels, reg; |
| unsigned int index = 0; |
| int ret; |
| |
| num_channels = device_get_child_node_count(dev); |
| if (num_channels > AD4851_MAX_CH_NR) |
| return dev_err_probe(dev, -EINVAL, "Too many channels: %u\n", |
| num_channels); |
| |
| channels = devm_kcalloc(dev, num_channels, sizeof(*channels), GFP_KERNEL); |
| if (!channels) |
| return -ENOMEM; |
| |
| chan_start = channels; |
| |
| device_for_each_child_node_scoped(dev, child) { |
| ret = fwnode_property_read_u32(child, "reg", ®); |
| if (ret) |
| return dev_err_probe(dev, ret, |
| "Missing channel number\n"); |
| if (reg >= AD4851_MAX_CH_NR) |
| return dev_err_probe(dev, -EINVAL, |
| "Invalid channel number\n"); |
| *channels = ad4851_chan; |
| channels->scan_index = index++; |
| channels->channel = reg; |
| |
| if (fwnode_property_present(child, "diff-channels")) { |
| channels->channel2 = reg + st->info->max_channels; |
| channels->differential = 1; |
| } |
| |
| st->bipolar_ch[reg] = fwnode_property_read_bool(child, "bipolar"); |
| |
| if (st->bipolar_ch[reg]) { |
| channels->scan_type.sign = 's'; |
| } else { |
| ret = regmap_write(st->regmap, AD4851_REG_CHX_SOFTSPAN(reg), |
| AD4851_SOFTSPAN_0V_40V); |
| if (ret) |
| return ret; |
| } |
| |
| channels++; |
| } |
| |
| *chans = chan_start; |
| |
| return num_channels; |
| } |
| |
| static int ad4857_parse_channels(struct iio_dev *indio_dev) |
| { |
| struct iio_chan_spec *ad4851_channels; |
| const struct iio_chan_spec ad4851_chan = AD4857_IIO_CHANNEL; |
| int ret; |
| |
| ret = ad4851_parse_channels_common(indio_dev, &ad4851_channels, |
| ad4851_chan); |
| if (ret < 0) |
| return ret; |
| |
| indio_dev->channels = ad4851_channels; |
| indio_dev->num_channels = ret; |
| |
| return 0; |
| } |
| |
| static int ad4858_parse_channels(struct iio_dev *indio_dev) |
| { |
| struct ad4851_state *st = iio_priv(indio_dev); |
| struct device *dev = &st->spi->dev; |
| struct iio_chan_spec *ad4851_channels; |
| const struct iio_chan_spec ad4851_chan = AD4858_IIO_CHANNEL; |
| int ret, i = 0; |
| |
| ret = ad4851_parse_channels_common(indio_dev, &ad4851_channels, |
| ad4851_chan); |
| if (ret < 0) |
| return ret; |
| |
| device_for_each_child_node_scoped(dev, child) { |
| ad4851_channels[i].has_ext_scan_type = 1; |
| if (fwnode_property_read_bool(child, "bipolar")) { |
| ad4851_channels[i].ext_scan_type = ad4851_scan_type_20_b; |
| ad4851_channels[i].num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_b); |
| } else { |
| ad4851_channels[i].ext_scan_type = ad4851_scan_type_20_u; |
| ad4851_channels[i].num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_u); |
| } |
| i++; |
| } |
| |
| indio_dev->channels = ad4851_channels; |
| indio_dev->num_channels = ret; |
| |
| return 0; |
| } |
| |
| /* |
| * parse_channels() function handles the rest of the channel related attributes |
| * that are usually are stored in the chip info structure. |
| */ |
| static const struct ad4851_chip_info ad4851_info = { |
| .name = "ad4851", |
| .product_id = 0x67, |
| .max_sample_rate_hz = 250 * KILO, |
| .resolution = 16, |
| .max_channels = AD4851_MAX_CH_NR, |
| .parse_channels = ad4857_parse_channels, |
| }; |
| |
| static const struct ad4851_chip_info ad4852_info = { |
| .name = "ad4852", |
| .product_id = 0x66, |
| .max_sample_rate_hz = 250 * KILO, |
| .resolution = 20, |
| .max_channels = AD4851_MAX_CH_NR, |
| .parse_channels = ad4858_parse_channels, |
| }; |
| |
| static const struct ad4851_chip_info ad4853_info = { |
| .name = "ad4853", |
| .product_id = 0x65, |
| .max_sample_rate_hz = 1 * MEGA, |
| .resolution = 16, |
| .max_channels = AD4851_MAX_CH_NR, |
| .parse_channels = ad4857_parse_channels, |
| }; |
| |
| static const struct ad4851_chip_info ad4854_info = { |
| .name = "ad4854", |
| .product_id = 0x64, |
| .max_sample_rate_hz = 1 * MEGA, |
| .resolution = 20, |
| .max_channels = AD4851_MAX_CH_NR, |
| .parse_channels = ad4858_parse_channels, |
| }; |
| |
| static const struct ad4851_chip_info ad4855_info = { |
| .name = "ad4855", |
| .product_id = 0x63, |
| .max_sample_rate_hz = 250 * KILO, |
| .resolution = 16, |
| .max_channels = AD4851_MAX_CH_NR, |
| .parse_channels = ad4857_parse_channels, |
| }; |
| |
| static const struct ad4851_chip_info ad4856_info = { |
| .name = "ad4856", |
| .product_id = 0x62, |
| .max_sample_rate_hz = 250 * KILO, |
| .resolution = 20, |
| .max_channels = AD4851_MAX_CH_NR, |
| .parse_channels = ad4858_parse_channels, |
| }; |
| |
| static const struct ad4851_chip_info ad4857_info = { |
| .name = "ad4857", |
| .product_id = 0x61, |
| .max_sample_rate_hz = 1 * MEGA, |
| .resolution = 16, |
| .max_channels = AD4851_MAX_CH_NR, |
| .parse_channels = ad4857_parse_channels, |
| }; |
| |
| static const struct ad4851_chip_info ad4858_info = { |
| .name = "ad4858", |
| .product_id = 0x60, |
| .max_sample_rate_hz = 1 * MEGA, |
| .resolution = 20, |
| .max_channels = AD4851_MAX_CH_NR, |
| .parse_channels = ad4858_parse_channels, |
| }; |
| |
| static const struct ad4851_chip_info ad4858i_info = { |
| .name = "ad4858i", |
| .product_id = 0x6F, |
| .max_sample_rate_hz = 1 * MEGA, |
| .resolution = 20, |
| .max_channels = AD4851_MAX_CH_NR, |
| .parse_channels = ad4858_parse_channels, |
| }; |
| |
| static const struct iio_info ad4851_iio_info = { |
| .debugfs_reg_access = ad4851_reg_access, |
| .read_raw = ad4851_read_raw, |
| .write_raw = ad4851_write_raw, |
| .update_scan_mode = ad4851_update_scan_mode, |
| .get_current_scan_type = ad4851_get_current_scan_type, |
| .read_avail = ad4851_read_avail, |
| }; |
| |
| static const struct regmap_config regmap_config = { |
| .reg_bits = 16, |
| .val_bits = 8, |
| .read_flag_mask = BIT(7), |
| }; |
| |
| static const char * const ad4851_power_supplies[] = { |
| "vcc", "vdd", "vee", "vio", |
| }; |
| |
| static int ad4851_probe(struct spi_device *spi) |
| { |
| struct iio_dev *indio_dev; |
| struct device *dev = &spi->dev; |
| struct ad4851_state *st; |
| int ret; |
| |
| indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); |
| if (!indio_dev) |
| return -ENOMEM; |
| |
| st = iio_priv(indio_dev); |
| st->spi = spi; |
| |
| ret = devm_mutex_init(dev, &st->lock); |
| if (ret) |
| return ret; |
| |
| ret = devm_regulator_bulk_get_enable(dev, |
| ARRAY_SIZE(ad4851_power_supplies), |
| ad4851_power_supplies); |
| if (ret) |
| return dev_err_probe(dev, ret, |
| "failed to get and enable supplies\n"); |
| |
| ret = devm_regulator_get_enable_optional(dev, "vddh"); |
| if (ret < 0 && ret != -ENODEV) |
| return dev_err_probe(dev, ret, "failed to enable vddh voltage\n"); |
| |
| ret = devm_regulator_get_enable_optional(dev, "vddl"); |
| if (ret < 0 && ret != -ENODEV) |
| return dev_err_probe(dev, ret, "failed to enable vddl voltage\n"); |
| |
| ret = devm_regulator_get_enable_optional(dev, "vrefbuf"); |
| if (ret < 0 && ret != -ENODEV) |
| return dev_err_probe(dev, ret, "failed to enable vrefbuf voltage\n"); |
| |
| st->vrefbuf_en = ret != -ENODEV; |
| |
| ret = devm_regulator_get_enable_optional(dev, "vrefio"); |
| if (ret < 0 && ret != -ENODEV) |
| return dev_err_probe(dev, ret, "failed to enable vrefio voltage\n"); |
| |
| st->vrefio_en = ret != -ENODEV; |
| |
| st->pd_gpio = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_LOW); |
| if (IS_ERR(st->pd_gpio)) |
| return dev_err_probe(dev, PTR_ERR(st->pd_gpio), |
| "Error on requesting pd GPIO\n"); |
| |
| st->cnv = devm_pwm_get(dev, NULL); |
| if (IS_ERR(st->cnv)) |
| return dev_err_probe(dev, PTR_ERR(st->cnv), |
| "Error on requesting pwm\n"); |
| |
| st->info = spi_get_device_match_data(spi); |
| if (!st->info) |
| return -ENODEV; |
| |
| st->regmap = devm_regmap_init_spi(spi, ®map_config); |
| if (IS_ERR(st->regmap)) |
| return PTR_ERR(st->regmap); |
| |
| ret = ad4851_set_sampling_freq(st, HZ_PER_MHZ); |
| if (ret) |
| return ret; |
| |
| ret = devm_add_action_or_reset(&st->spi->dev, ad4851_pwm_disable, |
| st->cnv); |
| if (ret) |
| return ret; |
| |
| ret = ad4851_setup(st); |
| if (ret) |
| return ret; |
| |
| indio_dev->name = st->info->name; |
| indio_dev->info = &ad4851_iio_info; |
| indio_dev->modes = INDIO_DIRECT_MODE; |
| |
| ret = st->info->parse_channels(indio_dev); |
| if (ret) |
| return ret; |
| |
| ret = ad4851_scale_fill(indio_dev); |
| if (ret) |
| return ret; |
| |
| st->back = devm_iio_backend_get(dev, NULL); |
| if (IS_ERR(st->back)) |
| return PTR_ERR(st->back); |
| |
| ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); |
| if (ret) |
| return ret; |
| |
| ret = devm_iio_backend_enable(dev, st->back); |
| if (ret) |
| return ret; |
| |
| ret = ad4851_calibrate(indio_dev); |
| if (ret) |
| return ret; |
| |
| return devm_iio_device_register(dev, indio_dev); |
| } |
| |
| static const struct of_device_id ad4851_of_match[] = { |
| { .compatible = "adi,ad4851", .data = &ad4851_info, }, |
| { .compatible = "adi,ad4852", .data = &ad4852_info, }, |
| { .compatible = "adi,ad4853", .data = &ad4853_info, }, |
| { .compatible = "adi,ad4854", .data = &ad4854_info, }, |
| { .compatible = "adi,ad4855", .data = &ad4855_info, }, |
| { .compatible = "adi,ad4856", .data = &ad4856_info, }, |
| { .compatible = "adi,ad4857", .data = &ad4857_info, }, |
| { .compatible = "adi,ad4858", .data = &ad4858_info, }, |
| { .compatible = "adi,ad4858i", .data = &ad4858i_info, }, |
| { } |
| }; |
| |
| static const struct spi_device_id ad4851_spi_id[] = { |
| { "ad4851", (kernel_ulong_t)&ad4851_info }, |
| { "ad4852", (kernel_ulong_t)&ad4852_info }, |
| { "ad4853", (kernel_ulong_t)&ad4853_info }, |
| { "ad4854", (kernel_ulong_t)&ad4854_info }, |
| { "ad4855", (kernel_ulong_t)&ad4855_info }, |
| { "ad4856", (kernel_ulong_t)&ad4856_info }, |
| { "ad4857", (kernel_ulong_t)&ad4857_info }, |
| { "ad4858", (kernel_ulong_t)&ad4858_info }, |
| { "ad4858i", (kernel_ulong_t)&ad4858i_info }, |
| { } |
| }; |
| MODULE_DEVICE_TABLE(spi, ad4851_spi_id); |
| |
| static struct spi_driver ad4851_driver = { |
| .probe = ad4851_probe, |
| .driver = { |
| .name = "ad4851", |
| .of_match_table = ad4851_of_match, |
| }, |
| .id_table = ad4851_spi_id, |
| }; |
| module_spi_driver(ad4851_driver); |
| |
| MODULE_AUTHOR("Sergiu Cuciurean <sergiu.cuciurean@analog.com>"); |
| MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>"); |
| MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); |
| MODULE_DESCRIPTION("Analog Devices AD4851 DAS driver"); |
| MODULE_LICENSE("GPL"); |
| MODULE_IMPORT_NS("IIO_BACKEND"); |