138ffa3a3SAlexandru Ardelean // SPDX-License-Identifier: GPL-2.0
2e71d42e0SMichael Hennerich /*
3cee211f4SPaul Cercueil * AD8366 and similar Gain Amplifiers
4cee211f4SPaul Cercueil * This driver supports the following gain amplifiers:
5cee211f4SPaul Cercueil * AD8366 Dual-Digital Variable Gain Amplifier (VGA)
6cee211f4SPaul Cercueil * ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
7075da9cdSAlexandru Ardelean * ADL5240 Digitally controlled variable gain amplifier (VGA)
8*247d3b63SKim Seer Paller * HMC792A 0.25 dB LSB GaAs MMIC 6-Bit Digital Attenuator
9cc74a38dSSergiu Cuciurean * HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
10e71d42e0SMichael Hennerich *
1138ffa3a3SAlexandru Ardelean * Copyright 2012-2019 Analog Devices Inc.
12e71d42e0SMichael Hennerich */
13e71d42e0SMichael Hennerich
14e71d42e0SMichael Hennerich #include <linux/device.h>
15e71d42e0SMichael Hennerich #include <linux/kernel.h>
16e71d42e0SMichael Hennerich #include <linux/slab.h>
17e71d42e0SMichael Hennerich #include <linux/sysfs.h>
18e71d42e0SMichael Hennerich #include <linux/spi/spi.h>
19e71d42e0SMichael Hennerich #include <linux/regulator/consumer.h>
20cee211f4SPaul Cercueil #include <linux/gpio/consumer.h>
21e71d42e0SMichael Hennerich #include <linux/err.h>
22e71d42e0SMichael Hennerich #include <linux/module.h>
23e71d42e0SMichael Hennerich #include <linux/bitrev.h>
24e71d42e0SMichael Hennerich
25e71d42e0SMichael Hennerich #include <linux/iio/iio.h>
26e71d42e0SMichael Hennerich #include <linux/iio/sysfs.h>
27e71d42e0SMichael Hennerich
2811ab555aSAlexandru Ardelean enum ad8366_type {
2911ab555aSAlexandru Ardelean ID_AD8366,
30cee211f4SPaul Cercueil ID_ADA4961,
31075da9cdSAlexandru Ardelean ID_ADL5240,
32*247d3b63SKim Seer Paller ID_HMC792,
33cc74a38dSSergiu Cuciurean ID_HMC1119,
3411ab555aSAlexandru Ardelean };
3511ab555aSAlexandru Ardelean
3611ab555aSAlexandru Ardelean struct ad8366_info {
3711ab555aSAlexandru Ardelean int gain_min;
3811ab555aSAlexandru Ardelean int gain_max;
3911ab555aSAlexandru Ardelean };
4011ab555aSAlexandru Ardelean
41e71d42e0SMichael Hennerich struct ad8366_state {
42e71d42e0SMichael Hennerich struct spi_device *spi;
43e71d42e0SMichael Hennerich struct regulator *reg;
44dbcf6b5dSAlexandru Ardelean struct mutex lock; /* protect sensor state */
45cee211f4SPaul Cercueil struct gpio_desc *reset_gpio;
46e71d42e0SMichael Hennerich unsigned char ch[2];
4711ab555aSAlexandru Ardelean enum ad8366_type type;
4811ab555aSAlexandru Ardelean struct ad8366_info *info;
49e71d42e0SMichael Hennerich /*
50026bffa4SJonathan Cameron * DMA (thus cache coherency maintenance) may require the
51e71d42e0SMichael Hennerich * transfer buffers to live in their own cache lines.
52e71d42e0SMichael Hennerich */
53026bffa4SJonathan Cameron unsigned char data[2] __aligned(IIO_DMA_MINALIGN);
54e71d42e0SMichael Hennerich };
55e71d42e0SMichael Hennerich
5611ab555aSAlexandru Ardelean static struct ad8366_info ad8366_infos[] = {
5711ab555aSAlexandru Ardelean [ID_AD8366] = {
5811ab555aSAlexandru Ardelean .gain_min = 4500,
5911ab555aSAlexandru Ardelean .gain_max = 20500,
6011ab555aSAlexandru Ardelean },
61cee211f4SPaul Cercueil [ID_ADA4961] = {
62cee211f4SPaul Cercueil .gain_min = -6000,
63cee211f4SPaul Cercueil .gain_max = 15000,
64cee211f4SPaul Cercueil },
65075da9cdSAlexandru Ardelean [ID_ADL5240] = {
66075da9cdSAlexandru Ardelean .gain_min = -11500,
67075da9cdSAlexandru Ardelean .gain_max = 20000,
68075da9cdSAlexandru Ardelean },
69*247d3b63SKim Seer Paller [ID_HMC792] = {
70*247d3b63SKim Seer Paller .gain_min = -15750,
71*247d3b63SKim Seer Paller .gain_max = 0,
72*247d3b63SKim Seer Paller },
73cc74a38dSSergiu Cuciurean [ID_HMC1119] = {
74cc74a38dSSergiu Cuciurean .gain_min = -31750,
75cc74a38dSSergiu Cuciurean .gain_max = 0,
76cc74a38dSSergiu Cuciurean },
7711ab555aSAlexandru Ardelean };
7811ab555aSAlexandru Ardelean
ad8366_write(struct iio_dev * indio_dev,unsigned char ch_a,unsigned char ch_b)79e71d42e0SMichael Hennerich static int ad8366_write(struct iio_dev *indio_dev,
80ff6f4629SRoberta Dobrescu unsigned char ch_a, unsigned char ch_b)
81e71d42e0SMichael Hennerich {
82e71d42e0SMichael Hennerich struct ad8366_state *st = iio_priv(indio_dev);
83e71d42e0SMichael Hennerich int ret;
84e71d42e0SMichael Hennerich
8511ab555aSAlexandru Ardelean switch (st->type) {
8611ab555aSAlexandru Ardelean case ID_AD8366:
87e71d42e0SMichael Hennerich ch_a = bitrev8(ch_a & 0x3F);
88e71d42e0SMichael Hennerich ch_b = bitrev8(ch_b & 0x3F);
89e71d42e0SMichael Hennerich
90e71d42e0SMichael Hennerich st->data[0] = ch_b >> 4;
91e71d42e0SMichael Hennerich st->data[1] = (ch_b << 4) | (ch_a >> 2);
9211ab555aSAlexandru Ardelean break;
93cee211f4SPaul Cercueil case ID_ADA4961:
94cee211f4SPaul Cercueil st->data[0] = ch_a & 0x1F;
95cee211f4SPaul Cercueil break;
96075da9cdSAlexandru Ardelean case ID_ADL5240:
97075da9cdSAlexandru Ardelean st->data[0] = (ch_a & 0x3F);
98075da9cdSAlexandru Ardelean break;
99*247d3b63SKim Seer Paller case ID_HMC792:
100cc74a38dSSergiu Cuciurean case ID_HMC1119:
101cc74a38dSSergiu Cuciurean st->data[0] = ch_a;
102cc74a38dSSergiu Cuciurean break;
10311ab555aSAlexandru Ardelean }
104e71d42e0SMichael Hennerich
10511ab555aSAlexandru Ardelean ret = spi_write(st->spi, st->data, indio_dev->num_channels);
106e71d42e0SMichael Hennerich if (ret < 0)
107e71d42e0SMichael Hennerich dev_err(&indio_dev->dev, "write failed (%d)", ret);
108e71d42e0SMichael Hennerich
109e71d42e0SMichael Hennerich return ret;
110e71d42e0SMichael Hennerich }
111e71d42e0SMichael Hennerich
ad8366_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long m)112e71d42e0SMichael Hennerich static int ad8366_read_raw(struct iio_dev *indio_dev,
113e71d42e0SMichael Hennerich struct iio_chan_spec const *chan,
114e71d42e0SMichael Hennerich int *val,
115e71d42e0SMichael Hennerich int *val2,
116e71d42e0SMichael Hennerich long m)
117e71d42e0SMichael Hennerich {
118e71d42e0SMichael Hennerich struct ad8366_state *st = iio_priv(indio_dev);
119e71d42e0SMichael Hennerich int ret;
12011ab555aSAlexandru Ardelean int code, gain = 0;
121e71d42e0SMichael Hennerich
122dbcf6b5dSAlexandru Ardelean mutex_lock(&st->lock);
123e71d42e0SMichael Hennerich switch (m) {
124e71d42e0SMichael Hennerich case IIO_CHAN_INFO_HARDWAREGAIN:
125e71d42e0SMichael Hennerich code = st->ch[chan->channel];
126e71d42e0SMichael Hennerich
12711ab555aSAlexandru Ardelean switch (st->type) {
12811ab555aSAlexandru Ardelean case ID_AD8366:
12911ab555aSAlexandru Ardelean gain = code * 253 + 4500;
13011ab555aSAlexandru Ardelean break;
131cee211f4SPaul Cercueil case ID_ADA4961:
132cee211f4SPaul Cercueil gain = 15000 - code * 1000;
133cee211f4SPaul Cercueil break;
134075da9cdSAlexandru Ardelean case ID_ADL5240:
135075da9cdSAlexandru Ardelean gain = 20000 - 31500 + code * 500;
136075da9cdSAlexandru Ardelean break;
137*247d3b63SKim Seer Paller case ID_HMC792:
138*247d3b63SKim Seer Paller gain = -1 * code * 500;
139*247d3b63SKim Seer Paller break;
140cc74a38dSSergiu Cuciurean case ID_HMC1119:
141cc74a38dSSergiu Cuciurean gain = -1 * code * 250;
142cc74a38dSSergiu Cuciurean break;
14311ab555aSAlexandru Ardelean }
14411ab555aSAlexandru Ardelean
145e71d42e0SMichael Hennerich /* Values in dB */
14611ab555aSAlexandru Ardelean *val = gain / 1000;
14711ab555aSAlexandru Ardelean *val2 = (gain % 1000) * 1000;
148e71d42e0SMichael Hennerich
149e71d42e0SMichael Hennerich ret = IIO_VAL_INT_PLUS_MICRO_DB;
150e71d42e0SMichael Hennerich break;
151e71d42e0SMichael Hennerich default:
152e71d42e0SMichael Hennerich ret = -EINVAL;
153e71d42e0SMichael Hennerich }
154dbcf6b5dSAlexandru Ardelean mutex_unlock(&st->lock);
155e71d42e0SMichael Hennerich
156e71d42e0SMichael Hennerich return ret;
157e71d42e0SMichael Hennerich };
158e71d42e0SMichael Hennerich
ad8366_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)159e71d42e0SMichael Hennerich static int ad8366_write_raw(struct iio_dev *indio_dev,
160e71d42e0SMichael Hennerich struct iio_chan_spec const *chan,
161e71d42e0SMichael Hennerich int val,
162e71d42e0SMichael Hennerich int val2,
163e71d42e0SMichael Hennerich long mask)
164e71d42e0SMichael Hennerich {
165e71d42e0SMichael Hennerich struct ad8366_state *st = iio_priv(indio_dev);
16611ab555aSAlexandru Ardelean struct ad8366_info *inf = st->info;
16711ab555aSAlexandru Ardelean int code = 0, gain;
168e71d42e0SMichael Hennerich int ret;
169e71d42e0SMichael Hennerich
170e71d42e0SMichael Hennerich /* Values in dB */
17111ab555aSAlexandru Ardelean if (val < 0)
17211ab555aSAlexandru Ardelean gain = (val * 1000) - (val2 / 1000);
17311ab555aSAlexandru Ardelean else
17411ab555aSAlexandru Ardelean gain = (val * 1000) + (val2 / 1000);
175e71d42e0SMichael Hennerich
17611ab555aSAlexandru Ardelean if (gain > inf->gain_max || gain < inf->gain_min)
177e71d42e0SMichael Hennerich return -EINVAL;
178e71d42e0SMichael Hennerich
17911ab555aSAlexandru Ardelean switch (st->type) {
18011ab555aSAlexandru Ardelean case ID_AD8366:
18111ab555aSAlexandru Ardelean code = (gain - 4500) / 253;
18211ab555aSAlexandru Ardelean break;
183cee211f4SPaul Cercueil case ID_ADA4961:
184cee211f4SPaul Cercueil code = (15000 - gain) / 1000;
185cee211f4SPaul Cercueil break;
186075da9cdSAlexandru Ardelean case ID_ADL5240:
187075da9cdSAlexandru Ardelean code = ((gain - 500 - 20000) / 500) & 0x3F;
188075da9cdSAlexandru Ardelean break;
189*247d3b63SKim Seer Paller case ID_HMC792:
190*247d3b63SKim Seer Paller code = (abs(gain) / 500) & 0x3F;
191*247d3b63SKim Seer Paller break;
192cc74a38dSSergiu Cuciurean case ID_HMC1119:
193cc74a38dSSergiu Cuciurean code = (abs(gain) / 250) & 0x7F;
194cc74a38dSSergiu Cuciurean break;
19511ab555aSAlexandru Ardelean }
196e71d42e0SMichael Hennerich
197dbcf6b5dSAlexandru Ardelean mutex_lock(&st->lock);
198e71d42e0SMichael Hennerich switch (mask) {
199e71d42e0SMichael Hennerich case IIO_CHAN_INFO_HARDWAREGAIN:
200e71d42e0SMichael Hennerich st->ch[chan->channel] = code;
201e71d42e0SMichael Hennerich ret = ad8366_write(indio_dev, st->ch[0], st->ch[1]);
202e71d42e0SMichael Hennerich break;
203e71d42e0SMichael Hennerich default:
204e71d42e0SMichael Hennerich ret = -EINVAL;
205e71d42e0SMichael Hennerich }
206dbcf6b5dSAlexandru Ardelean mutex_unlock(&st->lock);
207e71d42e0SMichael Hennerich
208e71d42e0SMichael Hennerich return ret;
209e71d42e0SMichael Hennerich }
210e71d42e0SMichael Hennerich
ad8366_write_raw_get_fmt(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,long mask)2110cc97f2eSBeniamin Bia static int ad8366_write_raw_get_fmt(struct iio_dev *indio_dev,
2120cc97f2eSBeniamin Bia struct iio_chan_spec const *chan,
2130cc97f2eSBeniamin Bia long mask)
2140cc97f2eSBeniamin Bia {
2150cc97f2eSBeniamin Bia switch (mask) {
2160cc97f2eSBeniamin Bia case IIO_CHAN_INFO_HARDWAREGAIN:
2170cc97f2eSBeniamin Bia return IIO_VAL_INT_PLUS_MICRO_DB;
2180cc97f2eSBeniamin Bia default:
2190cc97f2eSBeniamin Bia return -EINVAL;
2200cc97f2eSBeniamin Bia }
2210cc97f2eSBeniamin Bia }
2220cc97f2eSBeniamin Bia
223e71d42e0SMichael Hennerich static const struct iio_info ad8366_info = {
224e71d42e0SMichael Hennerich .read_raw = &ad8366_read_raw,
225e71d42e0SMichael Hennerich .write_raw = &ad8366_write_raw,
2260cc97f2eSBeniamin Bia .write_raw_get_fmt = &ad8366_write_raw_get_fmt,
227e71d42e0SMichael Hennerich };
228e71d42e0SMichael Hennerich
229e71d42e0SMichael Hennerich #define AD8366_CHAN(_channel) { \
230e71d42e0SMichael Hennerich .type = IIO_VOLTAGE, \
231e71d42e0SMichael Hennerich .output = 1, \
232e71d42e0SMichael Hennerich .indexed = 1, \
233e71d42e0SMichael Hennerich .channel = _channel, \
234b34ec6f3SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN),\
235e71d42e0SMichael Hennerich }
236e71d42e0SMichael Hennerich
237e71d42e0SMichael Hennerich static const struct iio_chan_spec ad8366_channels[] = {
238e71d42e0SMichael Hennerich AD8366_CHAN(0),
239e71d42e0SMichael Hennerich AD8366_CHAN(1),
240e71d42e0SMichael Hennerich };
241e71d42e0SMichael Hennerich
242cee211f4SPaul Cercueil static const struct iio_chan_spec ada4961_channels[] = {
243cee211f4SPaul Cercueil AD8366_CHAN(0),
244cee211f4SPaul Cercueil };
245cee211f4SPaul Cercueil
ad8366_probe(struct spi_device * spi)246fc52692cSGreg Kroah-Hartman static int ad8366_probe(struct spi_device *spi)
247e71d42e0SMichael Hennerich {
248e71d42e0SMichael Hennerich struct iio_dev *indio_dev;
249e71d42e0SMichael Hennerich struct ad8366_state *st;
250e71d42e0SMichael Hennerich int ret;
251e71d42e0SMichael Hennerich
25236db8c72SSachin Kamat indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
253e71d42e0SMichael Hennerich if (indio_dev == NULL)
254e71d42e0SMichael Hennerich return -ENOMEM;
255e71d42e0SMichael Hennerich
256e71d42e0SMichael Hennerich st = iio_priv(indio_dev);
257e71d42e0SMichael Hennerich
25836db8c72SSachin Kamat st->reg = devm_regulator_get(&spi->dev, "vcc");
259e71d42e0SMichael Hennerich if (!IS_ERR(st->reg)) {
260e71d42e0SMichael Hennerich ret = regulator_enable(st->reg);
261e71d42e0SMichael Hennerich if (ret)
26236db8c72SSachin Kamat return ret;
263e71d42e0SMichael Hennerich }
264e71d42e0SMichael Hennerich
265e71d42e0SMichael Hennerich spi_set_drvdata(spi, indio_dev);
266dbcf6b5dSAlexandru Ardelean mutex_init(&st->lock);
267e71d42e0SMichael Hennerich st->spi = spi;
26811ab555aSAlexandru Ardelean st->type = spi_get_device_id(spi)->driver_data;
269e71d42e0SMichael Hennerich
27011ab555aSAlexandru Ardelean switch (st->type) {
27111ab555aSAlexandru Ardelean case ID_AD8366:
27211ab555aSAlexandru Ardelean indio_dev->channels = ad8366_channels;
27311ab555aSAlexandru Ardelean indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
27411ab555aSAlexandru Ardelean break;
275cee211f4SPaul Cercueil case ID_ADA4961:
276075da9cdSAlexandru Ardelean case ID_ADL5240:
277*247d3b63SKim Seer Paller case ID_HMC792:
278cc74a38dSSergiu Cuciurean case ID_HMC1119:
2799ca39411SChuhong Yuan st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH);
2809ca39411SChuhong Yuan if (IS_ERR(st->reset_gpio)) {
2819ca39411SChuhong Yuan ret = PTR_ERR(st->reset_gpio);
2829ca39411SChuhong Yuan goto error_disable_reg;
2839ca39411SChuhong Yuan }
284cee211f4SPaul Cercueil indio_dev->channels = ada4961_channels;
285cee211f4SPaul Cercueil indio_dev->num_channels = ARRAY_SIZE(ada4961_channels);
286cee211f4SPaul Cercueil break;
28711ab555aSAlexandru Ardelean default:
28811ab555aSAlexandru Ardelean dev_err(&spi->dev, "Invalid device ID\n");
28911ab555aSAlexandru Ardelean ret = -EINVAL;
29011ab555aSAlexandru Ardelean goto error_disable_reg;
29111ab555aSAlexandru Ardelean }
29211ab555aSAlexandru Ardelean
29311ab555aSAlexandru Ardelean st->info = &ad8366_infos[st->type];
294e71d42e0SMichael Hennerich indio_dev->name = spi_get_device_id(spi)->name;
295e71d42e0SMichael Hennerich indio_dev->info = &ad8366_info;
296e71d42e0SMichael Hennerich indio_dev->modes = INDIO_DIRECT_MODE;
297e71d42e0SMichael Hennerich
2982636d005SAlexandru Ardelean ret = ad8366_write(indio_dev, 0, 0);
2992636d005SAlexandru Ardelean if (ret < 0)
3002636d005SAlexandru Ardelean goto error_disable_reg;
3012636d005SAlexandru Ardelean
302e71d42e0SMichael Hennerich ret = iio_device_register(indio_dev);
303e71d42e0SMichael Hennerich if (ret)
304e71d42e0SMichael Hennerich goto error_disable_reg;
305e71d42e0SMichael Hennerich
306e71d42e0SMichael Hennerich return 0;
307e71d42e0SMichael Hennerich
308e71d42e0SMichael Hennerich error_disable_reg:
309e71d42e0SMichael Hennerich if (!IS_ERR(st->reg))
310e71d42e0SMichael Hennerich regulator_disable(st->reg);
311e71d42e0SMichael Hennerich
312e71d42e0SMichael Hennerich return ret;
313e71d42e0SMichael Hennerich }
314e71d42e0SMichael Hennerich
ad8366_remove(struct spi_device * spi)315a0386bbaSUwe Kleine-König static void ad8366_remove(struct spi_device *spi)
316e71d42e0SMichael Hennerich {
317e71d42e0SMichael Hennerich struct iio_dev *indio_dev = spi_get_drvdata(spi);
318e71d42e0SMichael Hennerich struct ad8366_state *st = iio_priv(indio_dev);
319e71d42e0SMichael Hennerich struct regulator *reg = st->reg;
320e71d42e0SMichael Hennerich
321e71d42e0SMichael Hennerich iio_device_unregister(indio_dev);
322e71d42e0SMichael Hennerich
323d3789c3eSSachin Kamat if (!IS_ERR(reg))
324e71d42e0SMichael Hennerich regulator_disable(reg);
325e71d42e0SMichael Hennerich }
326e71d42e0SMichael Hennerich
327e71d42e0SMichael Hennerich static const struct spi_device_id ad8366_id[] = {
32811ab555aSAlexandru Ardelean {"ad8366", ID_AD8366},
329cee211f4SPaul Cercueil {"ada4961", ID_ADA4961},
330075da9cdSAlexandru Ardelean {"adl5240", ID_ADL5240},
331*247d3b63SKim Seer Paller {"hmc792a", ID_HMC792},
332cc74a38dSSergiu Cuciurean {"hmc1119", ID_HMC1119},
333e71d42e0SMichael Hennerich {}
334e71d42e0SMichael Hennerich };
335ed199a11SJavier Martinez Canillas MODULE_DEVICE_TABLE(spi, ad8366_id);
336e71d42e0SMichael Hennerich
337e71d42e0SMichael Hennerich static struct spi_driver ad8366_driver = {
338e71d42e0SMichael Hennerich .driver = {
339e71d42e0SMichael Hennerich .name = KBUILD_MODNAME,
340e71d42e0SMichael Hennerich },
341e71d42e0SMichael Hennerich .probe = ad8366_probe,
342fc52692cSGreg Kroah-Hartman .remove = ad8366_remove,
343e71d42e0SMichael Hennerich .id_table = ad8366_id,
344e71d42e0SMichael Hennerich };
345e71d42e0SMichael Hennerich
346e71d42e0SMichael Hennerich module_spi_driver(ad8366_driver);
347e71d42e0SMichael Hennerich
3489920ed25SMichael Hennerich MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
349cee211f4SPaul Cercueil MODULE_DESCRIPTION("Analog Devices AD8366 and similar Gain Amplifiers");
350e71d42e0SMichael Hennerich MODULE_LICENSE("GPL v2");
351