18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, 48c2ecf20Sopenharmony_ci * AD5627, AD5627R, AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, 58c2ecf20Sopenharmony_ci * AD5666, AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616, 68c2ecf20Sopenharmony_ci * LTC2617, LTC2619, LTC2626, LTC2627, LTC2629, LTC2631, LTC2633, LTC2635 78c2ecf20Sopenharmony_ci * Digital to analog converters driver 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright 2011 Analog Devices Inc. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 178c2ecf20Sopenharmony_ci#include <linux/i2c.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 208c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 218c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 248c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define AD5064_MAX_DAC_CHANNELS 8 278c2ecf20Sopenharmony_ci#define AD5064_MAX_VREFS 4 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define AD5064_ADDR(x) ((x) << 20) 308c2ecf20Sopenharmony_ci#define AD5064_CMD(x) ((x) << 24) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define AD5064_ADDR_ALL_DAC 0xF 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define AD5064_CMD_WRITE_INPUT_N 0x0 358c2ecf20Sopenharmony_ci#define AD5064_CMD_UPDATE_DAC_N 0x1 368c2ecf20Sopenharmony_ci#define AD5064_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2 378c2ecf20Sopenharmony_ci#define AD5064_CMD_WRITE_INPUT_N_UPDATE_N 0x3 388c2ecf20Sopenharmony_ci#define AD5064_CMD_POWERDOWN_DAC 0x4 398c2ecf20Sopenharmony_ci#define AD5064_CMD_CLEAR 0x5 408c2ecf20Sopenharmony_ci#define AD5064_CMD_LDAC_MASK 0x6 418c2ecf20Sopenharmony_ci#define AD5064_CMD_RESET 0x7 428c2ecf20Sopenharmony_ci#define AD5064_CMD_CONFIG 0x8 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define AD5064_CMD_RESET_V2 0x5 458c2ecf20Sopenharmony_ci#define AD5064_CMD_CONFIG_V2 0x7 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define AD5064_CONFIG_DAISY_CHAIN_ENABLE BIT(1) 488c2ecf20Sopenharmony_ci#define AD5064_CONFIG_INT_VREF_ENABLE BIT(0) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define AD5064_LDAC_PWRDN_NONE 0x0 518c2ecf20Sopenharmony_ci#define AD5064_LDAC_PWRDN_1K 0x1 528c2ecf20Sopenharmony_ci#define AD5064_LDAC_PWRDN_100K 0x2 538c2ecf20Sopenharmony_ci#define AD5064_LDAC_PWRDN_3STATE 0x3 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/** 568c2ecf20Sopenharmony_ci * enum ad5064_regmap_type - Register layout variant 578c2ecf20Sopenharmony_ci * @AD5064_REGMAP_ADI: Old Analog Devices register map layout 588c2ecf20Sopenharmony_ci * @AD5064_REGMAP_ADI2: New Analog Devices register map layout 598c2ecf20Sopenharmony_ci * @AD5064_REGMAP_LTC: LTC register map layout 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cienum ad5064_regmap_type { 628c2ecf20Sopenharmony_ci AD5064_REGMAP_ADI, 638c2ecf20Sopenharmony_ci AD5064_REGMAP_ADI2, 648c2ecf20Sopenharmony_ci AD5064_REGMAP_LTC, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/** 688c2ecf20Sopenharmony_ci * struct ad5064_chip_info - chip specific information 698c2ecf20Sopenharmony_ci * @shared_vref: whether the vref supply is shared between channels 708c2ecf20Sopenharmony_ci * @internal_vref: internal reference voltage. 0 if the chip has no 718c2ecf20Sopenharmony_ci * internal vref. 728c2ecf20Sopenharmony_ci * @channels: channel specification 738c2ecf20Sopenharmony_ci * @num_channels: number of channels 748c2ecf20Sopenharmony_ci * @regmap_type: register map layout variant 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct ad5064_chip_info { 788c2ecf20Sopenharmony_ci bool shared_vref; 798c2ecf20Sopenharmony_ci unsigned long internal_vref; 808c2ecf20Sopenharmony_ci const struct iio_chan_spec *channels; 818c2ecf20Sopenharmony_ci unsigned int num_channels; 828c2ecf20Sopenharmony_ci enum ad5064_regmap_type regmap_type; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct ad5064_state; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_citypedef int (*ad5064_write_func)(struct ad5064_state *st, unsigned int cmd, 888c2ecf20Sopenharmony_ci unsigned int addr, unsigned int val); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/** 918c2ecf20Sopenharmony_ci * struct ad5064_state - driver instance specific data 928c2ecf20Sopenharmony_ci * @dev: the device for this driver instance 938c2ecf20Sopenharmony_ci * @chip_info: chip model specific constants, available modes etc 948c2ecf20Sopenharmony_ci * @vref_reg: vref supply regulators 958c2ecf20Sopenharmony_ci * @pwr_down: whether channel is powered down 968c2ecf20Sopenharmony_ci * @pwr_down_mode: channel's current power down mode 978c2ecf20Sopenharmony_ci * @dac_cache: current DAC raw value (chip does not support readback) 988c2ecf20Sopenharmony_ci * @use_internal_vref: set to true if the internal reference voltage should be 998c2ecf20Sopenharmony_ci * used. 1008c2ecf20Sopenharmony_ci * @write: register write callback 1018c2ecf20Sopenharmony_ci * @lock: maintain consistency between cached and dev state 1028c2ecf20Sopenharmony_ci * @data: i2c/spi transfer buffers 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistruct ad5064_state { 1068c2ecf20Sopenharmony_ci struct device *dev; 1078c2ecf20Sopenharmony_ci const struct ad5064_chip_info *chip_info; 1088c2ecf20Sopenharmony_ci struct regulator_bulk_data vref_reg[AD5064_MAX_VREFS]; 1098c2ecf20Sopenharmony_ci bool pwr_down[AD5064_MAX_DAC_CHANNELS]; 1108c2ecf20Sopenharmony_ci u8 pwr_down_mode[AD5064_MAX_DAC_CHANNELS]; 1118c2ecf20Sopenharmony_ci unsigned int dac_cache[AD5064_MAX_DAC_CHANNELS]; 1128c2ecf20Sopenharmony_ci bool use_internal_vref; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci ad5064_write_func write; 1158c2ecf20Sopenharmony_ci struct mutex lock; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * DMA (thus cache coherency maintenance) requires the 1198c2ecf20Sopenharmony_ci * transfer buffers to live in their own cache lines. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci union { 1228c2ecf20Sopenharmony_ci u8 i2c[3]; 1238c2ecf20Sopenharmony_ci __be32 spi; 1248c2ecf20Sopenharmony_ci } data ____cacheline_aligned; 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cienum ad5064_type { 1288c2ecf20Sopenharmony_ci ID_AD5024, 1298c2ecf20Sopenharmony_ci ID_AD5025, 1308c2ecf20Sopenharmony_ci ID_AD5044, 1318c2ecf20Sopenharmony_ci ID_AD5045, 1328c2ecf20Sopenharmony_ci ID_AD5064, 1338c2ecf20Sopenharmony_ci ID_AD5064_1, 1348c2ecf20Sopenharmony_ci ID_AD5065, 1358c2ecf20Sopenharmony_ci ID_AD5625, 1368c2ecf20Sopenharmony_ci ID_AD5625R_1V25, 1378c2ecf20Sopenharmony_ci ID_AD5625R_2V5, 1388c2ecf20Sopenharmony_ci ID_AD5627, 1398c2ecf20Sopenharmony_ci ID_AD5627R_1V25, 1408c2ecf20Sopenharmony_ci ID_AD5627R_2V5, 1418c2ecf20Sopenharmony_ci ID_AD5628_1, 1428c2ecf20Sopenharmony_ci ID_AD5628_2, 1438c2ecf20Sopenharmony_ci ID_AD5629_1, 1448c2ecf20Sopenharmony_ci ID_AD5629_2, 1458c2ecf20Sopenharmony_ci ID_AD5645R_1V25, 1468c2ecf20Sopenharmony_ci ID_AD5645R_2V5, 1478c2ecf20Sopenharmony_ci ID_AD5647R_1V25, 1488c2ecf20Sopenharmony_ci ID_AD5647R_2V5, 1498c2ecf20Sopenharmony_ci ID_AD5648_1, 1508c2ecf20Sopenharmony_ci ID_AD5648_2, 1518c2ecf20Sopenharmony_ci ID_AD5665, 1528c2ecf20Sopenharmony_ci ID_AD5665R_1V25, 1538c2ecf20Sopenharmony_ci ID_AD5665R_2V5, 1548c2ecf20Sopenharmony_ci ID_AD5666_1, 1558c2ecf20Sopenharmony_ci ID_AD5666_2, 1568c2ecf20Sopenharmony_ci ID_AD5667, 1578c2ecf20Sopenharmony_ci ID_AD5667R_1V25, 1588c2ecf20Sopenharmony_ci ID_AD5667R_2V5, 1598c2ecf20Sopenharmony_ci ID_AD5668_1, 1608c2ecf20Sopenharmony_ci ID_AD5668_2, 1618c2ecf20Sopenharmony_ci ID_AD5669_1, 1628c2ecf20Sopenharmony_ci ID_AD5669_2, 1638c2ecf20Sopenharmony_ci ID_LTC2606, 1648c2ecf20Sopenharmony_ci ID_LTC2607, 1658c2ecf20Sopenharmony_ci ID_LTC2609, 1668c2ecf20Sopenharmony_ci ID_LTC2616, 1678c2ecf20Sopenharmony_ci ID_LTC2617, 1688c2ecf20Sopenharmony_ci ID_LTC2619, 1698c2ecf20Sopenharmony_ci ID_LTC2626, 1708c2ecf20Sopenharmony_ci ID_LTC2627, 1718c2ecf20Sopenharmony_ci ID_LTC2629, 1728c2ecf20Sopenharmony_ci ID_LTC2631_L12, 1738c2ecf20Sopenharmony_ci ID_LTC2631_H12, 1748c2ecf20Sopenharmony_ci ID_LTC2631_L10, 1758c2ecf20Sopenharmony_ci ID_LTC2631_H10, 1768c2ecf20Sopenharmony_ci ID_LTC2631_L8, 1778c2ecf20Sopenharmony_ci ID_LTC2631_H8, 1788c2ecf20Sopenharmony_ci ID_LTC2633_L12, 1798c2ecf20Sopenharmony_ci ID_LTC2633_H12, 1808c2ecf20Sopenharmony_ci ID_LTC2633_L10, 1818c2ecf20Sopenharmony_ci ID_LTC2633_H10, 1828c2ecf20Sopenharmony_ci ID_LTC2633_L8, 1838c2ecf20Sopenharmony_ci ID_LTC2633_H8, 1848c2ecf20Sopenharmony_ci ID_LTC2635_L12, 1858c2ecf20Sopenharmony_ci ID_LTC2635_H12, 1868c2ecf20Sopenharmony_ci ID_LTC2635_L10, 1878c2ecf20Sopenharmony_ci ID_LTC2635_H10, 1888c2ecf20Sopenharmony_ci ID_LTC2635_L8, 1898c2ecf20Sopenharmony_ci ID_LTC2635_H8, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int ad5064_write(struct ad5064_state *st, unsigned int cmd, 1938c2ecf20Sopenharmony_ci unsigned int addr, unsigned int val, unsigned int shift) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci val <<= shift; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return st->write(st, cmd, addr, val); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int ad5064_sync_powerdown_mode(struct ad5064_state *st, 2018c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci unsigned int val, address; 2048c2ecf20Sopenharmony_ci unsigned int shift; 2058c2ecf20Sopenharmony_ci int ret; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (st->chip_info->regmap_type == AD5064_REGMAP_LTC) { 2088c2ecf20Sopenharmony_ci val = 0; 2098c2ecf20Sopenharmony_ci address = chan->address; 2108c2ecf20Sopenharmony_ci } else { 2118c2ecf20Sopenharmony_ci if (st->chip_info->regmap_type == AD5064_REGMAP_ADI2) 2128c2ecf20Sopenharmony_ci shift = 4; 2138c2ecf20Sopenharmony_ci else 2148c2ecf20Sopenharmony_ci shift = 8; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci val = (0x1 << chan->address); 2178c2ecf20Sopenharmony_ci address = 0; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (st->pwr_down[chan->channel]) 2208c2ecf20Sopenharmony_ci val |= st->pwr_down_mode[chan->channel] << shift; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ret = ad5064_write(st, AD5064_CMD_POWERDOWN_DAC, address, val, 0); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return ret; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic const char * const ad5064_powerdown_modes[] = { 2298c2ecf20Sopenharmony_ci "1kohm_to_gnd", 2308c2ecf20Sopenharmony_ci "100kohm_to_gnd", 2318c2ecf20Sopenharmony_ci "three_state", 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic const char * const ltc2617_powerdown_modes[] = { 2358c2ecf20Sopenharmony_ci "90kohm_to_gnd", 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int ad5064_get_powerdown_mode(struct iio_dev *indio_dev, 2398c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct ad5064_state *st = iio_priv(indio_dev); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return st->pwr_down_mode[chan->channel] - 1; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int ad5064_set_powerdown_mode(struct iio_dev *indio_dev, 2478c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, unsigned int mode) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct ad5064_state *st = iio_priv(indio_dev); 2508c2ecf20Sopenharmony_ci int ret; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 2538c2ecf20Sopenharmony_ci st->pwr_down_mode[chan->channel] = mode + 1; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ret = ad5064_sync_powerdown_mode(st, chan); 2568c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return ret; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic const struct iio_enum ad5064_powerdown_mode_enum = { 2628c2ecf20Sopenharmony_ci .items = ad5064_powerdown_modes, 2638c2ecf20Sopenharmony_ci .num_items = ARRAY_SIZE(ad5064_powerdown_modes), 2648c2ecf20Sopenharmony_ci .get = ad5064_get_powerdown_mode, 2658c2ecf20Sopenharmony_ci .set = ad5064_set_powerdown_mode, 2668c2ecf20Sopenharmony_ci}; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic const struct iio_enum ltc2617_powerdown_mode_enum = { 2698c2ecf20Sopenharmony_ci .items = ltc2617_powerdown_modes, 2708c2ecf20Sopenharmony_ci .num_items = ARRAY_SIZE(ltc2617_powerdown_modes), 2718c2ecf20Sopenharmony_ci .get = ad5064_get_powerdown_mode, 2728c2ecf20Sopenharmony_ci .set = ad5064_set_powerdown_mode, 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev, 2768c2ecf20Sopenharmony_ci uintptr_t private, const struct iio_chan_spec *chan, char *buf) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct ad5064_state *st = iio_priv(indio_dev); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", st->pwr_down[chan->channel]); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev, 2848c2ecf20Sopenharmony_ci uintptr_t private, const struct iio_chan_spec *chan, const char *buf, 2858c2ecf20Sopenharmony_ci size_t len) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct ad5064_state *st = iio_priv(indio_dev); 2888c2ecf20Sopenharmony_ci bool pwr_down; 2898c2ecf20Sopenharmony_ci int ret; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci ret = strtobool(buf, &pwr_down); 2928c2ecf20Sopenharmony_ci if (ret) 2938c2ecf20Sopenharmony_ci return ret; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 2968c2ecf20Sopenharmony_ci st->pwr_down[chan->channel] = pwr_down; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ret = ad5064_sync_powerdown_mode(st, chan); 2998c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 3008c2ecf20Sopenharmony_ci return ret ? ret : len; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int ad5064_get_vref(struct ad5064_state *st, 3048c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci unsigned int i; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (st->use_internal_vref) 3098c2ecf20Sopenharmony_ci return st->chip_info->internal_vref; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci i = st->chip_info->shared_vref ? 0 : chan->channel; 3128c2ecf20Sopenharmony_ci return regulator_get_voltage(st->vref_reg[i].consumer); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic int ad5064_read_raw(struct iio_dev *indio_dev, 3168c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3178c2ecf20Sopenharmony_ci int *val, 3188c2ecf20Sopenharmony_ci int *val2, 3198c2ecf20Sopenharmony_ci long m) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct ad5064_state *st = iio_priv(indio_dev); 3228c2ecf20Sopenharmony_ci int scale_uv; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci switch (m) { 3258c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3268c2ecf20Sopenharmony_ci *val = st->dac_cache[chan->channel]; 3278c2ecf20Sopenharmony_ci return IIO_VAL_INT; 3288c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 3298c2ecf20Sopenharmony_ci scale_uv = ad5064_get_vref(st, chan); 3308c2ecf20Sopenharmony_ci if (scale_uv < 0) 3318c2ecf20Sopenharmony_ci return scale_uv; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci *val = scale_uv / 1000; 3348c2ecf20Sopenharmony_ci *val2 = chan->scan_type.realbits; 3358c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 3368c2ecf20Sopenharmony_ci default: 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci return -EINVAL; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int ad5064_write_raw(struct iio_dev *indio_dev, 3438c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, int val, int val2, long mask) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct ad5064_state *st = iio_priv(indio_dev); 3468c2ecf20Sopenharmony_ci int ret; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci switch (mask) { 3498c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3508c2ecf20Sopenharmony_ci if (val >= (1 << chan->scan_type.realbits) || val < 0) 3518c2ecf20Sopenharmony_ci return -EINVAL; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 3548c2ecf20Sopenharmony_ci ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N, 3558c2ecf20Sopenharmony_ci chan->address, val, chan->scan_type.shift); 3568c2ecf20Sopenharmony_ci if (ret == 0) 3578c2ecf20Sopenharmony_ci st->dac_cache[chan->channel] = val; 3588c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 3598c2ecf20Sopenharmony_ci break; 3608c2ecf20Sopenharmony_ci default: 3618c2ecf20Sopenharmony_ci ret = -EINVAL; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return ret; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic const struct iio_info ad5064_info = { 3688c2ecf20Sopenharmony_ci .read_raw = ad5064_read_raw, 3698c2ecf20Sopenharmony_ci .write_raw = ad5064_write_raw, 3708c2ecf20Sopenharmony_ci}; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info ad5064_ext_info[] = { 3738c2ecf20Sopenharmony_ci { 3748c2ecf20Sopenharmony_ci .name = "powerdown", 3758c2ecf20Sopenharmony_ci .read = ad5064_read_dac_powerdown, 3768c2ecf20Sopenharmony_ci .write = ad5064_write_dac_powerdown, 3778c2ecf20Sopenharmony_ci .shared = IIO_SEPARATE, 3788c2ecf20Sopenharmony_ci }, 3798c2ecf20Sopenharmony_ci IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5064_powerdown_mode_enum), 3808c2ecf20Sopenharmony_ci IIO_ENUM_AVAILABLE("powerdown_mode", &ad5064_powerdown_mode_enum), 3818c2ecf20Sopenharmony_ci { }, 3828c2ecf20Sopenharmony_ci}; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info ltc2617_ext_info[] = { 3858c2ecf20Sopenharmony_ci { 3868c2ecf20Sopenharmony_ci .name = "powerdown", 3878c2ecf20Sopenharmony_ci .read = ad5064_read_dac_powerdown, 3888c2ecf20Sopenharmony_ci .write = ad5064_write_dac_powerdown, 3898c2ecf20Sopenharmony_ci .shared = IIO_SEPARATE, 3908c2ecf20Sopenharmony_ci }, 3918c2ecf20Sopenharmony_ci IIO_ENUM("powerdown_mode", IIO_SEPARATE, <c2617_powerdown_mode_enum), 3928c2ecf20Sopenharmony_ci IIO_ENUM_AVAILABLE("powerdown_mode", <c2617_powerdown_mode_enum), 3938c2ecf20Sopenharmony_ci { }, 3948c2ecf20Sopenharmony_ci}; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci#define AD5064_CHANNEL(chan, addr, bits, _shift, _ext_info) { \ 3978c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 3988c2ecf20Sopenharmony_ci .indexed = 1, \ 3998c2ecf20Sopenharmony_ci .output = 1, \ 4008c2ecf20Sopenharmony_ci .channel = (chan), \ 4018c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 4028c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), \ 4038c2ecf20Sopenharmony_ci .address = addr, \ 4048c2ecf20Sopenharmony_ci .scan_type = { \ 4058c2ecf20Sopenharmony_ci .sign = 'u', \ 4068c2ecf20Sopenharmony_ci .realbits = (bits), \ 4078c2ecf20Sopenharmony_ci .storagebits = 16, \ 4088c2ecf20Sopenharmony_ci .shift = (_shift), \ 4098c2ecf20Sopenharmony_ci }, \ 4108c2ecf20Sopenharmony_ci .ext_info = (_ext_info), \ 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci#define DECLARE_AD5064_CHANNELS(name, bits, shift, ext_info) \ 4148c2ecf20Sopenharmony_ciconst struct iio_chan_spec name[] = { \ 4158c2ecf20Sopenharmony_ci AD5064_CHANNEL(0, 0, bits, shift, ext_info), \ 4168c2ecf20Sopenharmony_ci AD5064_CHANNEL(1, 1, bits, shift, ext_info), \ 4178c2ecf20Sopenharmony_ci AD5064_CHANNEL(2, 2, bits, shift, ext_info), \ 4188c2ecf20Sopenharmony_ci AD5064_CHANNEL(3, 3, bits, shift, ext_info), \ 4198c2ecf20Sopenharmony_ci AD5064_CHANNEL(4, 4, bits, shift, ext_info), \ 4208c2ecf20Sopenharmony_ci AD5064_CHANNEL(5, 5, bits, shift, ext_info), \ 4218c2ecf20Sopenharmony_ci AD5064_CHANNEL(6, 6, bits, shift, ext_info), \ 4228c2ecf20Sopenharmony_ci AD5064_CHANNEL(7, 7, bits, shift, ext_info), \ 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci#define DECLARE_AD5065_CHANNELS(name, bits, shift, ext_info) \ 4268c2ecf20Sopenharmony_ciconst struct iio_chan_spec name[] = { \ 4278c2ecf20Sopenharmony_ci AD5064_CHANNEL(0, 0, bits, shift, ext_info), \ 4288c2ecf20Sopenharmony_ci AD5064_CHANNEL(1, 3, bits, shift, ext_info), \ 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ad5024_channels, 12, 8, ad5064_ext_info); 4328c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ad5044_channels, 14, 6, ad5064_ext_info); 4338c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ad5064_channels, 16, 4, ad5064_ext_info); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic DECLARE_AD5065_CHANNELS(ad5025_channels, 12, 8, ad5064_ext_info); 4368c2ecf20Sopenharmony_cistatic DECLARE_AD5065_CHANNELS(ad5045_channels, 14, 6, ad5064_ext_info); 4378c2ecf20Sopenharmony_cistatic DECLARE_AD5065_CHANNELS(ad5065_channels, 16, 4, ad5064_ext_info); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ad5629_channels, 12, 4, ad5064_ext_info); 4408c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ad5645_channels, 14, 2, ad5064_ext_info); 4418c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0, ad5064_ext_info); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ltc2607_channels, 16, 0, ltc2617_ext_info); 4448c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ltc2617_channels, 14, 2, ltc2617_ext_info); 4458c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ltc2627_channels, 12, 4, ltc2617_ext_info); 4468c2ecf20Sopenharmony_ci#define ltc2631_12_channels ltc2627_channels 4478c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ltc2631_10_channels, 10, 6, ltc2617_ext_info); 4488c2ecf20Sopenharmony_cistatic DECLARE_AD5064_CHANNELS(ltc2631_8_channels, 8, 8, ltc2617_ext_info); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci#define LTC2631_INFO(vref, pchannels, nchannels) \ 4518c2ecf20Sopenharmony_ci { \ 4528c2ecf20Sopenharmony_ci .shared_vref = true, \ 4538c2ecf20Sopenharmony_ci .internal_vref = vref, \ 4548c2ecf20Sopenharmony_ci .channels = pchannels, \ 4558c2ecf20Sopenharmony_ci .num_channels = nchannels, \ 4568c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, \ 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic const struct ad5064_chip_info ad5064_chip_info_tbl[] = { 4618c2ecf20Sopenharmony_ci [ID_AD5024] = { 4628c2ecf20Sopenharmony_ci .shared_vref = false, 4638c2ecf20Sopenharmony_ci .channels = ad5024_channels, 4648c2ecf20Sopenharmony_ci .num_channels = 4, 4658c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 4668c2ecf20Sopenharmony_ci }, 4678c2ecf20Sopenharmony_ci [ID_AD5025] = { 4688c2ecf20Sopenharmony_ci .shared_vref = false, 4698c2ecf20Sopenharmony_ci .channels = ad5025_channels, 4708c2ecf20Sopenharmony_ci .num_channels = 2, 4718c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 4728c2ecf20Sopenharmony_ci }, 4738c2ecf20Sopenharmony_ci [ID_AD5044] = { 4748c2ecf20Sopenharmony_ci .shared_vref = false, 4758c2ecf20Sopenharmony_ci .channels = ad5044_channels, 4768c2ecf20Sopenharmony_ci .num_channels = 4, 4778c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 4788c2ecf20Sopenharmony_ci }, 4798c2ecf20Sopenharmony_ci [ID_AD5045] = { 4808c2ecf20Sopenharmony_ci .shared_vref = false, 4818c2ecf20Sopenharmony_ci .channels = ad5045_channels, 4828c2ecf20Sopenharmony_ci .num_channels = 2, 4838c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 4848c2ecf20Sopenharmony_ci }, 4858c2ecf20Sopenharmony_ci [ID_AD5064] = { 4868c2ecf20Sopenharmony_ci .shared_vref = false, 4878c2ecf20Sopenharmony_ci .channels = ad5064_channels, 4888c2ecf20Sopenharmony_ci .num_channels = 4, 4898c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 4908c2ecf20Sopenharmony_ci }, 4918c2ecf20Sopenharmony_ci [ID_AD5064_1] = { 4928c2ecf20Sopenharmony_ci .shared_vref = true, 4938c2ecf20Sopenharmony_ci .channels = ad5064_channels, 4948c2ecf20Sopenharmony_ci .num_channels = 4, 4958c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 4968c2ecf20Sopenharmony_ci }, 4978c2ecf20Sopenharmony_ci [ID_AD5065] = { 4988c2ecf20Sopenharmony_ci .shared_vref = false, 4998c2ecf20Sopenharmony_ci .channels = ad5065_channels, 5008c2ecf20Sopenharmony_ci .num_channels = 2, 5018c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 5028c2ecf20Sopenharmony_ci }, 5038c2ecf20Sopenharmony_ci [ID_AD5625] = { 5048c2ecf20Sopenharmony_ci .shared_vref = true, 5058c2ecf20Sopenharmony_ci .channels = ad5629_channels, 5068c2ecf20Sopenharmony_ci .num_channels = 4, 5078c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5088c2ecf20Sopenharmony_ci }, 5098c2ecf20Sopenharmony_ci [ID_AD5625R_1V25] = { 5108c2ecf20Sopenharmony_ci .shared_vref = true, 5118c2ecf20Sopenharmony_ci .internal_vref = 1250000, 5128c2ecf20Sopenharmony_ci .channels = ad5629_channels, 5138c2ecf20Sopenharmony_ci .num_channels = 4, 5148c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5158c2ecf20Sopenharmony_ci }, 5168c2ecf20Sopenharmony_ci [ID_AD5625R_2V5] = { 5178c2ecf20Sopenharmony_ci .shared_vref = true, 5188c2ecf20Sopenharmony_ci .internal_vref = 2500000, 5198c2ecf20Sopenharmony_ci .channels = ad5629_channels, 5208c2ecf20Sopenharmony_ci .num_channels = 4, 5218c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5228c2ecf20Sopenharmony_ci }, 5238c2ecf20Sopenharmony_ci [ID_AD5627] = { 5248c2ecf20Sopenharmony_ci .shared_vref = true, 5258c2ecf20Sopenharmony_ci .channels = ad5629_channels, 5268c2ecf20Sopenharmony_ci .num_channels = 2, 5278c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5288c2ecf20Sopenharmony_ci }, 5298c2ecf20Sopenharmony_ci [ID_AD5627R_1V25] = { 5308c2ecf20Sopenharmony_ci .shared_vref = true, 5318c2ecf20Sopenharmony_ci .internal_vref = 1250000, 5328c2ecf20Sopenharmony_ci .channels = ad5629_channels, 5338c2ecf20Sopenharmony_ci .num_channels = 2, 5348c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5358c2ecf20Sopenharmony_ci }, 5368c2ecf20Sopenharmony_ci [ID_AD5627R_2V5] = { 5378c2ecf20Sopenharmony_ci .shared_vref = true, 5388c2ecf20Sopenharmony_ci .internal_vref = 2500000, 5398c2ecf20Sopenharmony_ci .channels = ad5629_channels, 5408c2ecf20Sopenharmony_ci .num_channels = 2, 5418c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5428c2ecf20Sopenharmony_ci }, 5438c2ecf20Sopenharmony_ci [ID_AD5628_1] = { 5448c2ecf20Sopenharmony_ci .shared_vref = true, 5458c2ecf20Sopenharmony_ci .internal_vref = 2500000, 5468c2ecf20Sopenharmony_ci .channels = ad5024_channels, 5478c2ecf20Sopenharmony_ci .num_channels = 8, 5488c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 5498c2ecf20Sopenharmony_ci }, 5508c2ecf20Sopenharmony_ci [ID_AD5628_2] = { 5518c2ecf20Sopenharmony_ci .shared_vref = true, 5528c2ecf20Sopenharmony_ci .internal_vref = 5000000, 5538c2ecf20Sopenharmony_ci .channels = ad5024_channels, 5548c2ecf20Sopenharmony_ci .num_channels = 8, 5558c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 5568c2ecf20Sopenharmony_ci }, 5578c2ecf20Sopenharmony_ci [ID_AD5629_1] = { 5588c2ecf20Sopenharmony_ci .shared_vref = true, 5598c2ecf20Sopenharmony_ci .internal_vref = 2500000, 5608c2ecf20Sopenharmony_ci .channels = ad5629_channels, 5618c2ecf20Sopenharmony_ci .num_channels = 8, 5628c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 5638c2ecf20Sopenharmony_ci }, 5648c2ecf20Sopenharmony_ci [ID_AD5629_2] = { 5658c2ecf20Sopenharmony_ci .shared_vref = true, 5668c2ecf20Sopenharmony_ci .internal_vref = 5000000, 5678c2ecf20Sopenharmony_ci .channels = ad5629_channels, 5688c2ecf20Sopenharmony_ci .num_channels = 8, 5698c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 5708c2ecf20Sopenharmony_ci }, 5718c2ecf20Sopenharmony_ci [ID_AD5645R_1V25] = { 5728c2ecf20Sopenharmony_ci .shared_vref = true, 5738c2ecf20Sopenharmony_ci .internal_vref = 1250000, 5748c2ecf20Sopenharmony_ci .channels = ad5645_channels, 5758c2ecf20Sopenharmony_ci .num_channels = 4, 5768c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5778c2ecf20Sopenharmony_ci }, 5788c2ecf20Sopenharmony_ci [ID_AD5645R_2V5] = { 5798c2ecf20Sopenharmony_ci .shared_vref = true, 5808c2ecf20Sopenharmony_ci .internal_vref = 2500000, 5818c2ecf20Sopenharmony_ci .channels = ad5645_channels, 5828c2ecf20Sopenharmony_ci .num_channels = 4, 5838c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5848c2ecf20Sopenharmony_ci }, 5858c2ecf20Sopenharmony_ci [ID_AD5647R_1V25] = { 5868c2ecf20Sopenharmony_ci .shared_vref = true, 5878c2ecf20Sopenharmony_ci .internal_vref = 1250000, 5888c2ecf20Sopenharmony_ci .channels = ad5645_channels, 5898c2ecf20Sopenharmony_ci .num_channels = 2, 5908c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5918c2ecf20Sopenharmony_ci }, 5928c2ecf20Sopenharmony_ci [ID_AD5647R_2V5] = { 5938c2ecf20Sopenharmony_ci .shared_vref = true, 5948c2ecf20Sopenharmony_ci .internal_vref = 2500000, 5958c2ecf20Sopenharmony_ci .channels = ad5645_channels, 5968c2ecf20Sopenharmony_ci .num_channels = 2, 5978c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 5988c2ecf20Sopenharmony_ci }, 5998c2ecf20Sopenharmony_ci [ID_AD5648_1] = { 6008c2ecf20Sopenharmony_ci .shared_vref = true, 6018c2ecf20Sopenharmony_ci .internal_vref = 2500000, 6028c2ecf20Sopenharmony_ci .channels = ad5044_channels, 6038c2ecf20Sopenharmony_ci .num_channels = 8, 6048c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 6058c2ecf20Sopenharmony_ci }, 6068c2ecf20Sopenharmony_ci [ID_AD5648_2] = { 6078c2ecf20Sopenharmony_ci .shared_vref = true, 6088c2ecf20Sopenharmony_ci .internal_vref = 5000000, 6098c2ecf20Sopenharmony_ci .channels = ad5044_channels, 6108c2ecf20Sopenharmony_ci .num_channels = 8, 6118c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 6128c2ecf20Sopenharmony_ci }, 6138c2ecf20Sopenharmony_ci [ID_AD5665] = { 6148c2ecf20Sopenharmony_ci .shared_vref = true, 6158c2ecf20Sopenharmony_ci .channels = ad5669_channels, 6168c2ecf20Sopenharmony_ci .num_channels = 4, 6178c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 6188c2ecf20Sopenharmony_ci }, 6198c2ecf20Sopenharmony_ci [ID_AD5665R_1V25] = { 6208c2ecf20Sopenharmony_ci .shared_vref = true, 6218c2ecf20Sopenharmony_ci .internal_vref = 1250000, 6228c2ecf20Sopenharmony_ci .channels = ad5669_channels, 6238c2ecf20Sopenharmony_ci .num_channels = 4, 6248c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 6258c2ecf20Sopenharmony_ci }, 6268c2ecf20Sopenharmony_ci [ID_AD5665R_2V5] = { 6278c2ecf20Sopenharmony_ci .shared_vref = true, 6288c2ecf20Sopenharmony_ci .internal_vref = 2500000, 6298c2ecf20Sopenharmony_ci .channels = ad5669_channels, 6308c2ecf20Sopenharmony_ci .num_channels = 4, 6318c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 6328c2ecf20Sopenharmony_ci }, 6338c2ecf20Sopenharmony_ci [ID_AD5666_1] = { 6348c2ecf20Sopenharmony_ci .shared_vref = true, 6358c2ecf20Sopenharmony_ci .internal_vref = 2500000, 6368c2ecf20Sopenharmony_ci .channels = ad5064_channels, 6378c2ecf20Sopenharmony_ci .num_channels = 4, 6388c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 6398c2ecf20Sopenharmony_ci }, 6408c2ecf20Sopenharmony_ci [ID_AD5666_2] = { 6418c2ecf20Sopenharmony_ci .shared_vref = true, 6428c2ecf20Sopenharmony_ci .internal_vref = 5000000, 6438c2ecf20Sopenharmony_ci .channels = ad5064_channels, 6448c2ecf20Sopenharmony_ci .num_channels = 4, 6458c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 6468c2ecf20Sopenharmony_ci }, 6478c2ecf20Sopenharmony_ci [ID_AD5667] = { 6488c2ecf20Sopenharmony_ci .shared_vref = true, 6498c2ecf20Sopenharmony_ci .channels = ad5669_channels, 6508c2ecf20Sopenharmony_ci .num_channels = 2, 6518c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 6528c2ecf20Sopenharmony_ci }, 6538c2ecf20Sopenharmony_ci [ID_AD5667R_1V25] = { 6548c2ecf20Sopenharmony_ci .shared_vref = true, 6558c2ecf20Sopenharmony_ci .internal_vref = 1250000, 6568c2ecf20Sopenharmony_ci .channels = ad5669_channels, 6578c2ecf20Sopenharmony_ci .num_channels = 2, 6588c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 6598c2ecf20Sopenharmony_ci }, 6608c2ecf20Sopenharmony_ci [ID_AD5667R_2V5] = { 6618c2ecf20Sopenharmony_ci .shared_vref = true, 6628c2ecf20Sopenharmony_ci .internal_vref = 2500000, 6638c2ecf20Sopenharmony_ci .channels = ad5669_channels, 6648c2ecf20Sopenharmony_ci .num_channels = 2, 6658c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI2 6668c2ecf20Sopenharmony_ci }, 6678c2ecf20Sopenharmony_ci [ID_AD5668_1] = { 6688c2ecf20Sopenharmony_ci .shared_vref = true, 6698c2ecf20Sopenharmony_ci .internal_vref = 2500000, 6708c2ecf20Sopenharmony_ci .channels = ad5064_channels, 6718c2ecf20Sopenharmony_ci .num_channels = 8, 6728c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 6738c2ecf20Sopenharmony_ci }, 6748c2ecf20Sopenharmony_ci [ID_AD5668_2] = { 6758c2ecf20Sopenharmony_ci .shared_vref = true, 6768c2ecf20Sopenharmony_ci .internal_vref = 5000000, 6778c2ecf20Sopenharmony_ci .channels = ad5064_channels, 6788c2ecf20Sopenharmony_ci .num_channels = 8, 6798c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 6808c2ecf20Sopenharmony_ci }, 6818c2ecf20Sopenharmony_ci [ID_AD5669_1] = { 6828c2ecf20Sopenharmony_ci .shared_vref = true, 6838c2ecf20Sopenharmony_ci .internal_vref = 2500000, 6848c2ecf20Sopenharmony_ci .channels = ad5669_channels, 6858c2ecf20Sopenharmony_ci .num_channels = 8, 6868c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 6878c2ecf20Sopenharmony_ci }, 6888c2ecf20Sopenharmony_ci [ID_AD5669_2] = { 6898c2ecf20Sopenharmony_ci .shared_vref = true, 6908c2ecf20Sopenharmony_ci .internal_vref = 5000000, 6918c2ecf20Sopenharmony_ci .channels = ad5669_channels, 6928c2ecf20Sopenharmony_ci .num_channels = 8, 6938c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_ADI, 6948c2ecf20Sopenharmony_ci }, 6958c2ecf20Sopenharmony_ci [ID_LTC2606] = { 6968c2ecf20Sopenharmony_ci .shared_vref = true, 6978c2ecf20Sopenharmony_ci .internal_vref = 0, 6988c2ecf20Sopenharmony_ci .channels = ltc2607_channels, 6998c2ecf20Sopenharmony_ci .num_channels = 1, 7008c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, 7018c2ecf20Sopenharmony_ci }, 7028c2ecf20Sopenharmony_ci [ID_LTC2607] = { 7038c2ecf20Sopenharmony_ci .shared_vref = true, 7048c2ecf20Sopenharmony_ci .internal_vref = 0, 7058c2ecf20Sopenharmony_ci .channels = ltc2607_channels, 7068c2ecf20Sopenharmony_ci .num_channels = 2, 7078c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, 7088c2ecf20Sopenharmony_ci }, 7098c2ecf20Sopenharmony_ci [ID_LTC2609] = { 7108c2ecf20Sopenharmony_ci .shared_vref = false, 7118c2ecf20Sopenharmony_ci .internal_vref = 0, 7128c2ecf20Sopenharmony_ci .channels = ltc2607_channels, 7138c2ecf20Sopenharmony_ci .num_channels = 4, 7148c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, 7158c2ecf20Sopenharmony_ci }, 7168c2ecf20Sopenharmony_ci [ID_LTC2616] = { 7178c2ecf20Sopenharmony_ci .shared_vref = true, 7188c2ecf20Sopenharmony_ci .internal_vref = 0, 7198c2ecf20Sopenharmony_ci .channels = ltc2617_channels, 7208c2ecf20Sopenharmony_ci .num_channels = 1, 7218c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, 7228c2ecf20Sopenharmony_ci }, 7238c2ecf20Sopenharmony_ci [ID_LTC2617] = { 7248c2ecf20Sopenharmony_ci .shared_vref = true, 7258c2ecf20Sopenharmony_ci .internal_vref = 0, 7268c2ecf20Sopenharmony_ci .channels = ltc2617_channels, 7278c2ecf20Sopenharmony_ci .num_channels = 2, 7288c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, 7298c2ecf20Sopenharmony_ci }, 7308c2ecf20Sopenharmony_ci [ID_LTC2619] = { 7318c2ecf20Sopenharmony_ci .shared_vref = false, 7328c2ecf20Sopenharmony_ci .internal_vref = 0, 7338c2ecf20Sopenharmony_ci .channels = ltc2617_channels, 7348c2ecf20Sopenharmony_ci .num_channels = 4, 7358c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, 7368c2ecf20Sopenharmony_ci }, 7378c2ecf20Sopenharmony_ci [ID_LTC2626] = { 7388c2ecf20Sopenharmony_ci .shared_vref = true, 7398c2ecf20Sopenharmony_ci .internal_vref = 0, 7408c2ecf20Sopenharmony_ci .channels = ltc2627_channels, 7418c2ecf20Sopenharmony_ci .num_channels = 1, 7428c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, 7438c2ecf20Sopenharmony_ci }, 7448c2ecf20Sopenharmony_ci [ID_LTC2627] = { 7458c2ecf20Sopenharmony_ci .shared_vref = true, 7468c2ecf20Sopenharmony_ci .internal_vref = 0, 7478c2ecf20Sopenharmony_ci .channels = ltc2627_channels, 7488c2ecf20Sopenharmony_ci .num_channels = 2, 7498c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, 7508c2ecf20Sopenharmony_ci }, 7518c2ecf20Sopenharmony_ci [ID_LTC2629] = { 7528c2ecf20Sopenharmony_ci .shared_vref = false, 7538c2ecf20Sopenharmony_ci .internal_vref = 0, 7548c2ecf20Sopenharmony_ci .channels = ltc2627_channels, 7558c2ecf20Sopenharmony_ci .num_channels = 4, 7568c2ecf20Sopenharmony_ci .regmap_type = AD5064_REGMAP_LTC, 7578c2ecf20Sopenharmony_ci }, 7588c2ecf20Sopenharmony_ci [ID_LTC2631_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 1), 7598c2ecf20Sopenharmony_ci [ID_LTC2631_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 1), 7608c2ecf20Sopenharmony_ci [ID_LTC2631_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 1), 7618c2ecf20Sopenharmony_ci [ID_LTC2631_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 1), 7628c2ecf20Sopenharmony_ci [ID_LTC2631_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 1), 7638c2ecf20Sopenharmony_ci [ID_LTC2631_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 1), 7648c2ecf20Sopenharmony_ci [ID_LTC2633_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 2), 7658c2ecf20Sopenharmony_ci [ID_LTC2633_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 2), 7668c2ecf20Sopenharmony_ci [ID_LTC2633_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 2), 7678c2ecf20Sopenharmony_ci [ID_LTC2633_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 2), 7688c2ecf20Sopenharmony_ci [ID_LTC2633_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 2), 7698c2ecf20Sopenharmony_ci [ID_LTC2633_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 2), 7708c2ecf20Sopenharmony_ci [ID_LTC2635_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 4), 7718c2ecf20Sopenharmony_ci [ID_LTC2635_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 4), 7728c2ecf20Sopenharmony_ci [ID_LTC2635_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 4), 7738c2ecf20Sopenharmony_ci [ID_LTC2635_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 4), 7748c2ecf20Sopenharmony_ci [ID_LTC2635_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 4), 7758c2ecf20Sopenharmony_ci [ID_LTC2635_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 4), 7768c2ecf20Sopenharmony_ci}; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cistatic inline unsigned int ad5064_num_vref(struct ad5064_state *st) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci return st->chip_info->shared_vref ? 1 : st->chip_info->num_channels; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic const char * const ad5064_vref_names[] = { 7848c2ecf20Sopenharmony_ci "vrefA", 7858c2ecf20Sopenharmony_ci "vrefB", 7868c2ecf20Sopenharmony_ci "vrefC", 7878c2ecf20Sopenharmony_ci "vrefD", 7888c2ecf20Sopenharmony_ci}; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic const char *ad5064_vref_name(struct ad5064_state *st, 7918c2ecf20Sopenharmony_ci unsigned int vref) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci return st->chip_info->shared_vref ? "vref" : ad5064_vref_names[vref]; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic int ad5064_set_config(struct ad5064_state *st, unsigned int val) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci unsigned int cmd; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci switch (st->chip_info->regmap_type) { 8018c2ecf20Sopenharmony_ci case AD5064_REGMAP_ADI2: 8028c2ecf20Sopenharmony_ci cmd = AD5064_CMD_CONFIG_V2; 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci default: 8058c2ecf20Sopenharmony_ci cmd = AD5064_CMD_CONFIG; 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci return ad5064_write(st, cmd, 0, val, 0); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic int ad5064_request_vref(struct ad5064_state *st, struct device *dev) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci unsigned int i; 8158c2ecf20Sopenharmony_ci int ret; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci for (i = 0; i < ad5064_num_vref(st); ++i) 8188c2ecf20Sopenharmony_ci st->vref_reg[i].supply = ad5064_vref_name(st, i); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (!st->chip_info->internal_vref) 8218c2ecf20Sopenharmony_ci return devm_regulator_bulk_get(dev, ad5064_num_vref(st), 8228c2ecf20Sopenharmony_ci st->vref_reg); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* 8258c2ecf20Sopenharmony_ci * This assumes that when the regulator has an internal VREF 8268c2ecf20Sopenharmony_ci * there is only one external VREF connection, which is 8278c2ecf20Sopenharmony_ci * currently the case for all supported devices. 8288c2ecf20Sopenharmony_ci */ 8298c2ecf20Sopenharmony_ci st->vref_reg[0].consumer = devm_regulator_get_optional(dev, "vref"); 8308c2ecf20Sopenharmony_ci if (!IS_ERR(st->vref_reg[0].consumer)) 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci ret = PTR_ERR(st->vref_reg[0].consumer); 8348c2ecf20Sopenharmony_ci if (ret != -ENODEV) 8358c2ecf20Sopenharmony_ci return ret; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* If no external regulator was supplied use the internal VREF */ 8388c2ecf20Sopenharmony_ci st->use_internal_vref = true; 8398c2ecf20Sopenharmony_ci ret = ad5064_set_config(st, AD5064_CONFIG_INT_VREF_ENABLE); 8408c2ecf20Sopenharmony_ci if (ret) 8418c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable internal vref: %d\n", ret); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return ret; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic int ad5064_probe(struct device *dev, enum ad5064_type type, 8478c2ecf20Sopenharmony_ci const char *name, ad5064_write_func write) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 8508c2ecf20Sopenharmony_ci struct ad5064_state *st; 8518c2ecf20Sopenharmony_ci unsigned int midscale; 8528c2ecf20Sopenharmony_ci unsigned int i; 8538c2ecf20Sopenharmony_ci int ret; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 8568c2ecf20Sopenharmony_ci if (indio_dev == NULL) 8578c2ecf20Sopenharmony_ci return -ENOMEM; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 8608c2ecf20Sopenharmony_ci mutex_init(&st->lock); 8618c2ecf20Sopenharmony_ci dev_set_drvdata(dev, indio_dev); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci st->chip_info = &ad5064_chip_info_tbl[type]; 8648c2ecf20Sopenharmony_ci st->dev = dev; 8658c2ecf20Sopenharmony_ci st->write = write; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci ret = ad5064_request_vref(st, dev); 8688c2ecf20Sopenharmony_ci if (ret) 8698c2ecf20Sopenharmony_ci return ret; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (!st->use_internal_vref) { 8728c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg); 8738c2ecf20Sopenharmony_ci if (ret) 8748c2ecf20Sopenharmony_ci return ret; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci indio_dev->name = name; 8788c2ecf20Sopenharmony_ci indio_dev->info = &ad5064_info; 8798c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 8808c2ecf20Sopenharmony_ci indio_dev->channels = st->chip_info->channels; 8818c2ecf20Sopenharmony_ci indio_dev->num_channels = st->chip_info->num_channels; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci midscale = (1 << indio_dev->channels[0].scan_type.realbits) / 2; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci for (i = 0; i < st->chip_info->num_channels; ++i) { 8868c2ecf20Sopenharmony_ci st->pwr_down_mode[i] = AD5064_LDAC_PWRDN_1K; 8878c2ecf20Sopenharmony_ci st->dac_cache[i] = midscale; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 8918c2ecf20Sopenharmony_ci if (ret) 8928c2ecf20Sopenharmony_ci goto error_disable_reg; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cierror_disable_reg: 8978c2ecf20Sopenharmony_ci if (!st->use_internal_vref) 8988c2ecf20Sopenharmony_ci regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci return ret; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic int ad5064_remove(struct device *dev) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 9068c2ecf20Sopenharmony_ci struct ad5064_state *st = iio_priv(indio_dev); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (!st->use_internal_vref) 9118c2ecf20Sopenharmony_ci regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return 0; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SPI_MASTER) 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd, 9198c2ecf20Sopenharmony_ci unsigned int addr, unsigned int val) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(st->dev); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci st->data.spi = cpu_to_be32(AD5064_CMD(cmd) | AD5064_ADDR(addr) | val); 9248c2ecf20Sopenharmony_ci return spi_write(spi, &st->data.spi, sizeof(st->data.spi)); 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic int ad5064_spi_probe(struct spi_device *spi) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci const struct spi_device_id *id = spi_get_device_id(spi); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return ad5064_probe(&spi->dev, id->driver_data, id->name, 9328c2ecf20Sopenharmony_ci ad5064_spi_write); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int ad5064_spi_remove(struct spi_device *spi) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci return ad5064_remove(&spi->dev); 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic const struct spi_device_id ad5064_spi_ids[] = { 9418c2ecf20Sopenharmony_ci {"ad5024", ID_AD5024}, 9428c2ecf20Sopenharmony_ci {"ad5025", ID_AD5025}, 9438c2ecf20Sopenharmony_ci {"ad5044", ID_AD5044}, 9448c2ecf20Sopenharmony_ci {"ad5045", ID_AD5045}, 9458c2ecf20Sopenharmony_ci {"ad5064", ID_AD5064}, 9468c2ecf20Sopenharmony_ci {"ad5064-1", ID_AD5064_1}, 9478c2ecf20Sopenharmony_ci {"ad5065", ID_AD5065}, 9488c2ecf20Sopenharmony_ci {"ad5628-1", ID_AD5628_1}, 9498c2ecf20Sopenharmony_ci {"ad5628-2", ID_AD5628_2}, 9508c2ecf20Sopenharmony_ci {"ad5648-1", ID_AD5648_1}, 9518c2ecf20Sopenharmony_ci {"ad5648-2", ID_AD5648_2}, 9528c2ecf20Sopenharmony_ci {"ad5666-1", ID_AD5666_1}, 9538c2ecf20Sopenharmony_ci {"ad5666-2", ID_AD5666_2}, 9548c2ecf20Sopenharmony_ci {"ad5668-1", ID_AD5668_1}, 9558c2ecf20Sopenharmony_ci {"ad5668-2", ID_AD5668_2}, 9568c2ecf20Sopenharmony_ci {"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */ 9578c2ecf20Sopenharmony_ci {} 9588c2ecf20Sopenharmony_ci}; 9598c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad5064_spi_ids); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic struct spi_driver ad5064_spi_driver = { 9628c2ecf20Sopenharmony_ci .driver = { 9638c2ecf20Sopenharmony_ci .name = "ad5064", 9648c2ecf20Sopenharmony_ci }, 9658c2ecf20Sopenharmony_ci .probe = ad5064_spi_probe, 9668c2ecf20Sopenharmony_ci .remove = ad5064_spi_remove, 9678c2ecf20Sopenharmony_ci .id_table = ad5064_spi_ids, 9688c2ecf20Sopenharmony_ci}; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic int __init ad5064_spi_register_driver(void) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci return spi_register_driver(&ad5064_spi_driver); 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic void ad5064_spi_unregister_driver(void) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci spi_unregister_driver(&ad5064_spi_driver); 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci#else 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic inline int ad5064_spi_register_driver(void) { return 0; } 9838c2ecf20Sopenharmony_cistatic inline void ad5064_spi_unregister_driver(void) { } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci#endif 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C) 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd, 9908c2ecf20Sopenharmony_ci unsigned int addr, unsigned int val) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct i2c_client *i2c = to_i2c_client(st->dev); 9938c2ecf20Sopenharmony_ci unsigned int cmd_shift; 9948c2ecf20Sopenharmony_ci int ret; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci switch (st->chip_info->regmap_type) { 9978c2ecf20Sopenharmony_ci case AD5064_REGMAP_ADI2: 9988c2ecf20Sopenharmony_ci cmd_shift = 3; 9998c2ecf20Sopenharmony_ci break; 10008c2ecf20Sopenharmony_ci default: 10018c2ecf20Sopenharmony_ci cmd_shift = 4; 10028c2ecf20Sopenharmony_ci break; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci st->data.i2c[0] = (cmd << cmd_shift) | addr; 10068c2ecf20Sopenharmony_ci put_unaligned_be16(val, &st->data.i2c[1]); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci ret = i2c_master_send(i2c, st->data.i2c, 3); 10098c2ecf20Sopenharmony_ci if (ret < 0) 10108c2ecf20Sopenharmony_ci return ret; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci return 0; 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic int ad5064_i2c_probe(struct i2c_client *i2c, 10168c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci return ad5064_probe(&i2c->dev, id->driver_data, id->name, 10198c2ecf20Sopenharmony_ci ad5064_i2c_write); 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic int ad5064_i2c_remove(struct i2c_client *i2c) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci return ad5064_remove(&i2c->dev); 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic const struct i2c_device_id ad5064_i2c_ids[] = { 10288c2ecf20Sopenharmony_ci {"ad5625", ID_AD5625 }, 10298c2ecf20Sopenharmony_ci {"ad5625r-1v25", ID_AD5625R_1V25 }, 10308c2ecf20Sopenharmony_ci {"ad5625r-2v5", ID_AD5625R_2V5 }, 10318c2ecf20Sopenharmony_ci {"ad5627", ID_AD5627 }, 10328c2ecf20Sopenharmony_ci {"ad5627r-1v25", ID_AD5627R_1V25 }, 10338c2ecf20Sopenharmony_ci {"ad5627r-2v5", ID_AD5627R_2V5 }, 10348c2ecf20Sopenharmony_ci {"ad5629-1", ID_AD5629_1}, 10358c2ecf20Sopenharmony_ci {"ad5629-2", ID_AD5629_2}, 10368c2ecf20Sopenharmony_ci {"ad5629-3", ID_AD5629_2}, /* similar enough to ad5629-2 */ 10378c2ecf20Sopenharmony_ci {"ad5645r-1v25", ID_AD5645R_1V25 }, 10388c2ecf20Sopenharmony_ci {"ad5645r-2v5", ID_AD5645R_2V5 }, 10398c2ecf20Sopenharmony_ci {"ad5665", ID_AD5665 }, 10408c2ecf20Sopenharmony_ci {"ad5665r-1v25", ID_AD5665R_1V25 }, 10418c2ecf20Sopenharmony_ci {"ad5665r-2v5", ID_AD5665R_2V5 }, 10428c2ecf20Sopenharmony_ci {"ad5667", ID_AD5667 }, 10438c2ecf20Sopenharmony_ci {"ad5667r-1v25", ID_AD5667R_1V25 }, 10448c2ecf20Sopenharmony_ci {"ad5667r-2v5", ID_AD5667R_2V5 }, 10458c2ecf20Sopenharmony_ci {"ad5669-1", ID_AD5669_1}, 10468c2ecf20Sopenharmony_ci {"ad5669-2", ID_AD5669_2}, 10478c2ecf20Sopenharmony_ci {"ad5669-3", ID_AD5669_2}, /* similar enough to ad5669-2 */ 10488c2ecf20Sopenharmony_ci {"ltc2606", ID_LTC2606}, 10498c2ecf20Sopenharmony_ci {"ltc2607", ID_LTC2607}, 10508c2ecf20Sopenharmony_ci {"ltc2609", ID_LTC2609}, 10518c2ecf20Sopenharmony_ci {"ltc2616", ID_LTC2616}, 10528c2ecf20Sopenharmony_ci {"ltc2617", ID_LTC2617}, 10538c2ecf20Sopenharmony_ci {"ltc2619", ID_LTC2619}, 10548c2ecf20Sopenharmony_ci {"ltc2626", ID_LTC2626}, 10558c2ecf20Sopenharmony_ci {"ltc2627", ID_LTC2627}, 10568c2ecf20Sopenharmony_ci {"ltc2629", ID_LTC2629}, 10578c2ecf20Sopenharmony_ci {"ltc2631-l12", ID_LTC2631_L12}, 10588c2ecf20Sopenharmony_ci {"ltc2631-h12", ID_LTC2631_H12}, 10598c2ecf20Sopenharmony_ci {"ltc2631-l10", ID_LTC2631_L10}, 10608c2ecf20Sopenharmony_ci {"ltc2631-h10", ID_LTC2631_H10}, 10618c2ecf20Sopenharmony_ci {"ltc2631-l8", ID_LTC2631_L8}, 10628c2ecf20Sopenharmony_ci {"ltc2631-h8", ID_LTC2631_H8}, 10638c2ecf20Sopenharmony_ci {"ltc2633-l12", ID_LTC2633_L12}, 10648c2ecf20Sopenharmony_ci {"ltc2633-h12", ID_LTC2633_H12}, 10658c2ecf20Sopenharmony_ci {"ltc2633-l10", ID_LTC2633_L10}, 10668c2ecf20Sopenharmony_ci {"ltc2633-h10", ID_LTC2633_H10}, 10678c2ecf20Sopenharmony_ci {"ltc2633-l8", ID_LTC2633_L8}, 10688c2ecf20Sopenharmony_ci {"ltc2633-h8", ID_LTC2633_H8}, 10698c2ecf20Sopenharmony_ci {"ltc2635-l12", ID_LTC2635_L12}, 10708c2ecf20Sopenharmony_ci {"ltc2635-h12", ID_LTC2635_H12}, 10718c2ecf20Sopenharmony_ci {"ltc2635-l10", ID_LTC2635_L10}, 10728c2ecf20Sopenharmony_ci {"ltc2635-h10", ID_LTC2635_H10}, 10738c2ecf20Sopenharmony_ci {"ltc2635-l8", ID_LTC2635_L8}, 10748c2ecf20Sopenharmony_ci {"ltc2635-h8", ID_LTC2635_H8}, 10758c2ecf20Sopenharmony_ci {} 10768c2ecf20Sopenharmony_ci}; 10778c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic struct i2c_driver ad5064_i2c_driver = { 10808c2ecf20Sopenharmony_ci .driver = { 10818c2ecf20Sopenharmony_ci .name = "ad5064", 10828c2ecf20Sopenharmony_ci }, 10838c2ecf20Sopenharmony_ci .probe = ad5064_i2c_probe, 10848c2ecf20Sopenharmony_ci .remove = ad5064_i2c_remove, 10858c2ecf20Sopenharmony_ci .id_table = ad5064_i2c_ids, 10868c2ecf20Sopenharmony_ci}; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic int __init ad5064_i2c_register_driver(void) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci return i2c_add_driver(&ad5064_i2c_driver); 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic void __exit ad5064_i2c_unregister_driver(void) 10948c2ecf20Sopenharmony_ci{ 10958c2ecf20Sopenharmony_ci i2c_del_driver(&ad5064_i2c_driver); 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci#else 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cistatic inline int ad5064_i2c_register_driver(void) { return 0; } 11018c2ecf20Sopenharmony_cistatic inline void ad5064_i2c_unregister_driver(void) { } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci#endif 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_cistatic int __init ad5064_init(void) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci int ret; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci ret = ad5064_spi_register_driver(); 11108c2ecf20Sopenharmony_ci if (ret) 11118c2ecf20Sopenharmony_ci return ret; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci ret = ad5064_i2c_register_driver(); 11148c2ecf20Sopenharmony_ci if (ret) { 11158c2ecf20Sopenharmony_ci ad5064_spi_unregister_driver(); 11168c2ecf20Sopenharmony_ci return ret; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci return 0; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_cimodule_init(ad5064_init); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic void __exit ad5064_exit(void) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci ad5064_i2c_unregister_driver(); 11268c2ecf20Sopenharmony_ci ad5064_spi_unregister_driver(); 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_cimodule_exit(ad5064_exit); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 11318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5024 and similar multi-channel DACs"); 11328c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1133