162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AD5686R, AD5685R, AD5684R Digital to analog converters driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011 Analog Devices Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/fs.h> 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/sysfs.h> 1562306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/iio/iio.h> 1862306a36Sopenharmony_ci#include <linux/iio/sysfs.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "ad5686.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic const char * const ad5686_powerdown_modes[] = { 2362306a36Sopenharmony_ci "1kohm_to_gnd", 2462306a36Sopenharmony_ci "100kohm_to_gnd", 2562306a36Sopenharmony_ci "three_state" 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int ad5686_get_powerdown_mode(struct iio_dev *indio_dev, 2962306a36Sopenharmony_ci const struct iio_chan_spec *chan) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct ad5686_state *st = iio_priv(indio_dev); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1; 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int ad5686_set_powerdown_mode(struct iio_dev *indio_dev, 3762306a36Sopenharmony_ci const struct iio_chan_spec *chan, 3862306a36Sopenharmony_ci unsigned int mode) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct ad5686_state *st = iio_priv(indio_dev); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci st->pwr_down_mode &= ~(0x3 << (chan->channel * 2)); 4362306a36Sopenharmony_ci st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2)); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci return 0; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic const struct iio_enum ad5686_powerdown_mode_enum = { 4962306a36Sopenharmony_ci .items = ad5686_powerdown_modes, 5062306a36Sopenharmony_ci .num_items = ARRAY_SIZE(ad5686_powerdown_modes), 5162306a36Sopenharmony_ci .get = ad5686_get_powerdown_mode, 5262306a36Sopenharmony_ci .set = ad5686_set_powerdown_mode, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev, 5662306a36Sopenharmony_ci uintptr_t private, const struct iio_chan_spec *chan, char *buf) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct ad5686_state *st = iio_priv(indio_dev); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask & 6162306a36Sopenharmony_ci (0x3 << (chan->channel * 2)))); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, 6562306a36Sopenharmony_ci uintptr_t private, 6662306a36Sopenharmony_ci const struct iio_chan_spec *chan, 6762306a36Sopenharmony_ci const char *buf, 6862306a36Sopenharmony_ci size_t len) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci bool readin; 7162306a36Sopenharmony_ci int ret; 7262306a36Sopenharmony_ci struct ad5686_state *st = iio_priv(indio_dev); 7362306a36Sopenharmony_ci unsigned int val, ref_bit_msk; 7462306a36Sopenharmony_ci u8 shift, address = 0; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci ret = kstrtobool(buf, &readin); 7762306a36Sopenharmony_ci if (ret) 7862306a36Sopenharmony_ci return ret; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (readin) 8162306a36Sopenharmony_ci st->pwr_down_mask |= (0x3 << (chan->channel * 2)); 8262306a36Sopenharmony_ci else 8362306a36Sopenharmony_ci st->pwr_down_mask &= ~(0x3 << (chan->channel * 2)); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci switch (st->chip_info->regmap_type) { 8662306a36Sopenharmony_ci case AD5310_REGMAP: 8762306a36Sopenharmony_ci shift = 9; 8862306a36Sopenharmony_ci ref_bit_msk = AD5310_REF_BIT_MSK; 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci case AD5683_REGMAP: 9162306a36Sopenharmony_ci shift = 13; 9262306a36Sopenharmony_ci ref_bit_msk = AD5683_REF_BIT_MSK; 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci case AD5686_REGMAP: 9562306a36Sopenharmony_ci shift = 0; 9662306a36Sopenharmony_ci ref_bit_msk = 0; 9762306a36Sopenharmony_ci /* AD5674R/AD5679R have 16 channels and 2 powerdown registers */ 9862306a36Sopenharmony_ci if (chan->channel > 0x7) 9962306a36Sopenharmony_ci address = 0x8; 10062306a36Sopenharmony_ci break; 10162306a36Sopenharmony_ci case AD5693_REGMAP: 10262306a36Sopenharmony_ci shift = 13; 10362306a36Sopenharmony_ci ref_bit_msk = AD5693_REF_BIT_MSK; 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci default: 10662306a36Sopenharmony_ci return -EINVAL; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci val = ((st->pwr_down_mask & st->pwr_down_mode) << shift); 11062306a36Sopenharmony_ci if (!st->use_internal_vref) 11162306a36Sopenharmony_ci val |= ref_bit_msk; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, 11462306a36Sopenharmony_ci address, val >> (address * 2)); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return ret ? ret : len; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int ad5686_read_raw(struct iio_dev *indio_dev, 12062306a36Sopenharmony_ci struct iio_chan_spec const *chan, 12162306a36Sopenharmony_ci int *val, 12262306a36Sopenharmony_ci int *val2, 12362306a36Sopenharmony_ci long m) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct ad5686_state *st = iio_priv(indio_dev); 12662306a36Sopenharmony_ci int ret; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci switch (m) { 12962306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 13062306a36Sopenharmony_ci mutex_lock(&st->lock); 13162306a36Sopenharmony_ci ret = st->read(st, chan->address); 13262306a36Sopenharmony_ci mutex_unlock(&st->lock); 13362306a36Sopenharmony_ci if (ret < 0) 13462306a36Sopenharmony_ci return ret; 13562306a36Sopenharmony_ci *val = (ret >> chan->scan_type.shift) & 13662306a36Sopenharmony_ci GENMASK(chan->scan_type.realbits - 1, 0); 13762306a36Sopenharmony_ci return IIO_VAL_INT; 13862306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 13962306a36Sopenharmony_ci *val = st->vref_mv; 14062306a36Sopenharmony_ci *val2 = chan->scan_type.realbits; 14162306a36Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci return -EINVAL; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int ad5686_write_raw(struct iio_dev *indio_dev, 14762306a36Sopenharmony_ci struct iio_chan_spec const *chan, 14862306a36Sopenharmony_ci int val, 14962306a36Sopenharmony_ci int val2, 15062306a36Sopenharmony_ci long mask) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct ad5686_state *st = iio_priv(indio_dev); 15362306a36Sopenharmony_ci int ret; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci switch (mask) { 15662306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 15762306a36Sopenharmony_ci if (val > (1 << chan->scan_type.realbits) || val < 0) 15862306a36Sopenharmony_ci return -EINVAL; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci mutex_lock(&st->lock); 16162306a36Sopenharmony_ci ret = st->write(st, 16262306a36Sopenharmony_ci AD5686_CMD_WRITE_INPUT_N_UPDATE_N, 16362306a36Sopenharmony_ci chan->address, 16462306a36Sopenharmony_ci val << chan->scan_type.shift); 16562306a36Sopenharmony_ci mutex_unlock(&st->lock); 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci default: 16862306a36Sopenharmony_ci ret = -EINVAL; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return ret; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic const struct iio_info ad5686_info = { 17562306a36Sopenharmony_ci .read_raw = ad5686_read_raw, 17662306a36Sopenharmony_ci .write_raw = ad5686_write_raw, 17762306a36Sopenharmony_ci}; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic const struct iio_chan_spec_ext_info ad5686_ext_info[] = { 18062306a36Sopenharmony_ci { 18162306a36Sopenharmony_ci .name = "powerdown", 18262306a36Sopenharmony_ci .read = ad5686_read_dac_powerdown, 18362306a36Sopenharmony_ci .write = ad5686_write_dac_powerdown, 18462306a36Sopenharmony_ci .shared = IIO_SEPARATE, 18562306a36Sopenharmony_ci }, 18662306a36Sopenharmony_ci IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5686_powerdown_mode_enum), 18762306a36Sopenharmony_ci IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5686_powerdown_mode_enum), 18862306a36Sopenharmony_ci { }, 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci#define AD5868_CHANNEL(chan, addr, bits, _shift) { \ 19262306a36Sopenharmony_ci .type = IIO_VOLTAGE, \ 19362306a36Sopenharmony_ci .indexed = 1, \ 19462306a36Sopenharmony_ci .output = 1, \ 19562306a36Sopenharmony_ci .channel = chan, \ 19662306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 19762306a36Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ 19862306a36Sopenharmony_ci .address = addr, \ 19962306a36Sopenharmony_ci .scan_type = { \ 20062306a36Sopenharmony_ci .sign = 'u', \ 20162306a36Sopenharmony_ci .realbits = (bits), \ 20262306a36Sopenharmony_ci .storagebits = 16, \ 20362306a36Sopenharmony_ci .shift = (_shift), \ 20462306a36Sopenharmony_ci }, \ 20562306a36Sopenharmony_ci .ext_info = ad5686_ext_info, \ 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#define DECLARE_AD5693_CHANNELS(name, bits, _shift) \ 20962306a36Sopenharmony_cistatic const struct iio_chan_spec name[] = { \ 21062306a36Sopenharmony_ci AD5868_CHANNEL(0, 0, bits, _shift), \ 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci#define DECLARE_AD5338_CHANNELS(name, bits, _shift) \ 21462306a36Sopenharmony_cistatic const struct iio_chan_spec name[] = { \ 21562306a36Sopenharmony_ci AD5868_CHANNEL(0, 1, bits, _shift), \ 21662306a36Sopenharmony_ci AD5868_CHANNEL(1, 8, bits, _shift), \ 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#define DECLARE_AD5686_CHANNELS(name, bits, _shift) \ 22062306a36Sopenharmony_cistatic const struct iio_chan_spec name[] = { \ 22162306a36Sopenharmony_ci AD5868_CHANNEL(0, 1, bits, _shift), \ 22262306a36Sopenharmony_ci AD5868_CHANNEL(1, 2, bits, _shift), \ 22362306a36Sopenharmony_ci AD5868_CHANNEL(2, 4, bits, _shift), \ 22462306a36Sopenharmony_ci AD5868_CHANNEL(3, 8, bits, _shift), \ 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci#define DECLARE_AD5676_CHANNELS(name, bits, _shift) \ 22862306a36Sopenharmony_cistatic const struct iio_chan_spec name[] = { \ 22962306a36Sopenharmony_ci AD5868_CHANNEL(0, 0, bits, _shift), \ 23062306a36Sopenharmony_ci AD5868_CHANNEL(1, 1, bits, _shift), \ 23162306a36Sopenharmony_ci AD5868_CHANNEL(2, 2, bits, _shift), \ 23262306a36Sopenharmony_ci AD5868_CHANNEL(3, 3, bits, _shift), \ 23362306a36Sopenharmony_ci AD5868_CHANNEL(4, 4, bits, _shift), \ 23462306a36Sopenharmony_ci AD5868_CHANNEL(5, 5, bits, _shift), \ 23562306a36Sopenharmony_ci AD5868_CHANNEL(6, 6, bits, _shift), \ 23662306a36Sopenharmony_ci AD5868_CHANNEL(7, 7, bits, _shift), \ 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci#define DECLARE_AD5679_CHANNELS(name, bits, _shift) \ 24062306a36Sopenharmony_cistatic const struct iio_chan_spec name[] = { \ 24162306a36Sopenharmony_ci AD5868_CHANNEL(0, 0, bits, _shift), \ 24262306a36Sopenharmony_ci AD5868_CHANNEL(1, 1, bits, _shift), \ 24362306a36Sopenharmony_ci AD5868_CHANNEL(2, 2, bits, _shift), \ 24462306a36Sopenharmony_ci AD5868_CHANNEL(3, 3, bits, _shift), \ 24562306a36Sopenharmony_ci AD5868_CHANNEL(4, 4, bits, _shift), \ 24662306a36Sopenharmony_ci AD5868_CHANNEL(5, 5, bits, _shift), \ 24762306a36Sopenharmony_ci AD5868_CHANNEL(6, 6, bits, _shift), \ 24862306a36Sopenharmony_ci AD5868_CHANNEL(7, 7, bits, _shift), \ 24962306a36Sopenharmony_ci AD5868_CHANNEL(8, 8, bits, _shift), \ 25062306a36Sopenharmony_ci AD5868_CHANNEL(9, 9, bits, _shift), \ 25162306a36Sopenharmony_ci AD5868_CHANNEL(10, 10, bits, _shift), \ 25262306a36Sopenharmony_ci AD5868_CHANNEL(11, 11, bits, _shift), \ 25362306a36Sopenharmony_ci AD5868_CHANNEL(12, 12, bits, _shift), \ 25462306a36Sopenharmony_ci AD5868_CHANNEL(13, 13, bits, _shift), \ 25562306a36Sopenharmony_ci AD5868_CHANNEL(14, 14, bits, _shift), \ 25662306a36Sopenharmony_ci AD5868_CHANNEL(15, 15, bits, _shift), \ 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ciDECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2); 26062306a36Sopenharmony_ciDECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6); 26162306a36Sopenharmony_ciDECLARE_AD5338_CHANNELS(ad5337r_channels, 8, 8); 26262306a36Sopenharmony_ciDECLARE_AD5338_CHANNELS(ad5338r_channels, 10, 6); 26362306a36Sopenharmony_ciDECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4); 26462306a36Sopenharmony_ciDECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4); 26562306a36Sopenharmony_ciDECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0); 26662306a36Sopenharmony_ciDECLARE_AD5679_CHANNELS(ad5679r_channels, 16, 0); 26762306a36Sopenharmony_ciDECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4); 26862306a36Sopenharmony_ciDECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2); 26962306a36Sopenharmony_ciDECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0); 27062306a36Sopenharmony_ciDECLARE_AD5693_CHANNELS(ad5693_channels, 16, 0); 27162306a36Sopenharmony_ciDECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2); 27262306a36Sopenharmony_ciDECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic const struct ad5686_chip_info ad5686_chip_info_tbl[] = { 27562306a36Sopenharmony_ci [ID_AD5310R] = { 27662306a36Sopenharmony_ci .channels = ad5310r_channels, 27762306a36Sopenharmony_ci .int_vref_mv = 2500, 27862306a36Sopenharmony_ci .num_channels = 1, 27962306a36Sopenharmony_ci .regmap_type = AD5310_REGMAP, 28062306a36Sopenharmony_ci }, 28162306a36Sopenharmony_ci [ID_AD5311R] = { 28262306a36Sopenharmony_ci .channels = ad5311r_channels, 28362306a36Sopenharmony_ci .int_vref_mv = 2500, 28462306a36Sopenharmony_ci .num_channels = 1, 28562306a36Sopenharmony_ci .regmap_type = AD5693_REGMAP, 28662306a36Sopenharmony_ci }, 28762306a36Sopenharmony_ci [ID_AD5337R] = { 28862306a36Sopenharmony_ci .channels = ad5337r_channels, 28962306a36Sopenharmony_ci .int_vref_mv = 2500, 29062306a36Sopenharmony_ci .num_channels = 2, 29162306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 29262306a36Sopenharmony_ci }, 29362306a36Sopenharmony_ci [ID_AD5338R] = { 29462306a36Sopenharmony_ci .channels = ad5338r_channels, 29562306a36Sopenharmony_ci .int_vref_mv = 2500, 29662306a36Sopenharmony_ci .num_channels = 2, 29762306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 29862306a36Sopenharmony_ci }, 29962306a36Sopenharmony_ci [ID_AD5671R] = { 30062306a36Sopenharmony_ci .channels = ad5672_channels, 30162306a36Sopenharmony_ci .int_vref_mv = 2500, 30262306a36Sopenharmony_ci .num_channels = 8, 30362306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 30462306a36Sopenharmony_ci }, 30562306a36Sopenharmony_ci [ID_AD5672R] = { 30662306a36Sopenharmony_ci .channels = ad5672_channels, 30762306a36Sopenharmony_ci .int_vref_mv = 2500, 30862306a36Sopenharmony_ci .num_channels = 8, 30962306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 31062306a36Sopenharmony_ci }, 31162306a36Sopenharmony_ci [ID_AD5673R] = { 31262306a36Sopenharmony_ci .channels = ad5674r_channels, 31362306a36Sopenharmony_ci .int_vref_mv = 2500, 31462306a36Sopenharmony_ci .num_channels = 16, 31562306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 31662306a36Sopenharmony_ci }, 31762306a36Sopenharmony_ci [ID_AD5674R] = { 31862306a36Sopenharmony_ci .channels = ad5674r_channels, 31962306a36Sopenharmony_ci .int_vref_mv = 2500, 32062306a36Sopenharmony_ci .num_channels = 16, 32162306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 32262306a36Sopenharmony_ci }, 32362306a36Sopenharmony_ci [ID_AD5675R] = { 32462306a36Sopenharmony_ci .channels = ad5676_channels, 32562306a36Sopenharmony_ci .int_vref_mv = 2500, 32662306a36Sopenharmony_ci .num_channels = 8, 32762306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 32862306a36Sopenharmony_ci }, 32962306a36Sopenharmony_ci [ID_AD5676] = { 33062306a36Sopenharmony_ci .channels = ad5676_channels, 33162306a36Sopenharmony_ci .num_channels = 8, 33262306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 33362306a36Sopenharmony_ci }, 33462306a36Sopenharmony_ci [ID_AD5676R] = { 33562306a36Sopenharmony_ci .channels = ad5676_channels, 33662306a36Sopenharmony_ci .int_vref_mv = 2500, 33762306a36Sopenharmony_ci .num_channels = 8, 33862306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 33962306a36Sopenharmony_ci }, 34062306a36Sopenharmony_ci [ID_AD5677R] = { 34162306a36Sopenharmony_ci .channels = ad5679r_channels, 34262306a36Sopenharmony_ci .int_vref_mv = 2500, 34362306a36Sopenharmony_ci .num_channels = 16, 34462306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 34562306a36Sopenharmony_ci }, 34662306a36Sopenharmony_ci [ID_AD5679R] = { 34762306a36Sopenharmony_ci .channels = ad5679r_channels, 34862306a36Sopenharmony_ci .int_vref_mv = 2500, 34962306a36Sopenharmony_ci .num_channels = 16, 35062306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 35162306a36Sopenharmony_ci }, 35262306a36Sopenharmony_ci [ID_AD5681R] = { 35362306a36Sopenharmony_ci .channels = ad5691r_channels, 35462306a36Sopenharmony_ci .int_vref_mv = 2500, 35562306a36Sopenharmony_ci .num_channels = 1, 35662306a36Sopenharmony_ci .regmap_type = AD5683_REGMAP, 35762306a36Sopenharmony_ci }, 35862306a36Sopenharmony_ci [ID_AD5682R] = { 35962306a36Sopenharmony_ci .channels = ad5692r_channels, 36062306a36Sopenharmony_ci .int_vref_mv = 2500, 36162306a36Sopenharmony_ci .num_channels = 1, 36262306a36Sopenharmony_ci .regmap_type = AD5683_REGMAP, 36362306a36Sopenharmony_ci }, 36462306a36Sopenharmony_ci [ID_AD5683] = { 36562306a36Sopenharmony_ci .channels = ad5693_channels, 36662306a36Sopenharmony_ci .num_channels = 1, 36762306a36Sopenharmony_ci .regmap_type = AD5683_REGMAP, 36862306a36Sopenharmony_ci }, 36962306a36Sopenharmony_ci [ID_AD5683R] = { 37062306a36Sopenharmony_ci .channels = ad5693_channels, 37162306a36Sopenharmony_ci .int_vref_mv = 2500, 37262306a36Sopenharmony_ci .num_channels = 1, 37362306a36Sopenharmony_ci .regmap_type = AD5683_REGMAP, 37462306a36Sopenharmony_ci }, 37562306a36Sopenharmony_ci [ID_AD5684] = { 37662306a36Sopenharmony_ci .channels = ad5684_channels, 37762306a36Sopenharmony_ci .num_channels = 4, 37862306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 37962306a36Sopenharmony_ci }, 38062306a36Sopenharmony_ci [ID_AD5684R] = { 38162306a36Sopenharmony_ci .channels = ad5684_channels, 38262306a36Sopenharmony_ci .int_vref_mv = 2500, 38362306a36Sopenharmony_ci .num_channels = 4, 38462306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 38562306a36Sopenharmony_ci }, 38662306a36Sopenharmony_ci [ID_AD5685R] = { 38762306a36Sopenharmony_ci .channels = ad5685r_channels, 38862306a36Sopenharmony_ci .int_vref_mv = 2500, 38962306a36Sopenharmony_ci .num_channels = 4, 39062306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 39162306a36Sopenharmony_ci }, 39262306a36Sopenharmony_ci [ID_AD5686] = { 39362306a36Sopenharmony_ci .channels = ad5686_channels, 39462306a36Sopenharmony_ci .num_channels = 4, 39562306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 39662306a36Sopenharmony_ci }, 39762306a36Sopenharmony_ci [ID_AD5686R] = { 39862306a36Sopenharmony_ci .channels = ad5686_channels, 39962306a36Sopenharmony_ci .int_vref_mv = 2500, 40062306a36Sopenharmony_ci .num_channels = 4, 40162306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 40262306a36Sopenharmony_ci }, 40362306a36Sopenharmony_ci [ID_AD5691R] = { 40462306a36Sopenharmony_ci .channels = ad5691r_channels, 40562306a36Sopenharmony_ci .int_vref_mv = 2500, 40662306a36Sopenharmony_ci .num_channels = 1, 40762306a36Sopenharmony_ci .regmap_type = AD5693_REGMAP, 40862306a36Sopenharmony_ci }, 40962306a36Sopenharmony_ci [ID_AD5692R] = { 41062306a36Sopenharmony_ci .channels = ad5692r_channels, 41162306a36Sopenharmony_ci .int_vref_mv = 2500, 41262306a36Sopenharmony_ci .num_channels = 1, 41362306a36Sopenharmony_ci .regmap_type = AD5693_REGMAP, 41462306a36Sopenharmony_ci }, 41562306a36Sopenharmony_ci [ID_AD5693] = { 41662306a36Sopenharmony_ci .channels = ad5693_channels, 41762306a36Sopenharmony_ci .num_channels = 1, 41862306a36Sopenharmony_ci .regmap_type = AD5693_REGMAP, 41962306a36Sopenharmony_ci }, 42062306a36Sopenharmony_ci [ID_AD5693R] = { 42162306a36Sopenharmony_ci .channels = ad5693_channels, 42262306a36Sopenharmony_ci .int_vref_mv = 2500, 42362306a36Sopenharmony_ci .num_channels = 1, 42462306a36Sopenharmony_ci .regmap_type = AD5693_REGMAP, 42562306a36Sopenharmony_ci }, 42662306a36Sopenharmony_ci [ID_AD5694] = { 42762306a36Sopenharmony_ci .channels = ad5684_channels, 42862306a36Sopenharmony_ci .num_channels = 4, 42962306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 43062306a36Sopenharmony_ci }, 43162306a36Sopenharmony_ci [ID_AD5694R] = { 43262306a36Sopenharmony_ci .channels = ad5684_channels, 43362306a36Sopenharmony_ci .int_vref_mv = 2500, 43462306a36Sopenharmony_ci .num_channels = 4, 43562306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 43662306a36Sopenharmony_ci }, 43762306a36Sopenharmony_ci [ID_AD5696] = { 43862306a36Sopenharmony_ci .channels = ad5686_channels, 43962306a36Sopenharmony_ci .num_channels = 4, 44062306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 44162306a36Sopenharmony_ci }, 44262306a36Sopenharmony_ci [ID_AD5696R] = { 44362306a36Sopenharmony_ci .channels = ad5686_channels, 44462306a36Sopenharmony_ci .int_vref_mv = 2500, 44562306a36Sopenharmony_ci .num_channels = 4, 44662306a36Sopenharmony_ci .regmap_type = AD5686_REGMAP, 44762306a36Sopenharmony_ci }, 44862306a36Sopenharmony_ci}; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ciint ad5686_probe(struct device *dev, 45162306a36Sopenharmony_ci enum ad5686_supported_device_ids chip_type, 45262306a36Sopenharmony_ci const char *name, ad5686_write_func write, 45362306a36Sopenharmony_ci ad5686_read_func read) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct ad5686_state *st; 45662306a36Sopenharmony_ci struct iio_dev *indio_dev; 45762306a36Sopenharmony_ci unsigned int val, ref_bit_msk; 45862306a36Sopenharmony_ci u8 cmd; 45962306a36Sopenharmony_ci int ret, i, voltage_uv = 0; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 46262306a36Sopenharmony_ci if (indio_dev == NULL) 46362306a36Sopenharmony_ci return -ENOMEM; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci st = iio_priv(indio_dev); 46662306a36Sopenharmony_ci dev_set_drvdata(dev, indio_dev); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci st->dev = dev; 46962306a36Sopenharmony_ci st->write = write; 47062306a36Sopenharmony_ci st->read = read; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci st->reg = devm_regulator_get_optional(dev, "vcc"); 47362306a36Sopenharmony_ci if (!IS_ERR(st->reg)) { 47462306a36Sopenharmony_ci ret = regulator_enable(st->reg); 47562306a36Sopenharmony_ci if (ret) 47662306a36Sopenharmony_ci return ret; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci ret = regulator_get_voltage(st->reg); 47962306a36Sopenharmony_ci if (ret < 0) 48062306a36Sopenharmony_ci goto error_disable_reg; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci voltage_uv = ret; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci st->chip_info = &ad5686_chip_info_tbl[chip_type]; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (voltage_uv) 48862306a36Sopenharmony_ci st->vref_mv = voltage_uv / 1000; 48962306a36Sopenharmony_ci else 49062306a36Sopenharmony_ci st->vref_mv = st->chip_info->int_vref_mv; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Set all the power down mode for all channels to 1K pulldown */ 49362306a36Sopenharmony_ci for (i = 0; i < st->chip_info->num_channels; i++) 49462306a36Sopenharmony_ci st->pwr_down_mode |= (0x01 << (i * 2)); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci indio_dev->name = name; 49762306a36Sopenharmony_ci indio_dev->info = &ad5686_info; 49862306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 49962306a36Sopenharmony_ci indio_dev->channels = st->chip_info->channels; 50062306a36Sopenharmony_ci indio_dev->num_channels = st->chip_info->num_channels; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci mutex_init(&st->lock); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci switch (st->chip_info->regmap_type) { 50562306a36Sopenharmony_ci case AD5310_REGMAP: 50662306a36Sopenharmony_ci cmd = AD5686_CMD_CONTROL_REG; 50762306a36Sopenharmony_ci ref_bit_msk = AD5310_REF_BIT_MSK; 50862306a36Sopenharmony_ci st->use_internal_vref = !voltage_uv; 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci case AD5683_REGMAP: 51162306a36Sopenharmony_ci cmd = AD5686_CMD_CONTROL_REG; 51262306a36Sopenharmony_ci ref_bit_msk = AD5683_REF_BIT_MSK; 51362306a36Sopenharmony_ci st->use_internal_vref = !voltage_uv; 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci case AD5686_REGMAP: 51662306a36Sopenharmony_ci cmd = AD5686_CMD_INTERNAL_REFER_SETUP; 51762306a36Sopenharmony_ci ref_bit_msk = 0; 51862306a36Sopenharmony_ci break; 51962306a36Sopenharmony_ci case AD5693_REGMAP: 52062306a36Sopenharmony_ci cmd = AD5686_CMD_CONTROL_REG; 52162306a36Sopenharmony_ci ref_bit_msk = AD5693_REF_BIT_MSK; 52262306a36Sopenharmony_ci st->use_internal_vref = !voltage_uv; 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci default: 52562306a36Sopenharmony_ci ret = -EINVAL; 52662306a36Sopenharmony_ci goto error_disable_reg; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci val = (voltage_uv | ref_bit_msk); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci ret = st->write(st, cmd, 0, !!val); 53262306a36Sopenharmony_ci if (ret) 53362306a36Sopenharmony_ci goto error_disable_reg; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci ret = iio_device_register(indio_dev); 53662306a36Sopenharmony_ci if (ret) 53762306a36Sopenharmony_ci goto error_disable_reg; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cierror_disable_reg: 54262306a36Sopenharmony_ci if (!IS_ERR(st->reg)) 54362306a36Sopenharmony_ci regulator_disable(st->reg); 54462306a36Sopenharmony_ci return ret; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad5686_probe, IIO_AD5686); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_civoid ad5686_remove(struct device *dev) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 55162306a36Sopenharmony_ci struct ad5686_state *st = iio_priv(indio_dev); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci iio_device_unregister(indio_dev); 55462306a36Sopenharmony_ci if (!IS_ERR(st->reg)) 55562306a36Sopenharmony_ci regulator_disable(st->reg); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad5686_remove, IIO_AD5686); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ciMODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 56062306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC"); 56162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 562