xref: /openbmc/linux/drivers/iio/dac/ad5446.c (revision 4fa2a9e4)
1dbdc025bSLars-Peter Clausen /*
2dbdc025bSLars-Peter Clausen  * AD5446 SPI DAC driver
3dbdc025bSLars-Peter Clausen  *
4dbdc025bSLars-Peter Clausen  * Copyright 2010 Analog Devices Inc.
5dbdc025bSLars-Peter Clausen  *
6dbdc025bSLars-Peter Clausen  * Licensed under the GPL-2 or later.
7dbdc025bSLars-Peter Clausen  */
8dbdc025bSLars-Peter Clausen 
9dbdc025bSLars-Peter Clausen #include <linux/interrupt.h>
10dbdc025bSLars-Peter Clausen #include <linux/workqueue.h>
11dbdc025bSLars-Peter Clausen #include <linux/device.h>
12dbdc025bSLars-Peter Clausen #include <linux/kernel.h>
13dbdc025bSLars-Peter Clausen #include <linux/slab.h>
14dbdc025bSLars-Peter Clausen #include <linux/sysfs.h>
15dbdc025bSLars-Peter Clausen #include <linux/list.h>
16dbdc025bSLars-Peter Clausen #include <linux/spi/spi.h>
173ec36a2cSJean-Francois Dagenais #include <linux/i2c.h>
18dbdc025bSLars-Peter Clausen #include <linux/regulator/consumer.h>
19dbdc025bSLars-Peter Clausen #include <linux/err.h>
20dbdc025bSLars-Peter Clausen #include <linux/module.h>
21dbdc025bSLars-Peter Clausen 
22dbdc025bSLars-Peter Clausen #include <linux/iio/iio.h>
23dbdc025bSLars-Peter Clausen #include <linux/iio/sysfs.h>
24dbdc025bSLars-Peter Clausen 
252e15c903SJean-Francois Dagenais #define MODE_PWRDWN_1k		0x1
262e15c903SJean-Francois Dagenais #define MODE_PWRDWN_100k	0x2
272e15c903SJean-Francois Dagenais #define MODE_PWRDWN_TRISTATE	0x3
282e15c903SJean-Francois Dagenais 
292e15c903SJean-Francois Dagenais /**
302e15c903SJean-Francois Dagenais  * struct ad5446_state - driver instance specific data
312e15c903SJean-Francois Dagenais  * @spi:		spi_device
322e15c903SJean-Francois Dagenais  * @chip_info:		chip model specific constants, available modes etc
332e15c903SJean-Francois Dagenais  * @reg:		supply regulator
342e15c903SJean-Francois Dagenais  * @vref_mv:		actual reference voltage used
352e15c903SJean-Francois Dagenais  */
362e15c903SJean-Francois Dagenais 
372e15c903SJean-Francois Dagenais struct ad5446_state {
382e15c903SJean-Francois Dagenais 	struct device		*dev;
392e15c903SJean-Francois Dagenais 	const struct ad5446_chip_info	*chip_info;
402e15c903SJean-Francois Dagenais 	struct regulator		*reg;
412e15c903SJean-Francois Dagenais 	unsigned short			vref_mv;
422e15c903SJean-Francois Dagenais 	unsigned			cached_val;
432e15c903SJean-Francois Dagenais 	unsigned			pwr_down_mode;
442e15c903SJean-Francois Dagenais 	unsigned			pwr_down;
452e15c903SJean-Francois Dagenais };
462e15c903SJean-Francois Dagenais 
472e15c903SJean-Francois Dagenais /**
482e15c903SJean-Francois Dagenais  * struct ad5446_chip_info - chip specific information
492e15c903SJean-Francois Dagenais  * @channel:		channel spec for the DAC
502e15c903SJean-Francois Dagenais  * @int_vref_mv:	AD5620/40/60: the internal reference voltage
512e15c903SJean-Francois Dagenais  * @write:		chip specific helper function to write to the register
522e15c903SJean-Francois Dagenais  */
532e15c903SJean-Francois Dagenais 
542e15c903SJean-Francois Dagenais struct ad5446_chip_info {
552e15c903SJean-Francois Dagenais 	struct iio_chan_spec	channel;
562e15c903SJean-Francois Dagenais 	u16			int_vref_mv;
572e15c903SJean-Francois Dagenais 	int			(*write)(struct ad5446_state *st, unsigned val);
582e15c903SJean-Francois Dagenais };
59dbdc025bSLars-Peter Clausen 
60dbdc025bSLars-Peter Clausen static const char * const ad5446_powerdown_modes[] = {
61dbdc025bSLars-Peter Clausen 	"1kohm_to_gnd", "100kohm_to_gnd", "three_state"
62dbdc025bSLars-Peter Clausen };
63dbdc025bSLars-Peter Clausen 
64dbdc025bSLars-Peter Clausen static int ad5446_set_powerdown_mode(struct iio_dev *indio_dev,
65dbdc025bSLars-Peter Clausen 	const struct iio_chan_spec *chan, unsigned int mode)
66dbdc025bSLars-Peter Clausen {
67dbdc025bSLars-Peter Clausen 	struct ad5446_state *st = iio_priv(indio_dev);
68dbdc025bSLars-Peter Clausen 
69dbdc025bSLars-Peter Clausen 	st->pwr_down_mode = mode + 1;
70dbdc025bSLars-Peter Clausen 
71dbdc025bSLars-Peter Clausen 	return 0;
72dbdc025bSLars-Peter Clausen }
73dbdc025bSLars-Peter Clausen 
74dbdc025bSLars-Peter Clausen static int ad5446_get_powerdown_mode(struct iio_dev *indio_dev,
75dbdc025bSLars-Peter Clausen 	const struct iio_chan_spec *chan)
76dbdc025bSLars-Peter Clausen {
77dbdc025bSLars-Peter Clausen 	struct ad5446_state *st = iio_priv(indio_dev);
78dbdc025bSLars-Peter Clausen 
79dbdc025bSLars-Peter Clausen 	return st->pwr_down_mode - 1;
80dbdc025bSLars-Peter Clausen }
81dbdc025bSLars-Peter Clausen 
82dbdc025bSLars-Peter Clausen static const struct iio_enum ad5446_powerdown_mode_enum = {
83dbdc025bSLars-Peter Clausen 	.items = ad5446_powerdown_modes,
84dbdc025bSLars-Peter Clausen 	.num_items = ARRAY_SIZE(ad5446_powerdown_modes),
85dbdc025bSLars-Peter Clausen 	.get = ad5446_get_powerdown_mode,
86dbdc025bSLars-Peter Clausen 	.set = ad5446_set_powerdown_mode,
87dbdc025bSLars-Peter Clausen };
88dbdc025bSLars-Peter Clausen 
89dbdc025bSLars-Peter Clausen static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev,
90dbdc025bSLars-Peter Clausen 					   uintptr_t private,
91dbdc025bSLars-Peter Clausen 					   const struct iio_chan_spec *chan,
92dbdc025bSLars-Peter Clausen 					   char *buf)
93dbdc025bSLars-Peter Clausen {
94dbdc025bSLars-Peter Clausen 	struct ad5446_state *st = iio_priv(indio_dev);
95dbdc025bSLars-Peter Clausen 
96dbdc025bSLars-Peter Clausen 	return sprintf(buf, "%d\n", st->pwr_down);
97dbdc025bSLars-Peter Clausen }
98dbdc025bSLars-Peter Clausen 
99dbdc025bSLars-Peter Clausen static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
100dbdc025bSLars-Peter Clausen 					    uintptr_t private,
101dbdc025bSLars-Peter Clausen 					    const struct iio_chan_spec *chan,
102dbdc025bSLars-Peter Clausen 					    const char *buf, size_t len)
103dbdc025bSLars-Peter Clausen {
104dbdc025bSLars-Peter Clausen 	struct ad5446_state *st = iio_priv(indio_dev);
105dbdc025bSLars-Peter Clausen 	unsigned int shift;
106dbdc025bSLars-Peter Clausen 	unsigned int val;
107dbdc025bSLars-Peter Clausen 	bool powerdown;
108dbdc025bSLars-Peter Clausen 	int ret;
109dbdc025bSLars-Peter Clausen 
110dbdc025bSLars-Peter Clausen 	ret = strtobool(buf, &powerdown);
111dbdc025bSLars-Peter Clausen 	if (ret)
112dbdc025bSLars-Peter Clausen 		return ret;
113dbdc025bSLars-Peter Clausen 
114dbdc025bSLars-Peter Clausen 	mutex_lock(&indio_dev->mlock);
115dbdc025bSLars-Peter Clausen 	st->pwr_down = powerdown;
116dbdc025bSLars-Peter Clausen 
117dbdc025bSLars-Peter Clausen 	if (st->pwr_down) {
118dbdc025bSLars-Peter Clausen 		shift = chan->scan_type.realbits + chan->scan_type.shift;
119dbdc025bSLars-Peter Clausen 		val = st->pwr_down_mode << shift;
120dbdc025bSLars-Peter Clausen 	} else {
121dbdc025bSLars-Peter Clausen 		val = st->cached_val;
122dbdc025bSLars-Peter Clausen 	}
123dbdc025bSLars-Peter Clausen 
124dbdc025bSLars-Peter Clausen 	ret = st->chip_info->write(st, val);
125dbdc025bSLars-Peter Clausen 	mutex_unlock(&indio_dev->mlock);
126dbdc025bSLars-Peter Clausen 
127dbdc025bSLars-Peter Clausen 	return ret ? ret : len;
128dbdc025bSLars-Peter Clausen }
129dbdc025bSLars-Peter Clausen 
1303ec36a2cSJean-Francois Dagenais static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = {
131dbdc025bSLars-Peter Clausen 	{
132dbdc025bSLars-Peter Clausen 		.name = "powerdown",
133dbdc025bSLars-Peter Clausen 		.read = ad5446_read_dac_powerdown,
134dbdc025bSLars-Peter Clausen 		.write = ad5446_write_dac_powerdown,
1353704432fSJonathan Cameron 		.shared = IIO_SEPARATE,
136dbdc025bSLars-Peter Clausen 	},
1373704432fSJonathan Cameron 	IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5446_powerdown_mode_enum),
138dbdc025bSLars-Peter Clausen 	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5446_powerdown_mode_enum),
139dbdc025bSLars-Peter Clausen 	{ },
140dbdc025bSLars-Peter Clausen };
141dbdc025bSLars-Peter Clausen 
142dbdc025bSLars-Peter Clausen #define _AD5446_CHANNEL(bits, storage, shift, ext) { \
143dbdc025bSLars-Peter Clausen 	.type = IIO_VOLTAGE, \
144dbdc025bSLars-Peter Clausen 	.indexed = 1, \
145dbdc025bSLars-Peter Clausen 	.output = 1, \
146dbdc025bSLars-Peter Clausen 	.channel = 0, \
1472f6a4a44SJonathan Cameron 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
1482f6a4a44SJonathan Cameron 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
149dbdc025bSLars-Peter Clausen 	.scan_type = IIO_ST('u', (bits), (storage), (shift)), \
150dbdc025bSLars-Peter Clausen 	.ext_info = (ext), \
151dbdc025bSLars-Peter Clausen }
152dbdc025bSLars-Peter Clausen 
153dbdc025bSLars-Peter Clausen #define AD5446_CHANNEL(bits, storage, shift) \
154dbdc025bSLars-Peter Clausen 	_AD5446_CHANNEL(bits, storage, shift, NULL)
155dbdc025bSLars-Peter Clausen 
156dbdc025bSLars-Peter Clausen #define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
1573ec36a2cSJean-Francois Dagenais 	_AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown)
158dbdc025bSLars-Peter Clausen 
1593ec36a2cSJean-Francois Dagenais static int ad5446_read_raw(struct iio_dev *indio_dev,
1603ec36a2cSJean-Francois Dagenais 			   struct iio_chan_spec const *chan,
1613ec36a2cSJean-Francois Dagenais 			   int *val,
1623ec36a2cSJean-Francois Dagenais 			   int *val2,
1633ec36a2cSJean-Francois Dagenais 			   long m)
1643ec36a2cSJean-Francois Dagenais {
1653ec36a2cSJean-Francois Dagenais 	struct ad5446_state *st = iio_priv(indio_dev);
1663ec36a2cSJean-Francois Dagenais 	unsigned long scale_uv;
1673ec36a2cSJean-Francois Dagenais 
1683ec36a2cSJean-Francois Dagenais 	switch (m) {
1693ec36a2cSJean-Francois Dagenais 	case IIO_CHAN_INFO_RAW:
1703ec36a2cSJean-Francois Dagenais 		*val = st->cached_val;
1713ec36a2cSJean-Francois Dagenais 		return IIO_VAL_INT;
1723ec36a2cSJean-Francois Dagenais 	case IIO_CHAN_INFO_SCALE:
1733ec36a2cSJean-Francois Dagenais 		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
1743ec36a2cSJean-Francois Dagenais 		*val =  scale_uv / 1000;
1753ec36a2cSJean-Francois Dagenais 		*val2 = (scale_uv % 1000) * 1000;
1763ec36a2cSJean-Francois Dagenais 		return IIO_VAL_INT_PLUS_MICRO;
1773ec36a2cSJean-Francois Dagenais 
1783ec36a2cSJean-Francois Dagenais 	}
1793ec36a2cSJean-Francois Dagenais 	return -EINVAL;
1803ec36a2cSJean-Francois Dagenais }
1813ec36a2cSJean-Francois Dagenais 
1823ec36a2cSJean-Francois Dagenais static int ad5446_write_raw(struct iio_dev *indio_dev,
1833ec36a2cSJean-Francois Dagenais 			       struct iio_chan_spec const *chan,
1843ec36a2cSJean-Francois Dagenais 			       int val,
1853ec36a2cSJean-Francois Dagenais 			       int val2,
1863ec36a2cSJean-Francois Dagenais 			       long mask)
1873ec36a2cSJean-Francois Dagenais {
1883ec36a2cSJean-Francois Dagenais 	struct ad5446_state *st = iio_priv(indio_dev);
1893ec36a2cSJean-Francois Dagenais 	int ret = 0;
1903ec36a2cSJean-Francois Dagenais 
1913ec36a2cSJean-Francois Dagenais 	switch (mask) {
1923ec36a2cSJean-Francois Dagenais 	case IIO_CHAN_INFO_RAW:
1933ec36a2cSJean-Francois Dagenais 		if (val >= (1 << chan->scan_type.realbits) || val < 0)
1943ec36a2cSJean-Francois Dagenais 			return -EINVAL;
1953ec36a2cSJean-Francois Dagenais 
1963ec36a2cSJean-Francois Dagenais 		val <<= chan->scan_type.shift;
1973ec36a2cSJean-Francois Dagenais 		mutex_lock(&indio_dev->mlock);
1983ec36a2cSJean-Francois Dagenais 		st->cached_val = val;
1993ec36a2cSJean-Francois Dagenais 		if (!st->pwr_down)
2003ec36a2cSJean-Francois Dagenais 			ret = st->chip_info->write(st, val);
2013ec36a2cSJean-Francois Dagenais 		mutex_unlock(&indio_dev->mlock);
2023ec36a2cSJean-Francois Dagenais 		break;
2033ec36a2cSJean-Francois Dagenais 	default:
2043ec36a2cSJean-Francois Dagenais 		ret = -EINVAL;
2053ec36a2cSJean-Francois Dagenais 	}
2063ec36a2cSJean-Francois Dagenais 
2073ec36a2cSJean-Francois Dagenais 	return ret;
2083ec36a2cSJean-Francois Dagenais }
2093ec36a2cSJean-Francois Dagenais 
2103ec36a2cSJean-Francois Dagenais static const struct iio_info ad5446_info = {
2113ec36a2cSJean-Francois Dagenais 	.read_raw = ad5446_read_raw,
2123ec36a2cSJean-Francois Dagenais 	.write_raw = ad5446_write_raw,
2133ec36a2cSJean-Francois Dagenais 	.driver_module = THIS_MODULE,
2143ec36a2cSJean-Francois Dagenais };
2153ec36a2cSJean-Francois Dagenais 
216fc52692cSGreg Kroah-Hartman static int ad5446_probe(struct device *dev, const char *name,
2173ec36a2cSJean-Francois Dagenais 			const struct ad5446_chip_info *chip_info)
2183ec36a2cSJean-Francois Dagenais {
2193ec36a2cSJean-Francois Dagenais 	struct ad5446_state *st;
2203ec36a2cSJean-Francois Dagenais 	struct iio_dev *indio_dev;
2213ec36a2cSJean-Francois Dagenais 	struct regulator *reg;
2223ec36a2cSJean-Francois Dagenais 	int ret, voltage_uv = 0;
2233ec36a2cSJean-Francois Dagenais 
224ba727295SSachin Kamat 	reg = devm_regulator_get(dev, "vcc");
2253ec36a2cSJean-Francois Dagenais 	if (!IS_ERR(reg)) {
2263ec36a2cSJean-Francois Dagenais 		ret = regulator_enable(reg);
2273ec36a2cSJean-Francois Dagenais 		if (ret)
228ba727295SSachin Kamat 			return ret;
2293ec36a2cSJean-Francois Dagenais 
23013e57ee2SAxel Lin 		ret = regulator_get_voltage(reg);
23113e57ee2SAxel Lin 		if (ret < 0)
23213e57ee2SAxel Lin 			goto error_disable_reg;
23313e57ee2SAxel Lin 
23413e57ee2SAxel Lin 		voltage_uv = ret;
2353ec36a2cSJean-Francois Dagenais 	}
2363ec36a2cSJean-Francois Dagenais 
237ba727295SSachin Kamat 	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
2383ec36a2cSJean-Francois Dagenais 	if (indio_dev == NULL) {
2393ec36a2cSJean-Francois Dagenais 		ret = -ENOMEM;
2403ec36a2cSJean-Francois Dagenais 		goto error_disable_reg;
2413ec36a2cSJean-Francois Dagenais 	}
2423ec36a2cSJean-Francois Dagenais 	st = iio_priv(indio_dev);
2433ec36a2cSJean-Francois Dagenais 	st->chip_info = chip_info;
2443ec36a2cSJean-Francois Dagenais 
2453ec36a2cSJean-Francois Dagenais 	dev_set_drvdata(dev, indio_dev);
2463ec36a2cSJean-Francois Dagenais 	st->reg = reg;
2473ec36a2cSJean-Francois Dagenais 	st->dev = dev;
2483ec36a2cSJean-Francois Dagenais 
2493ec36a2cSJean-Francois Dagenais 	/* Establish that the iio_dev is a child of the device */
2503ec36a2cSJean-Francois Dagenais 	indio_dev->dev.parent = dev;
2513ec36a2cSJean-Francois Dagenais 	indio_dev->name = name;
2523ec36a2cSJean-Francois Dagenais 	indio_dev->info = &ad5446_info;
2533ec36a2cSJean-Francois Dagenais 	indio_dev->modes = INDIO_DIRECT_MODE;
2543ec36a2cSJean-Francois Dagenais 	indio_dev->channels = &st->chip_info->channel;
2553ec36a2cSJean-Francois Dagenais 	indio_dev->num_channels = 1;
2563ec36a2cSJean-Francois Dagenais 
2573ec36a2cSJean-Francois Dagenais 	st->pwr_down_mode = MODE_PWRDWN_1k;
2583ec36a2cSJean-Francois Dagenais 
2593ec36a2cSJean-Francois Dagenais 	if (st->chip_info->int_vref_mv)
2603ec36a2cSJean-Francois Dagenais 		st->vref_mv = st->chip_info->int_vref_mv;
2613ec36a2cSJean-Francois Dagenais 	else if (voltage_uv)
2623ec36a2cSJean-Francois Dagenais 		st->vref_mv = voltage_uv / 1000;
2633ec36a2cSJean-Francois Dagenais 	else
2643ec36a2cSJean-Francois Dagenais 		dev_warn(dev, "reference voltage unspecified\n");
2653ec36a2cSJean-Francois Dagenais 
2663ec36a2cSJean-Francois Dagenais 	ret = iio_device_register(indio_dev);
2673ec36a2cSJean-Francois Dagenais 	if (ret)
268ba727295SSachin Kamat 		goto error_disable_reg;
2693ec36a2cSJean-Francois Dagenais 
2703ec36a2cSJean-Francois Dagenais 	return 0;
2713ec36a2cSJean-Francois Dagenais 
2723ec36a2cSJean-Francois Dagenais error_disable_reg:
2733ec36a2cSJean-Francois Dagenais 	if (!IS_ERR(reg))
2743ec36a2cSJean-Francois Dagenais 		regulator_disable(reg);
2753ec36a2cSJean-Francois Dagenais 	return ret;
2763ec36a2cSJean-Francois Dagenais }
2773ec36a2cSJean-Francois Dagenais 
2783ec36a2cSJean-Francois Dagenais static int ad5446_remove(struct device *dev)
2793ec36a2cSJean-Francois Dagenais {
2803ec36a2cSJean-Francois Dagenais 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
2813ec36a2cSJean-Francois Dagenais 	struct ad5446_state *st = iio_priv(indio_dev);
2823ec36a2cSJean-Francois Dagenais 
2833ec36a2cSJean-Francois Dagenais 	iio_device_unregister(indio_dev);
284ba727295SSachin Kamat 	if (!IS_ERR(st->reg))
2853ec36a2cSJean-Francois Dagenais 		regulator_disable(st->reg);
2863ec36a2cSJean-Francois Dagenais 
2873ec36a2cSJean-Francois Dagenais 	return 0;
2883ec36a2cSJean-Francois Dagenais }
2893ec36a2cSJean-Francois Dagenais 
2903ec36a2cSJean-Francois Dagenais #if IS_ENABLED(CONFIG_SPI_MASTER)
2913ec36a2cSJean-Francois Dagenais 
2923ec36a2cSJean-Francois Dagenais static int ad5446_write(struct ad5446_state *st, unsigned val)
2933ec36a2cSJean-Francois Dagenais {
2943ec36a2cSJean-Francois Dagenais 	struct spi_device *spi = to_spi_device(st->dev);
2953ec36a2cSJean-Francois Dagenais 	__be16 data = cpu_to_be16(val);
2963ec36a2cSJean-Francois Dagenais 
2973ec36a2cSJean-Francois Dagenais 	return spi_write(spi, &data, sizeof(data));
2983ec36a2cSJean-Francois Dagenais }
2993ec36a2cSJean-Francois Dagenais 
3003ec36a2cSJean-Francois Dagenais static int ad5660_write(struct ad5446_state *st, unsigned val)
3013ec36a2cSJean-Francois Dagenais {
3023ec36a2cSJean-Francois Dagenais 	struct spi_device *spi = to_spi_device(st->dev);
3033ec36a2cSJean-Francois Dagenais 	uint8_t data[3];
3043ec36a2cSJean-Francois Dagenais 
3053ec36a2cSJean-Francois Dagenais 	data[0] = (val >> 16) & 0xFF;
3063ec36a2cSJean-Francois Dagenais 	data[1] = (val >> 8) & 0xFF;
3073ec36a2cSJean-Francois Dagenais 	data[2] = val & 0xFF;
3083ec36a2cSJean-Francois Dagenais 
3093ec36a2cSJean-Francois Dagenais 	return spi_write(spi, data, sizeof(data));
3103ec36a2cSJean-Francois Dagenais }
3113ec36a2cSJean-Francois Dagenais 
3123ec36a2cSJean-Francois Dagenais /**
3133ec36a2cSJean-Francois Dagenais  * ad5446_supported_spi_device_ids:
3143ec36a2cSJean-Francois Dagenais  * The AD5620/40/60 parts are available in different fixed internal reference
3153ec36a2cSJean-Francois Dagenais  * voltage options. The actual part numbers may look differently
3163ec36a2cSJean-Francois Dagenais  * (and a bit cryptic), however this style is used to make clear which
3173ec36a2cSJean-Francois Dagenais  * parts are supported here.
3183ec36a2cSJean-Francois Dagenais  */
3193ec36a2cSJean-Francois Dagenais enum ad5446_supported_spi_device_ids {
3202fafbce2SLars-Peter Clausen 	ID_AD5300,
3212fafbce2SLars-Peter Clausen 	ID_AD5310,
3222fafbce2SLars-Peter Clausen 	ID_AD5320,
3233ec36a2cSJean-Francois Dagenais 	ID_AD5444,
3243ec36a2cSJean-Francois Dagenais 	ID_AD5446,
3253ec36a2cSJean-Francois Dagenais 	ID_AD5450,
3263ec36a2cSJean-Francois Dagenais 	ID_AD5451,
3273ec36a2cSJean-Francois Dagenais 	ID_AD5541A,
3283ec36a2cSJean-Francois Dagenais 	ID_AD5512A,
3293ec36a2cSJean-Francois Dagenais 	ID_AD5553,
3303ec36a2cSJean-Francois Dagenais 	ID_AD5601,
3313ec36a2cSJean-Francois Dagenais 	ID_AD5611,
3323ec36a2cSJean-Francois Dagenais 	ID_AD5621,
3334fa2a9e4SAida Mynzhasova 	ID_AD5641,
3343ec36a2cSJean-Francois Dagenais 	ID_AD5620_2500,
3353ec36a2cSJean-Francois Dagenais 	ID_AD5620_1250,
3363ec36a2cSJean-Francois Dagenais 	ID_AD5640_2500,
3373ec36a2cSJean-Francois Dagenais 	ID_AD5640_1250,
3383ec36a2cSJean-Francois Dagenais 	ID_AD5660_2500,
3393ec36a2cSJean-Francois Dagenais 	ID_AD5660_1250,
3403ec36a2cSJean-Francois Dagenais 	ID_AD5662,
3413ec36a2cSJean-Francois Dagenais };
3423ec36a2cSJean-Francois Dagenais 
3433ec36a2cSJean-Francois Dagenais static const struct ad5446_chip_info ad5446_spi_chip_info[] = {
3442fafbce2SLars-Peter Clausen 	[ID_AD5300] = {
3452fafbce2SLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4),
3462fafbce2SLars-Peter Clausen 		.write = ad5446_write,
3472fafbce2SLars-Peter Clausen 	},
3482fafbce2SLars-Peter Clausen 	[ID_AD5310] = {
3492fafbce2SLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2),
3502fafbce2SLars-Peter Clausen 		.write = ad5446_write,
3512fafbce2SLars-Peter Clausen 	},
3522fafbce2SLars-Peter Clausen 	[ID_AD5320] = {
3532fafbce2SLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0),
3542fafbce2SLars-Peter Clausen 		.write = ad5446_write,
3552fafbce2SLars-Peter Clausen 	},
356dbdc025bSLars-Peter Clausen 	[ID_AD5444] = {
357dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL(12, 16, 2),
358dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
359dbdc025bSLars-Peter Clausen 	},
360dbdc025bSLars-Peter Clausen 	[ID_AD5446] = {
361dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL(14, 16, 0),
362dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
363dbdc025bSLars-Peter Clausen 	},
364779c0c46SLars-Peter Clausen 	[ID_AD5450] = {
365779c0c46SLars-Peter Clausen 		.channel = AD5446_CHANNEL(8, 16, 6),
366779c0c46SLars-Peter Clausen 		.write = ad5446_write,
367779c0c46SLars-Peter Clausen 	},
368779c0c46SLars-Peter Clausen 	[ID_AD5451] = {
369779c0c46SLars-Peter Clausen 		.channel = AD5446_CHANNEL(10, 16, 4),
370779c0c46SLars-Peter Clausen 		.write = ad5446_write,
371779c0c46SLars-Peter Clausen 	},
372dbdc025bSLars-Peter Clausen 	[ID_AD5541A] = {
373dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL(16, 16, 0),
374dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
375dbdc025bSLars-Peter Clausen 	},
376dbdc025bSLars-Peter Clausen 	[ID_AD5512A] = {
377dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL(12, 16, 4),
378dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
379dbdc025bSLars-Peter Clausen 	},
380dbdc025bSLars-Peter Clausen 	[ID_AD5553] = {
381dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL(14, 16, 0),
382dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
383dbdc025bSLars-Peter Clausen 	},
384dbdc025bSLars-Peter Clausen 	[ID_AD5601] = {
385dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
386dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
387dbdc025bSLars-Peter Clausen 	},
388dbdc025bSLars-Peter Clausen 	[ID_AD5611] = {
389dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
390dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
391dbdc025bSLars-Peter Clausen 	},
392dbdc025bSLars-Peter Clausen 	[ID_AD5621] = {
393dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
394dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
395dbdc025bSLars-Peter Clausen 	},
3964fa2a9e4SAida Mynzhasova 	[ID_AD5641] = {
3974fa2a9e4SAida Mynzhasova 		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
3984fa2a9e4SAida Mynzhasova 		.write = ad5446_write,
3994fa2a9e4SAida Mynzhasova 	},
400dbdc025bSLars-Peter Clausen 	[ID_AD5620_2500] = {
401dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
402dbdc025bSLars-Peter Clausen 		.int_vref_mv = 2500,
403dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
404dbdc025bSLars-Peter Clausen 	},
405dbdc025bSLars-Peter Clausen 	[ID_AD5620_1250] = {
406dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
407dbdc025bSLars-Peter Clausen 		.int_vref_mv = 1250,
408dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
409dbdc025bSLars-Peter Clausen 	},
410dbdc025bSLars-Peter Clausen 	[ID_AD5640_2500] = {
411dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
412dbdc025bSLars-Peter Clausen 		.int_vref_mv = 2500,
413dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
414dbdc025bSLars-Peter Clausen 	},
415dbdc025bSLars-Peter Clausen 	[ID_AD5640_1250] = {
416dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
417dbdc025bSLars-Peter Clausen 		.int_vref_mv = 1250,
418dbdc025bSLars-Peter Clausen 		.write = ad5446_write,
419dbdc025bSLars-Peter Clausen 	},
420dbdc025bSLars-Peter Clausen 	[ID_AD5660_2500] = {
421dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
422dbdc025bSLars-Peter Clausen 		.int_vref_mv = 2500,
423dbdc025bSLars-Peter Clausen 		.write = ad5660_write,
424dbdc025bSLars-Peter Clausen 	},
425dbdc025bSLars-Peter Clausen 	[ID_AD5660_1250] = {
426dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
427dbdc025bSLars-Peter Clausen 		.int_vref_mv = 1250,
428dbdc025bSLars-Peter Clausen 		.write = ad5660_write,
429dbdc025bSLars-Peter Clausen 	},
430dbdc025bSLars-Peter Clausen 	[ID_AD5662] = {
431dbdc025bSLars-Peter Clausen 		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
432dbdc025bSLars-Peter Clausen 		.write = ad5660_write,
433dbdc025bSLars-Peter Clausen 	},
434dbdc025bSLars-Peter Clausen };
435dbdc025bSLars-Peter Clausen 
4363ec36a2cSJean-Francois Dagenais static const struct spi_device_id ad5446_spi_ids[] = {
4372fafbce2SLars-Peter Clausen 	{"ad5300", ID_AD5300},
4382fafbce2SLars-Peter Clausen 	{"ad5310", ID_AD5310},
4392fafbce2SLars-Peter Clausen 	{"ad5320", ID_AD5320},
440dbdc025bSLars-Peter Clausen 	{"ad5444", ID_AD5444},
441dbdc025bSLars-Peter Clausen 	{"ad5446", ID_AD5446},
442779c0c46SLars-Peter Clausen 	{"ad5450", ID_AD5450},
443779c0c46SLars-Peter Clausen 	{"ad5451", ID_AD5451},
444779c0c46SLars-Peter Clausen 	{"ad5452", ID_AD5444}, /* ad5452 is compatible to the ad5444 */
445779c0c46SLars-Peter Clausen 	{"ad5453", ID_AD5446}, /* ad5453 is compatible to the ad5446 */
446dbdc025bSLars-Peter Clausen 	{"ad5512a", ID_AD5512A},
447dbdc025bSLars-Peter Clausen 	{"ad5541a", ID_AD5541A},
448dbdc025bSLars-Peter Clausen 	{"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
449dbdc025bSLars-Peter Clausen 	{"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
450dbdc025bSLars-Peter Clausen 	{"ad5553", ID_AD5553},
451dbdc025bSLars-Peter Clausen 	{"ad5601", ID_AD5601},
452dbdc025bSLars-Peter Clausen 	{"ad5611", ID_AD5611},
453dbdc025bSLars-Peter Clausen 	{"ad5621", ID_AD5621},
4544fa2a9e4SAida Mynzhasova 	{"ad5641", ID_AD5641},
455dbdc025bSLars-Peter Clausen 	{"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */
456dbdc025bSLars-Peter Clausen 	{"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */
457dbdc025bSLars-Peter Clausen 	{"ad5640-2500", ID_AD5640_2500},
458dbdc025bSLars-Peter Clausen 	{"ad5640-1250", ID_AD5640_1250},
459dbdc025bSLars-Peter Clausen 	{"ad5660-2500", ID_AD5660_2500},
460dbdc025bSLars-Peter Clausen 	{"ad5660-1250", ID_AD5660_1250},
461dbdc025bSLars-Peter Clausen 	{"ad5662", ID_AD5662},
462dbdc025bSLars-Peter Clausen 	{}
463dbdc025bSLars-Peter Clausen };
4643ec36a2cSJean-Francois Dagenais MODULE_DEVICE_TABLE(spi, ad5446_spi_ids);
465dbdc025bSLars-Peter Clausen 
466fc52692cSGreg Kroah-Hartman static int ad5446_spi_probe(struct spi_device *spi)
4673ec36a2cSJean-Francois Dagenais {
4683ec36a2cSJean-Francois Dagenais 	const struct spi_device_id *id = spi_get_device_id(spi);
4693ec36a2cSJean-Francois Dagenais 
4703ec36a2cSJean-Francois Dagenais 	return ad5446_probe(&spi->dev, id->name,
4713ec36a2cSJean-Francois Dagenais 		&ad5446_spi_chip_info[id->driver_data]);
4723ec36a2cSJean-Francois Dagenais }
4733ec36a2cSJean-Francois Dagenais 
474fc52692cSGreg Kroah-Hartman static int ad5446_spi_remove(struct spi_device *spi)
4753ec36a2cSJean-Francois Dagenais {
4763ec36a2cSJean-Francois Dagenais 	return ad5446_remove(&spi->dev);
4773ec36a2cSJean-Francois Dagenais }
4783ec36a2cSJean-Francois Dagenais 
4793ec36a2cSJean-Francois Dagenais static struct spi_driver ad5446_spi_driver = {
480dbdc025bSLars-Peter Clausen 	.driver = {
481dbdc025bSLars-Peter Clausen 		.name	= "ad5446",
482dbdc025bSLars-Peter Clausen 		.owner	= THIS_MODULE,
483dbdc025bSLars-Peter Clausen 	},
4843ec36a2cSJean-Francois Dagenais 	.probe		= ad5446_spi_probe,
485fc52692cSGreg Kroah-Hartman 	.remove		= ad5446_spi_remove,
4863ec36a2cSJean-Francois Dagenais 	.id_table	= ad5446_spi_ids,
487dbdc025bSLars-Peter Clausen };
4883ec36a2cSJean-Francois Dagenais 
4893ec36a2cSJean-Francois Dagenais static int __init ad5446_spi_register_driver(void)
4903ec36a2cSJean-Francois Dagenais {
4913ec36a2cSJean-Francois Dagenais 	return spi_register_driver(&ad5446_spi_driver);
4923ec36a2cSJean-Francois Dagenais }
4933ec36a2cSJean-Francois Dagenais 
4943ec36a2cSJean-Francois Dagenais static void ad5446_spi_unregister_driver(void)
4953ec36a2cSJean-Francois Dagenais {
4963ec36a2cSJean-Francois Dagenais 	spi_unregister_driver(&ad5446_spi_driver);
4973ec36a2cSJean-Francois Dagenais }
4983ec36a2cSJean-Francois Dagenais 
4993ec36a2cSJean-Francois Dagenais #else
5003ec36a2cSJean-Francois Dagenais 
5013ec36a2cSJean-Francois Dagenais static inline int ad5446_spi_register_driver(void) { return 0; }
5023ec36a2cSJean-Francois Dagenais static inline void ad5446_spi_unregister_driver(void) { }
5033ec36a2cSJean-Francois Dagenais 
5043ec36a2cSJean-Francois Dagenais #endif
5053ec36a2cSJean-Francois Dagenais 
5063ec36a2cSJean-Francois Dagenais #if IS_ENABLED(CONFIG_I2C)
5073ec36a2cSJean-Francois Dagenais 
5083ec36a2cSJean-Francois Dagenais static int ad5622_write(struct ad5446_state *st, unsigned val)
5093ec36a2cSJean-Francois Dagenais {
5103ec36a2cSJean-Francois Dagenais 	struct i2c_client *client = to_i2c_client(st->dev);
5113ec36a2cSJean-Francois Dagenais 	__be16 data = cpu_to_be16(val);
5123ec36a2cSJean-Francois Dagenais 
5133ec36a2cSJean-Francois Dagenais 	return i2c_master_send(client, (char *)&data, sizeof(data));
5143ec36a2cSJean-Francois Dagenais }
5153ec36a2cSJean-Francois Dagenais 
5163ec36a2cSJean-Francois Dagenais /**
5173ec36a2cSJean-Francois Dagenais  * ad5446_supported_i2c_device_ids:
5183ec36a2cSJean-Francois Dagenais  * The AD5620/40/60 parts are available in different fixed internal reference
5193ec36a2cSJean-Francois Dagenais  * voltage options. The actual part numbers may look differently
5203ec36a2cSJean-Francois Dagenais  * (and a bit cryptic), however this style is used to make clear which
5213ec36a2cSJean-Francois Dagenais  * parts are supported here.
5223ec36a2cSJean-Francois Dagenais  */
5233ec36a2cSJean-Francois Dagenais enum ad5446_supported_i2c_device_ids {
5243ec36a2cSJean-Francois Dagenais 	ID_AD5602,
5253ec36a2cSJean-Francois Dagenais 	ID_AD5612,
5263ec36a2cSJean-Francois Dagenais 	ID_AD5622,
5273ec36a2cSJean-Francois Dagenais };
5283ec36a2cSJean-Francois Dagenais 
5293ec36a2cSJean-Francois Dagenais static const struct ad5446_chip_info ad5446_i2c_chip_info[] = {
5303ec36a2cSJean-Francois Dagenais 	[ID_AD5602] = {
5313ec36a2cSJean-Francois Dagenais 		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4),
5323ec36a2cSJean-Francois Dagenais 		.write = ad5622_write,
5333ec36a2cSJean-Francois Dagenais 	},
5343ec36a2cSJean-Francois Dagenais 	[ID_AD5612] = {
5353ec36a2cSJean-Francois Dagenais 		.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2),
5363ec36a2cSJean-Francois Dagenais 		.write = ad5622_write,
5373ec36a2cSJean-Francois Dagenais 	},
5383ec36a2cSJean-Francois Dagenais 	[ID_AD5622] = {
5393ec36a2cSJean-Francois Dagenais 		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0),
5403ec36a2cSJean-Francois Dagenais 		.write = ad5622_write,
5413ec36a2cSJean-Francois Dagenais 	},
5423ec36a2cSJean-Francois Dagenais };
5433ec36a2cSJean-Francois Dagenais 
544fc52692cSGreg Kroah-Hartman static int ad5446_i2c_probe(struct i2c_client *i2c,
5453ec36a2cSJean-Francois Dagenais 			    const struct i2c_device_id *id)
5463ec36a2cSJean-Francois Dagenais {
5473ec36a2cSJean-Francois Dagenais 	return ad5446_probe(&i2c->dev, id->name,
5483ec36a2cSJean-Francois Dagenais 		&ad5446_i2c_chip_info[id->driver_data]);
5493ec36a2cSJean-Francois Dagenais }
5503ec36a2cSJean-Francois Dagenais 
551fc52692cSGreg Kroah-Hartman static int ad5446_i2c_remove(struct i2c_client *i2c)
5523ec36a2cSJean-Francois Dagenais {
5533ec36a2cSJean-Francois Dagenais 	return ad5446_remove(&i2c->dev);
5543ec36a2cSJean-Francois Dagenais }
5553ec36a2cSJean-Francois Dagenais 
5563ec36a2cSJean-Francois Dagenais static const struct i2c_device_id ad5446_i2c_ids[] = {
557bf832380SLars-Peter Clausen 	{"ad5301", ID_AD5602},
558bf832380SLars-Peter Clausen 	{"ad5311", ID_AD5612},
559bf832380SLars-Peter Clausen 	{"ad5321", ID_AD5622},
5603ec36a2cSJean-Francois Dagenais 	{"ad5602", ID_AD5602},
5613ec36a2cSJean-Francois Dagenais 	{"ad5612", ID_AD5612},
5623ec36a2cSJean-Francois Dagenais 	{"ad5622", ID_AD5622},
5633ec36a2cSJean-Francois Dagenais 	{}
5643ec36a2cSJean-Francois Dagenais };
5653ec36a2cSJean-Francois Dagenais MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids);
5663ec36a2cSJean-Francois Dagenais 
5673ec36a2cSJean-Francois Dagenais static struct i2c_driver ad5446_i2c_driver = {
5683ec36a2cSJean-Francois Dagenais 	.driver = {
5693ec36a2cSJean-Francois Dagenais 		   .name = "ad5446",
5703ec36a2cSJean-Francois Dagenais 		   .owner = THIS_MODULE,
5713ec36a2cSJean-Francois Dagenais 	},
5723ec36a2cSJean-Francois Dagenais 	.probe = ad5446_i2c_probe,
573fc52692cSGreg Kroah-Hartman 	.remove = ad5446_i2c_remove,
5743ec36a2cSJean-Francois Dagenais 	.id_table = ad5446_i2c_ids,
5753ec36a2cSJean-Francois Dagenais };
5763ec36a2cSJean-Francois Dagenais 
5773ec36a2cSJean-Francois Dagenais static int __init ad5446_i2c_register_driver(void)
5783ec36a2cSJean-Francois Dagenais {
5793ec36a2cSJean-Francois Dagenais 	return i2c_add_driver(&ad5446_i2c_driver);
5803ec36a2cSJean-Francois Dagenais }
5813ec36a2cSJean-Francois Dagenais 
5823ec36a2cSJean-Francois Dagenais static void __exit ad5446_i2c_unregister_driver(void)
5833ec36a2cSJean-Francois Dagenais {
5843ec36a2cSJean-Francois Dagenais 	i2c_del_driver(&ad5446_i2c_driver);
5853ec36a2cSJean-Francois Dagenais }
5863ec36a2cSJean-Francois Dagenais 
5873ec36a2cSJean-Francois Dagenais #else
5883ec36a2cSJean-Francois Dagenais 
5893ec36a2cSJean-Francois Dagenais static inline int ad5446_i2c_register_driver(void) { return 0; }
5903ec36a2cSJean-Francois Dagenais static inline void ad5446_i2c_unregister_driver(void) { }
5913ec36a2cSJean-Francois Dagenais 
5923ec36a2cSJean-Francois Dagenais #endif
5933ec36a2cSJean-Francois Dagenais 
5943ec36a2cSJean-Francois Dagenais static int __init ad5446_init(void)
5953ec36a2cSJean-Francois Dagenais {
5963ec36a2cSJean-Francois Dagenais 	int ret;
5973ec36a2cSJean-Francois Dagenais 
5983ec36a2cSJean-Francois Dagenais 	ret = ad5446_spi_register_driver();
5993ec36a2cSJean-Francois Dagenais 	if (ret)
6003ec36a2cSJean-Francois Dagenais 		return ret;
6013ec36a2cSJean-Francois Dagenais 
6023ec36a2cSJean-Francois Dagenais 	ret = ad5446_i2c_register_driver();
6033ec36a2cSJean-Francois Dagenais 	if (ret) {
6043ec36a2cSJean-Francois Dagenais 		ad5446_spi_unregister_driver();
6053ec36a2cSJean-Francois Dagenais 		return ret;
6063ec36a2cSJean-Francois Dagenais 	}
6073ec36a2cSJean-Francois Dagenais 
6083ec36a2cSJean-Francois Dagenais 	return 0;
6093ec36a2cSJean-Francois Dagenais }
6103ec36a2cSJean-Francois Dagenais module_init(ad5446_init);
6113ec36a2cSJean-Francois Dagenais 
6123ec36a2cSJean-Francois Dagenais static void __exit ad5446_exit(void)
6133ec36a2cSJean-Francois Dagenais {
6143ec36a2cSJean-Francois Dagenais 	ad5446_i2c_unregister_driver();
6153ec36a2cSJean-Francois Dagenais 	ad5446_spi_unregister_driver();
6163ec36a2cSJean-Francois Dagenais }
6173ec36a2cSJean-Francois Dagenais module_exit(ad5446_exit);
618dbdc025bSLars-Peter Clausen 
619dbdc025bSLars-Peter Clausen MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
620dbdc025bSLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
621dbdc025bSLars-Peter Clausen MODULE_LICENSE("GPL v2");
622