1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | /* |
3 | * AD7606 SPI ADC driver |
4 | * |
5 | * Copyright 2011 Analog Devices Inc. |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/spi/spi.h> |
10 | #include <linux/types.h> |
11 | #include <linux/err.h> |
12 | |
13 | #include <linux/iio/iio.h> |
14 | #include "ad7606.h" |
15 | |
16 | #define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */ |
17 | |
18 | #define AD7616_CONFIGURATION_REGISTER 0x02 |
19 | #define AD7616_OS_MASK GENMASK(4, 2) |
20 | #define AD7616_BURST_MODE BIT(6) |
21 | #define AD7616_SEQEN_MODE BIT(5) |
22 | #define AD7616_RANGE_CH_A_ADDR_OFF 0x04 |
23 | #define AD7616_RANGE_CH_B_ADDR_OFF 0x06 |
24 | /* |
25 | * Range of channels from a group are stored in 2 registers. |
26 | * 0, 1, 2, 3 in a register followed by 4, 5, 6, 7 in second register. |
27 | * For channels from second group(8-15) the order is the same, only with |
28 | * an offset of 2 for register address. |
29 | */ |
30 | #define AD7616_RANGE_CH_ADDR(ch) ((ch) >> 2) |
31 | /* The range of the channel is stored in 2 bits */ |
32 | #define AD7616_RANGE_CH_MSK(ch) (0b11 << (((ch) & 0b11) * 2)) |
33 | #define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << ((((ch) & 0b11)) * 2)) |
34 | |
35 | #define AD7606_CONFIGURATION_REGISTER 0x02 |
36 | #define AD7606_SINGLE_DOUT 0x00 |
37 | |
38 | /* |
39 | * Range for AD7606B channels are stored in registers starting with address 0x3. |
40 | * Each register stores range for 2 channels(4 bits per channel). |
41 | */ |
42 | #define AD7606_RANGE_CH_MSK(ch) (GENMASK(3, 0) << (4 * ((ch) & 0x1))) |
43 | #define AD7606_RANGE_CH_MODE(ch, mode) \ |
44 | ((GENMASK(3, 0) & mode) << (4 * ((ch) & 0x1))) |
45 | #define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1)) |
46 | #define AD7606_OS_MODE 0x08 |
47 | |
48 | static const struct iio_chan_spec ad7616_sw_channels[] = { |
49 | IIO_CHAN_SOFT_TIMESTAMP(16), |
50 | AD7616_CHANNEL(0), |
51 | AD7616_CHANNEL(1), |
52 | AD7616_CHANNEL(2), |
53 | AD7616_CHANNEL(3), |
54 | AD7616_CHANNEL(4), |
55 | AD7616_CHANNEL(5), |
56 | AD7616_CHANNEL(6), |
57 | AD7616_CHANNEL(7), |
58 | AD7616_CHANNEL(8), |
59 | AD7616_CHANNEL(9), |
60 | AD7616_CHANNEL(10), |
61 | AD7616_CHANNEL(11), |
62 | AD7616_CHANNEL(12), |
63 | AD7616_CHANNEL(13), |
64 | AD7616_CHANNEL(14), |
65 | AD7616_CHANNEL(15), |
66 | }; |
67 | |
68 | static const struct iio_chan_spec ad7606b_sw_channels[] = { |
69 | IIO_CHAN_SOFT_TIMESTAMP(8), |
70 | AD7616_CHANNEL(0), |
71 | AD7616_CHANNEL(1), |
72 | AD7616_CHANNEL(2), |
73 | AD7616_CHANNEL(3), |
74 | AD7616_CHANNEL(4), |
75 | AD7616_CHANNEL(5), |
76 | AD7616_CHANNEL(6), |
77 | AD7616_CHANNEL(7), |
78 | }; |
79 | |
80 | static const unsigned int ad7606B_oversampling_avail[9] = { |
81 | 1, 2, 4, 8, 16, 32, 64, 128, 256 |
82 | }; |
83 | |
84 | static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp) |
85 | { |
86 | /* |
87 | * The address of register consist of one w/r bit |
88 | * 6 bits of address followed by one reserved bit. |
89 | */ |
90 | return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7); |
91 | } |
92 | |
93 | static u16 ad7606B_spi_rd_wr_cmd(int addr, char is_write_op) |
94 | { |
95 | /* |
96 | * The address of register consists of one bit which |
97 | * specifies a read command placed in bit 6, followed by |
98 | * 6 bits of address. |
99 | */ |
100 | return (addr & 0x3F) | (((~is_write_op) & 0x1) << 6); |
101 | } |
102 | |
103 | static int ad7606_spi_read_block(struct device *dev, |
104 | int count, void *buf) |
105 | { |
106 | struct spi_device *spi = to_spi_device(dev); |
107 | int i, ret; |
108 | unsigned short *data = buf; |
109 | __be16 *bdata = buf; |
110 | |
111 | ret = spi_read(spi, buf, len: count * 2); |
112 | if (ret < 0) { |
113 | dev_err(&spi->dev, "SPI read error\n"); |
114 | return ret; |
115 | } |
116 | |
117 | for (i = 0; i < count; i++) |
118 | data[i] = be16_to_cpu(bdata[i]); |
119 | |
120 | return 0; |
121 | } |
122 | |
123 | static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr) |
124 | { |
125 | struct spi_device *spi = to_spi_device(dev: st->dev); |
126 | struct spi_transfer t[] = { |
127 | { |
128 | .tx_buf = &st->d16[0], |
129 | .len = 2, |
130 | .cs_change = 0, |
131 | }, { |
132 | .rx_buf = &st->d16[1], |
133 | .len = 2, |
134 | }, |
135 | }; |
136 | int ret; |
137 | |
138 | st->d16[0] = cpu_to_be16(st->bops->rd_wr_cmd(addr, 0) << 8); |
139 | |
140 | ret = spi_sync_transfer(spi, xfers: t, ARRAY_SIZE(t)); |
141 | if (ret < 0) |
142 | return ret; |
143 | |
144 | return be16_to_cpu(st->d16[1]); |
145 | } |
146 | |
147 | static int ad7606_spi_reg_write(struct ad7606_state *st, |
148 | unsigned int addr, |
149 | unsigned int val) |
150 | { |
151 | struct spi_device *spi = to_spi_device(dev: st->dev); |
152 | |
153 | st->d16[0] = cpu_to_be16((st->bops->rd_wr_cmd(addr, 1) << 8) | |
154 | (val & 0x1FF)); |
155 | |
156 | return spi_write(spi, buf: &st->d16[0], len: sizeof(st->d16[0])); |
157 | } |
158 | |
159 | static int ad7606_spi_write_mask(struct ad7606_state *st, |
160 | unsigned int addr, |
161 | unsigned long mask, |
162 | unsigned int val) |
163 | { |
164 | int readval; |
165 | |
166 | readval = st->bops->reg_read(st, addr); |
167 | if (readval < 0) |
168 | return readval; |
169 | |
170 | readval &= ~mask; |
171 | readval |= val; |
172 | |
173 | return st->bops->reg_write(st, addr, readval); |
174 | } |
175 | |
176 | static int ad7616_write_scale_sw(struct iio_dev *indio_dev, int ch, int val) |
177 | { |
178 | struct ad7606_state *st = iio_priv(indio_dev); |
179 | unsigned int ch_addr, mode, ch_index; |
180 | |
181 | |
182 | /* |
183 | * Ad7616 has 16 channels divided in group A and group B. |
184 | * The range of channels from A are stored in registers with address 4 |
185 | * while channels from B are stored in register with address 6. |
186 | * The last bit from channels determines if it is from group A or B |
187 | * because the order of channels in iio is 0A, 0B, 1A, 1B... |
188 | */ |
189 | ch_index = ch >> 1; |
190 | |
191 | ch_addr = AD7616_RANGE_CH_ADDR(ch_index); |
192 | |
193 | if ((ch & 0x1) == 0) /* channel A */ |
194 | ch_addr += AD7616_RANGE_CH_A_ADDR_OFF; |
195 | else /* channel B */ |
196 | ch_addr += AD7616_RANGE_CH_B_ADDR_OFF; |
197 | |
198 | /* 0b01 for 2.5v, 0b10 for 5v and 0b11 for 10v */ |
199 | mode = AD7616_RANGE_CH_MODE(ch_index, ((val + 1) & 0b11)); |
200 | return st->bops->write_mask(st, ch_addr, AD7616_RANGE_CH_MSK(ch_index), |
201 | mode); |
202 | } |
203 | |
204 | static int ad7616_write_os_sw(struct iio_dev *indio_dev, int val) |
205 | { |
206 | struct ad7606_state *st = iio_priv(indio_dev); |
207 | |
208 | return st->bops->write_mask(st, AD7616_CONFIGURATION_REGISTER, |
209 | AD7616_OS_MASK, val << 2); |
210 | } |
211 | |
212 | static int ad7606_write_scale_sw(struct iio_dev *indio_dev, int ch, int val) |
213 | { |
214 | struct ad7606_state *st = iio_priv(indio_dev); |
215 | |
216 | return ad7606_spi_write_mask(st, |
217 | AD7606_RANGE_CH_ADDR(ch), |
218 | AD7606_RANGE_CH_MSK(ch), |
219 | AD7606_RANGE_CH_MODE(ch, val)); |
220 | } |
221 | |
222 | static int ad7606_write_os_sw(struct iio_dev *indio_dev, int val) |
223 | { |
224 | struct ad7606_state *st = iio_priv(indio_dev); |
225 | |
226 | return ad7606_spi_reg_write(st, AD7606_OS_MODE, val); |
227 | } |
228 | |
229 | static int ad7616_sw_mode_config(struct iio_dev *indio_dev) |
230 | { |
231 | struct ad7606_state *st = iio_priv(indio_dev); |
232 | |
233 | /* |
234 | * Scale can be configured individually for each channel |
235 | * in software mode. |
236 | */ |
237 | indio_dev->channels = ad7616_sw_channels; |
238 | |
239 | st->write_scale = ad7616_write_scale_sw; |
240 | st->write_os = &ad7616_write_os_sw; |
241 | |
242 | /* Activate Burst mode and SEQEN MODE */ |
243 | return st->bops->write_mask(st, |
244 | AD7616_CONFIGURATION_REGISTER, |
245 | AD7616_BURST_MODE | AD7616_SEQEN_MODE, |
246 | AD7616_BURST_MODE | AD7616_SEQEN_MODE); |
247 | } |
248 | |
249 | static int ad7606B_sw_mode_config(struct iio_dev *indio_dev) |
250 | { |
251 | struct ad7606_state *st = iio_priv(indio_dev); |
252 | unsigned long os[3] = {1}; |
253 | |
254 | /* |
255 | * Software mode is enabled when all three oversampling |
256 | * pins are set to high. If oversampling gpios are defined |
257 | * in the device tree, then they need to be set to high, |
258 | * otherwise, they must be hardwired to VDD |
259 | */ |
260 | if (st->gpio_os) { |
261 | gpiod_set_array_value(ARRAY_SIZE(os), |
262 | desc_array: st->gpio_os->desc, array_info: st->gpio_os->info, value_bitmap: os); |
263 | } |
264 | /* OS of 128 and 256 are available only in software mode */ |
265 | st->oversampling_avail = ad7606B_oversampling_avail; |
266 | st->num_os_ratios = ARRAY_SIZE(ad7606B_oversampling_avail); |
267 | |
268 | st->write_scale = ad7606_write_scale_sw; |
269 | st->write_os = &ad7606_write_os_sw; |
270 | |
271 | /* Configure device spi to output on a single channel */ |
272 | st->bops->reg_write(st, |
273 | AD7606_CONFIGURATION_REGISTER, |
274 | AD7606_SINGLE_DOUT); |
275 | |
276 | /* |
277 | * Scale can be configured individually for each channel |
278 | * in software mode. |
279 | */ |
280 | indio_dev->channels = ad7606b_sw_channels; |
281 | |
282 | return 0; |
283 | } |
284 | |
285 | static const struct ad7606_bus_ops ad7606_spi_bops = { |
286 | .read_block = ad7606_spi_read_block, |
287 | }; |
288 | |
289 | static const struct ad7606_bus_ops ad7616_spi_bops = { |
290 | .read_block = ad7606_spi_read_block, |
291 | .reg_read = ad7606_spi_reg_read, |
292 | .reg_write = ad7606_spi_reg_write, |
293 | .write_mask = ad7606_spi_write_mask, |
294 | .rd_wr_cmd = ad7616_spi_rd_wr_cmd, |
295 | .sw_mode_config = ad7616_sw_mode_config, |
296 | }; |
297 | |
298 | static const struct ad7606_bus_ops ad7606B_spi_bops = { |
299 | .read_block = ad7606_spi_read_block, |
300 | .reg_read = ad7606_spi_reg_read, |
301 | .reg_write = ad7606_spi_reg_write, |
302 | .write_mask = ad7606_spi_write_mask, |
303 | .rd_wr_cmd = ad7606B_spi_rd_wr_cmd, |
304 | .sw_mode_config = ad7606B_sw_mode_config, |
305 | }; |
306 | |
307 | static int ad7606_spi_probe(struct spi_device *spi) |
308 | { |
309 | const struct spi_device_id *id = spi_get_device_id(sdev: spi); |
310 | const struct ad7606_bus_ops *bops; |
311 | |
312 | switch (id->driver_data) { |
313 | case ID_AD7616: |
314 | bops = &ad7616_spi_bops; |
315 | break; |
316 | case ID_AD7606B: |
317 | bops = &ad7606B_spi_bops; |
318 | break; |
319 | default: |
320 | bops = &ad7606_spi_bops; |
321 | break; |
322 | } |
323 | |
324 | return ad7606_probe(dev: &spi->dev, irq: spi->irq, NULL, |
325 | name: id->name, id: id->driver_data, |
326 | bops); |
327 | } |
328 | |
329 | static const struct spi_device_id ad7606_id_table[] = { |
330 | { "ad7605-4", ID_AD7605_4 }, |
331 | { "ad7606-4", ID_AD7606_4 }, |
332 | { "ad7606-6", ID_AD7606_6 }, |
333 | { "ad7606-8", ID_AD7606_8 }, |
334 | { "ad7606b", ID_AD7606B }, |
335 | { "ad7616", ID_AD7616 }, |
336 | {} |
337 | }; |
338 | MODULE_DEVICE_TABLE(spi, ad7606_id_table); |
339 | |
340 | static const struct of_device_id ad7606_of_match[] = { |
341 | { .compatible = "adi,ad7605-4"}, |
342 | { .compatible = "adi,ad7606-4"}, |
343 | { .compatible = "adi,ad7606-6"}, |
344 | { .compatible = "adi,ad7606-8"}, |
345 | { .compatible = "adi,ad7606b"}, |
346 | { .compatible = "adi,ad7616"}, |
347 | { }, |
348 | }; |
349 | MODULE_DEVICE_TABLE(of, ad7606_of_match); |
350 | |
351 | static struct spi_driver ad7606_driver = { |
352 | .driver = { |
353 | .name = "ad7606", |
354 | .of_match_table = ad7606_of_match, |
355 | .pm = AD7606_PM_OPS, |
356 | }, |
357 | .probe = ad7606_spi_probe, |
358 | .id_table = ad7606_id_table, |
359 | }; |
360 | module_spi_driver(ad7606_driver); |
361 | |
362 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); |
363 | MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); |
364 | MODULE_LICENSE("GPL v2"); |
365 | MODULE_IMPORT_NS(IIO_AD7606); |
366 |
Definitions
- ad7616_sw_channels
- ad7606b_sw_channels
- ad7606B_oversampling_avail
- ad7616_spi_rd_wr_cmd
- ad7606B_spi_rd_wr_cmd
- ad7606_spi_read_block
- ad7606_spi_reg_read
- ad7606_spi_reg_write
- ad7606_spi_write_mask
- ad7616_write_scale_sw
- ad7616_write_os_sw
- ad7606_write_scale_sw
- ad7606_write_os_sw
- ad7616_sw_mode_config
- ad7606B_sw_mode_config
- ad7606_spi_bops
- ad7616_spi_bops
- ad7606B_spi_bops
- ad7606_spi_probe
- ad7606_id_table
- ad7606_of_match
Improve your Profiling and Debugging skills
Find out more