180503b23SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2aa16c6bdSLars-Peter Clausen /*
3aa16c6bdSLars-Peter Clausen * AD7766/AD7767 SPI ADC driver
4aa16c6bdSLars-Peter Clausen *
5aa16c6bdSLars-Peter Clausen * Copyright 2016 Analog Devices Inc.
6aa16c6bdSLars-Peter Clausen */
7aa16c6bdSLars-Peter Clausen
8aa16c6bdSLars-Peter Clausen #include <linux/clk.h>
9aa16c6bdSLars-Peter Clausen #include <linux/delay.h>
10aa16c6bdSLars-Peter Clausen #include <linux/device.h>
11aa16c6bdSLars-Peter Clausen #include <linux/err.h>
12aa16c6bdSLars-Peter Clausen #include <linux/gpio/consumer.h>
13aa16c6bdSLars-Peter Clausen #include <linux/module.h>
14aa16c6bdSLars-Peter Clausen #include <linux/regulator/consumer.h>
15aa16c6bdSLars-Peter Clausen #include <linux/slab.h>
16aa16c6bdSLars-Peter Clausen #include <linux/spi/spi.h>
17aa16c6bdSLars-Peter Clausen
18aa16c6bdSLars-Peter Clausen #include <linux/iio/iio.h>
19aa16c6bdSLars-Peter Clausen #include <linux/iio/buffer.h>
20aa16c6bdSLars-Peter Clausen #include <linux/iio/trigger.h>
21aa16c6bdSLars-Peter Clausen #include <linux/iio/trigger_consumer.h>
22aa16c6bdSLars-Peter Clausen #include <linux/iio/triggered_buffer.h>
23aa16c6bdSLars-Peter Clausen
24aa16c6bdSLars-Peter Clausen struct ad7766_chip_info {
25aa16c6bdSLars-Peter Clausen unsigned int decimation_factor;
26aa16c6bdSLars-Peter Clausen };
27aa16c6bdSLars-Peter Clausen
28aa16c6bdSLars-Peter Clausen enum {
29aa16c6bdSLars-Peter Clausen AD7766_SUPPLY_AVDD = 0,
30aa16c6bdSLars-Peter Clausen AD7766_SUPPLY_DVDD = 1,
31aa16c6bdSLars-Peter Clausen AD7766_SUPPLY_VREF = 2,
32aa16c6bdSLars-Peter Clausen AD7766_NUM_SUPPLIES = 3
33aa16c6bdSLars-Peter Clausen };
34aa16c6bdSLars-Peter Clausen
35aa16c6bdSLars-Peter Clausen struct ad7766 {
36aa16c6bdSLars-Peter Clausen const struct ad7766_chip_info *chip_info;
37aa16c6bdSLars-Peter Clausen struct spi_device *spi;
38aa16c6bdSLars-Peter Clausen struct clk *mclk;
39aa16c6bdSLars-Peter Clausen struct gpio_desc *pd_gpio;
40aa16c6bdSLars-Peter Clausen struct regulator_bulk_data reg[AD7766_NUM_SUPPLIES];
41aa16c6bdSLars-Peter Clausen
42aa16c6bdSLars-Peter Clausen struct iio_trigger *trig;
43aa16c6bdSLars-Peter Clausen
44aa16c6bdSLars-Peter Clausen struct spi_transfer xfer;
45aa16c6bdSLars-Peter Clausen struct spi_message msg;
46aa16c6bdSLars-Peter Clausen
47aa16c6bdSLars-Peter Clausen /*
48*009ae227SJonathan Cameron * DMA (thus cache coherency maintenance) may require the
49aa16c6bdSLars-Peter Clausen * transfer buffers to live in their own cache lines.
50aa16c6bdSLars-Peter Clausen * Make the buffer large enough for one 24 bit sample and one 64 bit
51aa16c6bdSLars-Peter Clausen * aligned 64 bit timestamp.
52aa16c6bdSLars-Peter Clausen */
53*009ae227SJonathan Cameron unsigned char data[ALIGN(3, sizeof(s64)) + sizeof(s64)] __aligned(IIO_DMA_MINALIGN);
54aa16c6bdSLars-Peter Clausen };
55aa16c6bdSLars-Peter Clausen
56aa16c6bdSLars-Peter Clausen /*
57aa16c6bdSLars-Peter Clausen * AD7766 and AD7767 variations are interface compatible, the main difference is
58aa16c6bdSLars-Peter Clausen * analog performance. Both parts will use the same ID.
59aa16c6bdSLars-Peter Clausen */
60aa16c6bdSLars-Peter Clausen enum ad7766_device_ids {
61aa16c6bdSLars-Peter Clausen ID_AD7766,
62aa16c6bdSLars-Peter Clausen ID_AD7766_1,
63aa16c6bdSLars-Peter Clausen ID_AD7766_2,
64aa16c6bdSLars-Peter Clausen };
65aa16c6bdSLars-Peter Clausen
ad7766_trigger_handler(int irq,void * p)66aa16c6bdSLars-Peter Clausen static irqreturn_t ad7766_trigger_handler(int irq, void *p)
67aa16c6bdSLars-Peter Clausen {
68aa16c6bdSLars-Peter Clausen struct iio_poll_func *pf = p;
69aa16c6bdSLars-Peter Clausen struct iio_dev *indio_dev = pf->indio_dev;
70aa16c6bdSLars-Peter Clausen struct ad7766 *ad7766 = iio_priv(indio_dev);
71aa16c6bdSLars-Peter Clausen int ret;
72aa16c6bdSLars-Peter Clausen
73aa16c6bdSLars-Peter Clausen ret = spi_sync(ad7766->spi, &ad7766->msg);
74aa16c6bdSLars-Peter Clausen if (ret < 0)
75aa16c6bdSLars-Peter Clausen goto done;
76aa16c6bdSLars-Peter Clausen
77aa16c6bdSLars-Peter Clausen iio_push_to_buffers_with_timestamp(indio_dev, ad7766->data,
78aa16c6bdSLars-Peter Clausen pf->timestamp);
79aa16c6bdSLars-Peter Clausen done:
80aa16c6bdSLars-Peter Clausen iio_trigger_notify_done(indio_dev->trig);
81aa16c6bdSLars-Peter Clausen
82aa16c6bdSLars-Peter Clausen return IRQ_HANDLED;
83aa16c6bdSLars-Peter Clausen }
84aa16c6bdSLars-Peter Clausen
ad7766_preenable(struct iio_dev * indio_dev)85aa16c6bdSLars-Peter Clausen static int ad7766_preenable(struct iio_dev *indio_dev)
86aa16c6bdSLars-Peter Clausen {
87aa16c6bdSLars-Peter Clausen struct ad7766 *ad7766 = iio_priv(indio_dev);
88aa16c6bdSLars-Peter Clausen int ret;
89aa16c6bdSLars-Peter Clausen
90aa16c6bdSLars-Peter Clausen ret = regulator_bulk_enable(ARRAY_SIZE(ad7766->reg), ad7766->reg);
91aa16c6bdSLars-Peter Clausen if (ret < 0) {
92aa16c6bdSLars-Peter Clausen dev_err(&ad7766->spi->dev, "Failed to enable supplies: %d\n",
93aa16c6bdSLars-Peter Clausen ret);
94aa16c6bdSLars-Peter Clausen return ret;
95aa16c6bdSLars-Peter Clausen }
96aa16c6bdSLars-Peter Clausen
97aa16c6bdSLars-Peter Clausen ret = clk_prepare_enable(ad7766->mclk);
98aa16c6bdSLars-Peter Clausen if (ret < 0) {
99aa16c6bdSLars-Peter Clausen dev_err(&ad7766->spi->dev, "Failed to enable MCLK: %d\n", ret);
100aa16c6bdSLars-Peter Clausen regulator_bulk_disable(ARRAY_SIZE(ad7766->reg), ad7766->reg);
101aa16c6bdSLars-Peter Clausen return ret;
102aa16c6bdSLars-Peter Clausen }
103aa16c6bdSLars-Peter Clausen
104aa16c6bdSLars-Peter Clausen gpiod_set_value(ad7766->pd_gpio, 0);
105aa16c6bdSLars-Peter Clausen
106aa16c6bdSLars-Peter Clausen return 0;
107aa16c6bdSLars-Peter Clausen }
108aa16c6bdSLars-Peter Clausen
ad7766_postdisable(struct iio_dev * indio_dev)109aa16c6bdSLars-Peter Clausen static int ad7766_postdisable(struct iio_dev *indio_dev)
110aa16c6bdSLars-Peter Clausen {
111aa16c6bdSLars-Peter Clausen struct ad7766 *ad7766 = iio_priv(indio_dev);
112aa16c6bdSLars-Peter Clausen
113aa16c6bdSLars-Peter Clausen gpiod_set_value(ad7766->pd_gpio, 1);
114aa16c6bdSLars-Peter Clausen
115aa16c6bdSLars-Peter Clausen /*
116aa16c6bdSLars-Peter Clausen * The PD pin is synchronous to the clock, so give it some time to
117aa16c6bdSLars-Peter Clausen * notice the change before we disable the clock.
118aa16c6bdSLars-Peter Clausen */
119aa16c6bdSLars-Peter Clausen msleep(20);
120aa16c6bdSLars-Peter Clausen
121aa16c6bdSLars-Peter Clausen clk_disable_unprepare(ad7766->mclk);
122aa16c6bdSLars-Peter Clausen regulator_bulk_disable(ARRAY_SIZE(ad7766->reg), ad7766->reg);
123aa16c6bdSLars-Peter Clausen
124aa16c6bdSLars-Peter Clausen return 0;
125aa16c6bdSLars-Peter Clausen }
126aa16c6bdSLars-Peter Clausen
ad7766_read_raw(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int * val,int * val2,long info)127aa16c6bdSLars-Peter Clausen static int ad7766_read_raw(struct iio_dev *indio_dev,
128aa16c6bdSLars-Peter Clausen const struct iio_chan_spec *chan, int *val, int *val2, long info)
129aa16c6bdSLars-Peter Clausen {
130aa16c6bdSLars-Peter Clausen struct ad7766 *ad7766 = iio_priv(indio_dev);
131aa16c6bdSLars-Peter Clausen struct regulator *vref = ad7766->reg[AD7766_SUPPLY_VREF].consumer;
132aa16c6bdSLars-Peter Clausen int scale_uv;
133aa16c6bdSLars-Peter Clausen
134aa16c6bdSLars-Peter Clausen switch (info) {
135aa16c6bdSLars-Peter Clausen case IIO_CHAN_INFO_SCALE:
136aa16c6bdSLars-Peter Clausen scale_uv = regulator_get_voltage(vref);
137aa16c6bdSLars-Peter Clausen if (scale_uv < 0)
138aa16c6bdSLars-Peter Clausen return scale_uv;
139aa16c6bdSLars-Peter Clausen *val = scale_uv / 1000;
140aa16c6bdSLars-Peter Clausen *val2 = chan->scan_type.realbits;
141aa16c6bdSLars-Peter Clausen return IIO_VAL_FRACTIONAL_LOG2;
142aa16c6bdSLars-Peter Clausen case IIO_CHAN_INFO_SAMP_FREQ:
143aa16c6bdSLars-Peter Clausen *val = clk_get_rate(ad7766->mclk) /
144aa16c6bdSLars-Peter Clausen ad7766->chip_info->decimation_factor;
145aa16c6bdSLars-Peter Clausen return IIO_VAL_INT;
146aa16c6bdSLars-Peter Clausen }
147aa16c6bdSLars-Peter Clausen return -EINVAL;
148aa16c6bdSLars-Peter Clausen }
149aa16c6bdSLars-Peter Clausen
150aa16c6bdSLars-Peter Clausen static const struct iio_chan_spec ad7766_channels[] = {
151aa16c6bdSLars-Peter Clausen {
152aa16c6bdSLars-Peter Clausen .type = IIO_VOLTAGE,
153aa16c6bdSLars-Peter Clausen .indexed = 1,
154aa16c6bdSLars-Peter Clausen .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
155aa16c6bdSLars-Peter Clausen .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
156aa16c6bdSLars-Peter Clausen .scan_type = {
157aa16c6bdSLars-Peter Clausen .sign = 's',
158aa16c6bdSLars-Peter Clausen .realbits = 24,
159aa16c6bdSLars-Peter Clausen .storagebits = 32,
160aa16c6bdSLars-Peter Clausen .endianness = IIO_BE,
161aa16c6bdSLars-Peter Clausen },
162aa16c6bdSLars-Peter Clausen },
163aa16c6bdSLars-Peter Clausen IIO_CHAN_SOFT_TIMESTAMP(1),
164aa16c6bdSLars-Peter Clausen };
165aa16c6bdSLars-Peter Clausen
166aa16c6bdSLars-Peter Clausen static const struct ad7766_chip_info ad7766_chip_info[] = {
167aa16c6bdSLars-Peter Clausen [ID_AD7766] = {
168aa16c6bdSLars-Peter Clausen .decimation_factor = 8,
169aa16c6bdSLars-Peter Clausen },
170aa16c6bdSLars-Peter Clausen [ID_AD7766_1] = {
171aa16c6bdSLars-Peter Clausen .decimation_factor = 16,
172aa16c6bdSLars-Peter Clausen },
173aa16c6bdSLars-Peter Clausen [ID_AD7766_2] = {
174aa16c6bdSLars-Peter Clausen .decimation_factor = 32,
175aa16c6bdSLars-Peter Clausen },
176aa16c6bdSLars-Peter Clausen };
177aa16c6bdSLars-Peter Clausen
178aa16c6bdSLars-Peter Clausen static const struct iio_buffer_setup_ops ad7766_buffer_setup_ops = {
179aa16c6bdSLars-Peter Clausen .preenable = &ad7766_preenable,
180aa16c6bdSLars-Peter Clausen .postdisable = &ad7766_postdisable,
181aa16c6bdSLars-Peter Clausen };
182aa16c6bdSLars-Peter Clausen
183aa16c6bdSLars-Peter Clausen static const struct iio_info ad7766_info = {
184aa16c6bdSLars-Peter Clausen .read_raw = &ad7766_read_raw,
185aa16c6bdSLars-Peter Clausen };
186aa16c6bdSLars-Peter Clausen
ad7766_irq(int irq,void * private)187aa16c6bdSLars-Peter Clausen static irqreturn_t ad7766_irq(int irq, void *private)
188aa16c6bdSLars-Peter Clausen {
189aa16c6bdSLars-Peter Clausen iio_trigger_poll(private);
190aa16c6bdSLars-Peter Clausen return IRQ_HANDLED;
191aa16c6bdSLars-Peter Clausen }
192aa16c6bdSLars-Peter Clausen
ad7766_set_trigger_state(struct iio_trigger * trig,bool enable)193aa16c6bdSLars-Peter Clausen static int ad7766_set_trigger_state(struct iio_trigger *trig, bool enable)
194aa16c6bdSLars-Peter Clausen {
195aa16c6bdSLars-Peter Clausen struct ad7766 *ad7766 = iio_trigger_get_drvdata(trig);
196aa16c6bdSLars-Peter Clausen
197aa16c6bdSLars-Peter Clausen if (enable)
198aa16c6bdSLars-Peter Clausen enable_irq(ad7766->spi->irq);
199aa16c6bdSLars-Peter Clausen else
200aa16c6bdSLars-Peter Clausen disable_irq(ad7766->spi->irq);
201aa16c6bdSLars-Peter Clausen
202aa16c6bdSLars-Peter Clausen return 0;
203aa16c6bdSLars-Peter Clausen }
204aa16c6bdSLars-Peter Clausen
205aa16c6bdSLars-Peter Clausen static const struct iio_trigger_ops ad7766_trigger_ops = {
206aa16c6bdSLars-Peter Clausen .set_trigger_state = ad7766_set_trigger_state,
207aa16c6bdSLars-Peter Clausen .validate_device = iio_trigger_validate_own_device,
208aa16c6bdSLars-Peter Clausen };
209aa16c6bdSLars-Peter Clausen
ad7766_probe(struct spi_device * spi)210aa16c6bdSLars-Peter Clausen static int ad7766_probe(struct spi_device *spi)
211aa16c6bdSLars-Peter Clausen {
212aa16c6bdSLars-Peter Clausen const struct spi_device_id *id = spi_get_device_id(spi);
213aa16c6bdSLars-Peter Clausen struct iio_dev *indio_dev;
214aa16c6bdSLars-Peter Clausen struct ad7766 *ad7766;
215aa16c6bdSLars-Peter Clausen int ret;
216aa16c6bdSLars-Peter Clausen
217aa16c6bdSLars-Peter Clausen indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*ad7766));
218aa16c6bdSLars-Peter Clausen if (!indio_dev)
219aa16c6bdSLars-Peter Clausen return -ENOMEM;
220aa16c6bdSLars-Peter Clausen
221aa16c6bdSLars-Peter Clausen ad7766 = iio_priv(indio_dev);
222aa16c6bdSLars-Peter Clausen ad7766->chip_info = &ad7766_chip_info[id->driver_data];
223aa16c6bdSLars-Peter Clausen
224aa16c6bdSLars-Peter Clausen ad7766->mclk = devm_clk_get(&spi->dev, "mclk");
225aa16c6bdSLars-Peter Clausen if (IS_ERR(ad7766->mclk))
226aa16c6bdSLars-Peter Clausen return PTR_ERR(ad7766->mclk);
227aa16c6bdSLars-Peter Clausen
228aa16c6bdSLars-Peter Clausen ad7766->reg[AD7766_SUPPLY_AVDD].supply = "avdd";
229aa16c6bdSLars-Peter Clausen ad7766->reg[AD7766_SUPPLY_DVDD].supply = "dvdd";
230aa16c6bdSLars-Peter Clausen ad7766->reg[AD7766_SUPPLY_VREF].supply = "vref";
231aa16c6bdSLars-Peter Clausen
232aa16c6bdSLars-Peter Clausen ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(ad7766->reg),
233aa16c6bdSLars-Peter Clausen ad7766->reg);
2340d8391f3SDan Carpenter if (ret)
2350d8391f3SDan Carpenter return ret;
236aa16c6bdSLars-Peter Clausen
237aa16c6bdSLars-Peter Clausen ad7766->pd_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
238aa16c6bdSLars-Peter Clausen GPIOD_OUT_HIGH);
239aa16c6bdSLars-Peter Clausen if (IS_ERR(ad7766->pd_gpio))
240aa16c6bdSLars-Peter Clausen return PTR_ERR(ad7766->pd_gpio);
241aa16c6bdSLars-Peter Clausen
242aa16c6bdSLars-Peter Clausen indio_dev->name = spi_get_device_id(spi)->name;
243aa16c6bdSLars-Peter Clausen indio_dev->modes = INDIO_DIRECT_MODE;
244aa16c6bdSLars-Peter Clausen indio_dev->channels = ad7766_channels;
245aa16c6bdSLars-Peter Clausen indio_dev->num_channels = ARRAY_SIZE(ad7766_channels);
246aa16c6bdSLars-Peter Clausen indio_dev->info = &ad7766_info;
247aa16c6bdSLars-Peter Clausen
248aa16c6bdSLars-Peter Clausen if (spi->irq > 0) {
249aa16c6bdSLars-Peter Clausen ad7766->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
25015ea2878SJonathan Cameron indio_dev->name,
25115ea2878SJonathan Cameron iio_device_id(indio_dev));
252aa16c6bdSLars-Peter Clausen if (!ad7766->trig)
253aa16c6bdSLars-Peter Clausen return -ENOMEM;
254aa16c6bdSLars-Peter Clausen
255aa16c6bdSLars-Peter Clausen ad7766->trig->ops = &ad7766_trigger_ops;
256aa16c6bdSLars-Peter Clausen iio_trigger_set_drvdata(ad7766->trig, ad7766);
257aa16c6bdSLars-Peter Clausen
258aa16c6bdSLars-Peter Clausen /*
259aa16c6bdSLars-Peter Clausen * The device generates interrupts as long as it is powered up.
260aa16c6bdSLars-Peter Clausen * Some platforms might not allow the option to power it down so
2610be49bdeSJonathan Cameron * don't enable the interrupt to avoid extra load on the system
262aa16c6bdSLars-Peter Clausen */
2630be49bdeSJonathan Cameron ret = devm_request_irq(&spi->dev, spi->irq, ad7766_irq,
2640be49bdeSJonathan Cameron IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
2650be49bdeSJonathan Cameron dev_name(&spi->dev),
2660be49bdeSJonathan Cameron ad7766->trig);
2670be49bdeSJonathan Cameron if (ret < 0)
2680be49bdeSJonathan Cameron return ret;
269aa16c6bdSLars-Peter Clausen
270aa16c6bdSLars-Peter Clausen ret = devm_iio_trigger_register(&spi->dev, ad7766->trig);
271aa16c6bdSLars-Peter Clausen if (ret)
272aa16c6bdSLars-Peter Clausen return ret;
273aa16c6bdSLars-Peter Clausen }
274aa16c6bdSLars-Peter Clausen
275aa16c6bdSLars-Peter Clausen ad7766->spi = spi;
276aa16c6bdSLars-Peter Clausen
277aa16c6bdSLars-Peter Clausen /* First byte always 0 */
278aa16c6bdSLars-Peter Clausen ad7766->xfer.rx_buf = &ad7766->data[1];
279aa16c6bdSLars-Peter Clausen ad7766->xfer.len = 3;
280aa16c6bdSLars-Peter Clausen
281aa16c6bdSLars-Peter Clausen spi_message_init(&ad7766->msg);
282aa16c6bdSLars-Peter Clausen spi_message_add_tail(&ad7766->xfer, &ad7766->msg);
283aa16c6bdSLars-Peter Clausen
284aa16c6bdSLars-Peter Clausen ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
285aa16c6bdSLars-Peter Clausen &iio_pollfunc_store_time, &ad7766_trigger_handler,
286aa16c6bdSLars-Peter Clausen &ad7766_buffer_setup_ops);
287aa16c6bdSLars-Peter Clausen if (ret)
288aa16c6bdSLars-Peter Clausen return ret;
289aa16c6bdSLars-Peter Clausen
290bd145561STang Bin return devm_iio_device_register(&spi->dev, indio_dev);
291aa16c6bdSLars-Peter Clausen }
292aa16c6bdSLars-Peter Clausen
293aa16c6bdSLars-Peter Clausen static const struct spi_device_id ad7766_id[] = {
294aa16c6bdSLars-Peter Clausen {"ad7766", ID_AD7766},
295aa16c6bdSLars-Peter Clausen {"ad7766-1", ID_AD7766_1},
296aa16c6bdSLars-Peter Clausen {"ad7766-2", ID_AD7766_2},
297aa16c6bdSLars-Peter Clausen {"ad7767", ID_AD7766},
298aa16c6bdSLars-Peter Clausen {"ad7767-1", ID_AD7766_1},
299aa16c6bdSLars-Peter Clausen {"ad7767-2", ID_AD7766_2},
300aa16c6bdSLars-Peter Clausen {}
301aa16c6bdSLars-Peter Clausen };
302aa16c6bdSLars-Peter Clausen MODULE_DEVICE_TABLE(spi, ad7766_id);
303aa16c6bdSLars-Peter Clausen
304aa16c6bdSLars-Peter Clausen static struct spi_driver ad7766_driver = {
305aa16c6bdSLars-Peter Clausen .driver = {
306aa16c6bdSLars-Peter Clausen .name = "ad7766",
307aa16c6bdSLars-Peter Clausen },
308aa16c6bdSLars-Peter Clausen .probe = ad7766_probe,
309aa16c6bdSLars-Peter Clausen .id_table = ad7766_id,
310aa16c6bdSLars-Peter Clausen };
311aa16c6bdSLars-Peter Clausen module_spi_driver(ad7766_driver);
312aa16c6bdSLars-Peter Clausen
313aa16c6bdSLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
314aa16c6bdSLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices AD7766 and AD7767 ADCs driver support");
315aa16c6bdSLars-Peter Clausen MODULE_LICENSE("GPL v2");
316