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