1// SPDX-License-Identifier: GPL-2.0
2/*
3 * AD8366 and similar Gain Amplifiers
4 * This driver supports the following gain amplifiers:
5 * AD8366 Dual-Digital Variable Gain Amplifier (VGA)
6 * ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
7 * ADL5240 Digitally controlled variable gain amplifier (VGA)
8 * HMC792A 0.25 dB LSB GaAs MMIC 6-Bit Digital Attenuator
9 * HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
10 *
11 * Copyright 2012-2019 Analog Devices Inc.
12 */
13
14#include <linux/device.h>
15#include <linux/kernel.h>
16#include <linux/slab.h>
17#include <linux/sysfs.h>
18#include <linux/spi/spi.h>
19#include <linux/regulator/consumer.h>
20#include <linux/gpio/consumer.h>
21#include <linux/err.h>
22#include <linux/module.h>
23#include <linux/bitrev.h>
24
25#include <linux/iio/iio.h>
26#include <linux/iio/sysfs.h>
27
28enum ad8366_type {
29 ID_AD8366,
30 ID_ADA4961,
31 ID_ADL5240,
32 ID_HMC792,
33 ID_HMC1119,
34};
35
36struct ad8366_info {
37 int gain_min;
38 int gain_max;
39};
40
41struct ad8366_state {
42 struct spi_device *spi;
43 struct regulator *reg;
44 struct mutex lock; /* protect sensor state */
45 struct gpio_desc *reset_gpio;
46 unsigned char ch[2];
47 enum ad8366_type type;
48 struct ad8366_info *info;
49 /*
50 * DMA (thus cache coherency maintenance) may require the
51 * transfer buffers to live in their own cache lines.
52 */
53 unsigned char data[2] __aligned(IIO_DMA_MINALIGN);
54};
55
56static struct ad8366_info ad8366_infos[] = {
57 [ID_AD8366] = {
58 .gain_min = 4500,
59 .gain_max = 20500,
60 },
61 [ID_ADA4961] = {
62 .gain_min = -6000,
63 .gain_max = 15000,
64 },
65 [ID_ADL5240] = {
66 .gain_min = -11500,
67 .gain_max = 20000,
68 },
69 [ID_HMC792] = {
70 .gain_min = -15750,
71 .gain_max = 0,
72 },
73 [ID_HMC1119] = {
74 .gain_min = -31750,
75 .gain_max = 0,
76 },
77};
78
79static int ad8366_write(struct iio_dev *indio_dev,
80 unsigned char ch_a, unsigned char ch_b)
81{
82 struct ad8366_state *st = iio_priv(indio_dev);
83 int ret;
84
85 switch (st->type) {
86 case ID_AD8366:
87 ch_a = bitrev8(ch_a & 0x3F);
88 ch_b = bitrev8(ch_b & 0x3F);
89
90 st->data[0] = ch_b >> 4;
91 st->data[1] = (ch_b << 4) | (ch_a >> 2);
92 break;
93 case ID_ADA4961:
94 st->data[0] = ch_a & 0x1F;
95 break;
96 case ID_ADL5240:
97 st->data[0] = (ch_a & 0x3F);
98 break;
99 case ID_HMC792:
100 case ID_HMC1119:
101 st->data[0] = ch_a;
102 break;
103 }
104
105 ret = spi_write(spi: st->spi, buf: st->data, len: indio_dev->num_channels);
106 if (ret < 0)
107 dev_err(&indio_dev->dev, "write failed (%d)", ret);
108
109 return ret;
110}
111
112static int ad8366_read_raw(struct iio_dev *indio_dev,
113 struct iio_chan_spec const *chan,
114 int *val,
115 int *val2,
116 long m)
117{
118 struct ad8366_state *st = iio_priv(indio_dev);
119 int ret;
120 int code, gain = 0;
121
122 mutex_lock(&st->lock);
123 switch (m) {
124 case IIO_CHAN_INFO_HARDWAREGAIN:
125 code = st->ch[chan->channel];
126
127 switch (st->type) {
128 case ID_AD8366:
129 gain = code * 253 + 4500;
130 break;
131 case ID_ADA4961:
132 gain = 15000 - code * 1000;
133 break;
134 case ID_ADL5240:
135 gain = 20000 - 31500 + code * 500;
136 break;
137 case ID_HMC792:
138 gain = -1 * code * 500;
139 break;
140 case ID_HMC1119:
141 gain = -1 * code * 250;
142 break;
143 }
144
145 /* Values in dB */
146 *val = gain / 1000;
147 *val2 = (gain % 1000) * 1000;
148
149 ret = IIO_VAL_INT_PLUS_MICRO_DB;
150 break;
151 default:
152 ret = -EINVAL;
153 }
154 mutex_unlock(lock: &st->lock);
155
156 return ret;
157};
158
159static int ad8366_write_raw(struct iio_dev *indio_dev,
160 struct iio_chan_spec const *chan,
161 int val,
162 int val2,
163 long mask)
164{
165 struct ad8366_state *st = iio_priv(indio_dev);
166 struct ad8366_info *inf = st->info;
167 int code = 0, gain;
168 int ret;
169
170 /* Values in dB */
171 if (val < 0)
172 gain = (val * 1000) - (val2 / 1000);
173 else
174 gain = (val * 1000) + (val2 / 1000);
175
176 if (gain > inf->gain_max || gain < inf->gain_min)
177 return -EINVAL;
178
179 switch (st->type) {
180 case ID_AD8366:
181 code = (gain - 4500) / 253;
182 break;
183 case ID_ADA4961:
184 code = (15000 - gain) / 1000;
185 break;
186 case ID_ADL5240:
187 code = ((gain - 500 - 20000) / 500) & 0x3F;
188 break;
189 case ID_HMC792:
190 code = (abs(gain) / 500) & 0x3F;
191 break;
192 case ID_HMC1119:
193 code = (abs(gain) / 250) & 0x7F;
194 break;
195 }
196
197 mutex_lock(&st->lock);
198 switch (mask) {
199 case IIO_CHAN_INFO_HARDWAREGAIN:
200 st->ch[chan->channel] = code;
201 ret = ad8366_write(indio_dev, ch_a: st->ch[0], ch_b: st->ch[1]);
202 break;
203 default:
204 ret = -EINVAL;
205 }
206 mutex_unlock(lock: &st->lock);
207
208 return ret;
209}
210
211static int ad8366_write_raw_get_fmt(struct iio_dev *indio_dev,
212 struct iio_chan_spec const *chan,
213 long mask)
214{
215 switch (mask) {
216 case IIO_CHAN_INFO_HARDWAREGAIN:
217 return IIO_VAL_INT_PLUS_MICRO_DB;
218 default:
219 return -EINVAL;
220 }
221}
222
223static const struct iio_info ad8366_info = {
224 .read_raw = &ad8366_read_raw,
225 .write_raw = &ad8366_write_raw,
226 .write_raw_get_fmt = &ad8366_write_raw_get_fmt,
227};
228
229#define AD8366_CHAN(_channel) { \
230 .type = IIO_VOLTAGE, \
231 .output = 1, \
232 .indexed = 1, \
233 .channel = _channel, \
234 .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN),\
235}
236
237static const struct iio_chan_spec ad8366_channels[] = {
238 AD8366_CHAN(0),
239 AD8366_CHAN(1),
240};
241
242static const struct iio_chan_spec ada4961_channels[] = {
243 AD8366_CHAN(0),
244};
245
246static int ad8366_probe(struct spi_device *spi)
247{
248 struct iio_dev *indio_dev;
249 struct ad8366_state *st;
250 int ret;
251
252 indio_dev = devm_iio_device_alloc(parent: &spi->dev, sizeof_priv: sizeof(*st));
253 if (indio_dev == NULL)
254 return -ENOMEM;
255
256 st = iio_priv(indio_dev);
257
258 st->reg = devm_regulator_get(dev: &spi->dev, id: "vcc");
259 if (!IS_ERR(ptr: st->reg)) {
260 ret = regulator_enable(regulator: st->reg);
261 if (ret)
262 return ret;
263 }
264
265 spi_set_drvdata(spi, data: indio_dev);
266 mutex_init(&st->lock);
267 st->spi = spi;
268 st->type = spi_get_device_id(sdev: spi)->driver_data;
269
270 switch (st->type) {
271 case ID_AD8366:
272 indio_dev->channels = ad8366_channels;
273 indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
274 break;
275 case ID_ADA4961:
276 case ID_ADL5240:
277 case ID_HMC792:
278 case ID_HMC1119:
279 st->reset_gpio = devm_gpiod_get_optional(dev: &spi->dev, con_id: "reset", flags: GPIOD_OUT_HIGH);
280 if (IS_ERR(ptr: st->reset_gpio)) {
281 ret = PTR_ERR(ptr: st->reset_gpio);
282 goto error_disable_reg;
283 }
284 indio_dev->channels = ada4961_channels;
285 indio_dev->num_channels = ARRAY_SIZE(ada4961_channels);
286 break;
287 default:
288 dev_err(&spi->dev, "Invalid device ID\n");
289 ret = -EINVAL;
290 goto error_disable_reg;
291 }
292
293 st->info = &ad8366_infos[st->type];
294 indio_dev->name = spi_get_device_id(sdev: spi)->name;
295 indio_dev->info = &ad8366_info;
296 indio_dev->modes = INDIO_DIRECT_MODE;
297
298 ret = ad8366_write(indio_dev, ch_a: 0, ch_b: 0);
299 if (ret < 0)
300 goto error_disable_reg;
301
302 ret = iio_device_register(indio_dev);
303 if (ret)
304 goto error_disable_reg;
305
306 return 0;
307
308error_disable_reg:
309 if (!IS_ERR(ptr: st->reg))
310 regulator_disable(regulator: st->reg);
311
312 return ret;
313}
314
315static void ad8366_remove(struct spi_device *spi)
316{
317 struct iio_dev *indio_dev = spi_get_drvdata(spi);
318 struct ad8366_state *st = iio_priv(indio_dev);
319 struct regulator *reg = st->reg;
320
321 iio_device_unregister(indio_dev);
322
323 if (!IS_ERR(ptr: reg))
324 regulator_disable(regulator: reg);
325}
326
327static const struct spi_device_id ad8366_id[] = {
328 {"ad8366", ID_AD8366},
329 {"ada4961", ID_ADA4961},
330 {"adl5240", ID_ADL5240},
331 {"hmc792a", ID_HMC792},
332 {"hmc1119", ID_HMC1119},
333 {}
334};
335MODULE_DEVICE_TABLE(spi, ad8366_id);
336
337static struct spi_driver ad8366_driver = {
338 .driver = {
339 .name = KBUILD_MODNAME,
340 },
341 .probe = ad8366_probe,
342 .remove = ad8366_remove,
343 .id_table = ad8366_id,
344};
345
346module_spi_driver(ad8366_driver);
347
348MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
349MODULE_DESCRIPTION("Analog Devices AD8366 and similar Gain Amplifiers");
350MODULE_LICENSE("GPL v2");
351

source code of linux/drivers/iio/amplifiers/ad8366.c