18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD7170/AD7171 and AD7780/AD7781 SPI ADC driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2011 Analog Devices Inc. 68c2ecf20Sopenharmony_ci * Copyright 2019 Renato Lui Geh 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/sched.h> 188c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/bits.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 238c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 248c2ecf20Sopenharmony_ci#include <linux/iio/adc/ad_sigma_delta.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define AD7780_RDY BIT(7) 278c2ecf20Sopenharmony_ci#define AD7780_FILTER BIT(6) 288c2ecf20Sopenharmony_ci#define AD7780_ERR BIT(5) 298c2ecf20Sopenharmony_ci#define AD7780_ID1 BIT(4) 308c2ecf20Sopenharmony_ci#define AD7780_ID0 BIT(3) 318c2ecf20Sopenharmony_ci#define AD7780_GAIN BIT(2) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define AD7170_ID 0 348c2ecf20Sopenharmony_ci#define AD7171_ID 1 358c2ecf20Sopenharmony_ci#define AD7780_ID 1 368c2ecf20Sopenharmony_ci#define AD7781_ID 0 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define AD7780_ID_MASK (AD7780_ID0 | AD7780_ID1) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define AD7780_PATTERN_GOOD 1 418c2ecf20Sopenharmony_ci#define AD7780_PATTERN_MASK GENMASK(1, 0) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define AD7170_PATTERN_GOOD 5 448c2ecf20Sopenharmony_ci#define AD7170_PATTERN_MASK GENMASK(2, 0) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define AD7780_GAIN_MIDPOINT 64 478c2ecf20Sopenharmony_ci#define AD7780_FILTER_MIDPOINT 13350 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic const unsigned int ad778x_gain[2] = { 1, 128 }; 508c2ecf20Sopenharmony_cistatic const unsigned int ad778x_odr_avail[2] = { 10000, 16700 }; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct ad7780_chip_info { 538c2ecf20Sopenharmony_ci struct iio_chan_spec channel; 548c2ecf20Sopenharmony_ci unsigned int pattern_mask; 558c2ecf20Sopenharmony_ci unsigned int pattern; 568c2ecf20Sopenharmony_ci bool is_ad778x; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct ad7780_state { 608c2ecf20Sopenharmony_ci const struct ad7780_chip_info *chip_info; 618c2ecf20Sopenharmony_ci struct regulator *reg; 628c2ecf20Sopenharmony_ci struct gpio_desc *powerdown_gpio; 638c2ecf20Sopenharmony_ci struct gpio_desc *gain_gpio; 648c2ecf20Sopenharmony_ci struct gpio_desc *filter_gpio; 658c2ecf20Sopenharmony_ci unsigned int gain; 668c2ecf20Sopenharmony_ci unsigned int odr; 678c2ecf20Sopenharmony_ci unsigned int int_vref_mv; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci struct ad_sigma_delta sd; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cienum ad7780_supported_device_ids { 738c2ecf20Sopenharmony_ci ID_AD7170, 748c2ecf20Sopenharmony_ci ID_AD7171, 758c2ecf20Sopenharmony_ci ID_AD7780, 768c2ecf20Sopenharmony_ci ID_AD7781, 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic struct ad7780_state *ad_sigma_delta_to_ad7780(struct ad_sigma_delta *sd) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci return container_of(sd, struct ad7780_state, sd); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int ad7780_set_mode(struct ad_sigma_delta *sigma_delta, 858c2ecf20Sopenharmony_ci enum ad_sigma_delta_mode mode) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta); 888c2ecf20Sopenharmony_ci unsigned int val; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci switch (mode) { 918c2ecf20Sopenharmony_ci case AD_SD_MODE_SINGLE: 928c2ecf20Sopenharmony_ci case AD_SD_MODE_CONTINUOUS: 938c2ecf20Sopenharmony_ci val = 1; 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci default: 968c2ecf20Sopenharmony_ci val = 0; 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci gpiod_set_value(st->powerdown_gpio, val); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int ad7780_read_raw(struct iio_dev *indio_dev, 1068c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1078c2ecf20Sopenharmony_ci int *val, 1088c2ecf20Sopenharmony_ci int *val2, 1098c2ecf20Sopenharmony_ci long m) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct ad7780_state *st = iio_priv(indio_dev); 1128c2ecf20Sopenharmony_ci int voltage_uv; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci switch (m) { 1158c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 1168c2ecf20Sopenharmony_ci return ad_sigma_delta_single_conversion(indio_dev, chan, val); 1178c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 1188c2ecf20Sopenharmony_ci voltage_uv = regulator_get_voltage(st->reg); 1198c2ecf20Sopenharmony_ci if (voltage_uv < 0) 1208c2ecf20Sopenharmony_ci return voltage_uv; 1218c2ecf20Sopenharmony_ci voltage_uv /= 1000; 1228c2ecf20Sopenharmony_ci *val = voltage_uv * st->gain; 1238c2ecf20Sopenharmony_ci *val2 = chan->scan_type.realbits - 1; 1248c2ecf20Sopenharmony_ci st->int_vref_mv = voltage_uv; 1258c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 1268c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 1278c2ecf20Sopenharmony_ci *val = -(1 << (chan->scan_type.realbits - 1)); 1288c2ecf20Sopenharmony_ci return IIO_VAL_INT; 1298c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 1308c2ecf20Sopenharmony_ci *val = st->odr; 1318c2ecf20Sopenharmony_ci return IIO_VAL_INT; 1328c2ecf20Sopenharmony_ci default: 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return -EINVAL; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int ad7780_write_raw(struct iio_dev *indio_dev, 1408c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1418c2ecf20Sopenharmony_ci int val, 1428c2ecf20Sopenharmony_ci int val2, 1438c2ecf20Sopenharmony_ci long m) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct ad7780_state *st = iio_priv(indio_dev); 1468c2ecf20Sopenharmony_ci const struct ad7780_chip_info *chip_info = st->chip_info; 1478c2ecf20Sopenharmony_ci unsigned long long vref; 1488c2ecf20Sopenharmony_ci unsigned int full_scale, gain; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (!chip_info->is_ad778x) 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci switch (m) { 1548c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 1558c2ecf20Sopenharmony_ci if (val != 0) 1568c2ecf20Sopenharmony_ci return -EINVAL; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci vref = st->int_vref_mv * 1000000LL; 1598c2ecf20Sopenharmony_ci full_scale = 1 << (chip_info->channel.scan_type.realbits - 1); 1608c2ecf20Sopenharmony_ci gain = DIV_ROUND_CLOSEST_ULL(vref, full_scale); 1618c2ecf20Sopenharmony_ci gain = DIV_ROUND_CLOSEST(gain, val2); 1628c2ecf20Sopenharmony_ci st->gain = gain; 1638c2ecf20Sopenharmony_ci if (gain < AD7780_GAIN_MIDPOINT) 1648c2ecf20Sopenharmony_ci gain = 0; 1658c2ecf20Sopenharmony_ci else 1668c2ecf20Sopenharmony_ci gain = 1; 1678c2ecf20Sopenharmony_ci gpiod_set_value(st->gain_gpio, gain); 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 1708c2ecf20Sopenharmony_ci if (1000*val + val2/1000 < AD7780_FILTER_MIDPOINT) 1718c2ecf20Sopenharmony_ci val = 0; 1728c2ecf20Sopenharmony_ci else 1738c2ecf20Sopenharmony_ci val = 1; 1748c2ecf20Sopenharmony_ci st->odr = ad778x_odr_avail[val]; 1758c2ecf20Sopenharmony_ci gpiod_set_value(st->filter_gpio, val); 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci default: 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, 1858c2ecf20Sopenharmony_ci unsigned int raw_sample) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta); 1888c2ecf20Sopenharmony_ci const struct ad7780_chip_info *chip_info = st->chip_info; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if ((raw_sample & AD7780_ERR) || 1918c2ecf20Sopenharmony_ci ((raw_sample & chip_info->pattern_mask) != chip_info->pattern)) 1928c2ecf20Sopenharmony_ci return -EIO; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (chip_info->is_ad778x) { 1958c2ecf20Sopenharmony_ci st->gain = ad778x_gain[raw_sample & AD7780_GAIN]; 1968c2ecf20Sopenharmony_ci st->odr = ad778x_odr_avail[raw_sample & AD7780_FILTER]; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic const struct ad_sigma_delta_info ad7780_sigma_delta_info = { 2038c2ecf20Sopenharmony_ci .set_mode = ad7780_set_mode, 2048c2ecf20Sopenharmony_ci .postprocess_sample = ad7780_postprocess_sample, 2058c2ecf20Sopenharmony_ci .has_registers = false, 2068c2ecf20Sopenharmony_ci .irq_flags = IRQF_TRIGGER_FALLING, 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci#define _AD7780_CHANNEL(_bits, _wordsize, _mask_all) \ 2108c2ecf20Sopenharmony_ci{ \ 2118c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 2128c2ecf20Sopenharmony_ci .indexed = 1, \ 2138c2ecf20Sopenharmony_ci .channel = 0, \ 2148c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 2158c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET), \ 2168c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 2178c2ecf20Sopenharmony_ci .info_mask_shared_by_all = _mask_all, \ 2188c2ecf20Sopenharmony_ci .scan_index = 1, \ 2198c2ecf20Sopenharmony_ci .scan_type = { \ 2208c2ecf20Sopenharmony_ci .sign = 'u', \ 2218c2ecf20Sopenharmony_ci .realbits = (_bits), \ 2228c2ecf20Sopenharmony_ci .storagebits = 32, \ 2238c2ecf20Sopenharmony_ci .shift = (_wordsize) - (_bits), \ 2248c2ecf20Sopenharmony_ci .endianness = IIO_BE, \ 2258c2ecf20Sopenharmony_ci }, \ 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci#define AD7780_CHANNEL(_bits, _wordsize) \ 2298c2ecf20Sopenharmony_ci _AD7780_CHANNEL(_bits, _wordsize, BIT(IIO_CHAN_INFO_SAMP_FREQ)) 2308c2ecf20Sopenharmony_ci#define AD7170_CHANNEL(_bits, _wordsize) \ 2318c2ecf20Sopenharmony_ci _AD7780_CHANNEL(_bits, _wordsize, 0) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic const struct ad7780_chip_info ad7780_chip_info_tbl[] = { 2348c2ecf20Sopenharmony_ci [ID_AD7170] = { 2358c2ecf20Sopenharmony_ci .channel = AD7170_CHANNEL(12, 24), 2368c2ecf20Sopenharmony_ci .pattern = AD7170_PATTERN_GOOD, 2378c2ecf20Sopenharmony_ci .pattern_mask = AD7170_PATTERN_MASK, 2388c2ecf20Sopenharmony_ci .is_ad778x = false, 2398c2ecf20Sopenharmony_ci }, 2408c2ecf20Sopenharmony_ci [ID_AD7171] = { 2418c2ecf20Sopenharmony_ci .channel = AD7170_CHANNEL(16, 24), 2428c2ecf20Sopenharmony_ci .pattern = AD7170_PATTERN_GOOD, 2438c2ecf20Sopenharmony_ci .pattern_mask = AD7170_PATTERN_MASK, 2448c2ecf20Sopenharmony_ci .is_ad778x = false, 2458c2ecf20Sopenharmony_ci }, 2468c2ecf20Sopenharmony_ci [ID_AD7780] = { 2478c2ecf20Sopenharmony_ci .channel = AD7780_CHANNEL(24, 32), 2488c2ecf20Sopenharmony_ci .pattern = AD7780_PATTERN_GOOD, 2498c2ecf20Sopenharmony_ci .pattern_mask = AD7780_PATTERN_MASK, 2508c2ecf20Sopenharmony_ci .is_ad778x = true, 2518c2ecf20Sopenharmony_ci }, 2528c2ecf20Sopenharmony_ci [ID_AD7781] = { 2538c2ecf20Sopenharmony_ci .channel = AD7780_CHANNEL(20, 32), 2548c2ecf20Sopenharmony_ci .pattern = AD7780_PATTERN_GOOD, 2558c2ecf20Sopenharmony_ci .pattern_mask = AD7780_PATTERN_MASK, 2568c2ecf20Sopenharmony_ci .is_ad778x = true, 2578c2ecf20Sopenharmony_ci }, 2588c2ecf20Sopenharmony_ci}; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic const struct iio_info ad7780_info = { 2618c2ecf20Sopenharmony_ci .read_raw = ad7780_read_raw, 2628c2ecf20Sopenharmony_ci .write_raw = ad7780_write_raw, 2638c2ecf20Sopenharmony_ci}; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int ad7780_init_gpios(struct device *dev, struct ad7780_state *st) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci int ret; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci st->powerdown_gpio = devm_gpiod_get_optional(dev, 2708c2ecf20Sopenharmony_ci "powerdown", 2718c2ecf20Sopenharmony_ci GPIOD_OUT_LOW); 2728c2ecf20Sopenharmony_ci if (IS_ERR(st->powerdown_gpio)) { 2738c2ecf20Sopenharmony_ci ret = PTR_ERR(st->powerdown_gpio); 2748c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request powerdown GPIO: %d\n", ret); 2758c2ecf20Sopenharmony_ci return ret; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!st->chip_info->is_ad778x) 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci st->gain_gpio = devm_gpiod_get_optional(dev, 2838c2ecf20Sopenharmony_ci "adi,gain", 2848c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 2858c2ecf20Sopenharmony_ci if (IS_ERR(st->gain_gpio)) { 2868c2ecf20Sopenharmony_ci ret = PTR_ERR(st->gain_gpio); 2878c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request gain GPIO: %d\n", ret); 2888c2ecf20Sopenharmony_ci return ret; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci st->filter_gpio = devm_gpiod_get_optional(dev, 2928c2ecf20Sopenharmony_ci "adi,filter", 2938c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 2948c2ecf20Sopenharmony_ci if (IS_ERR(st->filter_gpio)) { 2958c2ecf20Sopenharmony_ci ret = PTR_ERR(st->filter_gpio); 2968c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request filter GPIO: %d\n", ret); 2978c2ecf20Sopenharmony_ci return ret; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int ad7780_probe(struct spi_device *spi) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct ad7780_state *st; 3068c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 3078c2ecf20Sopenharmony_ci int ret; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 3108c2ecf20Sopenharmony_ci if (!indio_dev) 3118c2ecf20Sopenharmony_ci return -ENOMEM; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 3148c2ecf20Sopenharmony_ci st->gain = 1; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci st->chip_info = 3198c2ecf20Sopenharmony_ci &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data]; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci spi_set_drvdata(spi, indio_dev); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci indio_dev->name = spi_get_device_id(spi)->name; 3248c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 3258c2ecf20Sopenharmony_ci indio_dev->channels = &st->chip_info->channel; 3268c2ecf20Sopenharmony_ci indio_dev->num_channels = 1; 3278c2ecf20Sopenharmony_ci indio_dev->info = &ad7780_info; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ret = ad7780_init_gpios(&spi->dev, st); 3308c2ecf20Sopenharmony_ci if (ret) 3318c2ecf20Sopenharmony_ci return ret; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci st->reg = devm_regulator_get(&spi->dev, "avdd"); 3348c2ecf20Sopenharmony_ci if (IS_ERR(st->reg)) 3358c2ecf20Sopenharmony_ci return PTR_ERR(st->reg); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci ret = regulator_enable(st->reg); 3388c2ecf20Sopenharmony_ci if (ret) { 3398c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to enable specified AVdd supply\n"); 3408c2ecf20Sopenharmony_ci return ret; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ret = ad_sd_setup_buffer_and_trigger(indio_dev); 3448c2ecf20Sopenharmony_ci if (ret) 3458c2ecf20Sopenharmony_ci goto error_disable_reg; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 3488c2ecf20Sopenharmony_ci if (ret) 3498c2ecf20Sopenharmony_ci goto error_cleanup_buffer_and_trigger; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cierror_cleanup_buffer_and_trigger: 3548c2ecf20Sopenharmony_ci ad_sd_cleanup_buffer_and_trigger(indio_dev); 3558c2ecf20Sopenharmony_cierror_disable_reg: 3568c2ecf20Sopenharmony_ci regulator_disable(st->reg); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return ret; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int ad7780_remove(struct spi_device *spi) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = spi_get_drvdata(spi); 3648c2ecf20Sopenharmony_ci struct ad7780_state *st = iio_priv(indio_dev); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 3678c2ecf20Sopenharmony_ci ad_sd_cleanup_buffer_and_trigger(indio_dev); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci regulator_disable(st->reg); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic const struct spi_device_id ad7780_id[] = { 3758c2ecf20Sopenharmony_ci {"ad7170", ID_AD7170}, 3768c2ecf20Sopenharmony_ci {"ad7171", ID_AD7171}, 3778c2ecf20Sopenharmony_ci {"ad7780", ID_AD7780}, 3788c2ecf20Sopenharmony_ci {"ad7781", ID_AD7781}, 3798c2ecf20Sopenharmony_ci {} 3808c2ecf20Sopenharmony_ci}; 3818c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad7780_id); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic struct spi_driver ad7780_driver = { 3848c2ecf20Sopenharmony_ci .driver = { 3858c2ecf20Sopenharmony_ci .name = "ad7780", 3868c2ecf20Sopenharmony_ci }, 3878c2ecf20Sopenharmony_ci .probe = ad7780_probe, 3888c2ecf20Sopenharmony_ci .remove = ad7780_remove, 3898c2ecf20Sopenharmony_ci .id_table = ad7780_id, 3908c2ecf20Sopenharmony_ci}; 3918c2ecf20Sopenharmony_cimodule_spi_driver(ad7780_driver); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 3948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs"); 3958c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 396