xref: /linux/drivers/iio/adc/ltc2309.c (revision 733e0fed9c275b7d9e07041cfca8b221c71e3bd2)
1*733e0fedSLiam Beguin // SPDX-License-Identifier: GPL-2.0
2*733e0fedSLiam Beguin /*
3*733e0fedSLiam Beguin  * The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface.
4*733e0fedSLiam Beguin  *
5*733e0fedSLiam Beguin  * Datasheet:
6*733e0fedSLiam Beguin  * https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf
7*733e0fedSLiam Beguin  *
8*733e0fedSLiam Beguin  * Copyright (c) 2023, Liam Beguin <liambeguin@gmail.com>
9*733e0fedSLiam Beguin  */
10*733e0fedSLiam Beguin #include <linux/bitfield.h>
11*733e0fedSLiam Beguin #include <linux/i2c.h>
12*733e0fedSLiam Beguin #include <linux/iio/iio.h>
13*733e0fedSLiam Beguin #include <linux/kernel.h>
14*733e0fedSLiam Beguin #include <linux/module.h>
15*733e0fedSLiam Beguin #include <linux/mutex.h>
16*733e0fedSLiam Beguin #include <linux/regulator/consumer.h>
17*733e0fedSLiam Beguin 
18*733e0fedSLiam Beguin #define LTC2309_ADC_RESOLUTION	12
19*733e0fedSLiam Beguin 
20*733e0fedSLiam Beguin #define LTC2309_DIN_CH_MASK	GENMASK(7, 4)
21*733e0fedSLiam Beguin #define LTC2309_DIN_SDN		BIT(7)
22*733e0fedSLiam Beguin #define LTC2309_DIN_OSN		BIT(6)
23*733e0fedSLiam Beguin #define LTC2309_DIN_S1		BIT(5)
24*733e0fedSLiam Beguin #define LTC2309_DIN_S0		BIT(4)
25*733e0fedSLiam Beguin #define LTC2309_DIN_UNI		BIT(3)
26*733e0fedSLiam Beguin #define LTC2309_DIN_SLEEP	BIT(2)
27*733e0fedSLiam Beguin 
28*733e0fedSLiam Beguin /**
29*733e0fedSLiam Beguin  * struct ltc2309 - internal device data structure
30*733e0fedSLiam Beguin  * @dev:	Device reference
31*733e0fedSLiam Beguin  * @client:	I2C reference
32*733e0fedSLiam Beguin  * @vref:	External reference source
33*733e0fedSLiam Beguin  * @lock:	Lock to serialize data access
34*733e0fedSLiam Beguin  * @vref_mv:	Internal voltage reference
35*733e0fedSLiam Beguin  */
36*733e0fedSLiam Beguin struct ltc2309 {
37*733e0fedSLiam Beguin 	struct device		*dev;
38*733e0fedSLiam Beguin 	struct i2c_client	*client;
39*733e0fedSLiam Beguin 	struct regulator	*vref;
40*733e0fedSLiam Beguin 	struct mutex		lock; /* serialize data access */
41*733e0fedSLiam Beguin 	int			vref_mv;
42*733e0fedSLiam Beguin };
43*733e0fedSLiam Beguin 
44*733e0fedSLiam Beguin /* Order matches expected channel address, See datasheet Table 1. */
45*733e0fedSLiam Beguin enum ltc2309_channels {
46*733e0fedSLiam Beguin 	LTC2309_CH0_CH1 = 0,
47*733e0fedSLiam Beguin 	LTC2309_CH2_CH3,
48*733e0fedSLiam Beguin 	LTC2309_CH4_CH5,
49*733e0fedSLiam Beguin 	LTC2309_CH6_CH7,
50*733e0fedSLiam Beguin 	LTC2309_CH1_CH0,
51*733e0fedSLiam Beguin 	LTC2309_CH3_CH2,
52*733e0fedSLiam Beguin 	LTC2309_CH5_CH4,
53*733e0fedSLiam Beguin 	LTC2309_CH7_CH6,
54*733e0fedSLiam Beguin 	LTC2309_CH0,
55*733e0fedSLiam Beguin 	LTC2309_CH2,
56*733e0fedSLiam Beguin 	LTC2309_CH4,
57*733e0fedSLiam Beguin 	LTC2309_CH6,
58*733e0fedSLiam Beguin 	LTC2309_CH1,
59*733e0fedSLiam Beguin 	LTC2309_CH3,
60*733e0fedSLiam Beguin 	LTC2309_CH5,
61*733e0fedSLiam Beguin 	LTC2309_CH7,
62*733e0fedSLiam Beguin };
63*733e0fedSLiam Beguin 
64*733e0fedSLiam Beguin #define LTC2309_CHAN(_chan, _addr) {				\
65*733e0fedSLiam Beguin 	.type = IIO_VOLTAGE,					\
66*733e0fedSLiam Beguin 	.indexed = 1,						\
67*733e0fedSLiam Beguin 	.address = _addr,					\
68*733e0fedSLiam Beguin 	.channel = _chan,					\
69*733e0fedSLiam Beguin 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
70*733e0fedSLiam Beguin 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
71*733e0fedSLiam Beguin }
72*733e0fedSLiam Beguin 
73*733e0fedSLiam Beguin #define LTC2309_DIFF_CHAN(_chan, _chan2, _addr) {		\
74*733e0fedSLiam Beguin 	.type = IIO_VOLTAGE,					\
75*733e0fedSLiam Beguin 	.differential = 1,					\
76*733e0fedSLiam Beguin 	.indexed = 1,						\
77*733e0fedSLiam Beguin 	.address = _addr,					\
78*733e0fedSLiam Beguin 	.channel = _chan,					\
79*733e0fedSLiam Beguin 	.channel2 = _chan2,					\
80*733e0fedSLiam Beguin 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
81*733e0fedSLiam Beguin 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
82*733e0fedSLiam Beguin }
83*733e0fedSLiam Beguin 
84*733e0fedSLiam Beguin static const struct iio_chan_spec ltc2309_channels[] = {
85*733e0fedSLiam Beguin 	LTC2309_CHAN(0, LTC2309_CH0),
86*733e0fedSLiam Beguin 	LTC2309_CHAN(1, LTC2309_CH1),
87*733e0fedSLiam Beguin 	LTC2309_CHAN(2, LTC2309_CH2),
88*733e0fedSLiam Beguin 	LTC2309_CHAN(3, LTC2309_CH3),
89*733e0fedSLiam Beguin 	LTC2309_CHAN(4, LTC2309_CH4),
90*733e0fedSLiam Beguin 	LTC2309_CHAN(5, LTC2309_CH5),
91*733e0fedSLiam Beguin 	LTC2309_CHAN(6, LTC2309_CH6),
92*733e0fedSLiam Beguin 	LTC2309_CHAN(7, LTC2309_CH7),
93*733e0fedSLiam Beguin 	LTC2309_DIFF_CHAN(0, 1, LTC2309_CH0_CH1),
94*733e0fedSLiam Beguin 	LTC2309_DIFF_CHAN(2, 3, LTC2309_CH2_CH3),
95*733e0fedSLiam Beguin 	LTC2309_DIFF_CHAN(4, 5, LTC2309_CH4_CH5),
96*733e0fedSLiam Beguin 	LTC2309_DIFF_CHAN(6, 7, LTC2309_CH6_CH7),
97*733e0fedSLiam Beguin 	LTC2309_DIFF_CHAN(1, 0, LTC2309_CH1_CH0),
98*733e0fedSLiam Beguin 	LTC2309_DIFF_CHAN(3, 2, LTC2309_CH3_CH2),
99*733e0fedSLiam Beguin 	LTC2309_DIFF_CHAN(5, 4, LTC2309_CH5_CH4),
100*733e0fedSLiam Beguin 	LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6),
101*733e0fedSLiam Beguin };
102*733e0fedSLiam Beguin 
103*733e0fedSLiam Beguin static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309,
104*733e0fedSLiam Beguin 				    unsigned long address, int *val)
105*733e0fedSLiam Beguin {
106*733e0fedSLiam Beguin 	int ret;
107*733e0fedSLiam Beguin 	u16 buf;
108*733e0fedSLiam Beguin 	u8 din;
109*733e0fedSLiam Beguin 
110*733e0fedSLiam Beguin 	din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) |
111*733e0fedSLiam Beguin 		FIELD_PREP(LTC2309_DIN_UNI, 1) |
112*733e0fedSLiam Beguin 		FIELD_PREP(LTC2309_DIN_SLEEP, 0);
113*733e0fedSLiam Beguin 
114*733e0fedSLiam Beguin 	ret = i2c_smbus_write_byte(ltc2309->client, din);
115*733e0fedSLiam Beguin 	if (ret < 0) {
116*733e0fedSLiam Beguin 		dev_err(ltc2309->dev, "i2c command failed: %pe\n",
117*733e0fedSLiam Beguin 			ERR_PTR(ret));
118*733e0fedSLiam Beguin 		return ret;
119*733e0fedSLiam Beguin 	}
120*733e0fedSLiam Beguin 
121*733e0fedSLiam Beguin 	ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2);
122*733e0fedSLiam Beguin 	if (ret < 0) {
123*733e0fedSLiam Beguin 		dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret));
124*733e0fedSLiam Beguin 		return ret;
125*733e0fedSLiam Beguin 	}
126*733e0fedSLiam Beguin 
127*733e0fedSLiam Beguin 	*val = be16_to_cpu(buf) >> 4;
128*733e0fedSLiam Beguin 
129*733e0fedSLiam Beguin 	return ret;
130*733e0fedSLiam Beguin }
131*733e0fedSLiam Beguin 
132*733e0fedSLiam Beguin static int ltc2309_read_raw(struct iio_dev *indio_dev,
133*733e0fedSLiam Beguin 			    struct iio_chan_spec const *chan, int *val,
134*733e0fedSLiam Beguin 			    int *val2, long mask)
135*733e0fedSLiam Beguin {
136*733e0fedSLiam Beguin 	struct ltc2309 *ltc2309 = iio_priv(indio_dev);
137*733e0fedSLiam Beguin 	int ret;
138*733e0fedSLiam Beguin 
139*733e0fedSLiam Beguin 	switch (mask) {
140*733e0fedSLiam Beguin 	case IIO_CHAN_INFO_RAW:
141*733e0fedSLiam Beguin 		mutex_lock(&ltc2309->lock);
142*733e0fedSLiam Beguin 		ret = ltc2309_read_raw_channel(ltc2309, chan->address, val);
143*733e0fedSLiam Beguin 		mutex_unlock(&ltc2309->lock);
144*733e0fedSLiam Beguin 		if (ret < 0)
145*733e0fedSLiam Beguin 			return -EINVAL;
146*733e0fedSLiam Beguin 		return IIO_VAL_INT;
147*733e0fedSLiam Beguin 	case IIO_CHAN_INFO_SCALE:
148*733e0fedSLiam Beguin 		*val = ltc2309->vref_mv;
149*733e0fedSLiam Beguin 		*val2 = LTC2309_ADC_RESOLUTION;
150*733e0fedSLiam Beguin 		return IIO_VAL_FRACTIONAL_LOG2;
151*733e0fedSLiam Beguin 	default:
152*733e0fedSLiam Beguin 		return -EINVAL;
153*733e0fedSLiam Beguin 	}
154*733e0fedSLiam Beguin }
155*733e0fedSLiam Beguin 
156*733e0fedSLiam Beguin static const struct iio_info ltc2309_info = {
157*733e0fedSLiam Beguin 	.read_raw = ltc2309_read_raw,
158*733e0fedSLiam Beguin };
159*733e0fedSLiam Beguin 
160*733e0fedSLiam Beguin static void ltc2309_regulator_disable(void *regulator)
161*733e0fedSLiam Beguin {
162*733e0fedSLiam Beguin 	regulator_disable(regulator);
163*733e0fedSLiam Beguin }
164*733e0fedSLiam Beguin 
165*733e0fedSLiam Beguin static int ltc2309_probe(struct i2c_client *client)
166*733e0fedSLiam Beguin {
167*733e0fedSLiam Beguin 	struct iio_dev *indio_dev;
168*733e0fedSLiam Beguin 	struct ltc2309 *ltc2309;
169*733e0fedSLiam Beguin 	int ret;
170*733e0fedSLiam Beguin 
171*733e0fedSLiam Beguin 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*ltc2309));
172*733e0fedSLiam Beguin 	if (!indio_dev)
173*733e0fedSLiam Beguin 		return -ENOMEM;
174*733e0fedSLiam Beguin 
175*733e0fedSLiam Beguin 	ltc2309 = iio_priv(indio_dev);
176*733e0fedSLiam Beguin 	ltc2309->dev = &indio_dev->dev;
177*733e0fedSLiam Beguin 	ltc2309->client = client;
178*733e0fedSLiam Beguin 	ltc2309->vref_mv = 4096; /* Default to the internal ref */
179*733e0fedSLiam Beguin 
180*733e0fedSLiam Beguin 	indio_dev->name = "ltc2309";
181*733e0fedSLiam Beguin 	indio_dev->modes = INDIO_DIRECT_MODE;
182*733e0fedSLiam Beguin 	indio_dev->channels = ltc2309_channels;
183*733e0fedSLiam Beguin 	indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels);
184*733e0fedSLiam Beguin 	indio_dev->info = &ltc2309_info;
185*733e0fedSLiam Beguin 
186*733e0fedSLiam Beguin 	ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref");
187*733e0fedSLiam Beguin 	if (IS_ERR(ltc2309->vref)) {
188*733e0fedSLiam Beguin 		ret = PTR_ERR(ltc2309->vref);
189*733e0fedSLiam Beguin 		if (ret == -ENODEV)
190*733e0fedSLiam Beguin 			ltc2309->vref = NULL;
191*733e0fedSLiam Beguin 		else
192*733e0fedSLiam Beguin 			return ret;
193*733e0fedSLiam Beguin 	}
194*733e0fedSLiam Beguin 
195*733e0fedSLiam Beguin 	if (ltc2309->vref) {
196*733e0fedSLiam Beguin 		ret = regulator_enable(ltc2309->vref);
197*733e0fedSLiam Beguin 		if (ret)
198*733e0fedSLiam Beguin 			return dev_err_probe(ltc2309->dev, ret,
199*733e0fedSLiam Beguin 					     "failed to enable vref\n");
200*733e0fedSLiam Beguin 
201*733e0fedSLiam Beguin 		ret = devm_add_action_or_reset(ltc2309->dev,
202*733e0fedSLiam Beguin 					       ltc2309_regulator_disable,
203*733e0fedSLiam Beguin 					       ltc2309->vref);
204*733e0fedSLiam Beguin 		if (ret) {
205*733e0fedSLiam Beguin 			return dev_err_probe(ltc2309->dev, ret,
206*733e0fedSLiam Beguin 					     "failed to add regulator_disable action: %d\n",
207*733e0fedSLiam Beguin 					     ret);
208*733e0fedSLiam Beguin 		}
209*733e0fedSLiam Beguin 
210*733e0fedSLiam Beguin 		ret = regulator_get_voltage(ltc2309->vref);
211*733e0fedSLiam Beguin 		if (ret < 0)
212*733e0fedSLiam Beguin 			return ret;
213*733e0fedSLiam Beguin 
214*733e0fedSLiam Beguin 		ltc2309->vref_mv = ret / 1000;
215*733e0fedSLiam Beguin 	}
216*733e0fedSLiam Beguin 
217*733e0fedSLiam Beguin 	mutex_init(&ltc2309->lock);
218*733e0fedSLiam Beguin 
219*733e0fedSLiam Beguin 	return devm_iio_device_register(&client->dev, indio_dev);
220*733e0fedSLiam Beguin }
221*733e0fedSLiam Beguin 
222*733e0fedSLiam Beguin static const struct of_device_id ltc2309_of_match[] = {
223*733e0fedSLiam Beguin 	{ .compatible = "lltc,ltc2309" },
224*733e0fedSLiam Beguin 	{ }
225*733e0fedSLiam Beguin };
226*733e0fedSLiam Beguin MODULE_DEVICE_TABLE(of, ltc2309_of_match);
227*733e0fedSLiam Beguin 
228*733e0fedSLiam Beguin static const struct i2c_device_id ltc2309_id[] = {
229*733e0fedSLiam Beguin 	{ "ltc2309" },
230*733e0fedSLiam Beguin 	{ }
231*733e0fedSLiam Beguin };
232*733e0fedSLiam Beguin MODULE_DEVICE_TABLE(i2c, ltc2309_id);
233*733e0fedSLiam Beguin 
234*733e0fedSLiam Beguin static struct i2c_driver ltc2309_driver = {
235*733e0fedSLiam Beguin 	.driver = {
236*733e0fedSLiam Beguin 		.name = "ltc2309",
237*733e0fedSLiam Beguin 		.of_match_table = ltc2309_of_match,
238*733e0fedSLiam Beguin 	},
239*733e0fedSLiam Beguin 	.probe		= ltc2309_probe,
240*733e0fedSLiam Beguin 	.id_table	= ltc2309_id,
241*733e0fedSLiam Beguin };
242*733e0fedSLiam Beguin module_i2c_driver(ltc2309_driver);
243*733e0fedSLiam Beguin 
244*733e0fedSLiam Beguin MODULE_AUTHOR("Liam Beguin <liambeguin@gmail.com>");
245*733e0fedSLiam Beguin MODULE_DESCRIPTION("Linear Technology LTC2309 ADC");
246*733e0fedSLiam Beguin MODULE_LICENSE("GPL v2");
247