1dbdc025bSLars-Peter Clausen /* 2dbdc025bSLars-Peter Clausen * Analog devices AD5360, AD5361, AD5362, AD5363, AD5370, AD5371, AD5373 3dbdc025bSLars-Peter Clausen * multi-channel Digital to Analog Converters driver 4dbdc025bSLars-Peter Clausen * 5dbdc025bSLars-Peter Clausen * Copyright 2011 Analog Devices Inc. 6dbdc025bSLars-Peter Clausen * 7dbdc025bSLars-Peter Clausen * Licensed under the GPL-2. 8dbdc025bSLars-Peter Clausen */ 9dbdc025bSLars-Peter Clausen 10dbdc025bSLars-Peter Clausen #include <linux/device.h> 11dbdc025bSLars-Peter Clausen #include <linux/err.h> 12dbdc025bSLars-Peter Clausen #include <linux/module.h> 13dbdc025bSLars-Peter Clausen #include <linux/kernel.h> 14dbdc025bSLars-Peter Clausen #include <linux/spi/spi.h> 15dbdc025bSLars-Peter Clausen #include <linux/slab.h> 16dbdc025bSLars-Peter Clausen #include <linux/sysfs.h> 17dbdc025bSLars-Peter Clausen #include <linux/regulator/consumer.h> 18dbdc025bSLars-Peter Clausen 19dbdc025bSLars-Peter Clausen #include <linux/iio/iio.h> 20dbdc025bSLars-Peter Clausen #include <linux/iio/sysfs.h> 21dbdc025bSLars-Peter Clausen 22dbdc025bSLars-Peter Clausen #define AD5360_CMD(x) ((x) << 22) 23dbdc025bSLars-Peter Clausen #define AD5360_ADDR(x) ((x) << 16) 24dbdc025bSLars-Peter Clausen 25dbdc025bSLars-Peter Clausen #define AD5360_READBACK_TYPE(x) ((x) << 13) 26dbdc025bSLars-Peter Clausen #define AD5360_READBACK_ADDR(x) ((x) << 7) 27dbdc025bSLars-Peter Clausen 28dbdc025bSLars-Peter Clausen #define AD5360_CHAN_ADDR(chan) ((chan) + 0x8) 29dbdc025bSLars-Peter Clausen 30dbdc025bSLars-Peter Clausen #define AD5360_CMD_WRITE_DATA 0x3 31dbdc025bSLars-Peter Clausen #define AD5360_CMD_WRITE_OFFSET 0x2 32dbdc025bSLars-Peter Clausen #define AD5360_CMD_WRITE_GAIN 0x1 33dbdc025bSLars-Peter Clausen #define AD5360_CMD_SPECIAL_FUNCTION 0x0 34dbdc025bSLars-Peter Clausen 35dbdc025bSLars-Peter Clausen /* Special function register addresses */ 36dbdc025bSLars-Peter Clausen #define AD5360_REG_SF_NOP 0x0 37dbdc025bSLars-Peter Clausen #define AD5360_REG_SF_CTRL 0x1 38dbdc025bSLars-Peter Clausen #define AD5360_REG_SF_OFS(x) (0x2 + (x)) 39dbdc025bSLars-Peter Clausen #define AD5360_REG_SF_READBACK 0x5 40dbdc025bSLars-Peter Clausen 41dbdc025bSLars-Peter Clausen #define AD5360_SF_CTRL_PWR_DOWN BIT(0) 42dbdc025bSLars-Peter Clausen 43dbdc025bSLars-Peter Clausen #define AD5360_READBACK_X1A 0x0 44dbdc025bSLars-Peter Clausen #define AD5360_READBACK_X1B 0x1 45dbdc025bSLars-Peter Clausen #define AD5360_READBACK_OFFSET 0x2 46dbdc025bSLars-Peter Clausen #define AD5360_READBACK_GAIN 0x3 47dbdc025bSLars-Peter Clausen #define AD5360_READBACK_SF 0x4 48dbdc025bSLars-Peter Clausen 49dbdc025bSLars-Peter Clausen 50dbdc025bSLars-Peter Clausen /** 51dbdc025bSLars-Peter Clausen * struct ad5360_chip_info - chip specific information 52dbdc025bSLars-Peter Clausen * @channel_template: channel specification template 53dbdc025bSLars-Peter Clausen * @num_channels: number of channels 54dbdc025bSLars-Peter Clausen * @channels_per_group: number of channels per group 55dbdc025bSLars-Peter Clausen * @num_vrefs: number of vref supplies for the chip 56dbdc025bSLars-Peter Clausen */ 57dbdc025bSLars-Peter Clausen 58dbdc025bSLars-Peter Clausen struct ad5360_chip_info { 59dbdc025bSLars-Peter Clausen struct iio_chan_spec channel_template; 60dbdc025bSLars-Peter Clausen unsigned int num_channels; 61dbdc025bSLars-Peter Clausen unsigned int channels_per_group; 62dbdc025bSLars-Peter Clausen unsigned int num_vrefs; 63dbdc025bSLars-Peter Clausen }; 64dbdc025bSLars-Peter Clausen 65dbdc025bSLars-Peter Clausen /** 66dbdc025bSLars-Peter Clausen * struct ad5360_state - driver instance specific data 67dbdc025bSLars-Peter Clausen * @spi: spi_device 68dbdc025bSLars-Peter Clausen * @chip_info: chip model specific constants, available modes etc 69dbdc025bSLars-Peter Clausen * @vref_reg: vref supply regulators 70dbdc025bSLars-Peter Clausen * @ctrl: control register cache 71dbdc025bSLars-Peter Clausen * @data: spi transfer buffers 72dbdc025bSLars-Peter Clausen */ 73dbdc025bSLars-Peter Clausen 74dbdc025bSLars-Peter Clausen struct ad5360_state { 75dbdc025bSLars-Peter Clausen struct spi_device *spi; 76dbdc025bSLars-Peter Clausen const struct ad5360_chip_info *chip_info; 77dbdc025bSLars-Peter Clausen struct regulator_bulk_data vref_reg[3]; 78dbdc025bSLars-Peter Clausen unsigned int ctrl; 79dbdc025bSLars-Peter Clausen 80dbdc025bSLars-Peter Clausen /* 81dbdc025bSLars-Peter Clausen * DMA (thus cache coherency maintenance) requires the 82dbdc025bSLars-Peter Clausen * transfer buffers to live in their own cache lines. 83dbdc025bSLars-Peter Clausen */ 84dbdc025bSLars-Peter Clausen union { 85dbdc025bSLars-Peter Clausen __be32 d32; 86dbdc025bSLars-Peter Clausen u8 d8[4]; 87dbdc025bSLars-Peter Clausen } data[2] ____cacheline_aligned; 88dbdc025bSLars-Peter Clausen }; 89dbdc025bSLars-Peter Clausen 90dbdc025bSLars-Peter Clausen enum ad5360_type { 91dbdc025bSLars-Peter Clausen ID_AD5360, 92dbdc025bSLars-Peter Clausen ID_AD5361, 93dbdc025bSLars-Peter Clausen ID_AD5362, 94dbdc025bSLars-Peter Clausen ID_AD5363, 95dbdc025bSLars-Peter Clausen ID_AD5370, 96dbdc025bSLars-Peter Clausen ID_AD5371, 97dbdc025bSLars-Peter Clausen ID_AD5372, 98dbdc025bSLars-Peter Clausen ID_AD5373, 99dbdc025bSLars-Peter Clausen }; 100dbdc025bSLars-Peter Clausen 101dbdc025bSLars-Peter Clausen #define AD5360_CHANNEL(bits) { \ 102dbdc025bSLars-Peter Clausen .type = IIO_VOLTAGE, \ 103dbdc025bSLars-Peter Clausen .indexed = 1, \ 104dbdc025bSLars-Peter Clausen .output = 1, \ 105dbdc025bSLars-Peter Clausen .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ 106dbdc025bSLars-Peter Clausen IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ 107dbdc025bSLars-Peter Clausen IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ 108dbdc025bSLars-Peter Clausen IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ 109dbdc025bSLars-Peter Clausen IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ 110dbdc025bSLars-Peter Clausen .scan_type = IIO_ST('u', (bits), 16, 16 - (bits)) \ 111dbdc025bSLars-Peter Clausen } 112dbdc025bSLars-Peter Clausen 113dbdc025bSLars-Peter Clausen static const struct ad5360_chip_info ad5360_chip_info_tbl[] = { 114dbdc025bSLars-Peter Clausen [ID_AD5360] = { 115dbdc025bSLars-Peter Clausen .channel_template = AD5360_CHANNEL(16), 116dbdc025bSLars-Peter Clausen .num_channels = 16, 117dbdc025bSLars-Peter Clausen .channels_per_group = 8, 118dbdc025bSLars-Peter Clausen .num_vrefs = 2, 119dbdc025bSLars-Peter Clausen }, 120dbdc025bSLars-Peter Clausen [ID_AD5361] = { 121dbdc025bSLars-Peter Clausen .channel_template = AD5360_CHANNEL(14), 122dbdc025bSLars-Peter Clausen .num_channels = 16, 123dbdc025bSLars-Peter Clausen .channels_per_group = 8, 124dbdc025bSLars-Peter Clausen .num_vrefs = 2, 125dbdc025bSLars-Peter Clausen }, 126dbdc025bSLars-Peter Clausen [ID_AD5362] = { 127dbdc025bSLars-Peter Clausen .channel_template = AD5360_CHANNEL(16), 128dbdc025bSLars-Peter Clausen .num_channels = 8, 129dbdc025bSLars-Peter Clausen .channels_per_group = 4, 130dbdc025bSLars-Peter Clausen .num_vrefs = 2, 131dbdc025bSLars-Peter Clausen }, 132dbdc025bSLars-Peter Clausen [ID_AD5363] = { 133dbdc025bSLars-Peter Clausen .channel_template = AD5360_CHANNEL(14), 134dbdc025bSLars-Peter Clausen .num_channels = 8, 135dbdc025bSLars-Peter Clausen .channels_per_group = 4, 136dbdc025bSLars-Peter Clausen .num_vrefs = 2, 137dbdc025bSLars-Peter Clausen }, 138dbdc025bSLars-Peter Clausen [ID_AD5370] = { 139dbdc025bSLars-Peter Clausen .channel_template = AD5360_CHANNEL(16), 140dbdc025bSLars-Peter Clausen .num_channels = 40, 141dbdc025bSLars-Peter Clausen .channels_per_group = 8, 142dbdc025bSLars-Peter Clausen .num_vrefs = 2, 143dbdc025bSLars-Peter Clausen }, 144dbdc025bSLars-Peter Clausen [ID_AD5371] = { 145dbdc025bSLars-Peter Clausen .channel_template = AD5360_CHANNEL(14), 146dbdc025bSLars-Peter Clausen .num_channels = 40, 147dbdc025bSLars-Peter Clausen .channels_per_group = 8, 148dbdc025bSLars-Peter Clausen .num_vrefs = 3, 149dbdc025bSLars-Peter Clausen }, 150dbdc025bSLars-Peter Clausen [ID_AD5372] = { 151dbdc025bSLars-Peter Clausen .channel_template = AD5360_CHANNEL(16), 152dbdc025bSLars-Peter Clausen .num_channels = 32, 153dbdc025bSLars-Peter Clausen .channels_per_group = 8, 154dbdc025bSLars-Peter Clausen .num_vrefs = 2, 155dbdc025bSLars-Peter Clausen }, 156dbdc025bSLars-Peter Clausen [ID_AD5373] = { 157dbdc025bSLars-Peter Clausen .channel_template = AD5360_CHANNEL(14), 158dbdc025bSLars-Peter Clausen .num_channels = 32, 159dbdc025bSLars-Peter Clausen .channels_per_group = 8, 160dbdc025bSLars-Peter Clausen .num_vrefs = 2, 161dbdc025bSLars-Peter Clausen }, 162dbdc025bSLars-Peter Clausen }; 163dbdc025bSLars-Peter Clausen 164dbdc025bSLars-Peter Clausen static unsigned int ad5360_get_channel_vref_index(struct ad5360_state *st, 165dbdc025bSLars-Peter Clausen unsigned int channel) 166dbdc025bSLars-Peter Clausen { 167dbdc025bSLars-Peter Clausen unsigned int i; 168dbdc025bSLars-Peter Clausen 169dbdc025bSLars-Peter Clausen /* The first groups have their own vref, while the remaining groups 170dbdc025bSLars-Peter Clausen * share the last vref */ 171dbdc025bSLars-Peter Clausen i = channel / st->chip_info->channels_per_group; 172dbdc025bSLars-Peter Clausen if (i >= st->chip_info->num_vrefs) 173dbdc025bSLars-Peter Clausen i = st->chip_info->num_vrefs - 1; 174dbdc025bSLars-Peter Clausen 175dbdc025bSLars-Peter Clausen return i; 176dbdc025bSLars-Peter Clausen } 177dbdc025bSLars-Peter Clausen 178dbdc025bSLars-Peter Clausen static int ad5360_get_channel_vref(struct ad5360_state *st, 179dbdc025bSLars-Peter Clausen unsigned int channel) 180dbdc025bSLars-Peter Clausen { 181dbdc025bSLars-Peter Clausen unsigned int i = ad5360_get_channel_vref_index(st, channel); 182dbdc025bSLars-Peter Clausen 183dbdc025bSLars-Peter Clausen return regulator_get_voltage(st->vref_reg[i].consumer); 184dbdc025bSLars-Peter Clausen } 185dbdc025bSLars-Peter Clausen 186dbdc025bSLars-Peter Clausen 187dbdc025bSLars-Peter Clausen static int ad5360_write_unlocked(struct iio_dev *indio_dev, 188dbdc025bSLars-Peter Clausen unsigned int cmd, unsigned int addr, unsigned int val, 189dbdc025bSLars-Peter Clausen unsigned int shift) 190dbdc025bSLars-Peter Clausen { 191dbdc025bSLars-Peter Clausen struct ad5360_state *st = iio_priv(indio_dev); 192dbdc025bSLars-Peter Clausen 193dbdc025bSLars-Peter Clausen val <<= shift; 194dbdc025bSLars-Peter Clausen val |= AD5360_CMD(cmd) | AD5360_ADDR(addr); 195dbdc025bSLars-Peter Clausen st->data[0].d32 = cpu_to_be32(val); 196dbdc025bSLars-Peter Clausen 197dbdc025bSLars-Peter Clausen return spi_write(st->spi, &st->data[0].d8[1], 3); 198dbdc025bSLars-Peter Clausen } 199dbdc025bSLars-Peter Clausen 200dbdc025bSLars-Peter Clausen static int ad5360_write(struct iio_dev *indio_dev, unsigned int cmd, 201dbdc025bSLars-Peter Clausen unsigned int addr, unsigned int val, unsigned int shift) 202dbdc025bSLars-Peter Clausen { 203dbdc025bSLars-Peter Clausen int ret; 204dbdc025bSLars-Peter Clausen 205dbdc025bSLars-Peter Clausen mutex_lock(&indio_dev->mlock); 206dbdc025bSLars-Peter Clausen ret = ad5360_write_unlocked(indio_dev, cmd, addr, val, shift); 207dbdc025bSLars-Peter Clausen mutex_unlock(&indio_dev->mlock); 208dbdc025bSLars-Peter Clausen 209dbdc025bSLars-Peter Clausen return ret; 210dbdc025bSLars-Peter Clausen } 211dbdc025bSLars-Peter Clausen 212dbdc025bSLars-Peter Clausen static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, 213dbdc025bSLars-Peter Clausen unsigned int addr) 214dbdc025bSLars-Peter Clausen { 215dbdc025bSLars-Peter Clausen struct ad5360_state *st = iio_priv(indio_dev); 216dbdc025bSLars-Peter Clausen int ret; 217dbdc025bSLars-Peter Clausen struct spi_transfer t[] = { 218dbdc025bSLars-Peter Clausen { 219dbdc025bSLars-Peter Clausen .tx_buf = &st->data[0].d8[1], 220dbdc025bSLars-Peter Clausen .len = 3, 221dbdc025bSLars-Peter Clausen .cs_change = 1, 222dbdc025bSLars-Peter Clausen }, { 223dbdc025bSLars-Peter Clausen .rx_buf = &st->data[1].d8[1], 224dbdc025bSLars-Peter Clausen .len = 3, 225dbdc025bSLars-Peter Clausen }, 226dbdc025bSLars-Peter Clausen }; 227dbdc025bSLars-Peter Clausen 228dbdc025bSLars-Peter Clausen mutex_lock(&indio_dev->mlock); 229dbdc025bSLars-Peter Clausen 230dbdc025bSLars-Peter Clausen st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) | 231dbdc025bSLars-Peter Clausen AD5360_ADDR(AD5360_REG_SF_READBACK) | 232dbdc025bSLars-Peter Clausen AD5360_READBACK_TYPE(type) | 233dbdc025bSLars-Peter Clausen AD5360_READBACK_ADDR(addr)); 234dbdc025bSLars-Peter Clausen 235*14543a00SLars-Peter Clausen ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); 236dbdc025bSLars-Peter Clausen if (ret >= 0) 237dbdc025bSLars-Peter Clausen ret = be32_to_cpu(st->data[1].d32) & 0xffff; 238dbdc025bSLars-Peter Clausen 239dbdc025bSLars-Peter Clausen mutex_unlock(&indio_dev->mlock); 240dbdc025bSLars-Peter Clausen 241dbdc025bSLars-Peter Clausen return ret; 242dbdc025bSLars-Peter Clausen } 243dbdc025bSLars-Peter Clausen 244dbdc025bSLars-Peter Clausen static ssize_t ad5360_read_dac_powerdown(struct device *dev, 245dbdc025bSLars-Peter Clausen struct device_attribute *attr, 246dbdc025bSLars-Peter Clausen char *buf) 247dbdc025bSLars-Peter Clausen { 248dbdc025bSLars-Peter Clausen struct iio_dev *indio_dev = dev_to_iio_dev(dev); 249dbdc025bSLars-Peter Clausen struct ad5360_state *st = iio_priv(indio_dev); 250dbdc025bSLars-Peter Clausen 251dbdc025bSLars-Peter Clausen return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN)); 252dbdc025bSLars-Peter Clausen } 253dbdc025bSLars-Peter Clausen 254dbdc025bSLars-Peter Clausen static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set, 255dbdc025bSLars-Peter Clausen unsigned int clr) 256dbdc025bSLars-Peter Clausen { 257dbdc025bSLars-Peter Clausen struct ad5360_state *st = iio_priv(indio_dev); 258dbdc025bSLars-Peter Clausen unsigned int ret; 259dbdc025bSLars-Peter Clausen 260dbdc025bSLars-Peter Clausen mutex_lock(&indio_dev->mlock); 261dbdc025bSLars-Peter Clausen 262dbdc025bSLars-Peter Clausen st->ctrl |= set; 263dbdc025bSLars-Peter Clausen st->ctrl &= ~clr; 264dbdc025bSLars-Peter Clausen 265dbdc025bSLars-Peter Clausen ret = ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION, 266dbdc025bSLars-Peter Clausen AD5360_REG_SF_CTRL, st->ctrl, 0); 267dbdc025bSLars-Peter Clausen 268dbdc025bSLars-Peter Clausen mutex_unlock(&indio_dev->mlock); 269dbdc025bSLars-Peter Clausen 270dbdc025bSLars-Peter Clausen return ret; 271dbdc025bSLars-Peter Clausen } 272dbdc025bSLars-Peter Clausen 273dbdc025bSLars-Peter Clausen static ssize_t ad5360_write_dac_powerdown(struct device *dev, 274dbdc025bSLars-Peter Clausen struct device_attribute *attr, const char *buf, size_t len) 275dbdc025bSLars-Peter Clausen { 276dbdc025bSLars-Peter Clausen struct iio_dev *indio_dev = dev_to_iio_dev(dev); 277dbdc025bSLars-Peter Clausen bool pwr_down; 278dbdc025bSLars-Peter Clausen int ret; 279dbdc025bSLars-Peter Clausen 280dbdc025bSLars-Peter Clausen ret = strtobool(buf, &pwr_down); 281dbdc025bSLars-Peter Clausen if (ret) 282dbdc025bSLars-Peter Clausen return ret; 283dbdc025bSLars-Peter Clausen 284dbdc025bSLars-Peter Clausen if (pwr_down) 285dbdc025bSLars-Peter Clausen ret = ad5360_update_ctrl(indio_dev, AD5360_SF_CTRL_PWR_DOWN, 0); 286dbdc025bSLars-Peter Clausen else 287dbdc025bSLars-Peter Clausen ret = ad5360_update_ctrl(indio_dev, 0, AD5360_SF_CTRL_PWR_DOWN); 288dbdc025bSLars-Peter Clausen 289dbdc025bSLars-Peter Clausen return ret ? ret : len; 290dbdc025bSLars-Peter Clausen } 291dbdc025bSLars-Peter Clausen 292dbdc025bSLars-Peter Clausen static IIO_DEVICE_ATTR(out_voltage_powerdown, 293dbdc025bSLars-Peter Clausen S_IRUGO | S_IWUSR, 294dbdc025bSLars-Peter Clausen ad5360_read_dac_powerdown, 295dbdc025bSLars-Peter Clausen ad5360_write_dac_powerdown, 0); 296dbdc025bSLars-Peter Clausen 297dbdc025bSLars-Peter Clausen static struct attribute *ad5360_attributes[] = { 298dbdc025bSLars-Peter Clausen &iio_dev_attr_out_voltage_powerdown.dev_attr.attr, 299dbdc025bSLars-Peter Clausen NULL, 300dbdc025bSLars-Peter Clausen }; 301dbdc025bSLars-Peter Clausen 302dbdc025bSLars-Peter Clausen static const struct attribute_group ad5360_attribute_group = { 303dbdc025bSLars-Peter Clausen .attrs = ad5360_attributes, 304dbdc025bSLars-Peter Clausen }; 305dbdc025bSLars-Peter Clausen 306dbdc025bSLars-Peter Clausen static int ad5360_write_raw(struct iio_dev *indio_dev, 307dbdc025bSLars-Peter Clausen struct iio_chan_spec const *chan, 308dbdc025bSLars-Peter Clausen int val, 309dbdc025bSLars-Peter Clausen int val2, 310dbdc025bSLars-Peter Clausen long mask) 311dbdc025bSLars-Peter Clausen { 312dbdc025bSLars-Peter Clausen struct ad5360_state *st = iio_priv(indio_dev); 313dbdc025bSLars-Peter Clausen int max_val = (1 << chan->scan_type.realbits); 314dbdc025bSLars-Peter Clausen unsigned int ofs_index; 315dbdc025bSLars-Peter Clausen 316dbdc025bSLars-Peter Clausen switch (mask) { 317dbdc025bSLars-Peter Clausen case IIO_CHAN_INFO_RAW: 318dbdc025bSLars-Peter Clausen if (val >= max_val || val < 0) 319dbdc025bSLars-Peter Clausen return -EINVAL; 320dbdc025bSLars-Peter Clausen 321dbdc025bSLars-Peter Clausen return ad5360_write(indio_dev, AD5360_CMD_WRITE_DATA, 322dbdc025bSLars-Peter Clausen chan->address, val, chan->scan_type.shift); 323dbdc025bSLars-Peter Clausen 324dbdc025bSLars-Peter Clausen case IIO_CHAN_INFO_CALIBBIAS: 325dbdc025bSLars-Peter Clausen if (val >= max_val || val < 0) 326dbdc025bSLars-Peter Clausen return -EINVAL; 327dbdc025bSLars-Peter Clausen 328dbdc025bSLars-Peter Clausen return ad5360_write(indio_dev, AD5360_CMD_WRITE_OFFSET, 329dbdc025bSLars-Peter Clausen chan->address, val, chan->scan_type.shift); 330dbdc025bSLars-Peter Clausen 331dbdc025bSLars-Peter Clausen case IIO_CHAN_INFO_CALIBSCALE: 332dbdc025bSLars-Peter Clausen if (val >= max_val || val < 0) 333dbdc025bSLars-Peter Clausen return -EINVAL; 334dbdc025bSLars-Peter Clausen 335dbdc025bSLars-Peter Clausen return ad5360_write(indio_dev, AD5360_CMD_WRITE_GAIN, 336dbdc025bSLars-Peter Clausen chan->address, val, chan->scan_type.shift); 337dbdc025bSLars-Peter Clausen 338dbdc025bSLars-Peter Clausen case IIO_CHAN_INFO_OFFSET: 339dbdc025bSLars-Peter Clausen if (val <= -max_val || val > 0) 340dbdc025bSLars-Peter Clausen return -EINVAL; 341dbdc025bSLars-Peter Clausen 342dbdc025bSLars-Peter Clausen val = -val; 343dbdc025bSLars-Peter Clausen 344dbdc025bSLars-Peter Clausen /* offset is supposed to have the same scale as raw, but it 345dbdc025bSLars-Peter Clausen * is always 14bits wide, so on a chip where the raw value has 346dbdc025bSLars-Peter Clausen * more bits, we need to shift offset. */ 347dbdc025bSLars-Peter Clausen val >>= (chan->scan_type.realbits - 14); 348dbdc025bSLars-Peter Clausen 349dbdc025bSLars-Peter Clausen /* There is one DAC offset register per vref. Changing one 350dbdc025bSLars-Peter Clausen * channels offset will also change the offset for all other 351dbdc025bSLars-Peter Clausen * channels which share the same vref supply. */ 352dbdc025bSLars-Peter Clausen ofs_index = ad5360_get_channel_vref_index(st, chan->channel); 353dbdc025bSLars-Peter Clausen return ad5360_write(indio_dev, AD5360_CMD_SPECIAL_FUNCTION, 354dbdc025bSLars-Peter Clausen AD5360_REG_SF_OFS(ofs_index), val, 0); 355dbdc025bSLars-Peter Clausen default: 356dbdc025bSLars-Peter Clausen break; 357dbdc025bSLars-Peter Clausen } 358dbdc025bSLars-Peter Clausen 359dbdc025bSLars-Peter Clausen return -EINVAL; 360dbdc025bSLars-Peter Clausen } 361dbdc025bSLars-Peter Clausen 362dbdc025bSLars-Peter Clausen static int ad5360_read_raw(struct iio_dev *indio_dev, 363dbdc025bSLars-Peter Clausen struct iio_chan_spec const *chan, 364dbdc025bSLars-Peter Clausen int *val, 365dbdc025bSLars-Peter Clausen int *val2, 366dbdc025bSLars-Peter Clausen long m) 367dbdc025bSLars-Peter Clausen { 368dbdc025bSLars-Peter Clausen struct ad5360_state *st = iio_priv(indio_dev); 369dbdc025bSLars-Peter Clausen unsigned int ofs_index; 370dbdc025bSLars-Peter Clausen int scale_uv; 371dbdc025bSLars-Peter Clausen int ret; 372dbdc025bSLars-Peter Clausen 373dbdc025bSLars-Peter Clausen switch (m) { 374dbdc025bSLars-Peter Clausen case IIO_CHAN_INFO_RAW: 375dbdc025bSLars-Peter Clausen ret = ad5360_read(indio_dev, AD5360_READBACK_X1A, 376dbdc025bSLars-Peter Clausen chan->address); 377dbdc025bSLars-Peter Clausen if (ret < 0) 378dbdc025bSLars-Peter Clausen return ret; 379dbdc025bSLars-Peter Clausen *val = ret >> chan->scan_type.shift; 380dbdc025bSLars-Peter Clausen return IIO_VAL_INT; 381dbdc025bSLars-Peter Clausen case IIO_CHAN_INFO_SCALE: 382dbdc025bSLars-Peter Clausen /* vout = 4 * vref * dac_code */ 383dbdc025bSLars-Peter Clausen scale_uv = ad5360_get_channel_vref(st, chan->channel) * 4 * 100; 384dbdc025bSLars-Peter Clausen if (scale_uv < 0) 385dbdc025bSLars-Peter Clausen return scale_uv; 386dbdc025bSLars-Peter Clausen 387dbdc025bSLars-Peter Clausen scale_uv >>= (chan->scan_type.realbits); 388dbdc025bSLars-Peter Clausen *val = scale_uv / 100000; 389dbdc025bSLars-Peter Clausen *val2 = (scale_uv % 100000) * 10; 390dbdc025bSLars-Peter Clausen return IIO_VAL_INT_PLUS_MICRO; 391dbdc025bSLars-Peter Clausen case IIO_CHAN_INFO_CALIBBIAS: 392dbdc025bSLars-Peter Clausen ret = ad5360_read(indio_dev, AD5360_READBACK_OFFSET, 393dbdc025bSLars-Peter Clausen chan->address); 394dbdc025bSLars-Peter Clausen if (ret < 0) 395dbdc025bSLars-Peter Clausen return ret; 396dbdc025bSLars-Peter Clausen *val = ret; 397dbdc025bSLars-Peter Clausen return IIO_VAL_INT; 398dbdc025bSLars-Peter Clausen case IIO_CHAN_INFO_CALIBSCALE: 399dbdc025bSLars-Peter Clausen ret = ad5360_read(indio_dev, AD5360_READBACK_GAIN, 400dbdc025bSLars-Peter Clausen chan->address); 401dbdc025bSLars-Peter Clausen if (ret < 0) 402dbdc025bSLars-Peter Clausen return ret; 403dbdc025bSLars-Peter Clausen *val = ret; 404dbdc025bSLars-Peter Clausen return IIO_VAL_INT; 405dbdc025bSLars-Peter Clausen case IIO_CHAN_INFO_OFFSET: 406dbdc025bSLars-Peter Clausen ofs_index = ad5360_get_channel_vref_index(st, chan->channel); 407dbdc025bSLars-Peter Clausen ret = ad5360_read(indio_dev, AD5360_READBACK_SF, 408dbdc025bSLars-Peter Clausen AD5360_REG_SF_OFS(ofs_index)); 409dbdc025bSLars-Peter Clausen if (ret < 0) 410dbdc025bSLars-Peter Clausen return ret; 411dbdc025bSLars-Peter Clausen 412dbdc025bSLars-Peter Clausen ret <<= (chan->scan_type.realbits - 14); 413dbdc025bSLars-Peter Clausen *val = -ret; 414dbdc025bSLars-Peter Clausen return IIO_VAL_INT; 415dbdc025bSLars-Peter Clausen } 416dbdc025bSLars-Peter Clausen 417dbdc025bSLars-Peter Clausen return -EINVAL; 418dbdc025bSLars-Peter Clausen } 419dbdc025bSLars-Peter Clausen 420dbdc025bSLars-Peter Clausen static const struct iio_info ad5360_info = { 421dbdc025bSLars-Peter Clausen .read_raw = ad5360_read_raw, 422dbdc025bSLars-Peter Clausen .write_raw = ad5360_write_raw, 423dbdc025bSLars-Peter Clausen .attrs = &ad5360_attribute_group, 424dbdc025bSLars-Peter Clausen .driver_module = THIS_MODULE, 425dbdc025bSLars-Peter Clausen }; 426dbdc025bSLars-Peter Clausen 427dbdc025bSLars-Peter Clausen static const char * const ad5360_vref_name[] = { 428dbdc025bSLars-Peter Clausen "vref0", "vref1", "vref2" 429dbdc025bSLars-Peter Clausen }; 430dbdc025bSLars-Peter Clausen 431fc52692cSGreg Kroah-Hartman static int ad5360_alloc_channels(struct iio_dev *indio_dev) 432dbdc025bSLars-Peter Clausen { 433dbdc025bSLars-Peter Clausen struct ad5360_state *st = iio_priv(indio_dev); 434dbdc025bSLars-Peter Clausen struct iio_chan_spec *channels; 435dbdc025bSLars-Peter Clausen unsigned int i; 436dbdc025bSLars-Peter Clausen 437dbdc025bSLars-Peter Clausen channels = kcalloc(st->chip_info->num_channels, 438dbdc025bSLars-Peter Clausen sizeof(struct iio_chan_spec), GFP_KERNEL); 439dbdc025bSLars-Peter Clausen 440dbdc025bSLars-Peter Clausen if (!channels) 441dbdc025bSLars-Peter Clausen return -ENOMEM; 442dbdc025bSLars-Peter Clausen 443dbdc025bSLars-Peter Clausen for (i = 0; i < st->chip_info->num_channels; ++i) { 444dbdc025bSLars-Peter Clausen channels[i] = st->chip_info->channel_template; 445dbdc025bSLars-Peter Clausen channels[i].channel = i; 446dbdc025bSLars-Peter Clausen channels[i].address = AD5360_CHAN_ADDR(i); 447dbdc025bSLars-Peter Clausen } 448dbdc025bSLars-Peter Clausen 449dbdc025bSLars-Peter Clausen indio_dev->channels = channels; 450dbdc025bSLars-Peter Clausen 451dbdc025bSLars-Peter Clausen return 0; 452dbdc025bSLars-Peter Clausen } 453dbdc025bSLars-Peter Clausen 454fc52692cSGreg Kroah-Hartman static int ad5360_probe(struct spi_device *spi) 455dbdc025bSLars-Peter Clausen { 456dbdc025bSLars-Peter Clausen enum ad5360_type type = spi_get_device_id(spi)->driver_data; 457dbdc025bSLars-Peter Clausen struct iio_dev *indio_dev; 458dbdc025bSLars-Peter Clausen struct ad5360_state *st; 459dbdc025bSLars-Peter Clausen unsigned int i; 460dbdc025bSLars-Peter Clausen int ret; 461dbdc025bSLars-Peter Clausen 462dbdc025bSLars-Peter Clausen indio_dev = iio_device_alloc(sizeof(*st)); 463dbdc025bSLars-Peter Clausen if (indio_dev == NULL) { 464dbdc025bSLars-Peter Clausen dev_err(&spi->dev, "Failed to allocate iio device\n"); 465dbdc025bSLars-Peter Clausen return -ENOMEM; 466dbdc025bSLars-Peter Clausen } 467dbdc025bSLars-Peter Clausen 468dbdc025bSLars-Peter Clausen st = iio_priv(indio_dev); 469dbdc025bSLars-Peter Clausen spi_set_drvdata(spi, indio_dev); 470dbdc025bSLars-Peter Clausen 471dbdc025bSLars-Peter Clausen st->chip_info = &ad5360_chip_info_tbl[type]; 472dbdc025bSLars-Peter Clausen st->spi = spi; 473dbdc025bSLars-Peter Clausen 474dbdc025bSLars-Peter Clausen indio_dev->dev.parent = &spi->dev; 475dbdc025bSLars-Peter Clausen indio_dev->name = spi_get_device_id(spi)->name; 476dbdc025bSLars-Peter Clausen indio_dev->info = &ad5360_info; 477dbdc025bSLars-Peter Clausen indio_dev->modes = INDIO_DIRECT_MODE; 478dbdc025bSLars-Peter Clausen indio_dev->num_channels = st->chip_info->num_channels; 479dbdc025bSLars-Peter Clausen 480dbdc025bSLars-Peter Clausen ret = ad5360_alloc_channels(indio_dev); 481dbdc025bSLars-Peter Clausen if (ret) { 482dbdc025bSLars-Peter Clausen dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret); 483dbdc025bSLars-Peter Clausen goto error_free; 484dbdc025bSLars-Peter Clausen } 485dbdc025bSLars-Peter Clausen 486dbdc025bSLars-Peter Clausen for (i = 0; i < st->chip_info->num_vrefs; ++i) 487dbdc025bSLars-Peter Clausen st->vref_reg[i].supply = ad5360_vref_name[i]; 488dbdc025bSLars-Peter Clausen 489dbdc025bSLars-Peter Clausen ret = regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs, 490dbdc025bSLars-Peter Clausen st->vref_reg); 491dbdc025bSLars-Peter Clausen if (ret) { 492dbdc025bSLars-Peter Clausen dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret); 493dbdc025bSLars-Peter Clausen goto error_free_channels; 494dbdc025bSLars-Peter Clausen } 495dbdc025bSLars-Peter Clausen 496dbdc025bSLars-Peter Clausen ret = regulator_bulk_enable(st->chip_info->num_vrefs, st->vref_reg); 497dbdc025bSLars-Peter Clausen if (ret) { 498dbdc025bSLars-Peter Clausen dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret); 499dbdc025bSLars-Peter Clausen goto error_free_reg; 500dbdc025bSLars-Peter Clausen } 501dbdc025bSLars-Peter Clausen 502dbdc025bSLars-Peter Clausen ret = iio_device_register(indio_dev); 503dbdc025bSLars-Peter Clausen if (ret) { 504dbdc025bSLars-Peter Clausen dev_err(&spi->dev, "Failed to register iio device: %d\n", ret); 505dbdc025bSLars-Peter Clausen goto error_disable_reg; 506dbdc025bSLars-Peter Clausen } 507dbdc025bSLars-Peter Clausen 508dbdc025bSLars-Peter Clausen return 0; 509dbdc025bSLars-Peter Clausen 510dbdc025bSLars-Peter Clausen error_disable_reg: 511dbdc025bSLars-Peter Clausen regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg); 512dbdc025bSLars-Peter Clausen error_free_reg: 513dbdc025bSLars-Peter Clausen regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg); 514dbdc025bSLars-Peter Clausen error_free_channels: 515dbdc025bSLars-Peter Clausen kfree(indio_dev->channels); 516dbdc025bSLars-Peter Clausen error_free: 517dbdc025bSLars-Peter Clausen iio_device_free(indio_dev); 518dbdc025bSLars-Peter Clausen 519dbdc025bSLars-Peter Clausen return ret; 520dbdc025bSLars-Peter Clausen } 521dbdc025bSLars-Peter Clausen 522fc52692cSGreg Kroah-Hartman static int ad5360_remove(struct spi_device *spi) 523dbdc025bSLars-Peter Clausen { 524dbdc025bSLars-Peter Clausen struct iio_dev *indio_dev = spi_get_drvdata(spi); 525dbdc025bSLars-Peter Clausen struct ad5360_state *st = iio_priv(indio_dev); 526dbdc025bSLars-Peter Clausen 527dbdc025bSLars-Peter Clausen iio_device_unregister(indio_dev); 528dbdc025bSLars-Peter Clausen 529dbdc025bSLars-Peter Clausen kfree(indio_dev->channels); 530dbdc025bSLars-Peter Clausen 531dbdc025bSLars-Peter Clausen regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg); 532dbdc025bSLars-Peter Clausen regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg); 533dbdc025bSLars-Peter Clausen 534dbdc025bSLars-Peter Clausen iio_device_free(indio_dev); 535dbdc025bSLars-Peter Clausen 536dbdc025bSLars-Peter Clausen return 0; 537dbdc025bSLars-Peter Clausen } 538dbdc025bSLars-Peter Clausen 539dbdc025bSLars-Peter Clausen static const struct spi_device_id ad5360_ids[] = { 540dbdc025bSLars-Peter Clausen { "ad5360", ID_AD5360 }, 541dbdc025bSLars-Peter Clausen { "ad5361", ID_AD5361 }, 542dbdc025bSLars-Peter Clausen { "ad5362", ID_AD5362 }, 543dbdc025bSLars-Peter Clausen { "ad5363", ID_AD5363 }, 544dbdc025bSLars-Peter Clausen { "ad5370", ID_AD5370 }, 545dbdc025bSLars-Peter Clausen { "ad5371", ID_AD5371 }, 546dbdc025bSLars-Peter Clausen { "ad5372", ID_AD5372 }, 547dbdc025bSLars-Peter Clausen { "ad5373", ID_AD5373 }, 548dbdc025bSLars-Peter Clausen {} 549dbdc025bSLars-Peter Clausen }; 550dbdc025bSLars-Peter Clausen MODULE_DEVICE_TABLE(spi, ad5360_ids); 551dbdc025bSLars-Peter Clausen 552dbdc025bSLars-Peter Clausen static struct spi_driver ad5360_driver = { 553dbdc025bSLars-Peter Clausen .driver = { 554dbdc025bSLars-Peter Clausen .name = "ad5360", 555dbdc025bSLars-Peter Clausen .owner = THIS_MODULE, 556dbdc025bSLars-Peter Clausen }, 557dbdc025bSLars-Peter Clausen .probe = ad5360_probe, 558fc52692cSGreg Kroah-Hartman .remove = ad5360_remove, 559dbdc025bSLars-Peter Clausen .id_table = ad5360_ids, 560dbdc025bSLars-Peter Clausen }; 561dbdc025bSLars-Peter Clausen module_spi_driver(ad5360_driver); 562dbdc025bSLars-Peter Clausen 563dbdc025bSLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 564dbdc025bSLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices AD5360/61/62/63/70/71/72/73 DAC"); 565dbdc025bSLars-Peter Clausen MODULE_LICENSE("GPL v2"); 566