18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD5446 SPI DAC driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2010 Analog Devices Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 148c2ecf20Sopenharmony_ci#include <linux/list.h> 158c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 168c2ecf20Sopenharmony_ci#include <linux/i2c.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 188c2ecf20Sopenharmony_ci#include <linux/err.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 238c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define MODE_PWRDWN_1k 0x1 288c2ecf20Sopenharmony_ci#define MODE_PWRDWN_100k 0x2 298c2ecf20Sopenharmony_ci#define MODE_PWRDWN_TRISTATE 0x3 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/** 328c2ecf20Sopenharmony_ci * struct ad5446_state - driver instance specific data 338c2ecf20Sopenharmony_ci * @dev: this device 348c2ecf20Sopenharmony_ci * @chip_info: chip model specific constants, available modes etc 358c2ecf20Sopenharmony_ci * @reg: supply regulator 368c2ecf20Sopenharmony_ci * @vref_mv: actual reference voltage used 378c2ecf20Sopenharmony_ci * @cached_val: store/retrieve values during power down 388c2ecf20Sopenharmony_ci * @pwr_down_mode: power down mode (1k, 100k or tristate) 398c2ecf20Sopenharmony_ci * @pwr_down: true if the device is in power down 408c2ecf20Sopenharmony_ci * @lock: lock to protect the data buffer during write ops 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct ad5446_state { 448c2ecf20Sopenharmony_ci struct device *dev; 458c2ecf20Sopenharmony_ci const struct ad5446_chip_info *chip_info; 468c2ecf20Sopenharmony_ci struct regulator *reg; 478c2ecf20Sopenharmony_ci unsigned short vref_mv; 488c2ecf20Sopenharmony_ci unsigned cached_val; 498c2ecf20Sopenharmony_ci unsigned pwr_down_mode; 508c2ecf20Sopenharmony_ci unsigned pwr_down; 518c2ecf20Sopenharmony_ci struct mutex lock; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/** 558c2ecf20Sopenharmony_ci * struct ad5446_chip_info - chip specific information 568c2ecf20Sopenharmony_ci * @channel: channel spec for the DAC 578c2ecf20Sopenharmony_ci * @int_vref_mv: AD5620/40/60: the internal reference voltage 588c2ecf20Sopenharmony_ci * @write: chip specific helper function to write to the register 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct ad5446_chip_info { 628c2ecf20Sopenharmony_ci struct iio_chan_spec channel; 638c2ecf20Sopenharmony_ci u16 int_vref_mv; 648c2ecf20Sopenharmony_ci int (*write)(struct ad5446_state *st, unsigned val); 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic const char * const ad5446_powerdown_modes[] = { 688c2ecf20Sopenharmony_ci "1kohm_to_gnd", "100kohm_to_gnd", "three_state" 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int ad5446_set_powerdown_mode(struct iio_dev *indio_dev, 728c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, unsigned int mode) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct ad5446_state *st = iio_priv(indio_dev); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci st->pwr_down_mode = mode + 1; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int ad5446_get_powerdown_mode(struct iio_dev *indio_dev, 828c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct ad5446_state *st = iio_priv(indio_dev); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return st->pwr_down_mode - 1; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic const struct iio_enum ad5446_powerdown_mode_enum = { 908c2ecf20Sopenharmony_ci .items = ad5446_powerdown_modes, 918c2ecf20Sopenharmony_ci .num_items = ARRAY_SIZE(ad5446_powerdown_modes), 928c2ecf20Sopenharmony_ci .get = ad5446_get_powerdown_mode, 938c2ecf20Sopenharmony_ci .set = ad5446_set_powerdown_mode, 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev, 978c2ecf20Sopenharmony_ci uintptr_t private, 988c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 998c2ecf20Sopenharmony_ci char *buf) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct ad5446_state *st = iio_priv(indio_dev); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", st->pwr_down); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev, 1078c2ecf20Sopenharmony_ci uintptr_t private, 1088c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 1098c2ecf20Sopenharmony_ci const char *buf, size_t len) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct ad5446_state *st = iio_priv(indio_dev); 1128c2ecf20Sopenharmony_ci unsigned int shift; 1138c2ecf20Sopenharmony_ci unsigned int val; 1148c2ecf20Sopenharmony_ci bool powerdown; 1158c2ecf20Sopenharmony_ci int ret; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci ret = strtobool(buf, &powerdown); 1188c2ecf20Sopenharmony_ci if (ret) 1198c2ecf20Sopenharmony_ci return ret; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 1228c2ecf20Sopenharmony_ci st->pwr_down = powerdown; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (st->pwr_down) { 1258c2ecf20Sopenharmony_ci shift = chan->scan_type.realbits + chan->scan_type.shift; 1268c2ecf20Sopenharmony_ci val = st->pwr_down_mode << shift; 1278c2ecf20Sopenharmony_ci } else { 1288c2ecf20Sopenharmony_ci val = st->cached_val; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci ret = st->chip_info->write(st, val); 1328c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return ret ? ret : len; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { 1388c2ecf20Sopenharmony_ci { 1398c2ecf20Sopenharmony_ci .name = "powerdown", 1408c2ecf20Sopenharmony_ci .read = ad5446_read_dac_powerdown, 1418c2ecf20Sopenharmony_ci .write = ad5446_write_dac_powerdown, 1428c2ecf20Sopenharmony_ci .shared = IIO_SEPARATE, 1438c2ecf20Sopenharmony_ci }, 1448c2ecf20Sopenharmony_ci IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5446_powerdown_mode_enum), 1458c2ecf20Sopenharmony_ci IIO_ENUM_AVAILABLE("powerdown_mode", &ad5446_powerdown_mode_enum), 1468c2ecf20Sopenharmony_ci { }, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#define _AD5446_CHANNEL(bits, storage, _shift, ext) { \ 1508c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 1518c2ecf20Sopenharmony_ci .indexed = 1, \ 1528c2ecf20Sopenharmony_ci .output = 1, \ 1538c2ecf20Sopenharmony_ci .channel = 0, \ 1548c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 1558c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 1568c2ecf20Sopenharmony_ci .scan_type = { \ 1578c2ecf20Sopenharmony_ci .sign = 'u', \ 1588c2ecf20Sopenharmony_ci .realbits = (bits), \ 1598c2ecf20Sopenharmony_ci .storagebits = (storage), \ 1608c2ecf20Sopenharmony_ci .shift = (_shift), \ 1618c2ecf20Sopenharmony_ci }, \ 1628c2ecf20Sopenharmony_ci .ext_info = (ext), \ 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#define AD5446_CHANNEL(bits, storage, shift) \ 1668c2ecf20Sopenharmony_ci _AD5446_CHANNEL(bits, storage, shift, NULL) 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \ 1698c2ecf20Sopenharmony_ci _AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int ad5446_read_raw(struct iio_dev *indio_dev, 1728c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1738c2ecf20Sopenharmony_ci int *val, 1748c2ecf20Sopenharmony_ci int *val2, 1758c2ecf20Sopenharmony_ci long m) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct ad5446_state *st = iio_priv(indio_dev); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci switch (m) { 1808c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 1818c2ecf20Sopenharmony_ci *val = st->cached_val >> chan->scan_type.shift; 1828c2ecf20Sopenharmony_ci return IIO_VAL_INT; 1838c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 1848c2ecf20Sopenharmony_ci *val = st->vref_mv; 1858c2ecf20Sopenharmony_ci *val2 = chan->scan_type.realbits; 1868c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci return -EINVAL; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int ad5446_write_raw(struct iio_dev *indio_dev, 1928c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1938c2ecf20Sopenharmony_ci int val, 1948c2ecf20Sopenharmony_ci int val2, 1958c2ecf20Sopenharmony_ci long mask) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct ad5446_state *st = iio_priv(indio_dev); 1988c2ecf20Sopenharmony_ci int ret = 0; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci switch (mask) { 2018c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 2028c2ecf20Sopenharmony_ci if (val >= (1 << chan->scan_type.realbits) || val < 0) 2038c2ecf20Sopenharmony_ci return -EINVAL; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci val <<= chan->scan_type.shift; 2068c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 2078c2ecf20Sopenharmony_ci st->cached_val = val; 2088c2ecf20Sopenharmony_ci if (!st->pwr_down) 2098c2ecf20Sopenharmony_ci ret = st->chip_info->write(st, val); 2108c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci default: 2138c2ecf20Sopenharmony_ci ret = -EINVAL; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic const struct iio_info ad5446_info = { 2208c2ecf20Sopenharmony_ci .read_raw = ad5446_read_raw, 2218c2ecf20Sopenharmony_ci .write_raw = ad5446_write_raw, 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int ad5446_probe(struct device *dev, const char *name, 2258c2ecf20Sopenharmony_ci const struct ad5446_chip_info *chip_info) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct ad5446_state *st; 2288c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 2298c2ecf20Sopenharmony_ci struct regulator *reg; 2308c2ecf20Sopenharmony_ci int ret, voltage_uv = 0; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci reg = devm_regulator_get(dev, "vcc"); 2338c2ecf20Sopenharmony_ci if (!IS_ERR(reg)) { 2348c2ecf20Sopenharmony_ci ret = regulator_enable(reg); 2358c2ecf20Sopenharmony_ci if (ret) 2368c2ecf20Sopenharmony_ci return ret; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci ret = regulator_get_voltage(reg); 2398c2ecf20Sopenharmony_ci if (ret < 0) 2408c2ecf20Sopenharmony_ci goto error_disable_reg; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci voltage_uv = ret; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 2468c2ecf20Sopenharmony_ci if (indio_dev == NULL) { 2478c2ecf20Sopenharmony_ci ret = -ENOMEM; 2488c2ecf20Sopenharmony_ci goto error_disable_reg; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 2518c2ecf20Sopenharmony_ci st->chip_info = chip_info; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci dev_set_drvdata(dev, indio_dev); 2548c2ecf20Sopenharmony_ci st->reg = reg; 2558c2ecf20Sopenharmony_ci st->dev = dev; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci indio_dev->name = name; 2588c2ecf20Sopenharmony_ci indio_dev->info = &ad5446_info; 2598c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 2608c2ecf20Sopenharmony_ci indio_dev->channels = &st->chip_info->channel; 2618c2ecf20Sopenharmony_ci indio_dev->num_channels = 1; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci mutex_init(&st->lock); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci st->pwr_down_mode = MODE_PWRDWN_1k; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (st->chip_info->int_vref_mv) 2688c2ecf20Sopenharmony_ci st->vref_mv = st->chip_info->int_vref_mv; 2698c2ecf20Sopenharmony_ci else if (voltage_uv) 2708c2ecf20Sopenharmony_ci st->vref_mv = voltage_uv / 1000; 2718c2ecf20Sopenharmony_ci else 2728c2ecf20Sopenharmony_ci dev_warn(dev, "reference voltage unspecified\n"); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 2758c2ecf20Sopenharmony_ci if (ret) 2768c2ecf20Sopenharmony_ci goto error_disable_reg; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return 0; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cierror_disable_reg: 2818c2ecf20Sopenharmony_ci if (!IS_ERR(reg)) 2828c2ecf20Sopenharmony_ci regulator_disable(reg); 2838c2ecf20Sopenharmony_ci return ret; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int ad5446_remove(struct device *dev) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 2898c2ecf20Sopenharmony_ci struct ad5446_state *st = iio_priv(indio_dev); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 2928c2ecf20Sopenharmony_ci if (!IS_ERR(st->reg)) 2938c2ecf20Sopenharmony_ci regulator_disable(st->reg); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SPI_MASTER) 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic int ad5446_write(struct ad5446_state *st, unsigned val) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(st->dev); 3038c2ecf20Sopenharmony_ci __be16 data = cpu_to_be16(val); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return spi_write(spi, &data, sizeof(data)); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int ad5660_write(struct ad5446_state *st, unsigned val) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(st->dev); 3118c2ecf20Sopenharmony_ci uint8_t data[3]; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci put_unaligned_be24(val, &data[0]); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return spi_write(spi, data, sizeof(data)); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci/* 3198c2ecf20Sopenharmony_ci * ad5446_supported_spi_device_ids: 3208c2ecf20Sopenharmony_ci * The AD5620/40/60 parts are available in different fixed internal reference 3218c2ecf20Sopenharmony_ci * voltage options. The actual part numbers may look differently 3228c2ecf20Sopenharmony_ci * (and a bit cryptic), however this style is used to make clear which 3238c2ecf20Sopenharmony_ci * parts are supported here. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_cienum ad5446_supported_spi_device_ids { 3268c2ecf20Sopenharmony_ci ID_AD5300, 3278c2ecf20Sopenharmony_ci ID_AD5310, 3288c2ecf20Sopenharmony_ci ID_AD5320, 3298c2ecf20Sopenharmony_ci ID_AD5444, 3308c2ecf20Sopenharmony_ci ID_AD5446, 3318c2ecf20Sopenharmony_ci ID_AD5450, 3328c2ecf20Sopenharmony_ci ID_AD5451, 3338c2ecf20Sopenharmony_ci ID_AD5541A, 3348c2ecf20Sopenharmony_ci ID_AD5512A, 3358c2ecf20Sopenharmony_ci ID_AD5553, 3368c2ecf20Sopenharmony_ci ID_AD5600, 3378c2ecf20Sopenharmony_ci ID_AD5601, 3388c2ecf20Sopenharmony_ci ID_AD5611, 3398c2ecf20Sopenharmony_ci ID_AD5621, 3408c2ecf20Sopenharmony_ci ID_AD5641, 3418c2ecf20Sopenharmony_ci ID_AD5620_2500, 3428c2ecf20Sopenharmony_ci ID_AD5620_1250, 3438c2ecf20Sopenharmony_ci ID_AD5640_2500, 3448c2ecf20Sopenharmony_ci ID_AD5640_1250, 3458c2ecf20Sopenharmony_ci ID_AD5660_2500, 3468c2ecf20Sopenharmony_ci ID_AD5660_1250, 3478c2ecf20Sopenharmony_ci ID_AD5662, 3488c2ecf20Sopenharmony_ci}; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic const struct ad5446_chip_info ad5446_spi_chip_info[] = { 3518c2ecf20Sopenharmony_ci [ID_AD5300] = { 3528c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), 3538c2ecf20Sopenharmony_ci .write = ad5446_write, 3548c2ecf20Sopenharmony_ci }, 3558c2ecf20Sopenharmony_ci [ID_AD5310] = { 3568c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), 3578c2ecf20Sopenharmony_ci .write = ad5446_write, 3588c2ecf20Sopenharmony_ci }, 3598c2ecf20Sopenharmony_ci [ID_AD5320] = { 3608c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), 3618c2ecf20Sopenharmony_ci .write = ad5446_write, 3628c2ecf20Sopenharmony_ci }, 3638c2ecf20Sopenharmony_ci [ID_AD5444] = { 3648c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL(12, 16, 2), 3658c2ecf20Sopenharmony_ci .write = ad5446_write, 3668c2ecf20Sopenharmony_ci }, 3678c2ecf20Sopenharmony_ci [ID_AD5446] = { 3688c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL(14, 16, 0), 3698c2ecf20Sopenharmony_ci .write = ad5446_write, 3708c2ecf20Sopenharmony_ci }, 3718c2ecf20Sopenharmony_ci [ID_AD5450] = { 3728c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL(8, 16, 6), 3738c2ecf20Sopenharmony_ci .write = ad5446_write, 3748c2ecf20Sopenharmony_ci }, 3758c2ecf20Sopenharmony_ci [ID_AD5451] = { 3768c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL(10, 16, 4), 3778c2ecf20Sopenharmony_ci .write = ad5446_write, 3788c2ecf20Sopenharmony_ci }, 3798c2ecf20Sopenharmony_ci [ID_AD5541A] = { 3808c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL(16, 16, 0), 3818c2ecf20Sopenharmony_ci .write = ad5446_write, 3828c2ecf20Sopenharmony_ci }, 3838c2ecf20Sopenharmony_ci [ID_AD5512A] = { 3848c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL(12, 16, 4), 3858c2ecf20Sopenharmony_ci .write = ad5446_write, 3868c2ecf20Sopenharmony_ci }, 3878c2ecf20Sopenharmony_ci [ID_AD5553] = { 3888c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL(14, 16, 0), 3898c2ecf20Sopenharmony_ci .write = ad5446_write, 3908c2ecf20Sopenharmony_ci }, 3918c2ecf20Sopenharmony_ci [ID_AD5600] = { 3928c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL(16, 16, 0), 3938c2ecf20Sopenharmony_ci .write = ad5446_write, 3948c2ecf20Sopenharmony_ci }, 3958c2ecf20Sopenharmony_ci [ID_AD5601] = { 3968c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6), 3978c2ecf20Sopenharmony_ci .write = ad5446_write, 3988c2ecf20Sopenharmony_ci }, 3998c2ecf20Sopenharmony_ci [ID_AD5611] = { 4008c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4), 4018c2ecf20Sopenharmony_ci .write = ad5446_write, 4028c2ecf20Sopenharmony_ci }, 4038c2ecf20Sopenharmony_ci [ID_AD5621] = { 4048c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), 4058c2ecf20Sopenharmony_ci .write = ad5446_write, 4068c2ecf20Sopenharmony_ci }, 4078c2ecf20Sopenharmony_ci [ID_AD5641] = { 4088c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), 4098c2ecf20Sopenharmony_ci .write = ad5446_write, 4108c2ecf20Sopenharmony_ci }, 4118c2ecf20Sopenharmony_ci [ID_AD5620_2500] = { 4128c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), 4138c2ecf20Sopenharmony_ci .int_vref_mv = 2500, 4148c2ecf20Sopenharmony_ci .write = ad5446_write, 4158c2ecf20Sopenharmony_ci }, 4168c2ecf20Sopenharmony_ci [ID_AD5620_1250] = { 4178c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), 4188c2ecf20Sopenharmony_ci .int_vref_mv = 1250, 4198c2ecf20Sopenharmony_ci .write = ad5446_write, 4208c2ecf20Sopenharmony_ci }, 4218c2ecf20Sopenharmony_ci [ID_AD5640_2500] = { 4228c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), 4238c2ecf20Sopenharmony_ci .int_vref_mv = 2500, 4248c2ecf20Sopenharmony_ci .write = ad5446_write, 4258c2ecf20Sopenharmony_ci }, 4268c2ecf20Sopenharmony_ci [ID_AD5640_1250] = { 4278c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), 4288c2ecf20Sopenharmony_ci .int_vref_mv = 1250, 4298c2ecf20Sopenharmony_ci .write = ad5446_write, 4308c2ecf20Sopenharmony_ci }, 4318c2ecf20Sopenharmony_ci [ID_AD5660_2500] = { 4328c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), 4338c2ecf20Sopenharmony_ci .int_vref_mv = 2500, 4348c2ecf20Sopenharmony_ci .write = ad5660_write, 4358c2ecf20Sopenharmony_ci }, 4368c2ecf20Sopenharmony_ci [ID_AD5660_1250] = { 4378c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), 4388c2ecf20Sopenharmony_ci .int_vref_mv = 1250, 4398c2ecf20Sopenharmony_ci .write = ad5660_write, 4408c2ecf20Sopenharmony_ci }, 4418c2ecf20Sopenharmony_ci [ID_AD5662] = { 4428c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), 4438c2ecf20Sopenharmony_ci .write = ad5660_write, 4448c2ecf20Sopenharmony_ci }, 4458c2ecf20Sopenharmony_ci}; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic const struct spi_device_id ad5446_spi_ids[] = { 4488c2ecf20Sopenharmony_ci {"ad5300", ID_AD5300}, 4498c2ecf20Sopenharmony_ci {"ad5310", ID_AD5310}, 4508c2ecf20Sopenharmony_ci {"ad5320", ID_AD5320}, 4518c2ecf20Sopenharmony_ci {"ad5444", ID_AD5444}, 4528c2ecf20Sopenharmony_ci {"ad5446", ID_AD5446}, 4538c2ecf20Sopenharmony_ci {"ad5450", ID_AD5450}, 4548c2ecf20Sopenharmony_ci {"ad5451", ID_AD5451}, 4558c2ecf20Sopenharmony_ci {"ad5452", ID_AD5444}, /* ad5452 is compatible to the ad5444 */ 4568c2ecf20Sopenharmony_ci {"ad5453", ID_AD5446}, /* ad5453 is compatible to the ad5446 */ 4578c2ecf20Sopenharmony_ci {"ad5512a", ID_AD5512A}, 4588c2ecf20Sopenharmony_ci {"ad5541a", ID_AD5541A}, 4598c2ecf20Sopenharmony_ci {"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */ 4608c2ecf20Sopenharmony_ci {"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */ 4618c2ecf20Sopenharmony_ci {"ad5553", ID_AD5553}, 4628c2ecf20Sopenharmony_ci {"ad5600", ID_AD5600}, 4638c2ecf20Sopenharmony_ci {"ad5601", ID_AD5601}, 4648c2ecf20Sopenharmony_ci {"ad5611", ID_AD5611}, 4658c2ecf20Sopenharmony_ci {"ad5621", ID_AD5621}, 4668c2ecf20Sopenharmony_ci {"ad5641", ID_AD5641}, 4678c2ecf20Sopenharmony_ci {"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */ 4688c2ecf20Sopenharmony_ci {"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */ 4698c2ecf20Sopenharmony_ci {"ad5640-2500", ID_AD5640_2500}, 4708c2ecf20Sopenharmony_ci {"ad5640-1250", ID_AD5640_1250}, 4718c2ecf20Sopenharmony_ci {"ad5660-2500", ID_AD5660_2500}, 4728c2ecf20Sopenharmony_ci {"ad5660-1250", ID_AD5660_1250}, 4738c2ecf20Sopenharmony_ci {"ad5662", ID_AD5662}, 4748c2ecf20Sopenharmony_ci {"dac081s101", ID_AD5300}, /* compatible Texas Instruments chips */ 4758c2ecf20Sopenharmony_ci {"dac101s101", ID_AD5310}, 4768c2ecf20Sopenharmony_ci {"dac121s101", ID_AD5320}, 4778c2ecf20Sopenharmony_ci {"dac7512", ID_AD5320}, 4788c2ecf20Sopenharmony_ci {} 4798c2ecf20Sopenharmony_ci}; 4808c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad5446_spi_ids); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic const struct of_device_id ad5446_of_ids[] = { 4838c2ecf20Sopenharmony_ci { .compatible = "ti,dac7512" }, 4848c2ecf20Sopenharmony_ci { } 4858c2ecf20Sopenharmony_ci}; 4868c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ad5446_of_ids); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int ad5446_spi_probe(struct spi_device *spi) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci const struct spi_device_id *id = spi_get_device_id(spi); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return ad5446_probe(&spi->dev, id->name, 4938c2ecf20Sopenharmony_ci &ad5446_spi_chip_info[id->driver_data]); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic int ad5446_spi_remove(struct spi_device *spi) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci return ad5446_remove(&spi->dev); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic struct spi_driver ad5446_spi_driver = { 5028c2ecf20Sopenharmony_ci .driver = { 5038c2ecf20Sopenharmony_ci .name = "ad5446", 5048c2ecf20Sopenharmony_ci .of_match_table = ad5446_of_ids, 5058c2ecf20Sopenharmony_ci }, 5068c2ecf20Sopenharmony_ci .probe = ad5446_spi_probe, 5078c2ecf20Sopenharmony_ci .remove = ad5446_spi_remove, 5088c2ecf20Sopenharmony_ci .id_table = ad5446_spi_ids, 5098c2ecf20Sopenharmony_ci}; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic int __init ad5446_spi_register_driver(void) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci return spi_register_driver(&ad5446_spi_driver); 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic void ad5446_spi_unregister_driver(void) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci spi_unregister_driver(&ad5446_spi_driver); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci#else 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic inline int ad5446_spi_register_driver(void) { return 0; } 5248c2ecf20Sopenharmony_cistatic inline void ad5446_spi_unregister_driver(void) { } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci#endif 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C) 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int ad5622_write(struct ad5446_state *st, unsigned val) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(st->dev); 5338c2ecf20Sopenharmony_ci __be16 data = cpu_to_be16(val); 5348c2ecf20Sopenharmony_ci int ret; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci ret = i2c_master_send(client, (char *)&data, sizeof(data)); 5378c2ecf20Sopenharmony_ci if (ret < 0) 5388c2ecf20Sopenharmony_ci return ret; 5398c2ecf20Sopenharmony_ci if (ret != sizeof(data)) 5408c2ecf20Sopenharmony_ci return -EIO; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return 0; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci/* 5468c2ecf20Sopenharmony_ci * ad5446_supported_i2c_device_ids: 5478c2ecf20Sopenharmony_ci * The AD5620/40/60 parts are available in different fixed internal reference 5488c2ecf20Sopenharmony_ci * voltage options. The actual part numbers may look differently 5498c2ecf20Sopenharmony_ci * (and a bit cryptic), however this style is used to make clear which 5508c2ecf20Sopenharmony_ci * parts are supported here. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_cienum ad5446_supported_i2c_device_ids { 5538c2ecf20Sopenharmony_ci ID_AD5602, 5548c2ecf20Sopenharmony_ci ID_AD5612, 5558c2ecf20Sopenharmony_ci ID_AD5622, 5568c2ecf20Sopenharmony_ci}; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic const struct ad5446_chip_info ad5446_i2c_chip_info[] = { 5598c2ecf20Sopenharmony_ci [ID_AD5602] = { 5608c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), 5618c2ecf20Sopenharmony_ci .write = ad5622_write, 5628c2ecf20Sopenharmony_ci }, 5638c2ecf20Sopenharmony_ci [ID_AD5612] = { 5648c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), 5658c2ecf20Sopenharmony_ci .write = ad5622_write, 5668c2ecf20Sopenharmony_ci }, 5678c2ecf20Sopenharmony_ci [ID_AD5622] = { 5688c2ecf20Sopenharmony_ci .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), 5698c2ecf20Sopenharmony_ci .write = ad5622_write, 5708c2ecf20Sopenharmony_ci }, 5718c2ecf20Sopenharmony_ci}; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic int ad5446_i2c_probe(struct i2c_client *i2c, 5748c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci return ad5446_probe(&i2c->dev, id->name, 5778c2ecf20Sopenharmony_ci &ad5446_i2c_chip_info[id->driver_data]); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic int ad5446_i2c_remove(struct i2c_client *i2c) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci return ad5446_remove(&i2c->dev); 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic const struct i2c_device_id ad5446_i2c_ids[] = { 5868c2ecf20Sopenharmony_ci {"ad5301", ID_AD5602}, 5878c2ecf20Sopenharmony_ci {"ad5311", ID_AD5612}, 5888c2ecf20Sopenharmony_ci {"ad5321", ID_AD5622}, 5898c2ecf20Sopenharmony_ci {"ad5602", ID_AD5602}, 5908c2ecf20Sopenharmony_ci {"ad5612", ID_AD5612}, 5918c2ecf20Sopenharmony_ci {"ad5622", ID_AD5622}, 5928c2ecf20Sopenharmony_ci {} 5938c2ecf20Sopenharmony_ci}; 5948c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic struct i2c_driver ad5446_i2c_driver = { 5978c2ecf20Sopenharmony_ci .driver = { 5988c2ecf20Sopenharmony_ci .name = "ad5446", 5998c2ecf20Sopenharmony_ci }, 6008c2ecf20Sopenharmony_ci .probe = ad5446_i2c_probe, 6018c2ecf20Sopenharmony_ci .remove = ad5446_i2c_remove, 6028c2ecf20Sopenharmony_ci .id_table = ad5446_i2c_ids, 6038c2ecf20Sopenharmony_ci}; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int __init ad5446_i2c_register_driver(void) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci return i2c_add_driver(&ad5446_i2c_driver); 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic void __exit ad5446_i2c_unregister_driver(void) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci i2c_del_driver(&ad5446_i2c_driver); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci#else 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic inline int ad5446_i2c_register_driver(void) { return 0; } 6188c2ecf20Sopenharmony_cistatic inline void ad5446_i2c_unregister_driver(void) { } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci#endif 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic int __init ad5446_init(void) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci int ret; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci ret = ad5446_spi_register_driver(); 6278c2ecf20Sopenharmony_ci if (ret) 6288c2ecf20Sopenharmony_ci return ret; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci ret = ad5446_i2c_register_driver(); 6318c2ecf20Sopenharmony_ci if (ret) { 6328c2ecf20Sopenharmony_ci ad5446_spi_unregister_driver(); 6338c2ecf20Sopenharmony_ci return ret; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return 0; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_cimodule_init(ad5446_init); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic void __exit ad5446_exit(void) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci ad5446_i2c_unregister_driver(); 6438c2ecf20Sopenharmony_ci ad5446_spi_unregister_driver(); 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_cimodule_exit(ad5446_exit); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 6488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); 6498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 650