18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD5721, AD5721R, AD5761, AD5761R, Voltage Output Digital to Analog Converter 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2016 Qtechnology A/S 68c2ecf20Sopenharmony_ci * 2016 Ricardo Ribalda <ribalda@kernel.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 138c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 148c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_data/ad5761.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define AD5761_ADDR(addr) ((addr & 0xf) << 16) 188c2ecf20Sopenharmony_ci#define AD5761_ADDR_NOOP 0x0 198c2ecf20Sopenharmony_ci#define AD5761_ADDR_DAC_WRITE 0x3 208c2ecf20Sopenharmony_ci#define AD5761_ADDR_CTRL_WRITE_REG 0x4 218c2ecf20Sopenharmony_ci#define AD5761_ADDR_SW_DATA_RESET 0x7 228c2ecf20Sopenharmony_ci#define AD5761_ADDR_DAC_READ 0xb 238c2ecf20Sopenharmony_ci#define AD5761_ADDR_CTRL_READ_REG 0xc 248c2ecf20Sopenharmony_ci#define AD5761_ADDR_SW_FULL_RESET 0xf 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define AD5761_CTRL_USE_INTVREF BIT(5) 278c2ecf20Sopenharmony_ci#define AD5761_CTRL_ETS BIT(6) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/** 308c2ecf20Sopenharmony_ci * struct ad5761_chip_info - chip specific information 318c2ecf20Sopenharmony_ci * @int_vref: Value of the internal reference voltage in mV - 0 if external 328c2ecf20Sopenharmony_ci * reference voltage is used 338c2ecf20Sopenharmony_ci * @channel: channel specification 348c2ecf20Sopenharmony_ci*/ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct ad5761_chip_info { 378c2ecf20Sopenharmony_ci unsigned long int_vref; 388c2ecf20Sopenharmony_ci const struct iio_chan_spec channel; 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct ad5761_range_params { 428c2ecf20Sopenharmony_ci int m; 438c2ecf20Sopenharmony_ci int c; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cienum ad5761_supported_device_ids { 478c2ecf20Sopenharmony_ci ID_AD5721, 488c2ecf20Sopenharmony_ci ID_AD5721R, 498c2ecf20Sopenharmony_ci ID_AD5761, 508c2ecf20Sopenharmony_ci ID_AD5761R, 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * struct ad5761_state - driver instance specific data 558c2ecf20Sopenharmony_ci * @spi: spi_device 568c2ecf20Sopenharmony_ci * @vref_reg: reference voltage regulator 578c2ecf20Sopenharmony_ci * @use_intref: true when the internal voltage reference is used 588c2ecf20Sopenharmony_ci * @vref: actual voltage reference in mVolts 598c2ecf20Sopenharmony_ci * @range: output range mode used 608c2ecf20Sopenharmony_ci * @lock: lock to protect the data buffer during SPI ops 618c2ecf20Sopenharmony_ci * @data: cache aligned spi buffer 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_cistruct ad5761_state { 648c2ecf20Sopenharmony_ci struct spi_device *spi; 658c2ecf20Sopenharmony_ci struct regulator *vref_reg; 668c2ecf20Sopenharmony_ci struct mutex lock; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci bool use_intref; 698c2ecf20Sopenharmony_ci int vref; 708c2ecf20Sopenharmony_ci enum ad5761_voltage_range range; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* 738c2ecf20Sopenharmony_ci * DMA (thus cache coherency maintenance) requires the 748c2ecf20Sopenharmony_ci * transfer buffers to live in their own cache lines. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci union { 778c2ecf20Sopenharmony_ci __be32 d32; 788c2ecf20Sopenharmony_ci u8 d8[4]; 798c2ecf20Sopenharmony_ci } data[3] ____cacheline_aligned; 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic const struct ad5761_range_params ad5761_range_params[] = { 838c2ecf20Sopenharmony_ci [AD5761_VOLTAGE_RANGE_M10V_10V] = { 848c2ecf20Sopenharmony_ci .m = 80, 858c2ecf20Sopenharmony_ci .c = 40, 868c2ecf20Sopenharmony_ci }, 878c2ecf20Sopenharmony_ci [AD5761_VOLTAGE_RANGE_0V_10V] = { 888c2ecf20Sopenharmony_ci .m = 40, 898c2ecf20Sopenharmony_ci .c = 0, 908c2ecf20Sopenharmony_ci }, 918c2ecf20Sopenharmony_ci [AD5761_VOLTAGE_RANGE_M5V_5V] = { 928c2ecf20Sopenharmony_ci .m = 40, 938c2ecf20Sopenharmony_ci .c = 20, 948c2ecf20Sopenharmony_ci }, 958c2ecf20Sopenharmony_ci [AD5761_VOLTAGE_RANGE_0V_5V] = { 968c2ecf20Sopenharmony_ci .m = 20, 978c2ecf20Sopenharmony_ci .c = 0, 988c2ecf20Sopenharmony_ci }, 998c2ecf20Sopenharmony_ci [AD5761_VOLTAGE_RANGE_M2V5_7V5] = { 1008c2ecf20Sopenharmony_ci .m = 40, 1018c2ecf20Sopenharmony_ci .c = 10, 1028c2ecf20Sopenharmony_ci }, 1038c2ecf20Sopenharmony_ci [AD5761_VOLTAGE_RANGE_M3V_3V] = { 1048c2ecf20Sopenharmony_ci .m = 24, 1058c2ecf20Sopenharmony_ci .c = 12, 1068c2ecf20Sopenharmony_ci }, 1078c2ecf20Sopenharmony_ci [AD5761_VOLTAGE_RANGE_0V_16V] = { 1088c2ecf20Sopenharmony_ci .m = 64, 1098c2ecf20Sopenharmony_ci .c = 0, 1108c2ecf20Sopenharmony_ci }, 1118c2ecf20Sopenharmony_ci [AD5761_VOLTAGE_RANGE_0V_20V] = { 1128c2ecf20Sopenharmony_ci .m = 80, 1138c2ecf20Sopenharmony_ci .c = 0, 1148c2ecf20Sopenharmony_ci }, 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int _ad5761_spi_write(struct ad5761_state *st, u8 addr, u16 val) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci st->data[0].d32 = cpu_to_be32(AD5761_ADDR(addr) | val); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return spi_write(st->spi, &st->data[0].d8[1], 3); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int ad5761_spi_write(struct iio_dev *indio_dev, u8 addr, u16 val) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct ad5761_state *st = iio_priv(indio_dev); 1278c2ecf20Sopenharmony_ci int ret; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 1308c2ecf20Sopenharmony_ci ret = _ad5761_spi_write(st, addr, val); 1318c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return ret; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int _ad5761_spi_read(struct ad5761_state *st, u8 addr, u16 *val) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci int ret; 1398c2ecf20Sopenharmony_ci struct spi_transfer xfers[] = { 1408c2ecf20Sopenharmony_ci { 1418c2ecf20Sopenharmony_ci .tx_buf = &st->data[0].d8[1], 1428c2ecf20Sopenharmony_ci .bits_per_word = 8, 1438c2ecf20Sopenharmony_ci .len = 3, 1448c2ecf20Sopenharmony_ci .cs_change = true, 1458c2ecf20Sopenharmony_ci }, { 1468c2ecf20Sopenharmony_ci .tx_buf = &st->data[1].d8[1], 1478c2ecf20Sopenharmony_ci .rx_buf = &st->data[2].d8[1], 1488c2ecf20Sopenharmony_ci .bits_per_word = 8, 1498c2ecf20Sopenharmony_ci .len = 3, 1508c2ecf20Sopenharmony_ci }, 1518c2ecf20Sopenharmony_ci }; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci st->data[0].d32 = cpu_to_be32(AD5761_ADDR(addr)); 1548c2ecf20Sopenharmony_ci st->data[1].d32 = cpu_to_be32(AD5761_ADDR(AD5761_ADDR_NOOP)); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci *val = be32_to_cpu(st->data[2].d32); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return ret; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int ad5761_spi_read(struct iio_dev *indio_dev, u8 addr, u16 *val) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct ad5761_state *st = iio_priv(indio_dev); 1668c2ecf20Sopenharmony_ci int ret; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 1698c2ecf20Sopenharmony_ci ret = _ad5761_spi_read(st, addr, val); 1708c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int ad5761_spi_set_range(struct ad5761_state *st, 1768c2ecf20Sopenharmony_ci enum ad5761_voltage_range range) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci u16 aux; 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci aux = (range & 0x7) | AD5761_CTRL_ETS; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (st->use_intref) 1848c2ecf20Sopenharmony_ci aux |= AD5761_CTRL_USE_INTVREF; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ret = _ad5761_spi_write(st, AD5761_ADDR_SW_FULL_RESET, 0); 1878c2ecf20Sopenharmony_ci if (ret) 1888c2ecf20Sopenharmony_ci return ret; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret = _ad5761_spi_write(st, AD5761_ADDR_CTRL_WRITE_REG, aux); 1918c2ecf20Sopenharmony_ci if (ret) 1928c2ecf20Sopenharmony_ci return ret; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci st->range = range; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return 0; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int ad5761_read_raw(struct iio_dev *indio_dev, 2008c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 2018c2ecf20Sopenharmony_ci int *val, 2028c2ecf20Sopenharmony_ci int *val2, 2038c2ecf20Sopenharmony_ci long mask) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct ad5761_state *st; 2068c2ecf20Sopenharmony_ci int ret; 2078c2ecf20Sopenharmony_ci u16 aux; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci switch (mask) { 2108c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 2118c2ecf20Sopenharmony_ci ret = ad5761_spi_read(indio_dev, AD5761_ADDR_DAC_READ, &aux); 2128c2ecf20Sopenharmony_ci if (ret) 2138c2ecf20Sopenharmony_ci return ret; 2148c2ecf20Sopenharmony_ci *val = aux >> chan->scan_type.shift; 2158c2ecf20Sopenharmony_ci return IIO_VAL_INT; 2168c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 2178c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 2188c2ecf20Sopenharmony_ci *val = st->vref * ad5761_range_params[st->range].m; 2198c2ecf20Sopenharmony_ci *val /= 10; 2208c2ecf20Sopenharmony_ci *val2 = chan->scan_type.realbits; 2218c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 2228c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 2238c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 2248c2ecf20Sopenharmony_ci *val = -(1 << chan->scan_type.realbits); 2258c2ecf20Sopenharmony_ci *val *= ad5761_range_params[st->range].c; 2268c2ecf20Sopenharmony_ci *val /= ad5761_range_params[st->range].m; 2278c2ecf20Sopenharmony_ci return IIO_VAL_INT; 2288c2ecf20Sopenharmony_ci default: 2298c2ecf20Sopenharmony_ci return -EINVAL; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int ad5761_write_raw(struct iio_dev *indio_dev, 2348c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 2358c2ecf20Sopenharmony_ci int val, 2368c2ecf20Sopenharmony_ci int val2, 2378c2ecf20Sopenharmony_ci long mask) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci u16 aux; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (mask != IIO_CHAN_INFO_RAW) 2428c2ecf20Sopenharmony_ci return -EINVAL; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (val2 || (val << chan->scan_type.shift) > 0xffff || val < 0) 2458c2ecf20Sopenharmony_ci return -EINVAL; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci aux = val << chan->scan_type.shift; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci return ad5761_spi_write(indio_dev, AD5761_ADDR_DAC_WRITE, aux); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic const struct iio_info ad5761_info = { 2538c2ecf20Sopenharmony_ci .read_raw = &ad5761_read_raw, 2548c2ecf20Sopenharmony_ci .write_raw = &ad5761_write_raw, 2558c2ecf20Sopenharmony_ci}; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define AD5761_CHAN(_bits) { \ 2588c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 2598c2ecf20Sopenharmony_ci .output = 1, \ 2608c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 2618c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 2628c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET), \ 2638c2ecf20Sopenharmony_ci .scan_type = { \ 2648c2ecf20Sopenharmony_ci .sign = 'u', \ 2658c2ecf20Sopenharmony_ci .realbits = (_bits), \ 2668c2ecf20Sopenharmony_ci .storagebits = 16, \ 2678c2ecf20Sopenharmony_ci .shift = 16 - (_bits), \ 2688c2ecf20Sopenharmony_ci }, \ 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const struct ad5761_chip_info ad5761_chip_infos[] = { 2728c2ecf20Sopenharmony_ci [ID_AD5721] = { 2738c2ecf20Sopenharmony_ci .int_vref = 0, 2748c2ecf20Sopenharmony_ci .channel = AD5761_CHAN(12), 2758c2ecf20Sopenharmony_ci }, 2768c2ecf20Sopenharmony_ci [ID_AD5721R] = { 2778c2ecf20Sopenharmony_ci .int_vref = 2500, 2788c2ecf20Sopenharmony_ci .channel = AD5761_CHAN(12), 2798c2ecf20Sopenharmony_ci }, 2808c2ecf20Sopenharmony_ci [ID_AD5761] = { 2818c2ecf20Sopenharmony_ci .int_vref = 0, 2828c2ecf20Sopenharmony_ci .channel = AD5761_CHAN(16), 2838c2ecf20Sopenharmony_ci }, 2848c2ecf20Sopenharmony_ci [ID_AD5761R] = { 2858c2ecf20Sopenharmony_ci .int_vref = 2500, 2868c2ecf20Sopenharmony_ci .channel = AD5761_CHAN(16), 2878c2ecf20Sopenharmony_ci }, 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int ad5761_get_vref(struct ad5761_state *st, 2918c2ecf20Sopenharmony_ci const struct ad5761_chip_info *chip_info) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci int ret; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci st->vref_reg = devm_regulator_get_optional(&st->spi->dev, "vref"); 2968c2ecf20Sopenharmony_ci if (PTR_ERR(st->vref_reg) == -ENODEV) { 2978c2ecf20Sopenharmony_ci /* Use Internal regulator */ 2988c2ecf20Sopenharmony_ci if (!chip_info->int_vref) { 2998c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, 3008c2ecf20Sopenharmony_ci "Voltage reference not found\n"); 3018c2ecf20Sopenharmony_ci return -EIO; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci st->use_intref = true; 3058c2ecf20Sopenharmony_ci st->vref = chip_info->int_vref; 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (IS_ERR(st->vref_reg)) { 3108c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, 3118c2ecf20Sopenharmony_ci "Error getting voltage reference regulator\n"); 3128c2ecf20Sopenharmony_ci return PTR_ERR(st->vref_reg); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ret = regulator_enable(st->vref_reg); 3168c2ecf20Sopenharmony_ci if (ret) { 3178c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, 3188c2ecf20Sopenharmony_ci "Failed to enable voltage reference\n"); 3198c2ecf20Sopenharmony_ci return ret; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci ret = regulator_get_voltage(st->vref_reg); 3238c2ecf20Sopenharmony_ci if (ret < 0) { 3248c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, 3258c2ecf20Sopenharmony_ci "Failed to get voltage reference value\n"); 3268c2ecf20Sopenharmony_ci goto disable_regulator_vref; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (ret < 2000000 || ret > 3000000) { 3308c2ecf20Sopenharmony_ci dev_warn(&st->spi->dev, 3318c2ecf20Sopenharmony_ci "Invalid external voltage ref. value %d uV\n", ret); 3328c2ecf20Sopenharmony_ci ret = -EIO; 3338c2ecf20Sopenharmony_ci goto disable_regulator_vref; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci st->vref = ret / 1000; 3378c2ecf20Sopenharmony_ci st->use_intref = false; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cidisable_regulator_vref: 3428c2ecf20Sopenharmony_ci regulator_disable(st->vref_reg); 3438c2ecf20Sopenharmony_ci st->vref_reg = NULL; 3448c2ecf20Sopenharmony_ci return ret; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int ad5761_probe(struct spi_device *spi) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct iio_dev *iio_dev; 3508c2ecf20Sopenharmony_ci struct ad5761_state *st; 3518c2ecf20Sopenharmony_ci int ret; 3528c2ecf20Sopenharmony_ci const struct ad5761_chip_info *chip_info = 3538c2ecf20Sopenharmony_ci &ad5761_chip_infos[spi_get_device_id(spi)->driver_data]; 3548c2ecf20Sopenharmony_ci enum ad5761_voltage_range voltage_range = AD5761_VOLTAGE_RANGE_0V_5V; 3558c2ecf20Sopenharmony_ci struct ad5761_platform_data *pdata = dev_get_platdata(&spi->dev); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci iio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 3588c2ecf20Sopenharmony_ci if (!iio_dev) 3598c2ecf20Sopenharmony_ci return -ENOMEM; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci st = iio_priv(iio_dev); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci st->spi = spi; 3648c2ecf20Sopenharmony_ci spi_set_drvdata(spi, iio_dev); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci ret = ad5761_get_vref(st, chip_info); 3678c2ecf20Sopenharmony_ci if (ret) 3688c2ecf20Sopenharmony_ci return ret; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (pdata) 3718c2ecf20Sopenharmony_ci voltage_range = pdata->voltage_range; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci mutex_init(&st->lock); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ret = ad5761_spi_set_range(st, voltage_range); 3768c2ecf20Sopenharmony_ci if (ret) 3778c2ecf20Sopenharmony_ci goto disable_regulator_err; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci iio_dev->info = &ad5761_info; 3808c2ecf20Sopenharmony_ci iio_dev->modes = INDIO_DIRECT_MODE; 3818c2ecf20Sopenharmony_ci iio_dev->channels = &chip_info->channel; 3828c2ecf20Sopenharmony_ci iio_dev->num_channels = 1; 3838c2ecf20Sopenharmony_ci iio_dev->name = spi_get_device_id(st->spi)->name; 3848c2ecf20Sopenharmony_ci ret = iio_device_register(iio_dev); 3858c2ecf20Sopenharmony_ci if (ret) 3868c2ecf20Sopenharmony_ci goto disable_regulator_err; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cidisable_regulator_err: 3918c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(st->vref_reg)) 3928c2ecf20Sopenharmony_ci regulator_disable(st->vref_reg); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return ret; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int ad5761_remove(struct spi_device *spi) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct iio_dev *iio_dev = spi_get_drvdata(spi); 4008c2ecf20Sopenharmony_ci struct ad5761_state *st = iio_priv(iio_dev); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci iio_device_unregister(iio_dev); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(st->vref_reg)) 4058c2ecf20Sopenharmony_ci regulator_disable(st->vref_reg); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic const struct spi_device_id ad5761_id[] = { 4118c2ecf20Sopenharmony_ci {"ad5721", ID_AD5721}, 4128c2ecf20Sopenharmony_ci {"ad5721r", ID_AD5721R}, 4138c2ecf20Sopenharmony_ci {"ad5761", ID_AD5761}, 4148c2ecf20Sopenharmony_ci {"ad5761r", ID_AD5761R}, 4158c2ecf20Sopenharmony_ci {} 4168c2ecf20Sopenharmony_ci}; 4178c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad5761_id); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic struct spi_driver ad5761_driver = { 4208c2ecf20Sopenharmony_ci .driver = { 4218c2ecf20Sopenharmony_ci .name = "ad5761", 4228c2ecf20Sopenharmony_ci }, 4238c2ecf20Sopenharmony_ci .probe = ad5761_probe, 4248c2ecf20Sopenharmony_ci .remove = ad5761_remove, 4258c2ecf20Sopenharmony_ci .id_table = ad5761_id, 4268c2ecf20Sopenharmony_ci}; 4278c2ecf20Sopenharmony_cimodule_spi_driver(ad5761_driver); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ricardo Ribalda <ribalda@kernel.org>"); 4308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5721, AD5721R, AD5761, AD5761R driver"); 4318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 432