xref: /kernel/linux/linux-6.6/drivers/iio/dac/ad5380.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Analog devices AD5380, AD5381, AD5382, AD5383, AD5390, AD5391, AD5392
462306a36Sopenharmony_ci * multi-channel Digital to Analog Converters driver
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright 2011 Analog Devices Inc.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/i2c.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/spi/spi.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/sysfs.h>
1762306a36Sopenharmony_ci#include <linux/regmap.h>
1862306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/iio/iio.h>
2162306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define AD5380_REG_DATA(x)	(((x) << 2) | 3)
2462306a36Sopenharmony_ci#define AD5380_REG_OFFSET(x)	(((x) << 2) | 2)
2562306a36Sopenharmony_ci#define AD5380_REG_GAIN(x)	(((x) << 2) | 1)
2662306a36Sopenharmony_ci#define AD5380_REG_SF_PWR_DOWN	(8 << 2)
2762306a36Sopenharmony_ci#define AD5380_REG_SF_PWR_UP	(9 << 2)
2862306a36Sopenharmony_ci#define AD5380_REG_SF_CTRL	(12 << 2)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define AD5380_CTRL_PWR_DOWN_MODE_OFFSET	13
3162306a36Sopenharmony_ci#define AD5380_CTRL_INT_VREF_2V5		BIT(12)
3262306a36Sopenharmony_ci#define AD5380_CTRL_INT_VREF_EN			BIT(10)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/**
3562306a36Sopenharmony_ci * struct ad5380_chip_info - chip specific information
3662306a36Sopenharmony_ci * @channel_template:	channel specification template
3762306a36Sopenharmony_ci * @num_channels:	number of channels
3862306a36Sopenharmony_ci * @int_vref:		internal vref in uV
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_cistruct ad5380_chip_info {
4162306a36Sopenharmony_ci	struct iio_chan_spec	channel_template;
4262306a36Sopenharmony_ci	unsigned int		num_channels;
4362306a36Sopenharmony_ci	unsigned int		int_vref;
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/**
4762306a36Sopenharmony_ci * struct ad5380_state - driver instance specific data
4862306a36Sopenharmony_ci * @regmap:		regmap instance used by the device
4962306a36Sopenharmony_ci * @chip_info:		chip model specific constants, available modes etc
5062306a36Sopenharmony_ci * @vref_reg:		vref supply regulator
5162306a36Sopenharmony_ci * @vref:		actual reference voltage used in uA
5262306a36Sopenharmony_ci * @pwr_down:		whether the chip is currently in power down mode
5362306a36Sopenharmony_ci * @lock:		lock to protect the data buffer during regmap ops
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_cistruct ad5380_state {
5662306a36Sopenharmony_ci	struct regmap			*regmap;
5762306a36Sopenharmony_ci	const struct ad5380_chip_info	*chip_info;
5862306a36Sopenharmony_ci	struct regulator		*vref_reg;
5962306a36Sopenharmony_ci	int				vref;
6062306a36Sopenharmony_ci	bool				pwr_down;
6162306a36Sopenharmony_ci	struct mutex			lock;
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cienum ad5380_type {
6562306a36Sopenharmony_ci	ID_AD5380_3,
6662306a36Sopenharmony_ci	ID_AD5380_5,
6762306a36Sopenharmony_ci	ID_AD5381_3,
6862306a36Sopenharmony_ci	ID_AD5381_5,
6962306a36Sopenharmony_ci	ID_AD5382_3,
7062306a36Sopenharmony_ci	ID_AD5382_5,
7162306a36Sopenharmony_ci	ID_AD5383_3,
7262306a36Sopenharmony_ci	ID_AD5383_5,
7362306a36Sopenharmony_ci	ID_AD5390_3,
7462306a36Sopenharmony_ci	ID_AD5390_5,
7562306a36Sopenharmony_ci	ID_AD5391_3,
7662306a36Sopenharmony_ci	ID_AD5391_5,
7762306a36Sopenharmony_ci	ID_AD5392_3,
7862306a36Sopenharmony_ci	ID_AD5392_5,
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic ssize_t ad5380_read_dac_powerdown(struct iio_dev *indio_dev,
8262306a36Sopenharmony_ci	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct ad5380_state *st = iio_priv(indio_dev);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", st->pwr_down);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic ssize_t ad5380_write_dac_powerdown(struct iio_dev *indio_dev,
9062306a36Sopenharmony_ci	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
9162306a36Sopenharmony_ci	 size_t len)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct ad5380_state *st = iio_priv(indio_dev);
9462306a36Sopenharmony_ci	bool pwr_down;
9562306a36Sopenharmony_ci	int ret;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	ret = kstrtobool(buf, &pwr_down);
9862306a36Sopenharmony_ci	if (ret)
9962306a36Sopenharmony_ci		return ret;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	mutex_lock(&st->lock);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (pwr_down)
10462306a36Sopenharmony_ci		ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_DOWN, 0);
10562306a36Sopenharmony_ci	else
10662306a36Sopenharmony_ci		ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_UP, 0);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	st->pwr_down = pwr_down;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	mutex_unlock(&st->lock);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return ret ? ret : len;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic const char * const ad5380_powerdown_modes[] = {
11662306a36Sopenharmony_ci	"100kohm_to_gnd",
11762306a36Sopenharmony_ci	"three_state",
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int ad5380_get_powerdown_mode(struct iio_dev *indio_dev,
12162306a36Sopenharmony_ci	const struct iio_chan_spec *chan)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct ad5380_state *st = iio_priv(indio_dev);
12462306a36Sopenharmony_ci	unsigned int mode;
12562306a36Sopenharmony_ci	int ret;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	ret = regmap_read(st->regmap, AD5380_REG_SF_CTRL, &mode);
12862306a36Sopenharmony_ci	if (ret)
12962306a36Sopenharmony_ci		return ret;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	mode = (mode >> AD5380_CTRL_PWR_DOWN_MODE_OFFSET) & 1;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return mode;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic int ad5380_set_powerdown_mode(struct iio_dev *indio_dev,
13762306a36Sopenharmony_ci	const struct iio_chan_spec *chan, unsigned int mode)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct ad5380_state *st = iio_priv(indio_dev);
14062306a36Sopenharmony_ci	int ret;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	ret = regmap_update_bits(st->regmap, AD5380_REG_SF_CTRL,
14362306a36Sopenharmony_ci		1 << AD5380_CTRL_PWR_DOWN_MODE_OFFSET,
14462306a36Sopenharmony_ci		mode << AD5380_CTRL_PWR_DOWN_MODE_OFFSET);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return ret;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic const struct iio_enum ad5380_powerdown_mode_enum = {
15062306a36Sopenharmony_ci	.items = ad5380_powerdown_modes,
15162306a36Sopenharmony_ci	.num_items = ARRAY_SIZE(ad5380_powerdown_modes),
15262306a36Sopenharmony_ci	.get = ad5380_get_powerdown_mode,
15362306a36Sopenharmony_ci	.set = ad5380_set_powerdown_mode,
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic unsigned int ad5380_info_to_reg(struct iio_chan_spec const *chan,
15762306a36Sopenharmony_ci	long info)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	switch (info) {
16062306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
16162306a36Sopenharmony_ci		return AD5380_REG_DATA(chan->address);
16262306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
16362306a36Sopenharmony_ci		return AD5380_REG_OFFSET(chan->address);
16462306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBSCALE:
16562306a36Sopenharmony_ci		return AD5380_REG_GAIN(chan->address);
16662306a36Sopenharmony_ci	default:
16762306a36Sopenharmony_ci		break;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return 0;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int ad5380_write_raw(struct iio_dev *indio_dev,
17462306a36Sopenharmony_ci	struct iio_chan_spec const *chan, int val, int val2, long info)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	const unsigned int max_val = (1 << chan->scan_type.realbits);
17762306a36Sopenharmony_ci	struct ad5380_state *st = iio_priv(indio_dev);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	switch (info) {
18062306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
18162306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBSCALE:
18262306a36Sopenharmony_ci		if (val >= max_val || val < 0)
18362306a36Sopenharmony_ci			return -EINVAL;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci		return regmap_write(st->regmap,
18662306a36Sopenharmony_ci			ad5380_info_to_reg(chan, info),
18762306a36Sopenharmony_ci			val << chan->scan_type.shift);
18862306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
18962306a36Sopenharmony_ci		val += (1 << chan->scan_type.realbits) / 2;
19062306a36Sopenharmony_ci		if (val >= max_val || val < 0)
19162306a36Sopenharmony_ci			return -EINVAL;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		return regmap_write(st->regmap,
19462306a36Sopenharmony_ci			AD5380_REG_OFFSET(chan->address),
19562306a36Sopenharmony_ci			val << chan->scan_type.shift);
19662306a36Sopenharmony_ci	default:
19762306a36Sopenharmony_ci		break;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci	return -EINVAL;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic int ad5380_read_raw(struct iio_dev *indio_dev,
20362306a36Sopenharmony_ci	struct iio_chan_spec const *chan, int *val, int *val2, long info)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct ad5380_state *st = iio_priv(indio_dev);
20662306a36Sopenharmony_ci	int ret;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	switch (info) {
20962306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
21062306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBSCALE:
21162306a36Sopenharmony_ci		ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info),
21262306a36Sopenharmony_ci					val);
21362306a36Sopenharmony_ci		if (ret)
21462306a36Sopenharmony_ci			return ret;
21562306a36Sopenharmony_ci		*val >>= chan->scan_type.shift;
21662306a36Sopenharmony_ci		return IIO_VAL_INT;
21762306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
21862306a36Sopenharmony_ci		ret = regmap_read(st->regmap, AD5380_REG_OFFSET(chan->address),
21962306a36Sopenharmony_ci					val);
22062306a36Sopenharmony_ci		if (ret)
22162306a36Sopenharmony_ci			return ret;
22262306a36Sopenharmony_ci		*val >>= chan->scan_type.shift;
22362306a36Sopenharmony_ci		*val -= (1 << chan->scan_type.realbits) / 2;
22462306a36Sopenharmony_ci		return IIO_VAL_INT;
22562306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
22662306a36Sopenharmony_ci		*val = 2 * st->vref;
22762306a36Sopenharmony_ci		*val2 = chan->scan_type.realbits;
22862306a36Sopenharmony_ci		return IIO_VAL_FRACTIONAL_LOG2;
22962306a36Sopenharmony_ci	default:
23062306a36Sopenharmony_ci		break;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	return -EINVAL;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic const struct iio_info ad5380_info = {
23762306a36Sopenharmony_ci	.read_raw = ad5380_read_raw,
23862306a36Sopenharmony_ci	.write_raw = ad5380_write_raw,
23962306a36Sopenharmony_ci};
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic const struct iio_chan_spec_ext_info ad5380_ext_info[] = {
24262306a36Sopenharmony_ci	{
24362306a36Sopenharmony_ci		.name = "powerdown",
24462306a36Sopenharmony_ci		.read = ad5380_read_dac_powerdown,
24562306a36Sopenharmony_ci		.write = ad5380_write_dac_powerdown,
24662306a36Sopenharmony_ci		.shared = IIO_SEPARATE,
24762306a36Sopenharmony_ci	},
24862306a36Sopenharmony_ci	IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
24962306a36Sopenharmony_ci		 &ad5380_powerdown_mode_enum),
25062306a36Sopenharmony_ci	IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5380_powerdown_mode_enum),
25162306a36Sopenharmony_ci	{ },
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci#define AD5380_CHANNEL(_bits) {					\
25562306a36Sopenharmony_ci	.type = IIO_VOLTAGE,					\
25662306a36Sopenharmony_ci	.indexed = 1,						\
25762306a36Sopenharmony_ci	.output = 1,						\
25862306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
25962306a36Sopenharmony_ci		BIT(IIO_CHAN_INFO_CALIBSCALE) |			\
26062306a36Sopenharmony_ci		BIT(IIO_CHAN_INFO_CALIBBIAS),			\
26162306a36Sopenharmony_ci	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
26262306a36Sopenharmony_ci	.scan_type = {						\
26362306a36Sopenharmony_ci		.sign = 'u',					\
26462306a36Sopenharmony_ci		.realbits = (_bits),				\
26562306a36Sopenharmony_ci		.storagebits =  16,				\
26662306a36Sopenharmony_ci		.shift = 14 - (_bits),				\
26762306a36Sopenharmony_ci	},							\
26862306a36Sopenharmony_ci	.ext_info = ad5380_ext_info,				\
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
27262306a36Sopenharmony_ci	[ID_AD5380_3] = {
27362306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(14),
27462306a36Sopenharmony_ci		.num_channels = 40,
27562306a36Sopenharmony_ci		.int_vref = 1250,
27662306a36Sopenharmony_ci	},
27762306a36Sopenharmony_ci	[ID_AD5380_5] = {
27862306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(14),
27962306a36Sopenharmony_ci		.num_channels = 40,
28062306a36Sopenharmony_ci		.int_vref = 2500,
28162306a36Sopenharmony_ci	},
28262306a36Sopenharmony_ci	[ID_AD5381_3] = {
28362306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(12),
28462306a36Sopenharmony_ci		.num_channels = 16,
28562306a36Sopenharmony_ci		.int_vref = 1250,
28662306a36Sopenharmony_ci	},
28762306a36Sopenharmony_ci	[ID_AD5381_5] = {
28862306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(12),
28962306a36Sopenharmony_ci		.num_channels = 16,
29062306a36Sopenharmony_ci		.int_vref = 2500,
29162306a36Sopenharmony_ci	},
29262306a36Sopenharmony_ci	[ID_AD5382_3] = {
29362306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(14),
29462306a36Sopenharmony_ci		.num_channels = 32,
29562306a36Sopenharmony_ci		.int_vref = 1250,
29662306a36Sopenharmony_ci	},
29762306a36Sopenharmony_ci	[ID_AD5382_5] = {
29862306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(14),
29962306a36Sopenharmony_ci		.num_channels = 32,
30062306a36Sopenharmony_ci		.int_vref = 2500,
30162306a36Sopenharmony_ci	},
30262306a36Sopenharmony_ci	[ID_AD5383_3] = {
30362306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(12),
30462306a36Sopenharmony_ci		.num_channels = 32,
30562306a36Sopenharmony_ci		.int_vref = 1250,
30662306a36Sopenharmony_ci	},
30762306a36Sopenharmony_ci	[ID_AD5383_5] = {
30862306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(12),
30962306a36Sopenharmony_ci		.num_channels = 32,
31062306a36Sopenharmony_ci		.int_vref = 2500,
31162306a36Sopenharmony_ci	},
31262306a36Sopenharmony_ci	[ID_AD5390_3] = {
31362306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(14),
31462306a36Sopenharmony_ci		.num_channels = 16,
31562306a36Sopenharmony_ci		.int_vref = 1250,
31662306a36Sopenharmony_ci	},
31762306a36Sopenharmony_ci	[ID_AD5390_5] = {
31862306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(14),
31962306a36Sopenharmony_ci		.num_channels = 16,
32062306a36Sopenharmony_ci		.int_vref = 2500,
32162306a36Sopenharmony_ci	},
32262306a36Sopenharmony_ci	[ID_AD5391_3] = {
32362306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(12),
32462306a36Sopenharmony_ci		.num_channels = 16,
32562306a36Sopenharmony_ci		.int_vref = 1250,
32662306a36Sopenharmony_ci	},
32762306a36Sopenharmony_ci	[ID_AD5391_5] = {
32862306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(12),
32962306a36Sopenharmony_ci		.num_channels = 16,
33062306a36Sopenharmony_ci		.int_vref = 2500,
33162306a36Sopenharmony_ci	},
33262306a36Sopenharmony_ci	[ID_AD5392_3] = {
33362306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(14),
33462306a36Sopenharmony_ci		.num_channels = 8,
33562306a36Sopenharmony_ci		.int_vref = 1250,
33662306a36Sopenharmony_ci	},
33762306a36Sopenharmony_ci	[ID_AD5392_5] = {
33862306a36Sopenharmony_ci		.channel_template = AD5380_CHANNEL(14),
33962306a36Sopenharmony_ci		.num_channels = 8,
34062306a36Sopenharmony_ci		.int_vref = 2500,
34162306a36Sopenharmony_ci	},
34262306a36Sopenharmony_ci};
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int ad5380_alloc_channels(struct iio_dev *indio_dev)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct ad5380_state *st = iio_priv(indio_dev);
34762306a36Sopenharmony_ci	struct iio_chan_spec *channels;
34862306a36Sopenharmony_ci	unsigned int i;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	channels = kcalloc(st->chip_info->num_channels,
35162306a36Sopenharmony_ci			   sizeof(struct iio_chan_spec), GFP_KERNEL);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (!channels)
35462306a36Sopenharmony_ci		return -ENOMEM;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	for (i = 0; i < st->chip_info->num_channels; ++i) {
35762306a36Sopenharmony_ci		channels[i] = st->chip_info->channel_template;
35862306a36Sopenharmony_ci		channels[i].channel = i;
35962306a36Sopenharmony_ci		channels[i].address = i;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	indio_dev->channels = channels;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	return 0;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic int ad5380_probe(struct device *dev, struct regmap *regmap,
36862306a36Sopenharmony_ci			enum ad5380_type type, const char *name)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct iio_dev *indio_dev;
37162306a36Sopenharmony_ci	struct ad5380_state *st;
37262306a36Sopenharmony_ci	unsigned int ctrl = 0;
37362306a36Sopenharmony_ci	int ret;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
37662306a36Sopenharmony_ci	if (indio_dev == NULL) {
37762306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate iio device\n");
37862306a36Sopenharmony_ci		return -ENOMEM;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	st = iio_priv(indio_dev);
38262306a36Sopenharmony_ci	dev_set_drvdata(dev, indio_dev);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	st->chip_info = &ad5380_chip_info_tbl[type];
38562306a36Sopenharmony_ci	st->regmap = regmap;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	indio_dev->name = name;
38862306a36Sopenharmony_ci	indio_dev->info = &ad5380_info;
38962306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
39062306a36Sopenharmony_ci	indio_dev->num_channels = st->chip_info->num_channels;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	mutex_init(&st->lock);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	ret = ad5380_alloc_channels(indio_dev);
39562306a36Sopenharmony_ci	if (ret) {
39662306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
39762306a36Sopenharmony_ci		return ret;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (st->chip_info->int_vref == 2500)
40162306a36Sopenharmony_ci		ctrl |= AD5380_CTRL_INT_VREF_2V5;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	st->vref_reg = devm_regulator_get(dev, "vref");
40462306a36Sopenharmony_ci	if (!IS_ERR(st->vref_reg)) {
40562306a36Sopenharmony_ci		ret = regulator_enable(st->vref_reg);
40662306a36Sopenharmony_ci		if (ret) {
40762306a36Sopenharmony_ci			dev_err(dev, "Failed to enable vref regulators: %d\n",
40862306a36Sopenharmony_ci				ret);
40962306a36Sopenharmony_ci			goto error_free_reg;
41062306a36Sopenharmony_ci		}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		ret = regulator_get_voltage(st->vref_reg);
41362306a36Sopenharmony_ci		if (ret < 0)
41462306a36Sopenharmony_ci			goto error_disable_reg;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci		st->vref = ret / 1000;
41762306a36Sopenharmony_ci	} else {
41862306a36Sopenharmony_ci		st->vref = st->chip_info->int_vref;
41962306a36Sopenharmony_ci		ctrl |= AD5380_CTRL_INT_VREF_EN;
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl);
42362306a36Sopenharmony_ci	if (ret) {
42462306a36Sopenharmony_ci		dev_err(dev, "Failed to write to device: %d\n", ret);
42562306a36Sopenharmony_ci		goto error_disable_reg;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	ret = iio_device_register(indio_dev);
42962306a36Sopenharmony_ci	if (ret) {
43062306a36Sopenharmony_ci		dev_err(dev, "Failed to register iio device: %d\n", ret);
43162306a36Sopenharmony_ci		goto error_disable_reg;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return 0;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cierror_disable_reg:
43762306a36Sopenharmony_ci	if (!IS_ERR(st->vref_reg))
43862306a36Sopenharmony_ci		regulator_disable(st->vref_reg);
43962306a36Sopenharmony_cierror_free_reg:
44062306a36Sopenharmony_ci	kfree(indio_dev->channels);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return ret;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic void ad5380_remove(struct device *dev)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_get_drvdata(dev);
44862306a36Sopenharmony_ci	struct ad5380_state *st = iio_priv(indio_dev);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	kfree(indio_dev->channels);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (!IS_ERR(st->vref_reg))
45562306a36Sopenharmony_ci		regulator_disable(st->vref_reg);
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic bool ad5380_reg_false(struct device *dev, unsigned int reg)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	return false;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic const struct regmap_config ad5380_regmap_config = {
46462306a36Sopenharmony_ci	.reg_bits = 10,
46562306a36Sopenharmony_ci	.val_bits = 14,
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	.max_register = AD5380_REG_DATA(40),
46862306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	.volatile_reg = ad5380_reg_false,
47162306a36Sopenharmony_ci	.readable_reg = ad5380_reg_false,
47262306a36Sopenharmony_ci};
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SPI_MASTER)
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic int ad5380_spi_probe(struct spi_device *spi)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	const struct spi_device_id *id = spi_get_device_id(spi);
47962306a36Sopenharmony_ci	struct regmap *regmap;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	regmap = devm_regmap_init_spi(spi, &ad5380_regmap_config);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (IS_ERR(regmap))
48462306a36Sopenharmony_ci		return PTR_ERR(regmap);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name);
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic void ad5380_spi_remove(struct spi_device *spi)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	ad5380_remove(&spi->dev);
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic const struct spi_device_id ad5380_spi_ids[] = {
49562306a36Sopenharmony_ci	{ "ad5380-3", ID_AD5380_3 },
49662306a36Sopenharmony_ci	{ "ad5380-5", ID_AD5380_5 },
49762306a36Sopenharmony_ci	{ "ad5381-3", ID_AD5381_3 },
49862306a36Sopenharmony_ci	{ "ad5381-5", ID_AD5381_5 },
49962306a36Sopenharmony_ci	{ "ad5382-3", ID_AD5382_3 },
50062306a36Sopenharmony_ci	{ "ad5382-5", ID_AD5382_5 },
50162306a36Sopenharmony_ci	{ "ad5383-3", ID_AD5383_3 },
50262306a36Sopenharmony_ci	{ "ad5383-5", ID_AD5383_5 },
50362306a36Sopenharmony_ci	{ "ad5384-3", ID_AD5380_3 },
50462306a36Sopenharmony_ci	{ "ad5384-5", ID_AD5380_5 },
50562306a36Sopenharmony_ci	{ "ad5390-3", ID_AD5390_3 },
50662306a36Sopenharmony_ci	{ "ad5390-5", ID_AD5390_5 },
50762306a36Sopenharmony_ci	{ "ad5391-3", ID_AD5391_3 },
50862306a36Sopenharmony_ci	{ "ad5391-5", ID_AD5391_5 },
50962306a36Sopenharmony_ci	{ "ad5392-3", ID_AD5392_3 },
51062306a36Sopenharmony_ci	{ "ad5392-5", ID_AD5392_5 },
51162306a36Sopenharmony_ci	{ }
51262306a36Sopenharmony_ci};
51362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad5380_spi_ids);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic struct spi_driver ad5380_spi_driver = {
51662306a36Sopenharmony_ci	.driver = {
51762306a36Sopenharmony_ci		   .name = "ad5380",
51862306a36Sopenharmony_ci	},
51962306a36Sopenharmony_ci	.probe = ad5380_spi_probe,
52062306a36Sopenharmony_ci	.remove = ad5380_spi_remove,
52162306a36Sopenharmony_ci	.id_table = ad5380_spi_ids,
52262306a36Sopenharmony_ci};
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic inline int ad5380_spi_register_driver(void)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	return spi_register_driver(&ad5380_spi_driver);
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic inline void ad5380_spi_unregister_driver(void)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	spi_unregister_driver(&ad5380_spi_driver);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci#else
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic inline int ad5380_spi_register_driver(void)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	return 0;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic inline void ad5380_spi_unregister_driver(void)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci#endif
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C)
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic int ad5380_i2c_probe(struct i2c_client *i2c)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
55262306a36Sopenharmony_ci	struct regmap *regmap;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	regmap = devm_regmap_init_i2c(i2c, &ad5380_regmap_config);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (IS_ERR(regmap))
55762306a36Sopenharmony_ci		return PTR_ERR(regmap);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name);
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic void ad5380_i2c_remove(struct i2c_client *i2c)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	ad5380_remove(&i2c->dev);
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic const struct i2c_device_id ad5380_i2c_ids[] = {
56862306a36Sopenharmony_ci	{ "ad5380-3", ID_AD5380_3 },
56962306a36Sopenharmony_ci	{ "ad5380-5", ID_AD5380_5 },
57062306a36Sopenharmony_ci	{ "ad5381-3", ID_AD5381_3 },
57162306a36Sopenharmony_ci	{ "ad5381-5", ID_AD5381_5 },
57262306a36Sopenharmony_ci	{ "ad5382-3", ID_AD5382_3 },
57362306a36Sopenharmony_ci	{ "ad5382-5", ID_AD5382_5 },
57462306a36Sopenharmony_ci	{ "ad5383-3", ID_AD5383_3 },
57562306a36Sopenharmony_ci	{ "ad5383-5", ID_AD5383_5 },
57662306a36Sopenharmony_ci	{ "ad5384-3", ID_AD5380_3 },
57762306a36Sopenharmony_ci	{ "ad5384-5", ID_AD5380_5 },
57862306a36Sopenharmony_ci	{ "ad5390-3", ID_AD5390_3 },
57962306a36Sopenharmony_ci	{ "ad5390-5", ID_AD5390_5 },
58062306a36Sopenharmony_ci	{ "ad5391-3", ID_AD5391_3 },
58162306a36Sopenharmony_ci	{ "ad5391-5", ID_AD5391_5 },
58262306a36Sopenharmony_ci	{ "ad5392-3", ID_AD5392_3 },
58362306a36Sopenharmony_ci	{ "ad5392-5", ID_AD5392_5 },
58462306a36Sopenharmony_ci	{ }
58562306a36Sopenharmony_ci};
58662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic struct i2c_driver ad5380_i2c_driver = {
58962306a36Sopenharmony_ci	.driver = {
59062306a36Sopenharmony_ci		   .name = "ad5380",
59162306a36Sopenharmony_ci	},
59262306a36Sopenharmony_ci	.probe = ad5380_i2c_probe,
59362306a36Sopenharmony_ci	.remove = ad5380_i2c_remove,
59462306a36Sopenharmony_ci	.id_table = ad5380_i2c_ids,
59562306a36Sopenharmony_ci};
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic inline int ad5380_i2c_register_driver(void)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	return i2c_add_driver(&ad5380_i2c_driver);
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic inline void ad5380_i2c_unregister_driver(void)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	i2c_del_driver(&ad5380_i2c_driver);
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci#else
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic inline int ad5380_i2c_register_driver(void)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	return 0;
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic inline void ad5380_i2c_unregister_driver(void)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci#endif
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic int __init ad5380_spi_init(void)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	int ret;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	ret = ad5380_spi_register_driver();
62562306a36Sopenharmony_ci	if (ret)
62662306a36Sopenharmony_ci		return ret;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	ret = ad5380_i2c_register_driver();
62962306a36Sopenharmony_ci	if (ret) {
63062306a36Sopenharmony_ci		ad5380_spi_unregister_driver();
63162306a36Sopenharmony_ci		return ret;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	return 0;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_cimodule_init(ad5380_spi_init);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic void __exit ad5380_spi_exit(void)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	ad5380_i2c_unregister_driver();
64162306a36Sopenharmony_ci	ad5380_spi_unregister_driver();
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_cimodule_exit(ad5380_spi_exit);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
64762306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5380/81/82/83/84/90/91/92 DAC");
64862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
649