.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | | - * AD8366 SPI Dual-Digital Variable Gain Amplifier (VGA) |
---|
| 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 | + * HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator |
---|
3 | 9 | * |
---|
4 | | - * Copyright 2012 Analog Devices Inc. |
---|
5 | | - * |
---|
6 | | - * Licensed under the GPL-2. |
---|
| 10 | + * Copyright 2012-2019 Analog Devices Inc. |
---|
7 | 11 | */ |
---|
8 | 12 | |
---|
9 | 13 | #include <linux/device.h> |
---|
.. | .. |
---|
12 | 16 | #include <linux/sysfs.h> |
---|
13 | 17 | #include <linux/spi/spi.h> |
---|
14 | 18 | #include <linux/regulator/consumer.h> |
---|
| 19 | +#include <linux/gpio/consumer.h> |
---|
15 | 20 | #include <linux/err.h> |
---|
16 | 21 | #include <linux/module.h> |
---|
17 | 22 | #include <linux/bitrev.h> |
---|
.. | .. |
---|
19 | 24 | #include <linux/iio/iio.h> |
---|
20 | 25 | #include <linux/iio/sysfs.h> |
---|
21 | 26 | |
---|
| 27 | +enum ad8366_type { |
---|
| 28 | + ID_AD8366, |
---|
| 29 | + ID_ADA4961, |
---|
| 30 | + ID_ADL5240, |
---|
| 31 | + ID_HMC1119, |
---|
| 32 | +}; |
---|
| 33 | + |
---|
| 34 | +struct ad8366_info { |
---|
| 35 | + int gain_min; |
---|
| 36 | + int gain_max; |
---|
| 37 | +}; |
---|
| 38 | + |
---|
22 | 39 | struct ad8366_state { |
---|
23 | 40 | struct spi_device *spi; |
---|
24 | 41 | struct regulator *reg; |
---|
| 42 | + struct mutex lock; /* protect sensor state */ |
---|
| 43 | + struct gpio_desc *reset_gpio; |
---|
25 | 44 | unsigned char ch[2]; |
---|
| 45 | + enum ad8366_type type; |
---|
| 46 | + struct ad8366_info *info; |
---|
26 | 47 | /* |
---|
27 | 48 | * DMA (thus cache coherency maintenance) requires the |
---|
28 | 49 | * transfer buffers to live in their own cache lines. |
---|
29 | 50 | */ |
---|
30 | 51 | unsigned char data[2] ____cacheline_aligned; |
---|
| 52 | +}; |
---|
| 53 | + |
---|
| 54 | +static struct ad8366_info ad8366_infos[] = { |
---|
| 55 | + [ID_AD8366] = { |
---|
| 56 | + .gain_min = 4500, |
---|
| 57 | + .gain_max = 20500, |
---|
| 58 | + }, |
---|
| 59 | + [ID_ADA4961] = { |
---|
| 60 | + .gain_min = -6000, |
---|
| 61 | + .gain_max = 15000, |
---|
| 62 | + }, |
---|
| 63 | + [ID_ADL5240] = { |
---|
| 64 | + .gain_min = -11500, |
---|
| 65 | + .gain_max = 20000, |
---|
| 66 | + }, |
---|
| 67 | + [ID_HMC1119] = { |
---|
| 68 | + .gain_min = -31750, |
---|
| 69 | + .gain_max = 0, |
---|
| 70 | + }, |
---|
31 | 71 | }; |
---|
32 | 72 | |
---|
33 | 73 | static int ad8366_write(struct iio_dev *indio_dev, |
---|
.. | .. |
---|
36 | 76 | struct ad8366_state *st = iio_priv(indio_dev); |
---|
37 | 77 | int ret; |
---|
38 | 78 | |
---|
39 | | - ch_a = bitrev8(ch_a & 0x3F); |
---|
40 | | - ch_b = bitrev8(ch_b & 0x3F); |
---|
| 79 | + switch (st->type) { |
---|
| 80 | + case ID_AD8366: |
---|
| 81 | + ch_a = bitrev8(ch_a & 0x3F); |
---|
| 82 | + ch_b = bitrev8(ch_b & 0x3F); |
---|
41 | 83 | |
---|
42 | | - st->data[0] = ch_b >> 4; |
---|
43 | | - st->data[1] = (ch_b << 4) | (ch_a >> 2); |
---|
| 84 | + st->data[0] = ch_b >> 4; |
---|
| 85 | + st->data[1] = (ch_b << 4) | (ch_a >> 2); |
---|
| 86 | + break; |
---|
| 87 | + case ID_ADA4961: |
---|
| 88 | + st->data[0] = ch_a & 0x1F; |
---|
| 89 | + break; |
---|
| 90 | + case ID_ADL5240: |
---|
| 91 | + st->data[0] = (ch_a & 0x3F); |
---|
| 92 | + break; |
---|
| 93 | + case ID_HMC1119: |
---|
| 94 | + st->data[0] = ch_a; |
---|
| 95 | + break; |
---|
| 96 | + } |
---|
44 | 97 | |
---|
45 | | - ret = spi_write(st->spi, st->data, ARRAY_SIZE(st->data)); |
---|
| 98 | + ret = spi_write(st->spi, st->data, indio_dev->num_channels); |
---|
46 | 99 | if (ret < 0) |
---|
47 | 100 | dev_err(&indio_dev->dev, "write failed (%d)", ret); |
---|
48 | 101 | |
---|
.. | .. |
---|
57 | 110 | { |
---|
58 | 111 | struct ad8366_state *st = iio_priv(indio_dev); |
---|
59 | 112 | int ret; |
---|
60 | | - unsigned code; |
---|
| 113 | + int code, gain = 0; |
---|
61 | 114 | |
---|
62 | | - mutex_lock(&indio_dev->mlock); |
---|
| 115 | + mutex_lock(&st->lock); |
---|
63 | 116 | switch (m) { |
---|
64 | 117 | case IIO_CHAN_INFO_HARDWAREGAIN: |
---|
65 | 118 | code = st->ch[chan->channel]; |
---|
66 | 119 | |
---|
| 120 | + switch (st->type) { |
---|
| 121 | + case ID_AD8366: |
---|
| 122 | + gain = code * 253 + 4500; |
---|
| 123 | + break; |
---|
| 124 | + case ID_ADA4961: |
---|
| 125 | + gain = 15000 - code * 1000; |
---|
| 126 | + break; |
---|
| 127 | + case ID_ADL5240: |
---|
| 128 | + gain = 20000 - 31500 + code * 500; |
---|
| 129 | + break; |
---|
| 130 | + case ID_HMC1119: |
---|
| 131 | + gain = -1 * code * 250; |
---|
| 132 | + break; |
---|
| 133 | + } |
---|
| 134 | + |
---|
67 | 135 | /* Values in dB */ |
---|
68 | | - code = code * 253 + 4500; |
---|
69 | | - *val = code / 1000; |
---|
70 | | - *val2 = (code % 1000) * 1000; |
---|
| 136 | + *val = gain / 1000; |
---|
| 137 | + *val2 = (gain % 1000) * 1000; |
---|
71 | 138 | |
---|
72 | 139 | ret = IIO_VAL_INT_PLUS_MICRO_DB; |
---|
73 | 140 | break; |
---|
74 | 141 | default: |
---|
75 | 142 | ret = -EINVAL; |
---|
76 | 143 | } |
---|
77 | | - mutex_unlock(&indio_dev->mlock); |
---|
| 144 | + mutex_unlock(&st->lock); |
---|
78 | 145 | |
---|
79 | 146 | return ret; |
---|
80 | 147 | }; |
---|
.. | .. |
---|
86 | 153 | long mask) |
---|
87 | 154 | { |
---|
88 | 155 | struct ad8366_state *st = iio_priv(indio_dev); |
---|
89 | | - unsigned code; |
---|
| 156 | + struct ad8366_info *inf = st->info; |
---|
| 157 | + int code = 0, gain; |
---|
90 | 158 | int ret; |
---|
91 | 159 | |
---|
92 | | - if (val < 0 || val2 < 0) |
---|
93 | | - return -EINVAL; |
---|
94 | | - |
---|
95 | 160 | /* Values in dB */ |
---|
96 | | - code = (((u8)val * 1000) + ((u32)val2 / 1000)); |
---|
| 161 | + if (val < 0) |
---|
| 162 | + gain = (val * 1000) - (val2 / 1000); |
---|
| 163 | + else |
---|
| 164 | + gain = (val * 1000) + (val2 / 1000); |
---|
97 | 165 | |
---|
98 | | - if (code > 20500 || code < 4500) |
---|
| 166 | + if (gain > inf->gain_max || gain < inf->gain_min) |
---|
99 | 167 | return -EINVAL; |
---|
100 | 168 | |
---|
101 | | - code = (code - 4500) / 253; |
---|
| 169 | + switch (st->type) { |
---|
| 170 | + case ID_AD8366: |
---|
| 171 | + code = (gain - 4500) / 253; |
---|
| 172 | + break; |
---|
| 173 | + case ID_ADA4961: |
---|
| 174 | + code = (15000 - gain) / 1000; |
---|
| 175 | + break; |
---|
| 176 | + case ID_ADL5240: |
---|
| 177 | + code = ((gain - 500 - 20000) / 500) & 0x3F; |
---|
| 178 | + break; |
---|
| 179 | + case ID_HMC1119: |
---|
| 180 | + code = (abs(gain) / 250) & 0x7F; |
---|
| 181 | + break; |
---|
| 182 | + } |
---|
102 | 183 | |
---|
103 | | - mutex_lock(&indio_dev->mlock); |
---|
| 184 | + mutex_lock(&st->lock); |
---|
104 | 185 | switch (mask) { |
---|
105 | 186 | case IIO_CHAN_INFO_HARDWAREGAIN: |
---|
106 | 187 | st->ch[chan->channel] = code; |
---|
.. | .. |
---|
109 | 190 | default: |
---|
110 | 191 | ret = -EINVAL; |
---|
111 | 192 | } |
---|
112 | | - mutex_unlock(&indio_dev->mlock); |
---|
| 193 | + mutex_unlock(&st->lock); |
---|
113 | 194 | |
---|
114 | 195 | return ret; |
---|
| 196 | +} |
---|
| 197 | + |
---|
| 198 | +static int ad8366_write_raw_get_fmt(struct iio_dev *indio_dev, |
---|
| 199 | + struct iio_chan_spec const *chan, |
---|
| 200 | + long mask) |
---|
| 201 | +{ |
---|
| 202 | + switch (mask) { |
---|
| 203 | + case IIO_CHAN_INFO_HARDWAREGAIN: |
---|
| 204 | + return IIO_VAL_INT_PLUS_MICRO_DB; |
---|
| 205 | + default: |
---|
| 206 | + return -EINVAL; |
---|
| 207 | + } |
---|
115 | 208 | } |
---|
116 | 209 | |
---|
117 | 210 | static const struct iio_info ad8366_info = { |
---|
118 | 211 | .read_raw = &ad8366_read_raw, |
---|
119 | 212 | .write_raw = &ad8366_write_raw, |
---|
| 213 | + .write_raw_get_fmt = &ad8366_write_raw_get_fmt, |
---|
120 | 214 | }; |
---|
121 | 215 | |
---|
122 | 216 | #define AD8366_CHAN(_channel) { \ |
---|
.. | .. |
---|
130 | 224 | static const struct iio_chan_spec ad8366_channels[] = { |
---|
131 | 225 | AD8366_CHAN(0), |
---|
132 | 226 | AD8366_CHAN(1), |
---|
| 227 | +}; |
---|
| 228 | + |
---|
| 229 | +static const struct iio_chan_spec ada4961_channels[] = { |
---|
| 230 | + AD8366_CHAN(0), |
---|
133 | 231 | }; |
---|
134 | 232 | |
---|
135 | 233 | static int ad8366_probe(struct spi_device *spi) |
---|
.. | .. |
---|
152 | 250 | } |
---|
153 | 251 | |
---|
154 | 252 | spi_set_drvdata(spi, indio_dev); |
---|
| 253 | + mutex_init(&st->lock); |
---|
155 | 254 | st->spi = spi; |
---|
| 255 | + st->type = spi_get_device_id(spi)->driver_data; |
---|
156 | 256 | |
---|
157 | | - indio_dev->dev.parent = &spi->dev; |
---|
| 257 | + switch (st->type) { |
---|
| 258 | + case ID_AD8366: |
---|
| 259 | + indio_dev->channels = ad8366_channels; |
---|
| 260 | + indio_dev->num_channels = ARRAY_SIZE(ad8366_channels); |
---|
| 261 | + break; |
---|
| 262 | + case ID_ADA4961: |
---|
| 263 | + case ID_ADL5240: |
---|
| 264 | + case ID_HMC1119: |
---|
| 265 | + st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH); |
---|
| 266 | + if (IS_ERR(st->reset_gpio)) { |
---|
| 267 | + ret = PTR_ERR(st->reset_gpio); |
---|
| 268 | + goto error_disable_reg; |
---|
| 269 | + } |
---|
| 270 | + indio_dev->channels = ada4961_channels; |
---|
| 271 | + indio_dev->num_channels = ARRAY_SIZE(ada4961_channels); |
---|
| 272 | + break; |
---|
| 273 | + default: |
---|
| 274 | + dev_err(&spi->dev, "Invalid device ID\n"); |
---|
| 275 | + ret = -EINVAL; |
---|
| 276 | + goto error_disable_reg; |
---|
| 277 | + } |
---|
| 278 | + |
---|
| 279 | + st->info = &ad8366_infos[st->type]; |
---|
158 | 280 | indio_dev->name = spi_get_device_id(spi)->name; |
---|
159 | 281 | indio_dev->info = &ad8366_info; |
---|
160 | 282 | indio_dev->modes = INDIO_DIRECT_MODE; |
---|
161 | | - indio_dev->channels = ad8366_channels; |
---|
162 | | - indio_dev->num_channels = ARRAY_SIZE(ad8366_channels); |
---|
163 | 283 | |
---|
164 | 284 | ret = ad8366_write(indio_dev, 0 , 0); |
---|
165 | 285 | if (ret < 0) |
---|
.. | .. |
---|
193 | 313 | } |
---|
194 | 314 | |
---|
195 | 315 | static const struct spi_device_id ad8366_id[] = { |
---|
196 | | - {"ad8366", 0}, |
---|
| 316 | + {"ad8366", ID_AD8366}, |
---|
| 317 | + {"ada4961", ID_ADA4961}, |
---|
| 318 | + {"adl5240", ID_ADL5240}, |
---|
| 319 | + {"hmc1119", ID_HMC1119}, |
---|
197 | 320 | {} |
---|
198 | 321 | }; |
---|
199 | 322 | MODULE_DEVICE_TABLE(spi, ad8366_id); |
---|
.. | .. |
---|
209 | 332 | |
---|
210 | 333 | module_spi_driver(ad8366_driver); |
---|
211 | 334 | |
---|
212 | | -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); |
---|
213 | | -MODULE_DESCRIPTION("Analog Devices AD8366 VGA"); |
---|
| 335 | +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); |
---|
| 336 | +MODULE_DESCRIPTION("Analog Devices AD8366 and similar Gain Amplifiers"); |
---|
214 | 337 | MODULE_LICENSE("GPL v2"); |
---|