1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AD5706R 16-bit Current Output Digital to Analog Converter 4 * 5 * Copyright 2026 Analog Devices Inc. 6 */ 7 8 #include <linux/array_size.h> 9 #include <linux/bits.h> 10 #include <linux/dev_printk.h> 11 #include <linux/err.h> 12 #include <linux/iio/iio.h> 13 #include <linux/mod_devicetable.h> 14 #include <linux/module.h> 15 #include <linux/regmap.h> 16 #include <linux/spi/spi.h> 17 #include <linux/types.h> 18 #include <linux/unaligned.h> 19 20 /* SPI frame layout */ 21 #define AD5706R_RD_MASK BIT(15) 22 #define AD5706R_ADDR_MASK GENMASK(11, 0) 23 24 /* Registers */ 25 #define AD5706R_REG_DAC_INPUT_A_CH(x) (0x60 + ((x) * 2)) 26 #define AD5706R_REG_DAC_DATA_READBACK_CH(x) (0x68 + ((x) * 2)) 27 28 #define AD5706R_DAC_RESOLUTION 16 29 #define AD5706R_DAC_MAX_CODE GENMASK(15, 0) 30 #define AD5706R_MULTIBYTE_REG_START 0x14 31 #define AD5706R_MULTIBYTE_REG_END 0x71 32 #define AD5706R_MAX_REG 0x77 33 34 struct ad5706r_state { 35 struct spi_device *spi; 36 struct regmap *regmap; 37 38 u8 tx_buf[4] __aligned(IIO_DMA_MINALIGN); 39 u8 rx_buf[4]; 40 }; 41 42 static int ad5706r_reg_len(unsigned int reg) 43 { 44 if (reg >= AD5706R_MULTIBYTE_REG_START && reg <= AD5706R_MULTIBYTE_REG_END) 45 return 2; 46 47 return 1; 48 } 49 50 static int ad5706r_regmap_write(void *context, const void *data, size_t count) 51 { 52 struct ad5706r_state *st = context; 53 unsigned int num_bytes; 54 u16 reg, val; 55 56 if (count != 4) 57 return -EINVAL; 58 59 reg = get_unaligned_be16(data); 60 val = get_unaligned_be16(data + 2); 61 num_bytes = ad5706r_reg_len(reg); 62 63 struct spi_transfer xfer = { 64 .tx_buf = st->tx_buf, 65 .len = num_bytes + 2, 66 }; 67 68 put_unaligned_be16(reg, &st->tx_buf[0]); 69 70 if (num_bytes == 1) 71 st->tx_buf[2] = (u8)val; 72 else if (num_bytes == 2) 73 put_unaligned_be16(val, &st->tx_buf[2]); 74 else 75 return -EINVAL; 76 77 return spi_sync_transfer(st->spi, &xfer, 1); 78 } 79 80 static int ad5706r_regmap_read(void *context, const void *reg_buf, 81 size_t reg_size, void *val_buf, size_t val_size) 82 { 83 struct ad5706r_state *st = context; 84 unsigned int num_bytes; 85 u16 reg, cmd, val; 86 int ret; 87 88 if (reg_size != 2 || val_size != 2) 89 return -EINVAL; 90 91 reg = get_unaligned_be16(reg_buf); 92 num_bytes = ad5706r_reg_len(reg); 93 94 /* Full duplex, device responds immediately after command */ 95 struct spi_transfer xfer = { 96 .tx_buf = st->tx_buf, 97 .rx_buf = st->rx_buf, 98 .len = 2 + num_bytes, 99 }; 100 101 cmd = AD5706R_RD_MASK | (reg & AD5706R_ADDR_MASK); 102 put_unaligned_be16(cmd, &st->tx_buf[0]); 103 put_unaligned_be16(0, &st->tx_buf[2]); 104 105 ret = spi_sync_transfer(st->spi, &xfer, 1); 106 if (ret) 107 return ret; 108 109 /* Extract value from response (skip 2-byte command echo) */ 110 if (num_bytes == 1) 111 val = st->rx_buf[2]; 112 else if (num_bytes == 2) 113 val = get_unaligned_be16(&st->rx_buf[2]); 114 else 115 return -EINVAL; 116 117 put_unaligned_be16(val, val_buf); 118 119 return 0; 120 } 121 122 static int ad5706r_read_raw(struct iio_dev *indio_dev, 123 struct iio_chan_spec const *chan, 124 int *val, int *val2, long mask) 125 { 126 struct ad5706r_state *st = iio_priv(indio_dev); 127 unsigned int reg, reg_val; 128 int ret; 129 130 switch (mask) { 131 case IIO_CHAN_INFO_RAW: 132 reg = AD5706R_REG_DAC_DATA_READBACK_CH(chan->channel); 133 ret = regmap_read(st->regmap, reg, ®_val); 134 if (ret) 135 return ret; 136 137 *val = reg_val; 138 return IIO_VAL_INT; 139 case IIO_CHAN_INFO_SCALE: 140 *val = 50; 141 *val2 = AD5706R_DAC_RESOLUTION; 142 return IIO_VAL_FRACTIONAL_LOG2; 143 default: 144 return -EINVAL; 145 } 146 } 147 148 static int ad5706r_write_raw(struct iio_dev *indio_dev, 149 struct iio_chan_spec const *chan, 150 int val, int val2, long mask) 151 { 152 struct ad5706r_state *st = iio_priv(indio_dev); 153 unsigned int reg; 154 155 switch (mask) { 156 case IIO_CHAN_INFO_RAW: 157 if (val < 0 || val > AD5706R_DAC_MAX_CODE) 158 return -EINVAL; 159 160 reg = AD5706R_REG_DAC_INPUT_A_CH(chan->channel); 161 return regmap_write(st->regmap, reg, val); 162 default: 163 return -EINVAL; 164 } 165 } 166 167 static const struct regmap_bus ad5706r_regmap_bus = { 168 .write = ad5706r_regmap_write, 169 .read = ad5706r_regmap_read, 170 .reg_format_endian_default = REGMAP_ENDIAN_BIG, 171 .val_format_endian_default = REGMAP_ENDIAN_BIG, 172 }; 173 174 static const struct regmap_config ad5706r_regmap_config = { 175 .reg_bits = 16, 176 .val_bits = 16, 177 .max_register = AD5706R_MAX_REG, 178 }; 179 180 static const struct iio_info ad5706r_info = { 181 .read_raw = ad5706r_read_raw, 182 .write_raw = ad5706r_write_raw, 183 }; 184 185 #define AD5706R_CHAN(_channel) { \ 186 .type = IIO_CURRENT, \ 187 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 188 BIT(IIO_CHAN_INFO_SCALE), \ 189 .output = 1, \ 190 .indexed = 1, \ 191 .channel = _channel, \ 192 } 193 194 static const struct iio_chan_spec ad5706r_channels[] = { 195 AD5706R_CHAN(0), 196 AD5706R_CHAN(1), 197 AD5706R_CHAN(2), 198 AD5706R_CHAN(3), 199 }; 200 201 static int ad5706r_probe(struct spi_device *spi) 202 { 203 struct device *dev = &spi->dev; 204 struct iio_dev *indio_dev; 205 struct ad5706r_state *st; 206 207 indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 208 if (!indio_dev) 209 return -ENOMEM; 210 211 st = iio_priv(indio_dev); 212 st->spi = spi; 213 214 st->regmap = devm_regmap_init(dev, &ad5706r_regmap_bus, 215 st, &ad5706r_regmap_config); 216 if (IS_ERR(st->regmap)) 217 return dev_err_probe(dev, PTR_ERR(st->regmap), 218 "Failed to init regmap\n"); 219 220 indio_dev->name = "ad5706r"; 221 indio_dev->info = &ad5706r_info; 222 indio_dev->modes = INDIO_DIRECT_MODE; 223 indio_dev->channels = ad5706r_channels; 224 indio_dev->num_channels = ARRAY_SIZE(ad5706r_channels); 225 226 return devm_iio_device_register(dev, indio_dev); 227 } 228 229 static const struct of_device_id ad5706r_of_match[] = { 230 { .compatible = "adi,ad5706r" }, 231 { } 232 }; 233 MODULE_DEVICE_TABLE(of, ad5706r_of_match); 234 235 static const struct spi_device_id ad5706r_id[] = { 236 { "ad5706r" }, 237 { } 238 }; 239 MODULE_DEVICE_TABLE(spi, ad5706r_id); 240 241 static struct spi_driver ad5706r_driver = { 242 .driver = { 243 .name = "ad5706r", 244 .of_match_table = ad5706r_of_match, 245 }, 246 .probe = ad5706r_probe, 247 .id_table = ad5706r_id, 248 }; 249 module_spi_driver(ad5706r_driver); 250 251 MODULE_AUTHOR("Alexis Czezar Torreno <alexisczezar.torreno@analog.com>"); 252 MODULE_DESCRIPTION("AD5706R 16-bit Current Output DAC driver"); 253 MODULE_LICENSE("GPL"); 254