xref: /kernel/linux/linux-6.6/drivers/iio/dac/max5522.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Maxim MAX5522
462306a36Sopenharmony_ci * Dual, Ultra-Low-Power 10-Bit, Voltage-Output DACs
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright 2022 Timesys Corp.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1362306a36Sopenharmony_ci#include <linux/regmap.h>
1462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/spi/spi.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/iio/iio.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define MAX5522_MAX_ADDR	15
2162306a36Sopenharmony_ci#define MAX5522_CTRL_NONE	0
2262306a36Sopenharmony_ci#define MAX5522_CTRL_LOAD_IN_A	9
2362306a36Sopenharmony_ci#define MAX5522_CTRL_LOAD_IN_B	10
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define MAX5522_REG_DATA(x)	((x) + MAX5522_CTRL_LOAD_IN_A)
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct max5522_chip_info {
2862306a36Sopenharmony_ci	const char *name;
2962306a36Sopenharmony_ci	const struct iio_chan_spec *channels;
3062306a36Sopenharmony_ci	unsigned int num_channels;
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistruct max5522_state {
3462306a36Sopenharmony_ci	struct regmap *regmap;
3562306a36Sopenharmony_ci	const struct max5522_chip_info *chip_info;
3662306a36Sopenharmony_ci	unsigned short dac_cache[2];
3762306a36Sopenharmony_ci	struct regulator *vrefin_reg;
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define MAX5522_CHANNEL(chan) {	\
4162306a36Sopenharmony_ci	.type = IIO_VOLTAGE, \
4262306a36Sopenharmony_ci	.indexed = 1, \
4362306a36Sopenharmony_ci	.output = 1, \
4462306a36Sopenharmony_ci	.channel = chan, \
4562306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
4662306a36Sopenharmony_ci			      BIT(IIO_CHAN_INFO_SCALE), \
4762306a36Sopenharmony_ci	.scan_type = { \
4862306a36Sopenharmony_ci		.sign = 'u', \
4962306a36Sopenharmony_ci		.realbits = 10, \
5062306a36Sopenharmony_ci		.storagebits = 16, \
5162306a36Sopenharmony_ci		.shift = 2, \
5262306a36Sopenharmony_ci	} \
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic const struct iio_chan_spec max5522_channels[] = {
5662306a36Sopenharmony_ci	MAX5522_CHANNEL(0),
5762306a36Sopenharmony_ci	MAX5522_CHANNEL(1),
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cienum max5522_type {
6162306a36Sopenharmony_ci	ID_MAX5522,
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const struct max5522_chip_info max5522_chip_info_tbl[] = {
6562306a36Sopenharmony_ci	[ID_MAX5522] = {
6662306a36Sopenharmony_ci		.name = "max5522",
6762306a36Sopenharmony_ci		.channels = max5522_channels,
6862306a36Sopenharmony_ci		.num_channels = 2,
6962306a36Sopenharmony_ci	},
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic inline int max5522_info_to_reg(struct iio_chan_spec const *chan)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	return MAX5522_REG_DATA(chan->channel);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic int max5522_read_raw(struct iio_dev *indio_dev,
7862306a36Sopenharmony_ci			    struct iio_chan_spec const *chan,
7962306a36Sopenharmony_ci			    int *val, int *val2, long info)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	struct max5522_state *state = iio_priv(indio_dev);
8262306a36Sopenharmony_ci	int ret;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	switch (info) {
8562306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
8662306a36Sopenharmony_ci		*val = state->dac_cache[chan->channel];
8762306a36Sopenharmony_ci		return IIO_VAL_INT;
8862306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
8962306a36Sopenharmony_ci		ret = regulator_get_voltage(state->vrefin_reg);
9062306a36Sopenharmony_ci		if (ret < 0)
9162306a36Sopenharmony_ci			return -EINVAL;
9262306a36Sopenharmony_ci		*val = ret / 1000;
9362306a36Sopenharmony_ci		*val2 = 10;
9462306a36Sopenharmony_ci		return IIO_VAL_FRACTIONAL_LOG2;
9562306a36Sopenharmony_ci	default:
9662306a36Sopenharmony_ci		return -EINVAL;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return -EINVAL;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int max5522_write_raw(struct iio_dev *indio_dev,
10362306a36Sopenharmony_ci			     struct iio_chan_spec const *chan,
10462306a36Sopenharmony_ci			     int val, int val2, long info)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct max5522_state *state = iio_priv(indio_dev);
10762306a36Sopenharmony_ci	int rval;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (val > 1023 || val < 0)
11062306a36Sopenharmony_ci		return -EINVAL;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	rval = regmap_write(state->regmap, max5522_info_to_reg(chan),
11362306a36Sopenharmony_ci			    val << chan->scan_type.shift);
11462306a36Sopenharmony_ci	if (rval < 0)
11562306a36Sopenharmony_ci		return rval;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	state->dac_cache[chan->channel] = val;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const struct iio_info max5522_info = {
12362306a36Sopenharmony_ci	.read_raw = max5522_read_raw,
12462306a36Sopenharmony_ci	.write_raw = max5522_write_raw,
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const struct regmap_config max5522_regmap_config = {
12862306a36Sopenharmony_ci	.reg_bits = 4,
12962306a36Sopenharmony_ci	.val_bits = 12,
13062306a36Sopenharmony_ci	.max_register = MAX5522_MAX_ADDR,
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int max5522_spi_probe(struct spi_device *spi)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	const struct spi_device_id *id = spi_get_device_id(spi);
13662306a36Sopenharmony_ci	struct iio_dev *indio_dev;
13762306a36Sopenharmony_ci	struct max5522_state *state;
13862306a36Sopenharmony_ci	int ret;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
14162306a36Sopenharmony_ci	if (indio_dev == NULL) {
14262306a36Sopenharmony_ci		dev_err(&spi->dev, "failed to allocate iio device\n");
14362306a36Sopenharmony_ci		return  -ENOMEM;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	state = iio_priv(indio_dev);
14762306a36Sopenharmony_ci	state->chip_info = device_get_match_data(&spi->dev);
14862306a36Sopenharmony_ci	if (!state->chip_info) {
14962306a36Sopenharmony_ci		state->chip_info =
15062306a36Sopenharmony_ci			(struct max5522_chip_info *)(id->driver_data);
15162306a36Sopenharmony_ci		if (!state->chip_info)
15262306a36Sopenharmony_ci			return -EINVAL;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	state->vrefin_reg = devm_regulator_get(&spi->dev, "vrefin");
15662306a36Sopenharmony_ci	if (IS_ERR(state->vrefin_reg))
15762306a36Sopenharmony_ci		return dev_err_probe(&spi->dev, PTR_ERR(state->vrefin_reg),
15862306a36Sopenharmony_ci				     "Vrefin regulator not specified\n");
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	ret = regulator_enable(state->vrefin_reg);
16162306a36Sopenharmony_ci	if (ret) {
16262306a36Sopenharmony_ci		return dev_err_probe(&spi->dev, ret,
16362306a36Sopenharmony_ci				     "Failed to enable vref regulators\n");
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	state->regmap = devm_regmap_init_spi(spi, &max5522_regmap_config);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (IS_ERR(state->regmap))
16962306a36Sopenharmony_ci		return PTR_ERR(state->regmap);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	indio_dev->info = &max5522_info;
17262306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
17362306a36Sopenharmony_ci	indio_dev->channels = max5522_channels;
17462306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(max5522_channels);
17562306a36Sopenharmony_ci	indio_dev->name = max5522_chip_info_tbl[ID_MAX5522].name;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return devm_iio_device_register(&spi->dev, indio_dev);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic const struct spi_device_id max5522_ids[] = {
18162306a36Sopenharmony_ci	{ "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] },
18262306a36Sopenharmony_ci	{}
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, max5522_ids);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic const struct of_device_id max5522_of_match[] = {
18762306a36Sopenharmony_ci	{
18862306a36Sopenharmony_ci		.compatible = "maxim,max5522",
18962306a36Sopenharmony_ci		.data = &max5522_chip_info_tbl[ID_MAX5522],
19062306a36Sopenharmony_ci	},
19162306a36Sopenharmony_ci	{}
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, max5522_of_match);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic struct spi_driver max5522_spi_driver = {
19662306a36Sopenharmony_ci	.driver = {
19762306a36Sopenharmony_ci		.name = "max5522",
19862306a36Sopenharmony_ci		.of_match_table = max5522_of_match,
19962306a36Sopenharmony_ci	},
20062306a36Sopenharmony_ci	.probe = max5522_spi_probe,
20162306a36Sopenharmony_ci	.id_table = max5522_ids,
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_cimodule_spi_driver(max5522_spi_driver);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ciMODULE_AUTHOR("Angelo Dureghello <angelo.dureghello@timesys.com");
20662306a36Sopenharmony_ciMODULE_DESCRIPTION("MAX5522 DAC driver");
20762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
208