1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * AD7746 capacitive sensor driver supporting AD7745, AD7746 and AD7747 |
4 | * |
5 | * Copyright 2011 Analog Devices Inc. |
6 | */ |
7 | |
8 | #include <linux/bitfield.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/device.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/stat.h> |
17 | #include <linux/sysfs.h> |
18 | |
19 | #include <asm/unaligned.h> |
20 | |
21 | #include <linux/iio/iio.h> |
22 | #include <linux/iio/sysfs.h> |
23 | |
24 | /* AD7746 Register Definition */ |
25 | |
26 | #define AD7746_REG_STATUS 0 |
27 | #define AD7746_REG_CAP_DATA_HIGH 1 |
28 | #define AD7746_REG_VT_DATA_HIGH 4 |
29 | #define AD7746_REG_CAP_SETUP 7 |
30 | #define AD7746_REG_VT_SETUP 8 |
31 | #define AD7746_REG_EXC_SETUP 9 |
32 | #define AD7746_REG_CFG 10 |
33 | #define AD7746_REG_CAPDACA 11 |
34 | #define AD7746_REG_CAPDACB 12 |
35 | #define AD7746_REG_CAP_OFFH 13 |
36 | #define AD7746_REG_CAP_GAINH 15 |
37 | #define AD7746_REG_VOLT_GAINH 17 |
38 | |
39 | /* Status Register Bit Designations (AD7746_REG_STATUS) */ |
40 | #define AD7746_STATUS_EXCERR BIT(3) |
41 | #define AD7746_STATUS_RDY BIT(2) |
42 | #define AD7746_STATUS_RDYVT BIT(1) |
43 | #define AD7746_STATUS_RDYCAP BIT(0) |
44 | |
45 | /* Capacitive Channel Setup Register Bit Designations (AD7746_REG_CAP_SETUP) */ |
46 | #define AD7746_CAPSETUP_CAPEN BIT(7) |
47 | #define AD7746_CAPSETUP_CIN2 BIT(6) /* AD7746 only */ |
48 | #define AD7746_CAPSETUP_CAPDIFF BIT(5) |
49 | #define AD7746_CAPSETUP_CACHOP BIT(0) |
50 | |
51 | /* Voltage/Temperature Setup Register Bit Designations (AD7746_REG_VT_SETUP) */ |
52 | #define AD7746_VTSETUP_VTEN BIT(7) |
53 | #define AD7746_VTSETUP_VTMD_MASK GENMASK(6, 5) |
54 | #define AD7746_VTSETUP_VTMD_INT_TEMP 0 |
55 | #define AD7746_VTSETUP_VTMD_EXT_TEMP 1 |
56 | #define AD7746_VTSETUP_VTMD_VDD_MON 2 |
57 | #define AD7746_VTSETUP_VTMD_EXT_VIN 3 |
58 | #define AD7746_VTSETUP_EXTREF BIT(4) |
59 | #define AD7746_VTSETUP_VTSHORT BIT(1) |
60 | #define AD7746_VTSETUP_VTCHOP BIT(0) |
61 | |
62 | /* Excitation Setup Register Bit Designations (AD7746_REG_EXC_SETUP) */ |
63 | #define AD7746_EXCSETUP_CLKCTRL BIT(7) |
64 | #define AD7746_EXCSETUP_EXCON BIT(6) |
65 | #define AD7746_EXCSETUP_EXCB BIT(5) |
66 | #define AD7746_EXCSETUP_NEXCB BIT(4) |
67 | #define AD7746_EXCSETUP_EXCA BIT(3) |
68 | #define AD7746_EXCSETUP_NEXCA BIT(2) |
69 | #define AD7746_EXCSETUP_EXCLVL_MASK GENMASK(1, 0) |
70 | |
71 | /* Config Register Bit Designations (AD7746_REG_CFG) */ |
72 | #define AD7746_CONF_VTFS_MASK GENMASK(7, 6) |
73 | #define AD7746_CONF_CAPFS_MASK GENMASK(5, 3) |
74 | #define AD7746_CONF_MODE_MASK GENMASK(2, 0) |
75 | #define AD7746_CONF_MODE_IDLE 0 |
76 | #define AD7746_CONF_MODE_CONT_CONV 1 |
77 | #define AD7746_CONF_MODE_SINGLE_CONV 2 |
78 | #define AD7746_CONF_MODE_PWRDN 3 |
79 | #define AD7746_CONF_MODE_OFFS_CAL 5 |
80 | #define AD7746_CONF_MODE_GAIN_CAL 6 |
81 | |
82 | /* CAPDAC Register Bit Designations (AD7746_REG_CAPDACx) */ |
83 | #define AD7746_CAPDAC_DACEN BIT(7) |
84 | #define AD7746_CAPDAC_DACP_MASK GENMASK(6, 0) |
85 | |
86 | struct ad7746_chip_info { |
87 | struct i2c_client *client; |
88 | struct mutex lock; /* protect sensor state */ |
89 | /* |
90 | * Capacitive channel digital filter setup; |
91 | * conversion time/update rate setup per channel |
92 | */ |
93 | u8 config; |
94 | u8 cap_setup; |
95 | u8 vt_setup; |
96 | u8 capdac[2][2]; |
97 | s8 capdac_set; |
98 | }; |
99 | |
100 | enum ad7746_chan { |
101 | VIN, |
102 | VIN_VDD, |
103 | TEMP_INT, |
104 | TEMP_EXT, |
105 | CIN1, |
106 | CIN1_DIFF, |
107 | CIN2, |
108 | CIN2_DIFF, |
109 | }; |
110 | |
111 | struct ad7746_chan_info { |
112 | u8 addr; |
113 | union { |
114 | u8 vtmd; |
115 | struct { /* CAP SETUP fields */ |
116 | unsigned int cin2 : 1; |
117 | unsigned int capdiff : 1; |
118 | }; |
119 | }; |
120 | }; |
121 | |
122 | static const struct ad7746_chan_info ad7746_chan_info[] = { |
123 | [VIN] = { |
124 | .addr = AD7746_REG_VT_DATA_HIGH, |
125 | .vtmd = AD7746_VTSETUP_VTMD_EXT_VIN, |
126 | }, |
127 | [VIN_VDD] = { |
128 | .addr = AD7746_REG_VT_DATA_HIGH, |
129 | .vtmd = AD7746_VTSETUP_VTMD_VDD_MON, |
130 | }, |
131 | [TEMP_INT] = { |
132 | .addr = AD7746_REG_VT_DATA_HIGH, |
133 | .vtmd = AD7746_VTSETUP_VTMD_INT_TEMP, |
134 | }, |
135 | [TEMP_EXT] = { |
136 | .addr = AD7746_REG_VT_DATA_HIGH, |
137 | .vtmd = AD7746_VTSETUP_VTMD_EXT_TEMP, |
138 | }, |
139 | [CIN1] = { |
140 | .addr = AD7746_REG_CAP_DATA_HIGH, |
141 | }, |
142 | [CIN1_DIFF] = { |
143 | .addr = AD7746_REG_CAP_DATA_HIGH, |
144 | .capdiff = 1, |
145 | }, |
146 | [CIN2] = { |
147 | .addr = AD7746_REG_CAP_DATA_HIGH, |
148 | .cin2 = 1, |
149 | }, |
150 | [CIN2_DIFF] = { |
151 | .addr = AD7746_REG_CAP_DATA_HIGH, |
152 | .cin2 = 1, |
153 | .capdiff = 1, |
154 | }, |
155 | }; |
156 | |
157 | static const struct iio_chan_spec ad7746_channels[] = { |
158 | [VIN] = { |
159 | .type = IIO_VOLTAGE, |
160 | .indexed = 1, |
161 | .channel = 0, |
162 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), |
163 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
164 | .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
165 | .address = VIN, |
166 | }, |
167 | [VIN_VDD] = { |
168 | .type = IIO_VOLTAGE, |
169 | .indexed = 1, |
170 | .channel = 1, |
171 | .extend_name = "supply" , |
172 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), |
173 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
174 | .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
175 | .address = VIN_VDD, |
176 | }, |
177 | [TEMP_INT] = { |
178 | .type = IIO_TEMP, |
179 | .indexed = 1, |
180 | .channel = 0, |
181 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
182 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), |
183 | .address = TEMP_INT, |
184 | }, |
185 | [TEMP_EXT] = { |
186 | .type = IIO_TEMP, |
187 | .indexed = 1, |
188 | .channel = 1, |
189 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
190 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), |
191 | .address = TEMP_EXT, |
192 | }, |
193 | [CIN1] = { |
194 | .type = IIO_CAPACITANCE, |
195 | .indexed = 1, |
196 | .channel = 0, |
197 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
198 | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), |
199 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | |
200 | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), |
201 | .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
202 | .address = CIN1, |
203 | }, |
204 | [CIN1_DIFF] = { |
205 | .type = IIO_CAPACITANCE, |
206 | .differential = 1, |
207 | .indexed = 1, |
208 | .channel = 0, |
209 | .channel2 = 2, |
210 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
211 | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_ZEROPOINT), |
212 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | |
213 | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), |
214 | .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
215 | .address = CIN1_DIFF, |
216 | }, |
217 | [CIN2] = { |
218 | .type = IIO_CAPACITANCE, |
219 | .indexed = 1, |
220 | .channel = 1, |
221 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
222 | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), |
223 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | |
224 | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), |
225 | .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
226 | .address = CIN2, |
227 | }, |
228 | [CIN2_DIFF] = { |
229 | .type = IIO_CAPACITANCE, |
230 | .differential = 1, |
231 | .indexed = 1, |
232 | .channel = 1, |
233 | .channel2 = 3, |
234 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
235 | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_ZEROPOINT), |
236 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | |
237 | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), |
238 | .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
239 | .address = CIN2_DIFF, |
240 | } |
241 | }; |
242 | |
243 | /* Values are Update Rate (Hz), Conversion Time (ms) + 1*/ |
244 | static const unsigned char ad7746_vt_filter_rate_table[][2] = { |
245 | { 50, 20 + 1 }, { 31, 32 + 1 }, { 16, 62 + 1 }, { 8, 122 + 1 }, |
246 | }; |
247 | |
248 | static const unsigned char ad7746_cap_filter_rate_table[][2] = { |
249 | { 91, 11 + 1 }, { 84, 12 + 1 }, { 50, 20 + 1 }, { 26, 38 + 1 }, |
250 | { 16, 62 + 1 }, { 13, 77 + 1 }, { 11, 92 + 1 }, { 9, 110 + 1 }, |
251 | }; |
252 | |
253 | static int ad7746_set_capdac(struct ad7746_chip_info *chip, int channel) |
254 | { |
255 | int ret = i2c_smbus_write_byte_data(client: chip->client, |
256 | AD7746_REG_CAPDACA, |
257 | value: chip->capdac[channel][0]); |
258 | if (ret < 0) |
259 | return ret; |
260 | |
261 | return i2c_smbus_write_byte_data(client: chip->client, |
262 | AD7746_REG_CAPDACB, |
263 | value: chip->capdac[channel][1]); |
264 | } |
265 | |
266 | static int ad7746_select_channel(struct iio_dev *indio_dev, |
267 | struct iio_chan_spec const *chan) |
268 | { |
269 | struct ad7746_chip_info *chip = iio_priv(indio_dev); |
270 | u8 vt_setup, cap_setup; |
271 | int ret, delay, idx; |
272 | |
273 | switch (chan->type) { |
274 | case IIO_CAPACITANCE: |
275 | cap_setup = FIELD_PREP(AD7746_CAPSETUP_CIN2, |
276 | ad7746_chan_info[chan->address].cin2) | |
277 | FIELD_PREP(AD7746_CAPSETUP_CAPDIFF, |
278 | ad7746_chan_info[chan->address].capdiff) | |
279 | FIELD_PREP(AD7746_CAPSETUP_CAPEN, 1); |
280 | vt_setup = chip->vt_setup & ~AD7746_VTSETUP_VTEN; |
281 | idx = FIELD_GET(AD7746_CONF_CAPFS_MASK, chip->config); |
282 | delay = ad7746_cap_filter_rate_table[idx][1]; |
283 | |
284 | ret = ad7746_set_capdac(chip, channel: chan->channel); |
285 | if (ret < 0) |
286 | return ret; |
287 | |
288 | chip->capdac_set = chan->channel; |
289 | break; |
290 | case IIO_VOLTAGE: |
291 | case IIO_TEMP: |
292 | vt_setup = FIELD_PREP(AD7746_VTSETUP_VTMD_MASK, |
293 | ad7746_chan_info[chan->address].vtmd) | |
294 | FIELD_PREP(AD7746_VTSETUP_VTEN, 1); |
295 | cap_setup = chip->cap_setup & ~AD7746_CAPSETUP_CAPEN; |
296 | idx = FIELD_GET(AD7746_CONF_VTFS_MASK, chip->config); |
297 | delay = ad7746_cap_filter_rate_table[idx][1]; |
298 | break; |
299 | default: |
300 | return -EINVAL; |
301 | } |
302 | |
303 | if (chip->cap_setup != cap_setup) { |
304 | ret = i2c_smbus_write_byte_data(client: chip->client, |
305 | AD7746_REG_CAP_SETUP, |
306 | value: cap_setup); |
307 | if (ret < 0) |
308 | return ret; |
309 | |
310 | chip->cap_setup = cap_setup; |
311 | } |
312 | |
313 | if (chip->vt_setup != vt_setup) { |
314 | ret = i2c_smbus_write_byte_data(client: chip->client, |
315 | AD7746_REG_VT_SETUP, |
316 | value: vt_setup); |
317 | if (ret < 0) |
318 | return ret; |
319 | |
320 | chip->vt_setup = vt_setup; |
321 | } |
322 | |
323 | return delay; |
324 | } |
325 | |
326 | static inline ssize_t ad7746_start_calib(struct device *dev, |
327 | struct device_attribute *attr, |
328 | const char *buf, |
329 | size_t len, |
330 | u8 regval) |
331 | { |
332 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
333 | struct ad7746_chip_info *chip = iio_priv(indio_dev); |
334 | int ret, timeout = 10; |
335 | bool doit; |
336 | |
337 | ret = kstrtobool(s: buf, res: &doit); |
338 | if (ret < 0) |
339 | return ret; |
340 | |
341 | if (!doit) |
342 | return 0; |
343 | |
344 | mutex_lock(&chip->lock); |
345 | regval |= chip->config; |
346 | ret = i2c_smbus_write_byte_data(client: chip->client, AD7746_REG_CFG, value: regval); |
347 | if (ret < 0) |
348 | goto unlock; |
349 | |
350 | do { |
351 | msleep(msecs: 20); |
352 | ret = i2c_smbus_read_byte_data(client: chip->client, AD7746_REG_CFG); |
353 | if (ret < 0) |
354 | goto unlock; |
355 | |
356 | } while ((ret == regval) && timeout--); |
357 | |
358 | mutex_unlock(lock: &chip->lock); |
359 | |
360 | return len; |
361 | |
362 | unlock: |
363 | mutex_unlock(lock: &chip->lock); |
364 | return ret; |
365 | } |
366 | |
367 | static ssize_t ad7746_start_offset_calib(struct device *dev, |
368 | struct device_attribute *attr, |
369 | const char *buf, |
370 | size_t len) |
371 | { |
372 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
373 | int ret = ad7746_select_channel(indio_dev, |
374 | chan: &ad7746_channels[to_iio_dev_attr(attr)->address]); |
375 | if (ret < 0) |
376 | return ret; |
377 | |
378 | return ad7746_start_calib(dev, attr, buf, len, |
379 | FIELD_PREP(AD7746_CONF_MODE_MASK, |
380 | AD7746_CONF_MODE_OFFS_CAL)); |
381 | } |
382 | |
383 | static ssize_t ad7746_start_gain_calib(struct device *dev, |
384 | struct device_attribute *attr, |
385 | const char *buf, |
386 | size_t len) |
387 | { |
388 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
389 | int ret = ad7746_select_channel(indio_dev, |
390 | chan: &ad7746_channels[to_iio_dev_attr(attr)->address]); |
391 | if (ret < 0) |
392 | return ret; |
393 | |
394 | return ad7746_start_calib(dev, attr, buf, len, |
395 | FIELD_PREP(AD7746_CONF_MODE_MASK, |
396 | AD7746_CONF_MODE_GAIN_CAL)); |
397 | } |
398 | |
399 | static IIO_DEVICE_ATTR(in_capacitance0_calibbias_calibration, |
400 | 0200, NULL, ad7746_start_offset_calib, CIN1); |
401 | static IIO_DEVICE_ATTR(in_capacitance1_calibbias_calibration, |
402 | 0200, NULL, ad7746_start_offset_calib, CIN2); |
403 | static IIO_DEVICE_ATTR(in_capacitance0_calibscale_calibration, |
404 | 0200, NULL, ad7746_start_gain_calib, CIN1); |
405 | static IIO_DEVICE_ATTR(in_capacitance1_calibscale_calibration, |
406 | 0200, NULL, ad7746_start_gain_calib, CIN2); |
407 | static IIO_DEVICE_ATTR(in_voltage0_calibscale_calibration, |
408 | 0200, NULL, ad7746_start_gain_calib, VIN); |
409 | |
410 | static int ad7746_store_cap_filter_rate_setup(struct ad7746_chip_info *chip, |
411 | int val) |
412 | { |
413 | int i; |
414 | |
415 | for (i = 0; i < ARRAY_SIZE(ad7746_cap_filter_rate_table); i++) |
416 | if (val >= ad7746_cap_filter_rate_table[i][0]) |
417 | break; |
418 | |
419 | if (i >= ARRAY_SIZE(ad7746_cap_filter_rate_table)) |
420 | i = ARRAY_SIZE(ad7746_cap_filter_rate_table) - 1; |
421 | |
422 | chip->config &= ~AD7746_CONF_CAPFS_MASK; |
423 | chip->config |= FIELD_PREP(AD7746_CONF_CAPFS_MASK, i); |
424 | |
425 | return 0; |
426 | } |
427 | |
428 | static int ad7746_store_vt_filter_rate_setup(struct ad7746_chip_info *chip, |
429 | int val) |
430 | { |
431 | int i; |
432 | |
433 | for (i = 0; i < ARRAY_SIZE(ad7746_vt_filter_rate_table); i++) |
434 | if (val >= ad7746_vt_filter_rate_table[i][0]) |
435 | break; |
436 | |
437 | if (i >= ARRAY_SIZE(ad7746_vt_filter_rate_table)) |
438 | i = ARRAY_SIZE(ad7746_vt_filter_rate_table) - 1; |
439 | |
440 | chip->config &= ~AD7746_CONF_VTFS_MASK; |
441 | chip->config |= FIELD_PREP(AD7746_CONF_VTFS_MASK, i); |
442 | |
443 | return 0; |
444 | } |
445 | |
446 | static struct attribute *ad7746_attributes[] = { |
447 | &iio_dev_attr_in_capacitance0_calibbias_calibration.dev_attr.attr, |
448 | &iio_dev_attr_in_capacitance0_calibscale_calibration.dev_attr.attr, |
449 | &iio_dev_attr_in_capacitance1_calibscale_calibration.dev_attr.attr, |
450 | &iio_dev_attr_in_capacitance1_calibbias_calibration.dev_attr.attr, |
451 | &iio_dev_attr_in_voltage0_calibscale_calibration.dev_attr.attr, |
452 | NULL, |
453 | }; |
454 | |
455 | static const struct attribute_group ad7746_attribute_group = { |
456 | .attrs = ad7746_attributes, |
457 | }; |
458 | |
459 | static int ad7746_write_raw(struct iio_dev *indio_dev, |
460 | struct iio_chan_spec const *chan, |
461 | int val, |
462 | int val2, |
463 | long mask) |
464 | { |
465 | struct ad7746_chip_info *chip = iio_priv(indio_dev); |
466 | int ret, reg; |
467 | |
468 | switch (mask) { |
469 | case IIO_CHAN_INFO_CALIBSCALE: |
470 | if (val != 1) |
471 | return -EINVAL; |
472 | |
473 | val = (val2 * 1024) / 15625; |
474 | |
475 | switch (chan->type) { |
476 | case IIO_CAPACITANCE: |
477 | reg = AD7746_REG_CAP_GAINH; |
478 | break; |
479 | case IIO_VOLTAGE: |
480 | reg = AD7746_REG_VOLT_GAINH; |
481 | break; |
482 | default: |
483 | return -EINVAL; |
484 | } |
485 | |
486 | mutex_lock(&chip->lock); |
487 | ret = i2c_smbus_write_word_swapped(client: chip->client, command: reg, value: val); |
488 | mutex_unlock(lock: &chip->lock); |
489 | if (ret < 0) |
490 | return ret; |
491 | |
492 | return 0; |
493 | case IIO_CHAN_INFO_CALIBBIAS: |
494 | if (val < 0 || val > 0xFFFF) |
495 | return -EINVAL; |
496 | |
497 | mutex_lock(&chip->lock); |
498 | ret = i2c_smbus_write_word_swapped(client: chip->client, |
499 | AD7746_REG_CAP_OFFH, value: val); |
500 | mutex_unlock(lock: &chip->lock); |
501 | if (ret < 0) |
502 | return ret; |
503 | |
504 | return 0; |
505 | case IIO_CHAN_INFO_OFFSET: |
506 | case IIO_CHAN_INFO_ZEROPOINT: |
507 | if (val < 0 || val > 43008000) /* 21pF */ |
508 | return -EINVAL; |
509 | |
510 | /* |
511 | * CAPDAC Scale = 21pF_typ / 127 |
512 | * CIN Scale = 8.192pF / 2^24 |
513 | * Offset Scale = CAPDAC Scale / CIN Scale = 338646 |
514 | */ |
515 | |
516 | val /= 338646; |
517 | mutex_lock(&chip->lock); |
518 | chip->capdac[chan->channel][chan->differential] = val > 0 ? |
519 | FIELD_PREP(AD7746_CAPDAC_DACP_MASK, val) | AD7746_CAPDAC_DACEN : 0; |
520 | |
521 | ret = ad7746_set_capdac(chip, channel: chan->channel); |
522 | if (ret < 0) { |
523 | mutex_unlock(lock: &chip->lock); |
524 | return ret; |
525 | } |
526 | |
527 | chip->capdac_set = chan->channel; |
528 | mutex_unlock(lock: &chip->lock); |
529 | |
530 | return 0; |
531 | case IIO_CHAN_INFO_SAMP_FREQ: |
532 | if (val2) |
533 | return -EINVAL; |
534 | |
535 | switch (chan->type) { |
536 | case IIO_CAPACITANCE: |
537 | mutex_lock(&chip->lock); |
538 | ret = ad7746_store_cap_filter_rate_setup(chip, val); |
539 | mutex_unlock(lock: &chip->lock); |
540 | return ret; |
541 | case IIO_VOLTAGE: |
542 | mutex_lock(&chip->lock); |
543 | ret = ad7746_store_vt_filter_rate_setup(chip, val); |
544 | mutex_unlock(lock: &chip->lock); |
545 | return ret; |
546 | default: |
547 | return -EINVAL; |
548 | } |
549 | default: |
550 | return -EINVAL; |
551 | } |
552 | } |
553 | |
554 | static const int ad7746_v_samp_freq[] = { 50, 31, 16, 8, }; |
555 | static const int ad7746_cap_samp_freq[] = { 91, 84, 50, 26, 16, 13, 11, 9, }; |
556 | |
557 | static int ad7746_read_avail(struct iio_dev *indio_dev, |
558 | struct iio_chan_spec const *chan, const int **vals, |
559 | int *type, int *length, long mask) |
560 | { |
561 | if (mask != IIO_CHAN_INFO_SAMP_FREQ) |
562 | return -EINVAL; |
563 | |
564 | switch (chan->type) { |
565 | case IIO_VOLTAGE: |
566 | *vals = ad7746_v_samp_freq; |
567 | *length = ARRAY_SIZE(ad7746_v_samp_freq); |
568 | break; |
569 | case IIO_CAPACITANCE: |
570 | *vals = ad7746_cap_samp_freq; |
571 | *length = ARRAY_SIZE(ad7746_cap_samp_freq); |
572 | break; |
573 | default: |
574 | return -EINVAL; |
575 | } |
576 | *type = IIO_VAL_INT; |
577 | return IIO_AVAIL_LIST; |
578 | } |
579 | |
580 | static int ad7746_read_channel(struct iio_dev *indio_dev, |
581 | struct iio_chan_spec const *chan, |
582 | int *val) |
583 | { |
584 | struct ad7746_chip_info *chip = iio_priv(indio_dev); |
585 | int ret, delay; |
586 | u8 data[3]; |
587 | u8 regval; |
588 | |
589 | ret = ad7746_select_channel(indio_dev, chan); |
590 | if (ret < 0) |
591 | return ret; |
592 | delay = ret; |
593 | |
594 | regval = chip->config | FIELD_PREP(AD7746_CONF_MODE_MASK, |
595 | AD7746_CONF_MODE_SINGLE_CONV); |
596 | ret = i2c_smbus_write_byte_data(client: chip->client, AD7746_REG_CFG, value: regval); |
597 | if (ret < 0) |
598 | return ret; |
599 | |
600 | msleep(msecs: delay); |
601 | /* Now read the actual register */ |
602 | ret = i2c_smbus_read_i2c_block_data(client: chip->client, |
603 | command: ad7746_chan_info[chan->address].addr, |
604 | length: sizeof(data), values: data); |
605 | if (ret < 0) |
606 | return ret; |
607 | |
608 | /* |
609 | * Offset applied internally becaue the _offset userspace interface is |
610 | * needed for the CAP DACs which apply a controllable offset. |
611 | */ |
612 | *val = get_unaligned_be24(p: data) - 0x800000; |
613 | |
614 | return 0; |
615 | } |
616 | |
617 | static int ad7746_read_raw(struct iio_dev *indio_dev, |
618 | struct iio_chan_spec const *chan, |
619 | int *val, int *val2, |
620 | long mask) |
621 | { |
622 | struct ad7746_chip_info *chip = iio_priv(indio_dev); |
623 | int ret, idx; |
624 | u8 reg; |
625 | |
626 | switch (mask) { |
627 | case IIO_CHAN_INFO_RAW: |
628 | mutex_lock(&chip->lock); |
629 | ret = ad7746_read_channel(indio_dev, chan, val); |
630 | mutex_unlock(lock: &chip->lock); |
631 | if (ret < 0) |
632 | return ret; |
633 | |
634 | return IIO_VAL_INT; |
635 | case IIO_CHAN_INFO_CALIBSCALE: |
636 | switch (chan->type) { |
637 | case IIO_CAPACITANCE: |
638 | reg = AD7746_REG_CAP_GAINH; |
639 | break; |
640 | case IIO_VOLTAGE: |
641 | reg = AD7746_REG_VOLT_GAINH; |
642 | break; |
643 | default: |
644 | return -EINVAL; |
645 | } |
646 | |
647 | mutex_lock(&chip->lock); |
648 | ret = i2c_smbus_read_word_swapped(client: chip->client, command: reg); |
649 | mutex_unlock(lock: &chip->lock); |
650 | if (ret < 0) |
651 | return ret; |
652 | /* 1 + gain_val / 2^16 */ |
653 | *val = 1; |
654 | *val2 = (15625 * ret) / 1024; |
655 | |
656 | return IIO_VAL_INT_PLUS_MICRO; |
657 | case IIO_CHAN_INFO_CALIBBIAS: |
658 | mutex_lock(&chip->lock); |
659 | ret = i2c_smbus_read_word_swapped(client: chip->client, |
660 | AD7746_REG_CAP_OFFH); |
661 | mutex_unlock(lock: &chip->lock); |
662 | if (ret < 0) |
663 | return ret; |
664 | *val = ret; |
665 | |
666 | return IIO_VAL_INT; |
667 | case IIO_CHAN_INFO_OFFSET: |
668 | case IIO_CHAN_INFO_ZEROPOINT: |
669 | *val = FIELD_GET(AD7746_CAPDAC_DACP_MASK, |
670 | chip->capdac[chan->channel][chan->differential]) * 338646; |
671 | |
672 | return IIO_VAL_INT; |
673 | case IIO_CHAN_INFO_SCALE: |
674 | switch (chan->type) { |
675 | case IIO_CAPACITANCE: |
676 | /* 8.192pf / 2^24 */ |
677 | *val = 0; |
678 | *val2 = 488; |
679 | return IIO_VAL_INT_PLUS_NANO; |
680 | case IIO_VOLTAGE: |
681 | /* 1170mV / 2^23 */ |
682 | *val = 1170; |
683 | if (chan->channel == 1) |
684 | *val *= 6; |
685 | *val2 = 23; |
686 | return IIO_VAL_FRACTIONAL_LOG2; |
687 | case IIO_TEMP: |
688 | *val = 125; |
689 | *val2 = 8; |
690 | return IIO_VAL_FRACTIONAL_LOG2; |
691 | default: |
692 | return -EINVAL; |
693 | } |
694 | case IIO_CHAN_INFO_SAMP_FREQ: |
695 | switch (chan->type) { |
696 | case IIO_CAPACITANCE: |
697 | idx = FIELD_GET(AD7746_CONF_CAPFS_MASK, chip->config); |
698 | *val = ad7746_cap_filter_rate_table[idx][0]; |
699 | return IIO_VAL_INT; |
700 | case IIO_VOLTAGE: |
701 | idx = FIELD_GET(AD7746_CONF_VTFS_MASK, chip->config); |
702 | *val = ad7746_vt_filter_rate_table[idx][0]; |
703 | return IIO_VAL_INT; |
704 | default: |
705 | return -EINVAL; |
706 | } |
707 | default: |
708 | return -EINVAL; |
709 | } |
710 | } |
711 | |
712 | static const struct iio_info ad7746_info = { |
713 | .attrs = &ad7746_attribute_group, |
714 | .read_raw = ad7746_read_raw, |
715 | .read_avail = ad7746_read_avail, |
716 | .write_raw = ad7746_write_raw, |
717 | }; |
718 | |
719 | static int ad7746_probe(struct i2c_client *client) |
720 | { |
721 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
722 | struct device *dev = &client->dev; |
723 | struct ad7746_chip_info *chip; |
724 | struct iio_dev *indio_dev; |
725 | unsigned char regval = 0; |
726 | unsigned int vdd_permille; |
727 | int ret; |
728 | |
729 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*chip)); |
730 | if (!indio_dev) |
731 | return -ENOMEM; |
732 | |
733 | chip = iio_priv(indio_dev); |
734 | mutex_init(&chip->lock); |
735 | |
736 | chip->client = client; |
737 | chip->capdac_set = -1; |
738 | |
739 | indio_dev->name = id->name; |
740 | indio_dev->info = &ad7746_info; |
741 | indio_dev->channels = ad7746_channels; |
742 | if (id->driver_data == 7746) |
743 | indio_dev->num_channels = ARRAY_SIZE(ad7746_channels); |
744 | else |
745 | indio_dev->num_channels = ARRAY_SIZE(ad7746_channels) - 2; |
746 | indio_dev->modes = INDIO_DIRECT_MODE; |
747 | |
748 | if (device_property_read_bool(dev, propname: "adi,exca-output-en" )) { |
749 | if (device_property_read_bool(dev, propname: "adi,exca-output-invert" )) |
750 | regval |= AD7746_EXCSETUP_NEXCA; |
751 | else |
752 | regval |= AD7746_EXCSETUP_EXCA; |
753 | } |
754 | |
755 | if (device_property_read_bool(dev, propname: "adi,excb-output-en" )) { |
756 | if (device_property_read_bool(dev, propname: "adi,excb-output-invert" )) |
757 | regval |= AD7746_EXCSETUP_NEXCB; |
758 | else |
759 | regval |= AD7746_EXCSETUP_EXCB; |
760 | } |
761 | |
762 | ret = device_property_read_u32(dev, propname: "adi,excitation-vdd-permille" , |
763 | val: &vdd_permille); |
764 | if (!ret) { |
765 | switch (vdd_permille) { |
766 | case 125: |
767 | regval |= FIELD_PREP(AD7746_EXCSETUP_EXCLVL_MASK, 0); |
768 | break; |
769 | case 250: |
770 | regval |= FIELD_PREP(AD7746_EXCSETUP_EXCLVL_MASK, 1); |
771 | break; |
772 | case 375: |
773 | regval |= FIELD_PREP(AD7746_EXCSETUP_EXCLVL_MASK, 2); |
774 | break; |
775 | case 500: |
776 | regval |= FIELD_PREP(AD7746_EXCSETUP_EXCLVL_MASK, 3); |
777 | break; |
778 | default: |
779 | break; |
780 | } |
781 | } |
782 | |
783 | ret = i2c_smbus_write_byte_data(client: chip->client, AD7746_REG_EXC_SETUP, |
784 | value: regval); |
785 | if (ret < 0) |
786 | return ret; |
787 | |
788 | return devm_iio_device_register(indio_dev->dev.parent, indio_dev); |
789 | } |
790 | |
791 | static const struct i2c_device_id ad7746_id[] = { |
792 | { "ad7745" , 7745 }, |
793 | { "ad7746" , 7746 }, |
794 | { "ad7747" , 7747 }, |
795 | {} |
796 | }; |
797 | MODULE_DEVICE_TABLE(i2c, ad7746_id); |
798 | |
799 | static const struct of_device_id ad7746_of_match[] = { |
800 | { .compatible = "adi,ad7745" }, |
801 | { .compatible = "adi,ad7746" }, |
802 | { .compatible = "adi,ad7747" }, |
803 | { }, |
804 | }; |
805 | MODULE_DEVICE_TABLE(of, ad7746_of_match); |
806 | |
807 | static struct i2c_driver ad7746_driver = { |
808 | .driver = { |
809 | .name = KBUILD_MODNAME, |
810 | .of_match_table = ad7746_of_match, |
811 | }, |
812 | .probe = ad7746_probe, |
813 | .id_table = ad7746_id, |
814 | }; |
815 | module_i2c_driver(ad7746_driver); |
816 | |
817 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>" ); |
818 | MODULE_DESCRIPTION("Analog Devices AD7746/5/7 capacitive sensor driver" ); |
819 | MODULE_LICENSE("GPL v2" ); |
820 | |