18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Analog devices AD5360, AD5361, AD5362, AD5363, AD5370, AD5371, AD5373 48c2ecf20Sopenharmony_ci * multi-channel Digital to Analog Converters driver 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2011 Analog Devices Inc. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 168c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 198c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define AD5360_CMD(x) ((x) << 22) 228c2ecf20Sopenharmony_ci#define AD5360_ADDR(x) ((x) << 16) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define AD5360_READBACK_TYPE(x) ((x) << 13) 258c2ecf20Sopenharmony_ci#define AD5360_READBACK_ADDR(x) ((x) << 7) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define AD5360_CHAN_ADDR(chan) ((chan) + 0x8) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define AD5360_CMD_WRITE_DATA 0x3 308c2ecf20Sopenharmony_ci#define AD5360_CMD_WRITE_OFFSET 0x2 318c2ecf20Sopenharmony_ci#define AD5360_CMD_WRITE_GAIN 0x1 328c2ecf20Sopenharmony_ci#define AD5360_CMD_SPECIAL_FUNCTION 0x0 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Special function register addresses */ 358c2ecf20Sopenharmony_ci#define AD5360_REG_SF_NOP 0x0 368c2ecf20Sopenharmony_ci#define AD5360_REG_SF_CTRL 0x1 378c2ecf20Sopenharmony_ci#define AD5360_REG_SF_OFS(x) (0x2 + (x)) 388c2ecf20Sopenharmony_ci#define AD5360_REG_SF_READBACK 0x5 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define AD5360_SF_CTRL_PWR_DOWN BIT(0) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define AD5360_READBACK_X1A 0x0 438c2ecf20Sopenharmony_ci#define AD5360_READBACK_X1B 0x1 448c2ecf20Sopenharmony_ci#define AD5360_READBACK_OFFSET 0x2 458c2ecf20Sopenharmony_ci#define AD5360_READBACK_GAIN 0x3 468c2ecf20Sopenharmony_ci#define AD5360_READBACK_SF 0x4 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/** 508c2ecf20Sopenharmony_ci * struct ad5360_chip_info - chip specific information 518c2ecf20Sopenharmony_ci * @channel_template: channel specification template 528c2ecf20Sopenharmony_ci * @num_channels: number of channels 538c2ecf20Sopenharmony_ci * @channels_per_group: number of channels per group 548c2ecf20Sopenharmony_ci * @num_vrefs: number of vref supplies for the chip 558c2ecf20Sopenharmony_ci*/ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct ad5360_chip_info { 588c2ecf20Sopenharmony_ci struct iio_chan_spec channel_template; 598c2ecf20Sopenharmony_ci unsigned int num_channels; 608c2ecf20Sopenharmony_ci unsigned int channels_per_group; 618c2ecf20Sopenharmony_ci unsigned int num_vrefs; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * struct ad5360_state - driver instance specific data 668c2ecf20Sopenharmony_ci * @spi: spi_device 678c2ecf20Sopenharmony_ci * @chip_info: chip model specific constants, available modes etc 688c2ecf20Sopenharmony_ci * @vref_reg: vref supply regulators 698c2ecf20Sopenharmony_ci * @ctrl: control register cache 708c2ecf20Sopenharmony_ci * @lock: lock to protect the data buffer during SPI ops 718c2ecf20Sopenharmony_ci * @data: spi transfer buffers 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct ad5360_state { 758c2ecf20Sopenharmony_ci struct spi_device *spi; 768c2ecf20Sopenharmony_ci const struct ad5360_chip_info *chip_info; 778c2ecf20Sopenharmony_ci struct regulator_bulk_data vref_reg[3]; 788c2ecf20Sopenharmony_ci unsigned int ctrl; 798c2ecf20Sopenharmony_ci struct mutex lock; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* 828c2ecf20Sopenharmony_ci * DMA (thus cache coherency maintenance) requires the 838c2ecf20Sopenharmony_ci * transfer buffers to live in their own cache lines. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci union { 868c2ecf20Sopenharmony_ci __be32 d32; 878c2ecf20Sopenharmony_ci u8 d8[4]; 888c2ecf20Sopenharmony_ci } data[2] ____cacheline_aligned; 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cienum ad5360_type { 928c2ecf20Sopenharmony_ci ID_AD5360, 938c2ecf20Sopenharmony_ci ID_AD5361, 948c2ecf20Sopenharmony_ci ID_AD5362, 958c2ecf20Sopenharmony_ci ID_AD5363, 968c2ecf20Sopenharmony_ci ID_AD5370, 978c2ecf20Sopenharmony_ci ID_AD5371, 988c2ecf20Sopenharmony_ci ID_AD5372, 998c2ecf20Sopenharmony_ci ID_AD5373, 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define AD5360_CHANNEL(bits) { \ 1038c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 1048c2ecf20Sopenharmony_ci .indexed = 1, \ 1058c2ecf20Sopenharmony_ci .output = 1, \ 1068c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 1078c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | \ 1088c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET) | \ 1098c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_CALIBSCALE) | \ 1108c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_CALIBBIAS), \ 1118c2ecf20Sopenharmony_ci .scan_type = { \ 1128c2ecf20Sopenharmony_ci .sign = 'u', \ 1138c2ecf20Sopenharmony_ci .realbits = (bits), \ 1148c2ecf20Sopenharmony_ci .storagebits = 16, \ 1158c2ecf20Sopenharmony_ci .shift = 16 - (bits), \ 1168c2ecf20Sopenharmony_ci }, \ 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const struct ad5360_chip_info ad5360_chip_info_tbl[] = { 1208c2ecf20Sopenharmony_ci [ID_AD5360] = { 1218c2ecf20Sopenharmony_ci .channel_template = AD5360_CHANNEL(16), 1228c2ecf20Sopenharmony_ci .num_channels = 16, 1238c2ecf20Sopenharmony_ci .channels_per_group = 8, 1248c2ecf20Sopenharmony_ci .num_vrefs = 2, 1258c2ecf20Sopenharmony_ci }, 1268c2ecf20Sopenharmony_ci [ID_AD5361] = { 1278c2ecf20Sopenharmony_ci .channel_template = AD5360_CHANNEL(14), 1288c2ecf20Sopenharmony_ci .num_channels = 16, 1298c2ecf20Sopenharmony_ci .channels_per_group = 8, 1308c2ecf20Sopenharmony_ci .num_vrefs = 2, 1318c2ecf20Sopenharmony_ci }, 1328c2ecf20Sopenharmony_ci [ID_AD5362] = { 1338c2ecf20Sopenharmony_ci .channel_template = AD5360_CHANNEL(16), 1348c2ecf20Sopenharmony_ci .num_channels = 8, 1358c2ecf20Sopenharmony_ci .channels_per_group = 4, 1368c2ecf20Sopenharmony_ci .num_vrefs = 2, 1378c2ecf20Sopenharmony_ci }, 1388c2ecf20Sopenharmony_ci [ID_AD5363] = { 1398c2ecf20Sopenharmony_ci .channel_template = AD5360_CHANNEL(14), 1408c2ecf20Sopenharmony_ci .num_channels = 8, 1418c2ecf20Sopenharmony_ci .channels_per_group = 4, 1428c2ecf20Sopenharmony_ci .num_vrefs = 2, 1438c2ecf20Sopenharmony_ci }, 1448c2ecf20Sopenharmony_ci [ID_AD5370] = { 1458c2ecf20Sopenharmony_ci .channel_template = AD5360_CHANNEL(16), 1468c2ecf20Sopenharmony_ci .num_channels = 40, 1478c2ecf20Sopenharmony_ci .channels_per_group = 8, 1488c2ecf20Sopenharmony_ci .num_vrefs = 2, 1498c2ecf20Sopenharmony_ci }, 1508c2ecf20Sopenharmony_ci [ID_AD5371] = { 1518c2ecf20Sopenharmony_ci .channel_template = AD5360_CHANNEL(14), 1528c2ecf20Sopenharmony_ci .num_channels = 40, 1538c2ecf20Sopenharmony_ci .channels_per_group = 8, 1548c2ecf20Sopenharmony_ci .num_vrefs = 3, 1558c2ecf20Sopenharmony_ci }, 1568c2ecf20Sopenharmony_ci [ID_AD5372] = { 1578c2ecf20Sopenharmony_ci .channel_template = AD5360_CHANNEL(16), 1588c2ecf20Sopenharmony_ci .num_channels = 32, 1598c2ecf20Sopenharmony_ci .channels_per_group = 8, 1608c2ecf20Sopenharmony_ci .num_vrefs = 2, 1618c2ecf20Sopenharmony_ci }, 1628c2ecf20Sopenharmony_ci [ID_AD5373] = { 1638c2ecf20Sopenharmony_ci .channel_template = AD5360_CHANNEL(14), 1648c2ecf20Sopenharmony_ci .num_channels = 32, 1658c2ecf20Sopenharmony_ci .channels_per_group = 8, 1668c2ecf20Sopenharmony_ci .num_vrefs = 2, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic unsigned int ad5360_get_channel_vref_index(struct ad5360_state *st, 1718c2ecf20Sopenharmony_ci unsigned int channel) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci unsigned int i; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* The first groups have their own vref, while the remaining groups 1768c2ecf20Sopenharmony_ci * share the last vref */ 1778c2ecf20Sopenharmony_ci i = channel / st->chip_info->channels_per_group; 1788c2ecf20Sopenharmony_ci if (i >= st->chip_info->num_vrefs) 1798c2ecf20Sopenharmony_ci i = st->chip_info->num_vrefs - 1; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return i; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int ad5360_get_channel_vref(struct ad5360_state *st, 1858c2ecf20Sopenharmony_ci unsigned int channel) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci unsigned int i = ad5360_get_channel_vref_index(st, channel); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return regulator_get_voltage(st->vref_reg[i].consumer); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int ad5360_write_unlocked(struct iio_dev *indio_dev, 1948c2ecf20Sopenharmony_ci unsigned int cmd, unsigned int addr, unsigned int val, 1958c2ecf20Sopenharmony_ci unsigned int shift) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct ad5360_state *st = iio_priv(indio_dev); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci val <<= shift; 2008c2ecf20Sopenharmony_ci val |= AD5360_CMD(cmd) | AD5360_ADDR(addr); 2018c2ecf20Sopenharmony_ci st->data[0].d32 = cpu_to_be32(val); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return spi_write(st->spi, &st->data[0].d8[1], 3); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int ad5360_write(struct iio_dev *indio_dev, unsigned int cmd, 2078c2ecf20Sopenharmony_ci unsigned int addr, unsigned int val, unsigned int shift) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci int ret; 2108c2ecf20Sopenharmony_ci struct ad5360_state *st = iio_priv(indio_dev); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 2138c2ecf20Sopenharmony_ci ret = ad5360_write_unlocked(indio_dev, cmd, addr, val, shift); 2148c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int ad5360_read(struct iio_dev *indio_dev, unsigned int type, 2208c2ecf20Sopenharmony_ci unsigned int addr) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct ad5360_state *st = iio_priv(indio_dev); 2238c2ecf20Sopenharmony_ci int ret; 2248c2ecf20Sopenharmony_ci struct spi_transfer t[] = { 2258c2ecf20Sopenharmony_ci { 2268c2ecf20Sopenharmony_ci .tx_buf = &st->data[0].d8[1], 2278c2ecf20Sopenharmony_ci .len = 3, 2288c2ecf20Sopenharmony_ci .cs_change = 1, 2298c2ecf20Sopenharmony_ci }, { 2308c2ecf20Sopenharmony_ci .rx_buf = &st->data[1].d8[1], 2318c2ecf20Sopenharmony_ci .len = 3, 2328c2ecf20Sopenharmony_ci }, 2338c2ecf20Sopenharmony_ci }; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) | 2388c2ecf20Sopenharmony_ci AD5360_ADDR(AD5360_REG_SF_READBACK) | 2398c2ecf20Sopenharmony_ci AD5360_READBACK_TYPE(type) | 2408c2ecf20Sopenharmony_ci AD5360_READBACK_ADDR(addr)); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); 2438c2ecf20Sopenharmony_ci if (ret >= 0) 2448c2ecf20Sopenharmony_ci ret = be32_to_cpu(st->data[1].d32) & 0xffff; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic ssize_t ad5360_read_dac_powerdown(struct device *dev, 2528c2ecf20Sopenharmony_ci struct device_attribute *attr, 2538c2ecf20Sopenharmony_ci char *buf) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 2568c2ecf20Sopenharmony_ci struct ad5360_state *st = iio_priv(indio_dev); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN)); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set, 2628c2ecf20Sopenharmony_ci unsigned int clr) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct ad5360_state *st = iio_priv(indio_dev); 2658c2ecf20Sopenharmony_ci unsigned int ret; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci st->ctrl |= set; 2708c2ecf20Sopenharmony_ci st->ctrl &= ~clr; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci ret = ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION, 2738c2ecf20Sopenharmony_ci AD5360_REG_SF_CTRL, st->ctrl, 0); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic ssize_t ad5360_write_dac_powerdown(struct device *dev, 2818c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 2848c2ecf20Sopenharmony_ci bool pwr_down; 2858c2ecf20Sopenharmony_ci int ret; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci ret = strtobool(buf, &pwr_down); 2888c2ecf20Sopenharmony_ci if (ret) 2898c2ecf20Sopenharmony_ci return ret; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (pwr_down) 2928c2ecf20Sopenharmony_ci ret = ad5360_update_ctrl(indio_dev, AD5360_SF_CTRL_PWR_DOWN, 0); 2938c2ecf20Sopenharmony_ci else 2948c2ecf20Sopenharmony_ci ret = ad5360_update_ctrl(indio_dev, 0, AD5360_SF_CTRL_PWR_DOWN); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return ret ? ret : len; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(out_voltage_powerdown, 3008c2ecf20Sopenharmony_ci S_IRUGO | S_IWUSR, 3018c2ecf20Sopenharmony_ci ad5360_read_dac_powerdown, 3028c2ecf20Sopenharmony_ci ad5360_write_dac_powerdown, 0); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic struct attribute *ad5360_attributes[] = { 3058c2ecf20Sopenharmony_ci &iio_dev_attr_out_voltage_powerdown.dev_attr.attr, 3068c2ecf20Sopenharmony_ci NULL, 3078c2ecf20Sopenharmony_ci}; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic const struct attribute_group ad5360_attribute_group = { 3108c2ecf20Sopenharmony_ci .attrs = ad5360_attributes, 3118c2ecf20Sopenharmony_ci}; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int ad5360_write_raw(struct iio_dev *indio_dev, 3148c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3158c2ecf20Sopenharmony_ci int val, 3168c2ecf20Sopenharmony_ci int val2, 3178c2ecf20Sopenharmony_ci long mask) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct ad5360_state *st = iio_priv(indio_dev); 3208c2ecf20Sopenharmony_ci int max_val = (1 << chan->scan_type.realbits); 3218c2ecf20Sopenharmony_ci unsigned int ofs_index; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci switch (mask) { 3248c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3258c2ecf20Sopenharmony_ci if (val >= max_val || val < 0) 3268c2ecf20Sopenharmony_ci return -EINVAL; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return ad5360_write(indio_dev, AD5360_CMD_WRITE_DATA, 3298c2ecf20Sopenharmony_ci chan->address, val, chan->scan_type.shift); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBBIAS: 3328c2ecf20Sopenharmony_ci if (val >= max_val || val < 0) 3338c2ecf20Sopenharmony_ci return -EINVAL; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return ad5360_write(indio_dev, AD5360_CMD_WRITE_OFFSET, 3368c2ecf20Sopenharmony_ci chan->address, val, chan->scan_type.shift); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBSCALE: 3398c2ecf20Sopenharmony_ci if (val >= max_val || val < 0) 3408c2ecf20Sopenharmony_ci return -EINVAL; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return ad5360_write(indio_dev, AD5360_CMD_WRITE_GAIN, 3438c2ecf20Sopenharmony_ci chan->address, val, chan->scan_type.shift); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 3468c2ecf20Sopenharmony_ci if (val <= -max_val || val > 0) 3478c2ecf20Sopenharmony_ci return -EINVAL; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci val = -val; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* offset is supposed to have the same scale as raw, but it 3528c2ecf20Sopenharmony_ci * is always 14bits wide, so on a chip where the raw value has 3538c2ecf20Sopenharmony_ci * more bits, we need to shift offset. */ 3548c2ecf20Sopenharmony_ci val >>= (chan->scan_type.realbits - 14); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* There is one DAC offset register per vref. Changing one 3578c2ecf20Sopenharmony_ci * channels offset will also change the offset for all other 3588c2ecf20Sopenharmony_ci * channels which share the same vref supply. */ 3598c2ecf20Sopenharmony_ci ofs_index = ad5360_get_channel_vref_index(st, chan->channel); 3608c2ecf20Sopenharmony_ci return ad5360_write(indio_dev, AD5360_CMD_SPECIAL_FUNCTION, 3618c2ecf20Sopenharmony_ci AD5360_REG_SF_OFS(ofs_index), val, 0); 3628c2ecf20Sopenharmony_ci default: 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return -EINVAL; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int ad5360_read_raw(struct iio_dev *indio_dev, 3708c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3718c2ecf20Sopenharmony_ci int *val, 3728c2ecf20Sopenharmony_ci int *val2, 3738c2ecf20Sopenharmony_ci long m) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct ad5360_state *st = iio_priv(indio_dev); 3768c2ecf20Sopenharmony_ci unsigned int ofs_index; 3778c2ecf20Sopenharmony_ci int scale_uv; 3788c2ecf20Sopenharmony_ci int ret; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci switch (m) { 3818c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3828c2ecf20Sopenharmony_ci ret = ad5360_read(indio_dev, AD5360_READBACK_X1A, 3838c2ecf20Sopenharmony_ci chan->address); 3848c2ecf20Sopenharmony_ci if (ret < 0) 3858c2ecf20Sopenharmony_ci return ret; 3868c2ecf20Sopenharmony_ci *val = ret >> chan->scan_type.shift; 3878c2ecf20Sopenharmony_ci return IIO_VAL_INT; 3888c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 3898c2ecf20Sopenharmony_ci scale_uv = ad5360_get_channel_vref(st, chan->channel); 3908c2ecf20Sopenharmony_ci if (scale_uv < 0) 3918c2ecf20Sopenharmony_ci return scale_uv; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* vout = 4 * vref * dac_code */ 3948c2ecf20Sopenharmony_ci *val = scale_uv * 4 / 1000; 3958c2ecf20Sopenharmony_ci *val2 = chan->scan_type.realbits; 3968c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 3978c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBBIAS: 3988c2ecf20Sopenharmony_ci ret = ad5360_read(indio_dev, AD5360_READBACK_OFFSET, 3998c2ecf20Sopenharmony_ci chan->address); 4008c2ecf20Sopenharmony_ci if (ret < 0) 4018c2ecf20Sopenharmony_ci return ret; 4028c2ecf20Sopenharmony_ci *val = ret; 4038c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4048c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBSCALE: 4058c2ecf20Sopenharmony_ci ret = ad5360_read(indio_dev, AD5360_READBACK_GAIN, 4068c2ecf20Sopenharmony_ci chan->address); 4078c2ecf20Sopenharmony_ci if (ret < 0) 4088c2ecf20Sopenharmony_ci return ret; 4098c2ecf20Sopenharmony_ci *val = ret; 4108c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4118c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 4128c2ecf20Sopenharmony_ci ofs_index = ad5360_get_channel_vref_index(st, chan->channel); 4138c2ecf20Sopenharmony_ci ret = ad5360_read(indio_dev, AD5360_READBACK_SF, 4148c2ecf20Sopenharmony_ci AD5360_REG_SF_OFS(ofs_index)); 4158c2ecf20Sopenharmony_ci if (ret < 0) 4168c2ecf20Sopenharmony_ci return ret; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci ret <<= (chan->scan_type.realbits - 14); 4198c2ecf20Sopenharmony_ci *val = -ret; 4208c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return -EINVAL; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic const struct iio_info ad5360_info = { 4278c2ecf20Sopenharmony_ci .read_raw = ad5360_read_raw, 4288c2ecf20Sopenharmony_ci .write_raw = ad5360_write_raw, 4298c2ecf20Sopenharmony_ci .attrs = &ad5360_attribute_group, 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic const char * const ad5360_vref_name[] = { 4338c2ecf20Sopenharmony_ci "vref0", "vref1", "vref2" 4348c2ecf20Sopenharmony_ci}; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int ad5360_alloc_channels(struct iio_dev *indio_dev) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct ad5360_state *st = iio_priv(indio_dev); 4398c2ecf20Sopenharmony_ci struct iio_chan_spec *channels; 4408c2ecf20Sopenharmony_ci unsigned int i; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci channels = kcalloc(st->chip_info->num_channels, 4438c2ecf20Sopenharmony_ci sizeof(struct iio_chan_spec), GFP_KERNEL); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (!channels) 4468c2ecf20Sopenharmony_ci return -ENOMEM; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci for (i = 0; i < st->chip_info->num_channels; ++i) { 4498c2ecf20Sopenharmony_ci channels[i] = st->chip_info->channel_template; 4508c2ecf20Sopenharmony_ci channels[i].channel = i; 4518c2ecf20Sopenharmony_ci channels[i].address = AD5360_CHAN_ADDR(i); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci indio_dev->channels = channels; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return 0; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int ad5360_probe(struct spi_device *spi) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci enum ad5360_type type = spi_get_device_id(spi)->driver_data; 4628c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 4638c2ecf20Sopenharmony_ci struct ad5360_state *st; 4648c2ecf20Sopenharmony_ci unsigned int i; 4658c2ecf20Sopenharmony_ci int ret; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 4688c2ecf20Sopenharmony_ci if (indio_dev == NULL) { 4698c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to allocate iio device\n"); 4708c2ecf20Sopenharmony_ci return -ENOMEM; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 4748c2ecf20Sopenharmony_ci spi_set_drvdata(spi, indio_dev); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci st->chip_info = &ad5360_chip_info_tbl[type]; 4778c2ecf20Sopenharmony_ci st->spi = spi; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci indio_dev->name = spi_get_device_id(spi)->name; 4808c2ecf20Sopenharmony_ci indio_dev->info = &ad5360_info; 4818c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 4828c2ecf20Sopenharmony_ci indio_dev->num_channels = st->chip_info->num_channels; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci mutex_init(&st->lock); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci ret = ad5360_alloc_channels(indio_dev); 4878c2ecf20Sopenharmony_ci if (ret) { 4888c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret); 4898c2ecf20Sopenharmony_ci return ret; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci for (i = 0; i < st->chip_info->num_vrefs; ++i) 4938c2ecf20Sopenharmony_ci st->vref_reg[i].supply = ad5360_vref_name[i]; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs, 4968c2ecf20Sopenharmony_ci st->vref_reg); 4978c2ecf20Sopenharmony_ci if (ret) { 4988c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret); 4998c2ecf20Sopenharmony_ci goto error_free_channels; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(st->chip_info->num_vrefs, st->vref_reg); 5038c2ecf20Sopenharmony_ci if (ret) { 5048c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret); 5058c2ecf20Sopenharmony_ci goto error_free_channels; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 5098c2ecf20Sopenharmony_ci if (ret) { 5108c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to register iio device: %d\n", ret); 5118c2ecf20Sopenharmony_ci goto error_disable_reg; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cierror_disable_reg: 5178c2ecf20Sopenharmony_ci regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg); 5188c2ecf20Sopenharmony_cierror_free_channels: 5198c2ecf20Sopenharmony_ci kfree(indio_dev->channels); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return ret; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic int ad5360_remove(struct spi_device *spi) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = spi_get_drvdata(spi); 5278c2ecf20Sopenharmony_ci struct ad5360_state *st = iio_priv(indio_dev); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci kfree(indio_dev->channels); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return 0; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic const struct spi_device_id ad5360_ids[] = { 5398c2ecf20Sopenharmony_ci { "ad5360", ID_AD5360 }, 5408c2ecf20Sopenharmony_ci { "ad5361", ID_AD5361 }, 5418c2ecf20Sopenharmony_ci { "ad5362", ID_AD5362 }, 5428c2ecf20Sopenharmony_ci { "ad5363", ID_AD5363 }, 5438c2ecf20Sopenharmony_ci { "ad5370", ID_AD5370 }, 5448c2ecf20Sopenharmony_ci { "ad5371", ID_AD5371 }, 5458c2ecf20Sopenharmony_ci { "ad5372", ID_AD5372 }, 5468c2ecf20Sopenharmony_ci { "ad5373", ID_AD5373 }, 5478c2ecf20Sopenharmony_ci {} 5488c2ecf20Sopenharmony_ci}; 5498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad5360_ids); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic struct spi_driver ad5360_driver = { 5528c2ecf20Sopenharmony_ci .driver = { 5538c2ecf20Sopenharmony_ci .name = "ad5360", 5548c2ecf20Sopenharmony_ci }, 5558c2ecf20Sopenharmony_ci .probe = ad5360_probe, 5568c2ecf20Sopenharmony_ci .remove = ad5360_remove, 5578c2ecf20Sopenharmony_ci .id_table = ad5360_ids, 5588c2ecf20Sopenharmony_ci}; 5598c2ecf20Sopenharmony_cimodule_spi_driver(ad5360_driver); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 5628c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5360/61/62/63/70/71/72/73 DAC"); 5638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 564