162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ADS8344 16-bit 8-Channel ADC driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Gregory CLEMENT <gregory.clement@bootlin.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Datasheet: https://www.ti.com/lit/ds/symlink/ads8344.pdf
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/iio/buffer.h>
1262306a36Sopenharmony_ci#include <linux/iio/iio.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1562306a36Sopenharmony_ci#include <linux/spi/spi.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define ADS8344_START BIT(7)
1862306a36Sopenharmony_ci#define ADS8344_SINGLE_END BIT(2)
1962306a36Sopenharmony_ci#define ADS8344_CHANNEL(channel) ((channel) << 4)
2062306a36Sopenharmony_ci#define ADS8344_CLOCK_INTERNAL 0x2 /* PD1 = 1 and PD0 = 0 */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct ads8344 {
2362306a36Sopenharmony_ci	struct spi_device *spi;
2462306a36Sopenharmony_ci	struct regulator *reg;
2562306a36Sopenharmony_ci	/*
2662306a36Sopenharmony_ci	 * Lock protecting access to adc->tx_buff and rx_buff,
2762306a36Sopenharmony_ci	 * especially from concurrent read on sysfs file.
2862306a36Sopenharmony_ci	 */
2962306a36Sopenharmony_ci	struct mutex lock;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	u8 tx_buf __aligned(IIO_DMA_MINALIGN);
3262306a36Sopenharmony_ci	u8 rx_buf[3];
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define ADS8344_VOLTAGE_CHANNEL(chan, addr)				\
3662306a36Sopenharmony_ci	{								\
3762306a36Sopenharmony_ci		.type = IIO_VOLTAGE,					\
3862306a36Sopenharmony_ci		.indexed = 1,						\
3962306a36Sopenharmony_ci		.channel = chan,					\
4062306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
4162306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
4262306a36Sopenharmony_ci		.address = addr,					\
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define ADS8344_VOLTAGE_CHANNEL_DIFF(chan1, chan2, addr)		\
4662306a36Sopenharmony_ci	{								\
4762306a36Sopenharmony_ci		.type = IIO_VOLTAGE,					\
4862306a36Sopenharmony_ci		.indexed = 1,						\
4962306a36Sopenharmony_ci		.channel = (chan1),					\
5062306a36Sopenharmony_ci		.channel2 = (chan2),					\
5162306a36Sopenharmony_ci		.differential = 1,					\
5262306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
5362306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
5462306a36Sopenharmony_ci		.address = addr,					\
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic const struct iio_chan_spec ads8344_channels[] = {
5862306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL(0, 0),
5962306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL(1, 4),
6062306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL(2, 1),
6162306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL(3, 5),
6262306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL(4, 2),
6362306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL(5, 6),
6462306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL(6, 3),
6562306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL(7, 7),
6662306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL_DIFF(0, 1, 8),
6762306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL_DIFF(2, 3, 9),
6862306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL_DIFF(4, 5, 10),
6962306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL_DIFF(6, 7, 11),
7062306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL_DIFF(1, 0, 12),
7162306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL_DIFF(3, 2, 13),
7262306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL_DIFF(5, 4, 14),
7362306a36Sopenharmony_ci	ADS8344_VOLTAGE_CHANNEL_DIFF(7, 6, 15),
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic int ads8344_adc_conversion(struct ads8344 *adc, int channel,
7762306a36Sopenharmony_ci				  bool differential)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	struct spi_device *spi = adc->spi;
8062306a36Sopenharmony_ci	int ret;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	adc->tx_buf = ADS8344_START;
8362306a36Sopenharmony_ci	if (!differential)
8462306a36Sopenharmony_ci		adc->tx_buf |= ADS8344_SINGLE_END;
8562306a36Sopenharmony_ci	adc->tx_buf |= ADS8344_CHANNEL(channel);
8662306a36Sopenharmony_ci	adc->tx_buf |= ADS8344_CLOCK_INTERNAL;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	ret = spi_write(spi, &adc->tx_buf, 1);
8962306a36Sopenharmony_ci	if (ret)
9062306a36Sopenharmony_ci		return ret;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	udelay(9);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	ret = spi_read(spi, adc->rx_buf, sizeof(adc->rx_buf));
9562306a36Sopenharmony_ci	if (ret)
9662306a36Sopenharmony_ci		return ret;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return adc->rx_buf[0] << 9 | adc->rx_buf[1] << 1 | adc->rx_buf[2] >> 7;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int ads8344_read_raw(struct iio_dev *iio,
10262306a36Sopenharmony_ci			    struct iio_chan_spec const *channel, int *value,
10362306a36Sopenharmony_ci			    int *shift, long mask)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct ads8344 *adc = iio_priv(iio);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	switch (mask) {
10862306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
10962306a36Sopenharmony_ci		mutex_lock(&adc->lock);
11062306a36Sopenharmony_ci		*value = ads8344_adc_conversion(adc, channel->address,
11162306a36Sopenharmony_ci						channel->differential);
11262306a36Sopenharmony_ci		mutex_unlock(&adc->lock);
11362306a36Sopenharmony_ci		if (*value < 0)
11462306a36Sopenharmony_ci			return *value;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		return IIO_VAL_INT;
11762306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
11862306a36Sopenharmony_ci		*value = regulator_get_voltage(adc->reg);
11962306a36Sopenharmony_ci		if (*value < 0)
12062306a36Sopenharmony_ci			return *value;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		/* convert regulator output voltage to mV */
12362306a36Sopenharmony_ci		*value /= 1000;
12462306a36Sopenharmony_ci		*shift = 16;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		return IIO_VAL_FRACTIONAL_LOG2;
12762306a36Sopenharmony_ci	default:
12862306a36Sopenharmony_ci		return -EINVAL;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic const struct iio_info ads8344_info = {
13362306a36Sopenharmony_ci	.read_raw = ads8344_read_raw,
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void ads8344_reg_disable(void *data)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	regulator_disable(data);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int ads8344_probe(struct spi_device *spi)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct iio_dev *indio_dev;
14462306a36Sopenharmony_ci	struct ads8344 *adc;
14562306a36Sopenharmony_ci	int ret;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
14862306a36Sopenharmony_ci	if (!indio_dev)
14962306a36Sopenharmony_ci		return -ENOMEM;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	adc = iio_priv(indio_dev);
15262306a36Sopenharmony_ci	adc->spi = spi;
15362306a36Sopenharmony_ci	mutex_init(&adc->lock);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	indio_dev->name = dev_name(&spi->dev);
15662306a36Sopenharmony_ci	indio_dev->info = &ads8344_info;
15762306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
15862306a36Sopenharmony_ci	indio_dev->channels = ads8344_channels;
15962306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(ads8344_channels);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	adc->reg = devm_regulator_get(&spi->dev, "vref");
16262306a36Sopenharmony_ci	if (IS_ERR(adc->reg))
16362306a36Sopenharmony_ci		return PTR_ERR(adc->reg);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	ret = regulator_enable(adc->reg);
16662306a36Sopenharmony_ci	if (ret)
16762306a36Sopenharmony_ci		return ret;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	ret = devm_add_action_or_reset(&spi->dev, ads8344_reg_disable, adc->reg);
17062306a36Sopenharmony_ci	if (ret)
17162306a36Sopenharmony_ci		return ret;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return devm_iio_device_register(&spi->dev, indio_dev);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic const struct of_device_id ads8344_of_match[] = {
17762306a36Sopenharmony_ci	{ .compatible = "ti,ads8344", },
17862306a36Sopenharmony_ci	{}
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ads8344_of_match);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic struct spi_driver ads8344_driver = {
18362306a36Sopenharmony_ci	.driver = {
18462306a36Sopenharmony_ci		.name = "ads8344",
18562306a36Sopenharmony_ci		.of_match_table = ads8344_of_match,
18662306a36Sopenharmony_ci	},
18762306a36Sopenharmony_ci	.probe = ads8344_probe,
18862306a36Sopenharmony_ci};
18962306a36Sopenharmony_cimodule_spi_driver(ads8344_driver);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ciMODULE_AUTHOR("Gregory CLEMENT <gregory.clement@bootlin.com>");
19262306a36Sopenharmony_ciMODULE_DESCRIPTION("ADS8344 driver");
19362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
194