xref: /kernel/linux/linux-6.6/drivers/iio/dac/ltc2632.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * LTC2632 Digital to analog convertors spi driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2017 Maxime Roussin-Bélanger
662306a36Sopenharmony_ci * expanded by Silvan Murer <silvan.murer@gmail.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/spi/spi.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/iio/iio.h>
1362306a36Sopenharmony_ci#include <linux/property.h>
1462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <asm/unaligned.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define LTC2632_CMD_WRITE_INPUT_N               0x0
1962306a36Sopenharmony_ci#define LTC2632_CMD_UPDATE_DAC_N                0x1
2062306a36Sopenharmony_ci#define LTC2632_CMD_WRITE_INPUT_N_UPDATE_ALL    0x2
2162306a36Sopenharmony_ci#define LTC2632_CMD_WRITE_INPUT_N_UPDATE_N      0x3
2262306a36Sopenharmony_ci#define LTC2632_CMD_POWERDOWN_DAC_N             0x4
2362306a36Sopenharmony_ci#define LTC2632_CMD_POWERDOWN_CHIP              0x5
2462306a36Sopenharmony_ci#define LTC2632_CMD_INTERNAL_REFER              0x6
2562306a36Sopenharmony_ci#define LTC2632_CMD_EXTERNAL_REFER              0x7
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/**
2862306a36Sopenharmony_ci * struct ltc2632_chip_info - chip specific information
2962306a36Sopenharmony_ci * @channels:		channel spec for the DAC
3062306a36Sopenharmony_ci * @num_channels:	DAC channel count of the chip
3162306a36Sopenharmony_ci * @vref_mv:		internal reference voltage
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_cistruct ltc2632_chip_info {
3462306a36Sopenharmony_ci	const struct iio_chan_spec *channels;
3562306a36Sopenharmony_ci	const size_t num_channels;
3662306a36Sopenharmony_ci	const int vref_mv;
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/**
4062306a36Sopenharmony_ci * struct ltc2632_state - driver instance specific data
4162306a36Sopenharmony_ci * @spi_dev:			pointer to the spi_device struct
4262306a36Sopenharmony_ci * @powerdown_cache_mask:	used to show current channel powerdown state
4362306a36Sopenharmony_ci * @vref_mv:			used reference voltage (internal or external)
4462306a36Sopenharmony_ci * @vref_reg:		regulator for the reference voltage
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_cistruct ltc2632_state {
4762306a36Sopenharmony_ci	struct spi_device *spi_dev;
4862306a36Sopenharmony_ci	unsigned int powerdown_cache_mask;
4962306a36Sopenharmony_ci	int vref_mv;
5062306a36Sopenharmony_ci	struct regulator *vref_reg;
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cienum ltc2632_supported_device_ids {
5462306a36Sopenharmony_ci	ID_LTC2632L12,
5562306a36Sopenharmony_ci	ID_LTC2632L10,
5662306a36Sopenharmony_ci	ID_LTC2632L8,
5762306a36Sopenharmony_ci	ID_LTC2632H12,
5862306a36Sopenharmony_ci	ID_LTC2632H10,
5962306a36Sopenharmony_ci	ID_LTC2632H8,
6062306a36Sopenharmony_ci	ID_LTC2634L12,
6162306a36Sopenharmony_ci	ID_LTC2634L10,
6262306a36Sopenharmony_ci	ID_LTC2634L8,
6362306a36Sopenharmony_ci	ID_LTC2634H12,
6462306a36Sopenharmony_ci	ID_LTC2634H10,
6562306a36Sopenharmony_ci	ID_LTC2634H8,
6662306a36Sopenharmony_ci	ID_LTC2636L12,
6762306a36Sopenharmony_ci	ID_LTC2636L10,
6862306a36Sopenharmony_ci	ID_LTC2636L8,
6962306a36Sopenharmony_ci	ID_LTC2636H12,
7062306a36Sopenharmony_ci	ID_LTC2636H10,
7162306a36Sopenharmony_ci	ID_LTC2636H8,
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int ltc2632_spi_write(struct spi_device *spi,
7562306a36Sopenharmony_ci			     u8 cmd, u8 addr, u16 val, u8 shift)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	u32 data;
7862306a36Sopenharmony_ci	u8 msg[3];
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/*
8162306a36Sopenharmony_ci	 * The input shift register is 24 bits wide.
8262306a36Sopenharmony_ci	 * The next four are the command bits, C3 to C0,
8362306a36Sopenharmony_ci	 * followed by the 4-bit DAC address, A3 to A0, and then the
8462306a36Sopenharmony_ci	 * 12-, 10-, 8-bit data-word. The data-word comprises the 12-,
8562306a36Sopenharmony_ci	 * 10-, 8-bit input code followed by 4, 6, or 8 don't care bits.
8662306a36Sopenharmony_ci	 */
8762306a36Sopenharmony_ci	data = (cmd << 20) | (addr << 16) | (val << shift);
8862306a36Sopenharmony_ci	put_unaligned_be24(data, &msg[0]);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return spi_write(spi, msg, sizeof(msg));
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int ltc2632_read_raw(struct iio_dev *indio_dev,
9462306a36Sopenharmony_ci			    struct iio_chan_spec const *chan,
9562306a36Sopenharmony_ci			    int *val,
9662306a36Sopenharmony_ci			    int *val2,
9762306a36Sopenharmony_ci			    long m)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	const struct ltc2632_state *st = iio_priv(indio_dev);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	switch (m) {
10262306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
10362306a36Sopenharmony_ci		*val = st->vref_mv;
10462306a36Sopenharmony_ci		*val2 = chan->scan_type.realbits;
10562306a36Sopenharmony_ci		return IIO_VAL_FRACTIONAL_LOG2;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci	return -EINVAL;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic int ltc2632_write_raw(struct iio_dev *indio_dev,
11162306a36Sopenharmony_ci			     struct iio_chan_spec const *chan,
11262306a36Sopenharmony_ci			     int val,
11362306a36Sopenharmony_ci			     int val2,
11462306a36Sopenharmony_ci			     long mask)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct ltc2632_state *st = iio_priv(indio_dev);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	switch (mask) {
11962306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
12062306a36Sopenharmony_ci		if (val >= (1 << chan->scan_type.realbits) || val < 0)
12162306a36Sopenharmony_ci			return -EINVAL;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		return ltc2632_spi_write(st->spi_dev,
12462306a36Sopenharmony_ci					 LTC2632_CMD_WRITE_INPUT_N_UPDATE_N,
12562306a36Sopenharmony_ci					 chan->address, val,
12662306a36Sopenharmony_ci					 chan->scan_type.shift);
12762306a36Sopenharmony_ci	default:
12862306a36Sopenharmony_ci		return -EINVAL;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic ssize_t ltc2632_read_dac_powerdown(struct iio_dev *indio_dev,
13362306a36Sopenharmony_ci					  uintptr_t private,
13462306a36Sopenharmony_ci					  const struct iio_chan_spec *chan,
13562306a36Sopenharmony_ci					  char *buf)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct ltc2632_state *st = iio_priv(indio_dev);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n",
14062306a36Sopenharmony_ci			  !!(st->powerdown_cache_mask & (1 << chan->channel)));
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic ssize_t ltc2632_write_dac_powerdown(struct iio_dev *indio_dev,
14462306a36Sopenharmony_ci					   uintptr_t private,
14562306a36Sopenharmony_ci					   const struct iio_chan_spec *chan,
14662306a36Sopenharmony_ci					   const char *buf,
14762306a36Sopenharmony_ci					   size_t len)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	bool pwr_down;
15062306a36Sopenharmony_ci	int ret;
15162306a36Sopenharmony_ci	struct ltc2632_state *st = iio_priv(indio_dev);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	ret = kstrtobool(buf, &pwr_down);
15462306a36Sopenharmony_ci	if (ret)
15562306a36Sopenharmony_ci		return ret;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (pwr_down)
15862306a36Sopenharmony_ci		st->powerdown_cache_mask |= (1 << chan->channel);
15962306a36Sopenharmony_ci	else
16062306a36Sopenharmony_ci		st->powerdown_cache_mask &= ~(1 << chan->channel);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	ret = ltc2632_spi_write(st->spi_dev,
16362306a36Sopenharmony_ci				LTC2632_CMD_POWERDOWN_DAC_N,
16462306a36Sopenharmony_ci				chan->channel, 0, 0);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return ret ? ret : len;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic const struct iio_info ltc2632_info = {
17062306a36Sopenharmony_ci	.write_raw	= ltc2632_write_raw,
17162306a36Sopenharmony_ci	.read_raw	= ltc2632_read_raw,
17262306a36Sopenharmony_ci};
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic const struct iio_chan_spec_ext_info ltc2632_ext_info[] = {
17562306a36Sopenharmony_ci	{
17662306a36Sopenharmony_ci		.name = "powerdown",
17762306a36Sopenharmony_ci		.read = ltc2632_read_dac_powerdown,
17862306a36Sopenharmony_ci		.write = ltc2632_write_dac_powerdown,
17962306a36Sopenharmony_ci		.shared = IIO_SEPARATE,
18062306a36Sopenharmony_ci	},
18162306a36Sopenharmony_ci	{ },
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci#define LTC2632_CHANNEL(_chan, _bits) { \
18562306a36Sopenharmony_ci		.type = IIO_VOLTAGE, \
18662306a36Sopenharmony_ci		.indexed = 1, \
18762306a36Sopenharmony_ci		.output = 1, \
18862306a36Sopenharmony_ci		.channel = (_chan), \
18962306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
19062306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
19162306a36Sopenharmony_ci		.address = (_chan), \
19262306a36Sopenharmony_ci		.scan_type = { \
19362306a36Sopenharmony_ci			.realbits	= (_bits), \
19462306a36Sopenharmony_ci			.shift		= 16 - (_bits), \
19562306a36Sopenharmony_ci		}, \
19662306a36Sopenharmony_ci		.ext_info = ltc2632_ext_info, \
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#define DECLARE_LTC2632_CHANNELS(_name, _bits) \
20062306a36Sopenharmony_ci	const struct iio_chan_spec _name ## _channels[] = { \
20162306a36Sopenharmony_ci		LTC2632_CHANNEL(0, _bits), \
20262306a36Sopenharmony_ci		LTC2632_CHANNEL(1, _bits), \
20362306a36Sopenharmony_ci		LTC2632_CHANNEL(2, _bits), \
20462306a36Sopenharmony_ci		LTC2632_CHANNEL(3, _bits), \
20562306a36Sopenharmony_ci		LTC2632_CHANNEL(4, _bits), \
20662306a36Sopenharmony_ci		LTC2632_CHANNEL(5, _bits), \
20762306a36Sopenharmony_ci		LTC2632_CHANNEL(6, _bits), \
20862306a36Sopenharmony_ci		LTC2632_CHANNEL(7, _bits), \
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic DECLARE_LTC2632_CHANNELS(ltc2632x12, 12);
21262306a36Sopenharmony_cistatic DECLARE_LTC2632_CHANNELS(ltc2632x10, 10);
21362306a36Sopenharmony_cistatic DECLARE_LTC2632_CHANNELS(ltc2632x8, 8);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = {
21662306a36Sopenharmony_ci	[ID_LTC2632L12] = {
21762306a36Sopenharmony_ci		.channels	= ltc2632x12_channels,
21862306a36Sopenharmony_ci		.num_channels	= 2,
21962306a36Sopenharmony_ci		.vref_mv	= 2500,
22062306a36Sopenharmony_ci	},
22162306a36Sopenharmony_ci	[ID_LTC2632L10] = {
22262306a36Sopenharmony_ci		.channels	= ltc2632x10_channels,
22362306a36Sopenharmony_ci		.num_channels	= 2,
22462306a36Sopenharmony_ci		.vref_mv	= 2500,
22562306a36Sopenharmony_ci	},
22662306a36Sopenharmony_ci	[ID_LTC2632L8] =  {
22762306a36Sopenharmony_ci		.channels	= ltc2632x8_channels,
22862306a36Sopenharmony_ci		.num_channels	= 2,
22962306a36Sopenharmony_ci		.vref_mv	= 2500,
23062306a36Sopenharmony_ci	},
23162306a36Sopenharmony_ci	[ID_LTC2632H12] = {
23262306a36Sopenharmony_ci		.channels	= ltc2632x12_channels,
23362306a36Sopenharmony_ci		.num_channels	= 2,
23462306a36Sopenharmony_ci		.vref_mv	= 4096,
23562306a36Sopenharmony_ci	},
23662306a36Sopenharmony_ci	[ID_LTC2632H10] = {
23762306a36Sopenharmony_ci		.channels	= ltc2632x10_channels,
23862306a36Sopenharmony_ci		.num_channels	= 2,
23962306a36Sopenharmony_ci		.vref_mv	= 4096,
24062306a36Sopenharmony_ci	},
24162306a36Sopenharmony_ci	[ID_LTC2632H8] =  {
24262306a36Sopenharmony_ci		.channels	= ltc2632x8_channels,
24362306a36Sopenharmony_ci		.num_channels	= 2,
24462306a36Sopenharmony_ci		.vref_mv	= 4096,
24562306a36Sopenharmony_ci	},
24662306a36Sopenharmony_ci	[ID_LTC2634L12] = {
24762306a36Sopenharmony_ci		.channels	= ltc2632x12_channels,
24862306a36Sopenharmony_ci		.num_channels	= 4,
24962306a36Sopenharmony_ci		.vref_mv	= 2500,
25062306a36Sopenharmony_ci	},
25162306a36Sopenharmony_ci	[ID_LTC2634L10] = {
25262306a36Sopenharmony_ci		.channels	= ltc2632x10_channels,
25362306a36Sopenharmony_ci		.num_channels	= 4,
25462306a36Sopenharmony_ci		.vref_mv	= 2500,
25562306a36Sopenharmony_ci	},
25662306a36Sopenharmony_ci	[ID_LTC2634L8] =  {
25762306a36Sopenharmony_ci		.channels	= ltc2632x8_channels,
25862306a36Sopenharmony_ci		.num_channels	= 4,
25962306a36Sopenharmony_ci		.vref_mv	= 2500,
26062306a36Sopenharmony_ci	},
26162306a36Sopenharmony_ci	[ID_LTC2634H12] = {
26262306a36Sopenharmony_ci		.channels	= ltc2632x12_channels,
26362306a36Sopenharmony_ci		.num_channels	= 4,
26462306a36Sopenharmony_ci		.vref_mv	= 4096,
26562306a36Sopenharmony_ci	},
26662306a36Sopenharmony_ci	[ID_LTC2634H10] = {
26762306a36Sopenharmony_ci		.channels	= ltc2632x10_channels,
26862306a36Sopenharmony_ci		.num_channels	= 4,
26962306a36Sopenharmony_ci		.vref_mv	= 4096,
27062306a36Sopenharmony_ci	},
27162306a36Sopenharmony_ci	[ID_LTC2634H8] =  {
27262306a36Sopenharmony_ci		.channels	= ltc2632x8_channels,
27362306a36Sopenharmony_ci		.num_channels	= 4,
27462306a36Sopenharmony_ci		.vref_mv	= 4096,
27562306a36Sopenharmony_ci	},
27662306a36Sopenharmony_ci	[ID_LTC2636L12] = {
27762306a36Sopenharmony_ci		.channels	= ltc2632x12_channels,
27862306a36Sopenharmony_ci		.num_channels	= 8,
27962306a36Sopenharmony_ci		.vref_mv	= 2500,
28062306a36Sopenharmony_ci	},
28162306a36Sopenharmony_ci	[ID_LTC2636L10] = {
28262306a36Sopenharmony_ci		.channels	= ltc2632x10_channels,
28362306a36Sopenharmony_ci		.num_channels	= 8,
28462306a36Sopenharmony_ci		.vref_mv	= 2500,
28562306a36Sopenharmony_ci	},
28662306a36Sopenharmony_ci	[ID_LTC2636L8] =  {
28762306a36Sopenharmony_ci		.channels	= ltc2632x8_channels,
28862306a36Sopenharmony_ci		.num_channels	= 8,
28962306a36Sopenharmony_ci		.vref_mv	= 2500,
29062306a36Sopenharmony_ci	},
29162306a36Sopenharmony_ci	[ID_LTC2636H12] = {
29262306a36Sopenharmony_ci		.channels	= ltc2632x12_channels,
29362306a36Sopenharmony_ci		.num_channels	= 8,
29462306a36Sopenharmony_ci		.vref_mv	= 4096,
29562306a36Sopenharmony_ci	},
29662306a36Sopenharmony_ci	[ID_LTC2636H10] = {
29762306a36Sopenharmony_ci		.channels	= ltc2632x10_channels,
29862306a36Sopenharmony_ci		.num_channels	= 8,
29962306a36Sopenharmony_ci		.vref_mv	= 4096,
30062306a36Sopenharmony_ci	},
30162306a36Sopenharmony_ci	[ID_LTC2636H8] =  {
30262306a36Sopenharmony_ci		.channels	= ltc2632x8_channels,
30362306a36Sopenharmony_ci		.num_channels	= 8,
30462306a36Sopenharmony_ci		.vref_mv	= 4096,
30562306a36Sopenharmony_ci	},
30662306a36Sopenharmony_ci};
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int ltc2632_probe(struct spi_device *spi)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct ltc2632_state *st;
31162306a36Sopenharmony_ci	struct iio_dev *indio_dev;
31262306a36Sopenharmony_ci	struct ltc2632_chip_info *chip_info;
31362306a36Sopenharmony_ci	int ret;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
31662306a36Sopenharmony_ci	if (!indio_dev)
31762306a36Sopenharmony_ci		return -ENOMEM;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	st = iio_priv(indio_dev);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	spi_set_drvdata(spi, indio_dev);
32262306a36Sopenharmony_ci	st->spi_dev = spi;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	chip_info = (struct ltc2632_chip_info *)
32562306a36Sopenharmony_ci			spi_get_device_id(spi)->driver_data;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
32862306a36Sopenharmony_ci	if (PTR_ERR(st->vref_reg) == -ENODEV) {
32962306a36Sopenharmony_ci		/* use internal reference voltage */
33062306a36Sopenharmony_ci		st->vref_reg = NULL;
33162306a36Sopenharmony_ci		st->vref_mv = chip_info->vref_mv;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER,
33462306a36Sopenharmony_ci				0, 0, 0);
33562306a36Sopenharmony_ci		if (ret) {
33662306a36Sopenharmony_ci			dev_err(&spi->dev,
33762306a36Sopenharmony_ci				"Set internal reference command failed, %d\n",
33862306a36Sopenharmony_ci				ret);
33962306a36Sopenharmony_ci			return ret;
34062306a36Sopenharmony_ci		}
34162306a36Sopenharmony_ci	} else if (IS_ERR(st->vref_reg)) {
34262306a36Sopenharmony_ci		dev_err(&spi->dev,
34362306a36Sopenharmony_ci				"Error getting voltage reference regulator\n");
34462306a36Sopenharmony_ci		return PTR_ERR(st->vref_reg);
34562306a36Sopenharmony_ci	} else {
34662306a36Sopenharmony_ci		/* use external reference voltage */
34762306a36Sopenharmony_ci		ret = regulator_enable(st->vref_reg);
34862306a36Sopenharmony_ci		if (ret) {
34962306a36Sopenharmony_ci			dev_err(&spi->dev,
35062306a36Sopenharmony_ci				"enable reference regulator failed, %d\n",
35162306a36Sopenharmony_ci				ret);
35262306a36Sopenharmony_ci			return ret;
35362306a36Sopenharmony_ci		}
35462306a36Sopenharmony_ci		st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER,
35762306a36Sopenharmony_ci				0, 0, 0);
35862306a36Sopenharmony_ci		if (ret) {
35962306a36Sopenharmony_ci			dev_err(&spi->dev,
36062306a36Sopenharmony_ci				"Set external reference command failed, %d\n",
36162306a36Sopenharmony_ci				ret);
36262306a36Sopenharmony_ci			return ret;
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	indio_dev->name = fwnode_get_name(dev_fwnode(&spi->dev)) ?: spi_get_device_id(spi)->name;
36762306a36Sopenharmony_ci	indio_dev->info = &ltc2632_info;
36862306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
36962306a36Sopenharmony_ci	indio_dev->channels = chip_info->channels;
37062306a36Sopenharmony_ci	indio_dev->num_channels = chip_info->num_channels;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	return iio_device_register(indio_dev);
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic void ltc2632_remove(struct spi_device *spi)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	struct iio_dev *indio_dev = spi_get_drvdata(spi);
37862306a36Sopenharmony_ci	struct ltc2632_state *st = iio_priv(indio_dev);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if (st->vref_reg)
38362306a36Sopenharmony_ci		regulator_disable(st->vref_reg);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic const struct spi_device_id ltc2632_id[] = {
38762306a36Sopenharmony_ci	{ "ltc2632-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L12] },
38862306a36Sopenharmony_ci	{ "ltc2632-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L10] },
38962306a36Sopenharmony_ci	{ "ltc2632-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L8] },
39062306a36Sopenharmony_ci	{ "ltc2632-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H12] },
39162306a36Sopenharmony_ci	{ "ltc2632-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H10] },
39262306a36Sopenharmony_ci	{ "ltc2632-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H8] },
39362306a36Sopenharmony_ci	{ "ltc2634-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L12] },
39462306a36Sopenharmony_ci	{ "ltc2634-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L10] },
39562306a36Sopenharmony_ci	{ "ltc2634-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L8] },
39662306a36Sopenharmony_ci	{ "ltc2634-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H12] },
39762306a36Sopenharmony_ci	{ "ltc2634-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H10] },
39862306a36Sopenharmony_ci	{ "ltc2634-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H8] },
39962306a36Sopenharmony_ci	{ "ltc2636-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L12] },
40062306a36Sopenharmony_ci	{ "ltc2636-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L10] },
40162306a36Sopenharmony_ci	{ "ltc2636-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L8] },
40262306a36Sopenharmony_ci	{ "ltc2636-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H12] },
40362306a36Sopenharmony_ci	{ "ltc2636-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H10] },
40462306a36Sopenharmony_ci	{ "ltc2636-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H8] },
40562306a36Sopenharmony_ci	{}
40662306a36Sopenharmony_ci};
40762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ltc2632_id);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic const struct of_device_id ltc2632_of_match[] = {
41062306a36Sopenharmony_ci	{
41162306a36Sopenharmony_ci		.compatible = "lltc,ltc2632-l12",
41262306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2632L12]
41362306a36Sopenharmony_ci	}, {
41462306a36Sopenharmony_ci		.compatible = "lltc,ltc2632-l10",
41562306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2632L10]
41662306a36Sopenharmony_ci	}, {
41762306a36Sopenharmony_ci		.compatible = "lltc,ltc2632-l8",
41862306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2632L8]
41962306a36Sopenharmony_ci	}, {
42062306a36Sopenharmony_ci		.compatible = "lltc,ltc2632-h12",
42162306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2632H12]
42262306a36Sopenharmony_ci	}, {
42362306a36Sopenharmony_ci		.compatible = "lltc,ltc2632-h10",
42462306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2632H10]
42562306a36Sopenharmony_ci	}, {
42662306a36Sopenharmony_ci		.compatible = "lltc,ltc2632-h8",
42762306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2632H8]
42862306a36Sopenharmony_ci	}, {
42962306a36Sopenharmony_ci		.compatible = "lltc,ltc2634-l12",
43062306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2634L12]
43162306a36Sopenharmony_ci	}, {
43262306a36Sopenharmony_ci		.compatible = "lltc,ltc2634-l10",
43362306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2634L10]
43462306a36Sopenharmony_ci	}, {
43562306a36Sopenharmony_ci		.compatible = "lltc,ltc2634-l8",
43662306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2634L8]
43762306a36Sopenharmony_ci	}, {
43862306a36Sopenharmony_ci		.compatible = "lltc,ltc2634-h12",
43962306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2634H12]
44062306a36Sopenharmony_ci	}, {
44162306a36Sopenharmony_ci		.compatible = "lltc,ltc2634-h10",
44262306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2634H10]
44362306a36Sopenharmony_ci	}, {
44462306a36Sopenharmony_ci		.compatible = "lltc,ltc2634-h8",
44562306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2634H8]
44662306a36Sopenharmony_ci	}, {
44762306a36Sopenharmony_ci		.compatible = "lltc,ltc2636-l12",
44862306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2636L12]
44962306a36Sopenharmony_ci	}, {
45062306a36Sopenharmony_ci		.compatible = "lltc,ltc2636-l10",
45162306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2636L10]
45262306a36Sopenharmony_ci	}, {
45362306a36Sopenharmony_ci		.compatible = "lltc,ltc2636-l8",
45462306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2636L8]
45562306a36Sopenharmony_ci	}, {
45662306a36Sopenharmony_ci		.compatible = "lltc,ltc2636-h12",
45762306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2636H12]
45862306a36Sopenharmony_ci	}, {
45962306a36Sopenharmony_ci		.compatible = "lltc,ltc2636-h10",
46062306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2636H10]
46162306a36Sopenharmony_ci	}, {
46262306a36Sopenharmony_ci		.compatible = "lltc,ltc2636-h8",
46362306a36Sopenharmony_ci		.data = &ltc2632_chip_info_tbl[ID_LTC2636H8]
46462306a36Sopenharmony_ci	},
46562306a36Sopenharmony_ci	{}
46662306a36Sopenharmony_ci};
46762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ltc2632_of_match);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic struct spi_driver ltc2632_driver = {
47062306a36Sopenharmony_ci	.driver		= {
47162306a36Sopenharmony_ci		.name	= "ltc2632",
47262306a36Sopenharmony_ci		.of_match_table = ltc2632_of_match,
47362306a36Sopenharmony_ci	},
47462306a36Sopenharmony_ci	.probe		= ltc2632_probe,
47562306a36Sopenharmony_ci	.remove		= ltc2632_remove,
47662306a36Sopenharmony_ci	.id_table	= ltc2632_id,
47762306a36Sopenharmony_ci};
47862306a36Sopenharmony_cimodule_spi_driver(ltc2632_driver);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ciMODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>");
48162306a36Sopenharmony_ciMODULE_DESCRIPTION("LTC2632 DAC SPI driver");
48262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
483