140b5c4d5SJonathan Cameron // SPDX-License-Identifier: GPL-2.0
240b5c4d5SJonathan Cameron /*
340b5c4d5SJonathan Cameron * AD7746 capacitive sensor driver supporting AD7745, AD7746 and AD7747
440b5c4d5SJonathan Cameron *
540b5c4d5SJonathan Cameron * Copyright 2011 Analog Devices Inc.
640b5c4d5SJonathan Cameron */
740b5c4d5SJonathan Cameron
840b5c4d5SJonathan Cameron #include <linux/bitfield.h>
940b5c4d5SJonathan Cameron #include <linux/delay.h>
1040b5c4d5SJonathan Cameron #include <linux/device.h>
1140b5c4d5SJonathan Cameron #include <linux/i2c.h>
1240b5c4d5SJonathan Cameron #include <linux/interrupt.h>
1340b5c4d5SJonathan Cameron #include <linux/kernel.h>
1440b5c4d5SJonathan Cameron #include <linux/module.h>
1540b5c4d5SJonathan Cameron #include <linux/slab.h>
1640b5c4d5SJonathan Cameron #include <linux/stat.h>
1740b5c4d5SJonathan Cameron #include <linux/sysfs.h>
1840b5c4d5SJonathan Cameron
19*5f60d5f6SAl Viro #include <linux/unaligned.h>
2040b5c4d5SJonathan Cameron
2140b5c4d5SJonathan Cameron #include <linux/iio/iio.h>
2240b5c4d5SJonathan Cameron #include <linux/iio/sysfs.h>
2340b5c4d5SJonathan Cameron
2440b5c4d5SJonathan Cameron /* AD7746 Register Definition */
2540b5c4d5SJonathan Cameron
2640b5c4d5SJonathan Cameron #define AD7746_REG_STATUS 0
2740b5c4d5SJonathan Cameron #define AD7746_REG_CAP_DATA_HIGH 1
2840b5c4d5SJonathan Cameron #define AD7746_REG_VT_DATA_HIGH 4
2940b5c4d5SJonathan Cameron #define AD7746_REG_CAP_SETUP 7
3040b5c4d5SJonathan Cameron #define AD7746_REG_VT_SETUP 8
3140b5c4d5SJonathan Cameron #define AD7746_REG_EXC_SETUP 9
3240b5c4d5SJonathan Cameron #define AD7746_REG_CFG 10
3340b5c4d5SJonathan Cameron #define AD7746_REG_CAPDACA 11
3440b5c4d5SJonathan Cameron #define AD7746_REG_CAPDACB 12
3540b5c4d5SJonathan Cameron #define AD7746_REG_CAP_OFFH 13
3640b5c4d5SJonathan Cameron #define AD7746_REG_CAP_GAINH 15
3740b5c4d5SJonathan Cameron #define AD7746_REG_VOLT_GAINH 17
3840b5c4d5SJonathan Cameron
3940b5c4d5SJonathan Cameron /* Status Register Bit Designations (AD7746_REG_STATUS) */
4040b5c4d5SJonathan Cameron #define AD7746_STATUS_EXCERR BIT(3)
4140b5c4d5SJonathan Cameron #define AD7746_STATUS_RDY BIT(2)
4240b5c4d5SJonathan Cameron #define AD7746_STATUS_RDYVT BIT(1)
4340b5c4d5SJonathan Cameron #define AD7746_STATUS_RDYCAP BIT(0)
4440b5c4d5SJonathan Cameron
4540b5c4d5SJonathan Cameron /* Capacitive Channel Setup Register Bit Designations (AD7746_REG_CAP_SETUP) */
4640b5c4d5SJonathan Cameron #define AD7746_CAPSETUP_CAPEN BIT(7)
4740b5c4d5SJonathan Cameron #define AD7746_CAPSETUP_CIN2 BIT(6) /* AD7746 only */
4840b5c4d5SJonathan Cameron #define AD7746_CAPSETUP_CAPDIFF BIT(5)
4940b5c4d5SJonathan Cameron #define AD7746_CAPSETUP_CACHOP BIT(0)
5040b5c4d5SJonathan Cameron
5140b5c4d5SJonathan Cameron /* Voltage/Temperature Setup Register Bit Designations (AD7746_REG_VT_SETUP) */
5240b5c4d5SJonathan Cameron #define AD7746_VTSETUP_VTEN BIT(7)
5340b5c4d5SJonathan Cameron #define AD7746_VTSETUP_VTMD_MASK GENMASK(6, 5)
5440b5c4d5SJonathan Cameron #define AD7746_VTSETUP_VTMD_INT_TEMP 0
5540b5c4d5SJonathan Cameron #define AD7746_VTSETUP_VTMD_EXT_TEMP 1
5640b5c4d5SJonathan Cameron #define AD7746_VTSETUP_VTMD_VDD_MON 2
5740b5c4d5SJonathan Cameron #define AD7746_VTSETUP_VTMD_EXT_VIN 3
5840b5c4d5SJonathan Cameron #define AD7746_VTSETUP_EXTREF BIT(4)
5940b5c4d5SJonathan Cameron #define AD7746_VTSETUP_VTSHORT BIT(1)
6040b5c4d5SJonathan Cameron #define AD7746_VTSETUP_VTCHOP BIT(0)
6140b5c4d5SJonathan Cameron
6240b5c4d5SJonathan Cameron /* Excitation Setup Register Bit Designations (AD7746_REG_EXC_SETUP) */
6340b5c4d5SJonathan Cameron #define AD7746_EXCSETUP_CLKCTRL BIT(7)
6440b5c4d5SJonathan Cameron #define AD7746_EXCSETUP_EXCON BIT(6)
6540b5c4d5SJonathan Cameron #define AD7746_EXCSETUP_EXCB BIT(5)
6640b5c4d5SJonathan Cameron #define AD7746_EXCSETUP_NEXCB BIT(4)
6740b5c4d5SJonathan Cameron #define AD7746_EXCSETUP_EXCA BIT(3)
6840b5c4d5SJonathan Cameron #define AD7746_EXCSETUP_NEXCA BIT(2)
6940b5c4d5SJonathan Cameron #define AD7746_EXCSETUP_EXCLVL_MASK GENMASK(1, 0)
7040b5c4d5SJonathan Cameron
7140b5c4d5SJonathan Cameron /* Config Register Bit Designations (AD7746_REG_CFG) */
7240b5c4d5SJonathan Cameron #define AD7746_CONF_VTFS_MASK GENMASK(7, 6)
7340b5c4d5SJonathan Cameron #define AD7746_CONF_CAPFS_MASK GENMASK(5, 3)
7440b5c4d5SJonathan Cameron #define AD7746_CONF_MODE_MASK GENMASK(2, 0)
7540b5c4d5SJonathan Cameron #define AD7746_CONF_MODE_IDLE 0
7640b5c4d5SJonathan Cameron #define AD7746_CONF_MODE_CONT_CONV 1
7740b5c4d5SJonathan Cameron #define AD7746_CONF_MODE_SINGLE_CONV 2
7840b5c4d5SJonathan Cameron #define AD7746_CONF_MODE_PWRDN 3
7940b5c4d5SJonathan Cameron #define AD7746_CONF_MODE_OFFS_CAL 5
8040b5c4d5SJonathan Cameron #define AD7746_CONF_MODE_GAIN_CAL 6
8140b5c4d5SJonathan Cameron
8240b5c4d5SJonathan Cameron /* CAPDAC Register Bit Designations (AD7746_REG_CAPDACx) */
8340b5c4d5SJonathan Cameron #define AD7746_CAPDAC_DACEN BIT(7)
8440b5c4d5SJonathan Cameron #define AD7746_CAPDAC_DACP_MASK GENMASK(6, 0)
8540b5c4d5SJonathan Cameron
8640b5c4d5SJonathan Cameron struct ad7746_chip_info {
8740b5c4d5SJonathan Cameron struct i2c_client *client;
8840b5c4d5SJonathan Cameron struct mutex lock; /* protect sensor state */
8940b5c4d5SJonathan Cameron /*
9040b5c4d5SJonathan Cameron * Capacitive channel digital filter setup;
9140b5c4d5SJonathan Cameron * conversion time/update rate setup per channel
9240b5c4d5SJonathan Cameron */
9340b5c4d5SJonathan Cameron u8 config;
9440b5c4d5SJonathan Cameron u8 cap_setup;
9540b5c4d5SJonathan Cameron u8 vt_setup;
9640b5c4d5SJonathan Cameron u8 capdac[2][2];
9740b5c4d5SJonathan Cameron s8 capdac_set;
9840b5c4d5SJonathan Cameron };
9940b5c4d5SJonathan Cameron
10040b5c4d5SJonathan Cameron enum ad7746_chan {
10140b5c4d5SJonathan Cameron VIN,
10240b5c4d5SJonathan Cameron VIN_VDD,
10340b5c4d5SJonathan Cameron TEMP_INT,
10440b5c4d5SJonathan Cameron TEMP_EXT,
10540b5c4d5SJonathan Cameron CIN1,
10640b5c4d5SJonathan Cameron CIN1_DIFF,
10740b5c4d5SJonathan Cameron CIN2,
10840b5c4d5SJonathan Cameron CIN2_DIFF,
10940b5c4d5SJonathan Cameron };
11040b5c4d5SJonathan Cameron
11140b5c4d5SJonathan Cameron struct ad7746_chan_info {
11240b5c4d5SJonathan Cameron u8 addr;
11340b5c4d5SJonathan Cameron union {
11440b5c4d5SJonathan Cameron u8 vtmd;
11540b5c4d5SJonathan Cameron struct { /* CAP SETUP fields */
11640b5c4d5SJonathan Cameron unsigned int cin2 : 1;
11740b5c4d5SJonathan Cameron unsigned int capdiff : 1;
11840b5c4d5SJonathan Cameron };
11940b5c4d5SJonathan Cameron };
12040b5c4d5SJonathan Cameron };
12140b5c4d5SJonathan Cameron
12240b5c4d5SJonathan Cameron static const struct ad7746_chan_info ad7746_chan_info[] = {
12340b5c4d5SJonathan Cameron [VIN] = {
12440b5c4d5SJonathan Cameron .addr = AD7746_REG_VT_DATA_HIGH,
12540b5c4d5SJonathan Cameron .vtmd = AD7746_VTSETUP_VTMD_EXT_VIN,
12640b5c4d5SJonathan Cameron },
12740b5c4d5SJonathan Cameron [VIN_VDD] = {
12840b5c4d5SJonathan Cameron .addr = AD7746_REG_VT_DATA_HIGH,
12940b5c4d5SJonathan Cameron .vtmd = AD7746_VTSETUP_VTMD_VDD_MON,
13040b5c4d5SJonathan Cameron },
13140b5c4d5SJonathan Cameron [TEMP_INT] = {
13240b5c4d5SJonathan Cameron .addr = AD7746_REG_VT_DATA_HIGH,
13340b5c4d5SJonathan Cameron .vtmd = AD7746_VTSETUP_VTMD_INT_TEMP,
13440b5c4d5SJonathan Cameron },
13540b5c4d5SJonathan Cameron [TEMP_EXT] = {
13640b5c4d5SJonathan Cameron .addr = AD7746_REG_VT_DATA_HIGH,
13740b5c4d5SJonathan Cameron .vtmd = AD7746_VTSETUP_VTMD_EXT_TEMP,
13840b5c4d5SJonathan Cameron },
13940b5c4d5SJonathan Cameron [CIN1] = {
14040b5c4d5SJonathan Cameron .addr = AD7746_REG_CAP_DATA_HIGH,
14140b5c4d5SJonathan Cameron },
14240b5c4d5SJonathan Cameron [CIN1_DIFF] = {
14340b5c4d5SJonathan Cameron .addr = AD7746_REG_CAP_DATA_HIGH,
14440b5c4d5SJonathan Cameron .capdiff = 1,
14540b5c4d5SJonathan Cameron },
14640b5c4d5SJonathan Cameron [CIN2] = {
14740b5c4d5SJonathan Cameron .addr = AD7746_REG_CAP_DATA_HIGH,
14840b5c4d5SJonathan Cameron .cin2 = 1,
14940b5c4d5SJonathan Cameron },
15040b5c4d5SJonathan Cameron [CIN2_DIFF] = {
15140b5c4d5SJonathan Cameron .addr = AD7746_REG_CAP_DATA_HIGH,
15240b5c4d5SJonathan Cameron .cin2 = 1,
15340b5c4d5SJonathan Cameron .capdiff = 1,
15440b5c4d5SJonathan Cameron },
15540b5c4d5SJonathan Cameron };
15640b5c4d5SJonathan Cameron
15740b5c4d5SJonathan Cameron static const struct iio_chan_spec ad7746_channels[] = {
15840b5c4d5SJonathan Cameron [VIN] = {
15940b5c4d5SJonathan Cameron .type = IIO_VOLTAGE,
16040b5c4d5SJonathan Cameron .indexed = 1,
16140b5c4d5SJonathan Cameron .channel = 0,
16240b5c4d5SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
16340b5c4d5SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
16440b5c4d5SJonathan Cameron .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
16540b5c4d5SJonathan Cameron .address = VIN,
16640b5c4d5SJonathan Cameron },
16740b5c4d5SJonathan Cameron [VIN_VDD] = {
16840b5c4d5SJonathan Cameron .type = IIO_VOLTAGE,
16940b5c4d5SJonathan Cameron .indexed = 1,
17040b5c4d5SJonathan Cameron .channel = 1,
17140b5c4d5SJonathan Cameron .extend_name = "supply",
17240b5c4d5SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
17340b5c4d5SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
17440b5c4d5SJonathan Cameron .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
17540b5c4d5SJonathan Cameron .address = VIN_VDD,
17640b5c4d5SJonathan Cameron },
17740b5c4d5SJonathan Cameron [TEMP_INT] = {
17840b5c4d5SJonathan Cameron .type = IIO_TEMP,
17940b5c4d5SJonathan Cameron .indexed = 1,
18040b5c4d5SJonathan Cameron .channel = 0,
18140b5c4d5SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
18240b5c4d5SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
18340b5c4d5SJonathan Cameron .address = TEMP_INT,
18440b5c4d5SJonathan Cameron },
18540b5c4d5SJonathan Cameron [TEMP_EXT] = {
18640b5c4d5SJonathan Cameron .type = IIO_TEMP,
18740b5c4d5SJonathan Cameron .indexed = 1,
18840b5c4d5SJonathan Cameron .channel = 1,
18940b5c4d5SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
19040b5c4d5SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
19140b5c4d5SJonathan Cameron .address = TEMP_EXT,
19240b5c4d5SJonathan Cameron },
19340b5c4d5SJonathan Cameron [CIN1] = {
19440b5c4d5SJonathan Cameron .type = IIO_CAPACITANCE,
19540b5c4d5SJonathan Cameron .indexed = 1,
19640b5c4d5SJonathan Cameron .channel = 0,
19740b5c4d5SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
19840b5c4d5SJonathan Cameron BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET),
19940b5c4d5SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) |
20040b5c4d5SJonathan Cameron BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ),
20140b5c4d5SJonathan Cameron .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
20240b5c4d5SJonathan Cameron .address = CIN1,
20340b5c4d5SJonathan Cameron },
20440b5c4d5SJonathan Cameron [CIN1_DIFF] = {
20540b5c4d5SJonathan Cameron .type = IIO_CAPACITANCE,
20640b5c4d5SJonathan Cameron .differential = 1,
20740b5c4d5SJonathan Cameron .indexed = 1,
20840b5c4d5SJonathan Cameron .channel = 0,
20940b5c4d5SJonathan Cameron .channel2 = 2,
21040b5c4d5SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
21140b5c4d5SJonathan Cameron BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_ZEROPOINT),
21240b5c4d5SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) |
21340b5c4d5SJonathan Cameron BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ),
21440b5c4d5SJonathan Cameron .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
21540b5c4d5SJonathan Cameron .address = CIN1_DIFF,
21640b5c4d5SJonathan Cameron },
21740b5c4d5SJonathan Cameron [CIN2] = {
21840b5c4d5SJonathan Cameron .type = IIO_CAPACITANCE,
21940b5c4d5SJonathan Cameron .indexed = 1,
22040b5c4d5SJonathan Cameron .channel = 1,
22140b5c4d5SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
22240b5c4d5SJonathan Cameron BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET),
22340b5c4d5SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) |
22440b5c4d5SJonathan Cameron BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ),
22540b5c4d5SJonathan Cameron .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
22640b5c4d5SJonathan Cameron .address = CIN2,
22740b5c4d5SJonathan Cameron },
22840b5c4d5SJonathan Cameron [CIN2_DIFF] = {
22940b5c4d5SJonathan Cameron .type = IIO_CAPACITANCE,
23040b5c4d5SJonathan Cameron .differential = 1,
23140b5c4d5SJonathan Cameron .indexed = 1,
23240b5c4d5SJonathan Cameron .channel = 1,
23340b5c4d5SJonathan Cameron .channel2 = 3,
23440b5c4d5SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
23540b5c4d5SJonathan Cameron BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_ZEROPOINT),
23640b5c4d5SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) |
23740b5c4d5SJonathan Cameron BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ),
23840b5c4d5SJonathan Cameron .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
23940b5c4d5SJonathan Cameron .address = CIN2_DIFF,
24040b5c4d5SJonathan Cameron }
24140b5c4d5SJonathan Cameron };
24240b5c4d5SJonathan Cameron
24340b5c4d5SJonathan Cameron /* Values are Update Rate (Hz), Conversion Time (ms) + 1*/
24440b5c4d5SJonathan Cameron static const unsigned char ad7746_vt_filter_rate_table[][2] = {
24540b5c4d5SJonathan Cameron { 50, 20 + 1 }, { 31, 32 + 1 }, { 16, 62 + 1 }, { 8, 122 + 1 },
24640b5c4d5SJonathan Cameron };
24740b5c4d5SJonathan Cameron
24840b5c4d5SJonathan Cameron static const unsigned char ad7746_cap_filter_rate_table[][2] = {
24940b5c4d5SJonathan Cameron { 91, 11 + 1 }, { 84, 12 + 1 }, { 50, 20 + 1 }, { 26, 38 + 1 },
25040b5c4d5SJonathan Cameron { 16, 62 + 1 }, { 13, 77 + 1 }, { 11, 92 + 1 }, { 9, 110 + 1 },
25140b5c4d5SJonathan Cameron };
25240b5c4d5SJonathan Cameron
ad7746_set_capdac(struct ad7746_chip_info * chip,int channel)25340b5c4d5SJonathan Cameron static int ad7746_set_capdac(struct ad7746_chip_info *chip, int channel)
25440b5c4d5SJonathan Cameron {
25540b5c4d5SJonathan Cameron int ret = i2c_smbus_write_byte_data(chip->client,
25640b5c4d5SJonathan Cameron AD7746_REG_CAPDACA,
25740b5c4d5SJonathan Cameron chip->capdac[channel][0]);
25840b5c4d5SJonathan Cameron if (ret < 0)
25940b5c4d5SJonathan Cameron return ret;
26040b5c4d5SJonathan Cameron
26140b5c4d5SJonathan Cameron return i2c_smbus_write_byte_data(chip->client,
26240b5c4d5SJonathan Cameron AD7746_REG_CAPDACB,
26340b5c4d5SJonathan Cameron chip->capdac[channel][1]);
26440b5c4d5SJonathan Cameron }
26540b5c4d5SJonathan Cameron
ad7746_select_channel(struct iio_dev * indio_dev,struct iio_chan_spec const * chan)26640b5c4d5SJonathan Cameron static int ad7746_select_channel(struct iio_dev *indio_dev,
26740b5c4d5SJonathan Cameron struct iio_chan_spec const *chan)
26840b5c4d5SJonathan Cameron {
26940b5c4d5SJonathan Cameron struct ad7746_chip_info *chip = iio_priv(indio_dev);
27040b5c4d5SJonathan Cameron u8 vt_setup, cap_setup;
27140b5c4d5SJonathan Cameron int ret, delay, idx;
27240b5c4d5SJonathan Cameron
27340b5c4d5SJonathan Cameron switch (chan->type) {
27440b5c4d5SJonathan Cameron case IIO_CAPACITANCE:
27540b5c4d5SJonathan Cameron cap_setup = FIELD_PREP(AD7746_CAPSETUP_CIN2,
27640b5c4d5SJonathan Cameron ad7746_chan_info[chan->address].cin2) |
27740b5c4d5SJonathan Cameron FIELD_PREP(AD7746_CAPSETUP_CAPDIFF,
27840b5c4d5SJonathan Cameron ad7746_chan_info[chan->address].capdiff) |
27940b5c4d5SJonathan Cameron FIELD_PREP(AD7746_CAPSETUP_CAPEN, 1);
28040b5c4d5SJonathan Cameron vt_setup = chip->vt_setup & ~AD7746_VTSETUP_VTEN;
28140b5c4d5SJonathan Cameron idx = FIELD_GET(AD7746_CONF_CAPFS_MASK, chip->config);
28240b5c4d5SJonathan Cameron delay = ad7746_cap_filter_rate_table[idx][1];
28340b5c4d5SJonathan Cameron
28440b5c4d5SJonathan Cameron ret = ad7746_set_capdac(chip, chan->channel);
28540b5c4d5SJonathan Cameron if (ret < 0)
28640b5c4d5SJonathan Cameron return ret;
28740b5c4d5SJonathan Cameron
28840b5c4d5SJonathan Cameron chip->capdac_set = chan->channel;
28940b5c4d5SJonathan Cameron break;
29040b5c4d5SJonathan Cameron case IIO_VOLTAGE:
29140b5c4d5SJonathan Cameron case IIO_TEMP:
29240b5c4d5SJonathan Cameron vt_setup = FIELD_PREP(AD7746_VTSETUP_VTMD_MASK,
29340b5c4d5SJonathan Cameron ad7746_chan_info[chan->address].vtmd) |
29440b5c4d5SJonathan Cameron FIELD_PREP(AD7746_VTSETUP_VTEN, 1);
29540b5c4d5SJonathan Cameron cap_setup = chip->cap_setup & ~AD7746_CAPSETUP_CAPEN;
29640b5c4d5SJonathan Cameron idx = FIELD_GET(AD7746_CONF_VTFS_MASK, chip->config);
29740b5c4d5SJonathan Cameron delay = ad7746_cap_filter_rate_table[idx][1];
29840b5c4d5SJonathan Cameron break;
29940b5c4d5SJonathan Cameron default:
30040b5c4d5SJonathan Cameron return -EINVAL;
30140b5c4d5SJonathan Cameron }
30240b5c4d5SJonathan Cameron
30340b5c4d5SJonathan Cameron if (chip->cap_setup != cap_setup) {
30440b5c4d5SJonathan Cameron ret = i2c_smbus_write_byte_data(chip->client,
30540b5c4d5SJonathan Cameron AD7746_REG_CAP_SETUP,
30640b5c4d5SJonathan Cameron cap_setup);
30740b5c4d5SJonathan Cameron if (ret < 0)
30840b5c4d5SJonathan Cameron return ret;
30940b5c4d5SJonathan Cameron
31040b5c4d5SJonathan Cameron chip->cap_setup = cap_setup;
31140b5c4d5SJonathan Cameron }
31240b5c4d5SJonathan Cameron
31340b5c4d5SJonathan Cameron if (chip->vt_setup != vt_setup) {
31440b5c4d5SJonathan Cameron ret = i2c_smbus_write_byte_data(chip->client,
31540b5c4d5SJonathan Cameron AD7746_REG_VT_SETUP,
31640b5c4d5SJonathan Cameron vt_setup);
31740b5c4d5SJonathan Cameron if (ret < 0)
31840b5c4d5SJonathan Cameron return ret;
31940b5c4d5SJonathan Cameron
32040b5c4d5SJonathan Cameron chip->vt_setup = vt_setup;
32140b5c4d5SJonathan Cameron }
32240b5c4d5SJonathan Cameron
32340b5c4d5SJonathan Cameron return delay;
32440b5c4d5SJonathan Cameron }
32540b5c4d5SJonathan Cameron
ad7746_start_calib(struct device * dev,struct device_attribute * attr,const char * buf,size_t len,u8 regval)32640b5c4d5SJonathan Cameron static inline ssize_t ad7746_start_calib(struct device *dev,
32740b5c4d5SJonathan Cameron struct device_attribute *attr,
32840b5c4d5SJonathan Cameron const char *buf,
32940b5c4d5SJonathan Cameron size_t len,
33040b5c4d5SJonathan Cameron u8 regval)
33140b5c4d5SJonathan Cameron {
33240b5c4d5SJonathan Cameron struct iio_dev *indio_dev = dev_to_iio_dev(dev);
33340b5c4d5SJonathan Cameron struct ad7746_chip_info *chip = iio_priv(indio_dev);
33440b5c4d5SJonathan Cameron int ret, timeout = 10;
33540b5c4d5SJonathan Cameron bool doit;
33640b5c4d5SJonathan Cameron
33740b5c4d5SJonathan Cameron ret = kstrtobool(buf, &doit);
33840b5c4d5SJonathan Cameron if (ret < 0)
33940b5c4d5SJonathan Cameron return ret;
34040b5c4d5SJonathan Cameron
34140b5c4d5SJonathan Cameron if (!doit)
34240b5c4d5SJonathan Cameron return 0;
34340b5c4d5SJonathan Cameron
34440b5c4d5SJonathan Cameron mutex_lock(&chip->lock);
34540b5c4d5SJonathan Cameron regval |= chip->config;
34640b5c4d5SJonathan Cameron ret = i2c_smbus_write_byte_data(chip->client, AD7746_REG_CFG, regval);
34740b5c4d5SJonathan Cameron if (ret < 0)
34840b5c4d5SJonathan Cameron goto unlock;
34940b5c4d5SJonathan Cameron
35040b5c4d5SJonathan Cameron do {
35140b5c4d5SJonathan Cameron msleep(20);
35240b5c4d5SJonathan Cameron ret = i2c_smbus_read_byte_data(chip->client, AD7746_REG_CFG);
35340b5c4d5SJonathan Cameron if (ret < 0)
35440b5c4d5SJonathan Cameron goto unlock;
35540b5c4d5SJonathan Cameron
35640b5c4d5SJonathan Cameron } while ((ret == regval) && timeout--);
35740b5c4d5SJonathan Cameron
35840b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
35940b5c4d5SJonathan Cameron
36040b5c4d5SJonathan Cameron return len;
36140b5c4d5SJonathan Cameron
36240b5c4d5SJonathan Cameron unlock:
36340b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
36440b5c4d5SJonathan Cameron return ret;
36540b5c4d5SJonathan Cameron }
36640b5c4d5SJonathan Cameron
ad7746_start_offset_calib(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)36740b5c4d5SJonathan Cameron static ssize_t ad7746_start_offset_calib(struct device *dev,
36840b5c4d5SJonathan Cameron struct device_attribute *attr,
36940b5c4d5SJonathan Cameron const char *buf,
37040b5c4d5SJonathan Cameron size_t len)
37140b5c4d5SJonathan Cameron {
37240b5c4d5SJonathan Cameron struct iio_dev *indio_dev = dev_to_iio_dev(dev);
37340b5c4d5SJonathan Cameron int ret = ad7746_select_channel(indio_dev,
37440b5c4d5SJonathan Cameron &ad7746_channels[to_iio_dev_attr(attr)->address]);
37540b5c4d5SJonathan Cameron if (ret < 0)
37640b5c4d5SJonathan Cameron return ret;
37740b5c4d5SJonathan Cameron
37840b5c4d5SJonathan Cameron return ad7746_start_calib(dev, attr, buf, len,
37940b5c4d5SJonathan Cameron FIELD_PREP(AD7746_CONF_MODE_MASK,
38040b5c4d5SJonathan Cameron AD7746_CONF_MODE_OFFS_CAL));
38140b5c4d5SJonathan Cameron }
38240b5c4d5SJonathan Cameron
ad7746_start_gain_calib(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)38340b5c4d5SJonathan Cameron static ssize_t ad7746_start_gain_calib(struct device *dev,
38440b5c4d5SJonathan Cameron struct device_attribute *attr,
38540b5c4d5SJonathan Cameron const char *buf,
38640b5c4d5SJonathan Cameron size_t len)
38740b5c4d5SJonathan Cameron {
38840b5c4d5SJonathan Cameron struct iio_dev *indio_dev = dev_to_iio_dev(dev);
38940b5c4d5SJonathan Cameron int ret = ad7746_select_channel(indio_dev,
39040b5c4d5SJonathan Cameron &ad7746_channels[to_iio_dev_attr(attr)->address]);
39140b5c4d5SJonathan Cameron if (ret < 0)
39240b5c4d5SJonathan Cameron return ret;
39340b5c4d5SJonathan Cameron
39440b5c4d5SJonathan Cameron return ad7746_start_calib(dev, attr, buf, len,
39540b5c4d5SJonathan Cameron FIELD_PREP(AD7746_CONF_MODE_MASK,
39640b5c4d5SJonathan Cameron AD7746_CONF_MODE_GAIN_CAL));
39740b5c4d5SJonathan Cameron }
39840b5c4d5SJonathan Cameron
39940b5c4d5SJonathan Cameron static IIO_DEVICE_ATTR(in_capacitance0_calibbias_calibration,
40040b5c4d5SJonathan Cameron 0200, NULL, ad7746_start_offset_calib, CIN1);
40140b5c4d5SJonathan Cameron static IIO_DEVICE_ATTR(in_capacitance1_calibbias_calibration,
40240b5c4d5SJonathan Cameron 0200, NULL, ad7746_start_offset_calib, CIN2);
40340b5c4d5SJonathan Cameron static IIO_DEVICE_ATTR(in_capacitance0_calibscale_calibration,
40440b5c4d5SJonathan Cameron 0200, NULL, ad7746_start_gain_calib, CIN1);
40540b5c4d5SJonathan Cameron static IIO_DEVICE_ATTR(in_capacitance1_calibscale_calibration,
40640b5c4d5SJonathan Cameron 0200, NULL, ad7746_start_gain_calib, CIN2);
40740b5c4d5SJonathan Cameron static IIO_DEVICE_ATTR(in_voltage0_calibscale_calibration,
40840b5c4d5SJonathan Cameron 0200, NULL, ad7746_start_gain_calib, VIN);
40940b5c4d5SJonathan Cameron
ad7746_store_cap_filter_rate_setup(struct ad7746_chip_info * chip,int val)41040b5c4d5SJonathan Cameron static int ad7746_store_cap_filter_rate_setup(struct ad7746_chip_info *chip,
41140b5c4d5SJonathan Cameron int val)
41240b5c4d5SJonathan Cameron {
41340b5c4d5SJonathan Cameron int i;
41440b5c4d5SJonathan Cameron
41540b5c4d5SJonathan Cameron for (i = 0; i < ARRAY_SIZE(ad7746_cap_filter_rate_table); i++)
41640b5c4d5SJonathan Cameron if (val >= ad7746_cap_filter_rate_table[i][0])
41740b5c4d5SJonathan Cameron break;
41840b5c4d5SJonathan Cameron
41940b5c4d5SJonathan Cameron if (i >= ARRAY_SIZE(ad7746_cap_filter_rate_table))
42040b5c4d5SJonathan Cameron i = ARRAY_SIZE(ad7746_cap_filter_rate_table) - 1;
42140b5c4d5SJonathan Cameron
42240b5c4d5SJonathan Cameron chip->config &= ~AD7746_CONF_CAPFS_MASK;
42340b5c4d5SJonathan Cameron chip->config |= FIELD_PREP(AD7746_CONF_CAPFS_MASK, i);
42440b5c4d5SJonathan Cameron
42540b5c4d5SJonathan Cameron return 0;
42640b5c4d5SJonathan Cameron }
42740b5c4d5SJonathan Cameron
ad7746_store_vt_filter_rate_setup(struct ad7746_chip_info * chip,int val)42840b5c4d5SJonathan Cameron static int ad7746_store_vt_filter_rate_setup(struct ad7746_chip_info *chip,
42940b5c4d5SJonathan Cameron int val)
43040b5c4d5SJonathan Cameron {
43140b5c4d5SJonathan Cameron int i;
43240b5c4d5SJonathan Cameron
43340b5c4d5SJonathan Cameron for (i = 0; i < ARRAY_SIZE(ad7746_vt_filter_rate_table); i++)
43440b5c4d5SJonathan Cameron if (val >= ad7746_vt_filter_rate_table[i][0])
43540b5c4d5SJonathan Cameron break;
43640b5c4d5SJonathan Cameron
43740b5c4d5SJonathan Cameron if (i >= ARRAY_SIZE(ad7746_vt_filter_rate_table))
43840b5c4d5SJonathan Cameron i = ARRAY_SIZE(ad7746_vt_filter_rate_table) - 1;
43940b5c4d5SJonathan Cameron
44040b5c4d5SJonathan Cameron chip->config &= ~AD7746_CONF_VTFS_MASK;
44140b5c4d5SJonathan Cameron chip->config |= FIELD_PREP(AD7746_CONF_VTFS_MASK, i);
44240b5c4d5SJonathan Cameron
44340b5c4d5SJonathan Cameron return 0;
44440b5c4d5SJonathan Cameron }
44540b5c4d5SJonathan Cameron
44640b5c4d5SJonathan Cameron static struct attribute *ad7746_attributes[] = {
44740b5c4d5SJonathan Cameron &iio_dev_attr_in_capacitance0_calibbias_calibration.dev_attr.attr,
44840b5c4d5SJonathan Cameron &iio_dev_attr_in_capacitance0_calibscale_calibration.dev_attr.attr,
44940b5c4d5SJonathan Cameron &iio_dev_attr_in_capacitance1_calibscale_calibration.dev_attr.attr,
45040b5c4d5SJonathan Cameron &iio_dev_attr_in_capacitance1_calibbias_calibration.dev_attr.attr,
45140b5c4d5SJonathan Cameron &iio_dev_attr_in_voltage0_calibscale_calibration.dev_attr.attr,
45240b5c4d5SJonathan Cameron NULL,
45340b5c4d5SJonathan Cameron };
45440b5c4d5SJonathan Cameron
45540b5c4d5SJonathan Cameron static const struct attribute_group ad7746_attribute_group = {
45640b5c4d5SJonathan Cameron .attrs = ad7746_attributes,
45740b5c4d5SJonathan Cameron };
45840b5c4d5SJonathan Cameron
ad7746_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)45940b5c4d5SJonathan Cameron static int ad7746_write_raw(struct iio_dev *indio_dev,
46040b5c4d5SJonathan Cameron struct iio_chan_spec const *chan,
46140b5c4d5SJonathan Cameron int val,
46240b5c4d5SJonathan Cameron int val2,
46340b5c4d5SJonathan Cameron long mask)
46440b5c4d5SJonathan Cameron {
46540b5c4d5SJonathan Cameron struct ad7746_chip_info *chip = iio_priv(indio_dev);
46640b5c4d5SJonathan Cameron int ret, reg;
46740b5c4d5SJonathan Cameron
46840b5c4d5SJonathan Cameron switch (mask) {
46940b5c4d5SJonathan Cameron case IIO_CHAN_INFO_CALIBSCALE:
47040b5c4d5SJonathan Cameron if (val != 1)
47140b5c4d5SJonathan Cameron return -EINVAL;
47240b5c4d5SJonathan Cameron
47340b5c4d5SJonathan Cameron val = (val2 * 1024) / 15625;
47440b5c4d5SJonathan Cameron
47540b5c4d5SJonathan Cameron switch (chan->type) {
47640b5c4d5SJonathan Cameron case IIO_CAPACITANCE:
47740b5c4d5SJonathan Cameron reg = AD7746_REG_CAP_GAINH;
47840b5c4d5SJonathan Cameron break;
47940b5c4d5SJonathan Cameron case IIO_VOLTAGE:
48040b5c4d5SJonathan Cameron reg = AD7746_REG_VOLT_GAINH;
48140b5c4d5SJonathan Cameron break;
48240b5c4d5SJonathan Cameron default:
48340b5c4d5SJonathan Cameron return -EINVAL;
48440b5c4d5SJonathan Cameron }
48540b5c4d5SJonathan Cameron
48640b5c4d5SJonathan Cameron mutex_lock(&chip->lock);
48740b5c4d5SJonathan Cameron ret = i2c_smbus_write_word_swapped(chip->client, reg, val);
48840b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
48940b5c4d5SJonathan Cameron if (ret < 0)
49040b5c4d5SJonathan Cameron return ret;
49140b5c4d5SJonathan Cameron
49240b5c4d5SJonathan Cameron return 0;
49340b5c4d5SJonathan Cameron case IIO_CHAN_INFO_CALIBBIAS:
49440b5c4d5SJonathan Cameron if (val < 0 || val > 0xFFFF)
49540b5c4d5SJonathan Cameron return -EINVAL;
49640b5c4d5SJonathan Cameron
49740b5c4d5SJonathan Cameron mutex_lock(&chip->lock);
49840b5c4d5SJonathan Cameron ret = i2c_smbus_write_word_swapped(chip->client,
49940b5c4d5SJonathan Cameron AD7746_REG_CAP_OFFH, val);
50040b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
50140b5c4d5SJonathan Cameron if (ret < 0)
50240b5c4d5SJonathan Cameron return ret;
50340b5c4d5SJonathan Cameron
50440b5c4d5SJonathan Cameron return 0;
50540b5c4d5SJonathan Cameron case IIO_CHAN_INFO_OFFSET:
50640b5c4d5SJonathan Cameron case IIO_CHAN_INFO_ZEROPOINT:
50740b5c4d5SJonathan Cameron if (val < 0 || val > 43008000) /* 21pF */
50840b5c4d5SJonathan Cameron return -EINVAL;
50940b5c4d5SJonathan Cameron
51040b5c4d5SJonathan Cameron /*
51140b5c4d5SJonathan Cameron * CAPDAC Scale = 21pF_typ / 127
51240b5c4d5SJonathan Cameron * CIN Scale = 8.192pF / 2^24
51340b5c4d5SJonathan Cameron * Offset Scale = CAPDAC Scale / CIN Scale = 338646
51440b5c4d5SJonathan Cameron */
51540b5c4d5SJonathan Cameron
51640b5c4d5SJonathan Cameron val /= 338646;
51740b5c4d5SJonathan Cameron mutex_lock(&chip->lock);
51840b5c4d5SJonathan Cameron chip->capdac[chan->channel][chan->differential] = val > 0 ?
51940b5c4d5SJonathan Cameron FIELD_PREP(AD7746_CAPDAC_DACP_MASK, val) | AD7746_CAPDAC_DACEN : 0;
52040b5c4d5SJonathan Cameron
52140b5c4d5SJonathan Cameron ret = ad7746_set_capdac(chip, chan->channel);
52240b5c4d5SJonathan Cameron if (ret < 0) {
52340b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
52440b5c4d5SJonathan Cameron return ret;
52540b5c4d5SJonathan Cameron }
52640b5c4d5SJonathan Cameron
52740b5c4d5SJonathan Cameron chip->capdac_set = chan->channel;
52840b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
52940b5c4d5SJonathan Cameron
53040b5c4d5SJonathan Cameron return 0;
53140b5c4d5SJonathan Cameron case IIO_CHAN_INFO_SAMP_FREQ:
53240b5c4d5SJonathan Cameron if (val2)
53340b5c4d5SJonathan Cameron return -EINVAL;
53440b5c4d5SJonathan Cameron
53540b5c4d5SJonathan Cameron switch (chan->type) {
53640b5c4d5SJonathan Cameron case IIO_CAPACITANCE:
53740b5c4d5SJonathan Cameron mutex_lock(&chip->lock);
53840b5c4d5SJonathan Cameron ret = ad7746_store_cap_filter_rate_setup(chip, val);
53940b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
54040b5c4d5SJonathan Cameron return ret;
54140b5c4d5SJonathan Cameron case IIO_VOLTAGE:
54240b5c4d5SJonathan Cameron mutex_lock(&chip->lock);
54340b5c4d5SJonathan Cameron ret = ad7746_store_vt_filter_rate_setup(chip, val);
54440b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
54540b5c4d5SJonathan Cameron return ret;
54640b5c4d5SJonathan Cameron default:
54740b5c4d5SJonathan Cameron return -EINVAL;
54840b5c4d5SJonathan Cameron }
54940b5c4d5SJonathan Cameron default:
55040b5c4d5SJonathan Cameron return -EINVAL;
55140b5c4d5SJonathan Cameron }
55240b5c4d5SJonathan Cameron }
55340b5c4d5SJonathan Cameron
55440b5c4d5SJonathan Cameron static const int ad7746_v_samp_freq[] = { 50, 31, 16, 8, };
55540b5c4d5SJonathan Cameron static const int ad7746_cap_samp_freq[] = { 91, 84, 50, 26, 16, 13, 11, 9, };
55640b5c4d5SJonathan Cameron
ad7746_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)55740b5c4d5SJonathan Cameron static int ad7746_read_avail(struct iio_dev *indio_dev,
55840b5c4d5SJonathan Cameron struct iio_chan_spec const *chan, const int **vals,
55940b5c4d5SJonathan Cameron int *type, int *length, long mask)
56040b5c4d5SJonathan Cameron {
56140b5c4d5SJonathan Cameron if (mask != IIO_CHAN_INFO_SAMP_FREQ)
56240b5c4d5SJonathan Cameron return -EINVAL;
56340b5c4d5SJonathan Cameron
56440b5c4d5SJonathan Cameron switch (chan->type) {
56540b5c4d5SJonathan Cameron case IIO_VOLTAGE:
56640b5c4d5SJonathan Cameron *vals = ad7746_v_samp_freq;
56740b5c4d5SJonathan Cameron *length = ARRAY_SIZE(ad7746_v_samp_freq);
56840b5c4d5SJonathan Cameron break;
56940b5c4d5SJonathan Cameron case IIO_CAPACITANCE:
57040b5c4d5SJonathan Cameron *vals = ad7746_cap_samp_freq;
57140b5c4d5SJonathan Cameron *length = ARRAY_SIZE(ad7746_cap_samp_freq);
57240b5c4d5SJonathan Cameron break;
57340b5c4d5SJonathan Cameron default:
57440b5c4d5SJonathan Cameron return -EINVAL;
57540b5c4d5SJonathan Cameron }
57640b5c4d5SJonathan Cameron *type = IIO_VAL_INT;
57740b5c4d5SJonathan Cameron return IIO_AVAIL_LIST;
57840b5c4d5SJonathan Cameron }
57940b5c4d5SJonathan Cameron
ad7746_read_channel(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val)58040b5c4d5SJonathan Cameron static int ad7746_read_channel(struct iio_dev *indio_dev,
58140b5c4d5SJonathan Cameron struct iio_chan_spec const *chan,
58240b5c4d5SJonathan Cameron int *val)
58340b5c4d5SJonathan Cameron {
58440b5c4d5SJonathan Cameron struct ad7746_chip_info *chip = iio_priv(indio_dev);
58540b5c4d5SJonathan Cameron int ret, delay;
58640b5c4d5SJonathan Cameron u8 data[3];
58740b5c4d5SJonathan Cameron u8 regval;
58840b5c4d5SJonathan Cameron
58940b5c4d5SJonathan Cameron ret = ad7746_select_channel(indio_dev, chan);
59040b5c4d5SJonathan Cameron if (ret < 0)
59140b5c4d5SJonathan Cameron return ret;
59240b5c4d5SJonathan Cameron delay = ret;
59340b5c4d5SJonathan Cameron
59440b5c4d5SJonathan Cameron regval = chip->config | FIELD_PREP(AD7746_CONF_MODE_MASK,
59540b5c4d5SJonathan Cameron AD7746_CONF_MODE_SINGLE_CONV);
59640b5c4d5SJonathan Cameron ret = i2c_smbus_write_byte_data(chip->client, AD7746_REG_CFG, regval);
59740b5c4d5SJonathan Cameron if (ret < 0)
59840b5c4d5SJonathan Cameron return ret;
59940b5c4d5SJonathan Cameron
60040b5c4d5SJonathan Cameron msleep(delay);
60140b5c4d5SJonathan Cameron /* Now read the actual register */
60240b5c4d5SJonathan Cameron ret = i2c_smbus_read_i2c_block_data(chip->client,
60340b5c4d5SJonathan Cameron ad7746_chan_info[chan->address].addr,
60440b5c4d5SJonathan Cameron sizeof(data), data);
60540b5c4d5SJonathan Cameron if (ret < 0)
60640b5c4d5SJonathan Cameron return ret;
60740b5c4d5SJonathan Cameron
60840b5c4d5SJonathan Cameron /*
60940b5c4d5SJonathan Cameron * Offset applied internally becaue the _offset userspace interface is
61040b5c4d5SJonathan Cameron * needed for the CAP DACs which apply a controllable offset.
61140b5c4d5SJonathan Cameron */
61240b5c4d5SJonathan Cameron *val = get_unaligned_be24(data) - 0x800000;
61340b5c4d5SJonathan Cameron
61440b5c4d5SJonathan Cameron return 0;
61540b5c4d5SJonathan Cameron }
61640b5c4d5SJonathan Cameron
ad7746_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)61740b5c4d5SJonathan Cameron static int ad7746_read_raw(struct iio_dev *indio_dev,
61840b5c4d5SJonathan Cameron struct iio_chan_spec const *chan,
61940b5c4d5SJonathan Cameron int *val, int *val2,
62040b5c4d5SJonathan Cameron long mask)
62140b5c4d5SJonathan Cameron {
62240b5c4d5SJonathan Cameron struct ad7746_chip_info *chip = iio_priv(indio_dev);
62340b5c4d5SJonathan Cameron int ret, idx;
62440b5c4d5SJonathan Cameron u8 reg;
62540b5c4d5SJonathan Cameron
62640b5c4d5SJonathan Cameron switch (mask) {
62740b5c4d5SJonathan Cameron case IIO_CHAN_INFO_RAW:
62840b5c4d5SJonathan Cameron mutex_lock(&chip->lock);
62940b5c4d5SJonathan Cameron ret = ad7746_read_channel(indio_dev, chan, val);
63040b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
63140b5c4d5SJonathan Cameron if (ret < 0)
63240b5c4d5SJonathan Cameron return ret;
63340b5c4d5SJonathan Cameron
63440b5c4d5SJonathan Cameron return IIO_VAL_INT;
63540b5c4d5SJonathan Cameron case IIO_CHAN_INFO_CALIBSCALE:
63640b5c4d5SJonathan Cameron switch (chan->type) {
63740b5c4d5SJonathan Cameron case IIO_CAPACITANCE:
63840b5c4d5SJonathan Cameron reg = AD7746_REG_CAP_GAINH;
63940b5c4d5SJonathan Cameron break;
64040b5c4d5SJonathan Cameron case IIO_VOLTAGE:
64140b5c4d5SJonathan Cameron reg = AD7746_REG_VOLT_GAINH;
64240b5c4d5SJonathan Cameron break;
64340b5c4d5SJonathan Cameron default:
64440b5c4d5SJonathan Cameron return -EINVAL;
64540b5c4d5SJonathan Cameron }
64640b5c4d5SJonathan Cameron
64740b5c4d5SJonathan Cameron mutex_lock(&chip->lock);
64840b5c4d5SJonathan Cameron ret = i2c_smbus_read_word_swapped(chip->client, reg);
64940b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
65040b5c4d5SJonathan Cameron if (ret < 0)
65140b5c4d5SJonathan Cameron return ret;
65240b5c4d5SJonathan Cameron /* 1 + gain_val / 2^16 */
65340b5c4d5SJonathan Cameron *val = 1;
65440b5c4d5SJonathan Cameron *val2 = (15625 * ret) / 1024;
65540b5c4d5SJonathan Cameron
65640b5c4d5SJonathan Cameron return IIO_VAL_INT_PLUS_MICRO;
65740b5c4d5SJonathan Cameron case IIO_CHAN_INFO_CALIBBIAS:
65840b5c4d5SJonathan Cameron mutex_lock(&chip->lock);
65940b5c4d5SJonathan Cameron ret = i2c_smbus_read_word_swapped(chip->client,
66040b5c4d5SJonathan Cameron AD7746_REG_CAP_OFFH);
66140b5c4d5SJonathan Cameron mutex_unlock(&chip->lock);
66240b5c4d5SJonathan Cameron if (ret < 0)
66340b5c4d5SJonathan Cameron return ret;
66440b5c4d5SJonathan Cameron *val = ret;
66540b5c4d5SJonathan Cameron
66640b5c4d5SJonathan Cameron return IIO_VAL_INT;
66740b5c4d5SJonathan Cameron case IIO_CHAN_INFO_OFFSET:
66840b5c4d5SJonathan Cameron case IIO_CHAN_INFO_ZEROPOINT:
66940b5c4d5SJonathan Cameron *val = FIELD_GET(AD7746_CAPDAC_DACP_MASK,
67040b5c4d5SJonathan Cameron chip->capdac[chan->channel][chan->differential]) * 338646;
67140b5c4d5SJonathan Cameron
67240b5c4d5SJonathan Cameron return IIO_VAL_INT;
67340b5c4d5SJonathan Cameron case IIO_CHAN_INFO_SCALE:
67440b5c4d5SJonathan Cameron switch (chan->type) {
67540b5c4d5SJonathan Cameron case IIO_CAPACITANCE:
67640b5c4d5SJonathan Cameron /* 8.192pf / 2^24 */
67740b5c4d5SJonathan Cameron *val = 0;
67840b5c4d5SJonathan Cameron *val2 = 488;
67940b5c4d5SJonathan Cameron return IIO_VAL_INT_PLUS_NANO;
68040b5c4d5SJonathan Cameron case IIO_VOLTAGE:
68140b5c4d5SJonathan Cameron /* 1170mV / 2^23 */
68240b5c4d5SJonathan Cameron *val = 1170;
68340b5c4d5SJonathan Cameron if (chan->channel == 1)
68440b5c4d5SJonathan Cameron *val *= 6;
68540b5c4d5SJonathan Cameron *val2 = 23;
68640b5c4d5SJonathan Cameron return IIO_VAL_FRACTIONAL_LOG2;
68740b5c4d5SJonathan Cameron case IIO_TEMP:
68840b5c4d5SJonathan Cameron *val = 125;
68940b5c4d5SJonathan Cameron *val2 = 8;
69040b5c4d5SJonathan Cameron return IIO_VAL_FRACTIONAL_LOG2;
69140b5c4d5SJonathan Cameron default:
69240b5c4d5SJonathan Cameron return -EINVAL;
69340b5c4d5SJonathan Cameron }
69440b5c4d5SJonathan Cameron case IIO_CHAN_INFO_SAMP_FREQ:
69540b5c4d5SJonathan Cameron switch (chan->type) {
69640b5c4d5SJonathan Cameron case IIO_CAPACITANCE:
69740b5c4d5SJonathan Cameron idx = FIELD_GET(AD7746_CONF_CAPFS_MASK, chip->config);
69840b5c4d5SJonathan Cameron *val = ad7746_cap_filter_rate_table[idx][0];
69940b5c4d5SJonathan Cameron return IIO_VAL_INT;
70040b5c4d5SJonathan Cameron case IIO_VOLTAGE:
70140b5c4d5SJonathan Cameron idx = FIELD_GET(AD7746_CONF_VTFS_MASK, chip->config);
70240b5c4d5SJonathan Cameron *val = ad7746_vt_filter_rate_table[idx][0];
70340b5c4d5SJonathan Cameron return IIO_VAL_INT;
70440b5c4d5SJonathan Cameron default:
70540b5c4d5SJonathan Cameron return -EINVAL;
70640b5c4d5SJonathan Cameron }
70740b5c4d5SJonathan Cameron default:
70840b5c4d5SJonathan Cameron return -EINVAL;
70940b5c4d5SJonathan Cameron }
71040b5c4d5SJonathan Cameron }
71140b5c4d5SJonathan Cameron
71240b5c4d5SJonathan Cameron static const struct iio_info ad7746_info = {
71340b5c4d5SJonathan Cameron .attrs = &ad7746_attribute_group,
71440b5c4d5SJonathan Cameron .read_raw = ad7746_read_raw,
71540b5c4d5SJonathan Cameron .read_avail = ad7746_read_avail,
71640b5c4d5SJonathan Cameron .write_raw = ad7746_write_raw,
71740b5c4d5SJonathan Cameron };
71840b5c4d5SJonathan Cameron
ad7746_probe(struct i2c_client * client)7199b1cd21eSUwe Kleine-König static int ad7746_probe(struct i2c_client *client)
72040b5c4d5SJonathan Cameron {
7219b1cd21eSUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client);
72240b5c4d5SJonathan Cameron struct device *dev = &client->dev;
72340b5c4d5SJonathan Cameron struct ad7746_chip_info *chip;
72440b5c4d5SJonathan Cameron struct iio_dev *indio_dev;
72540b5c4d5SJonathan Cameron unsigned char regval = 0;
72640b5c4d5SJonathan Cameron unsigned int vdd_permille;
72740b5c4d5SJonathan Cameron int ret;
72840b5c4d5SJonathan Cameron
72940b5c4d5SJonathan Cameron indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
73040b5c4d5SJonathan Cameron if (!indio_dev)
73140b5c4d5SJonathan Cameron return -ENOMEM;
73240b5c4d5SJonathan Cameron
73340b5c4d5SJonathan Cameron chip = iio_priv(indio_dev);
73440b5c4d5SJonathan Cameron mutex_init(&chip->lock);
73540b5c4d5SJonathan Cameron
73640b5c4d5SJonathan Cameron chip->client = client;
73740b5c4d5SJonathan Cameron chip->capdac_set = -1;
73840b5c4d5SJonathan Cameron
73940b5c4d5SJonathan Cameron indio_dev->name = id->name;
74040b5c4d5SJonathan Cameron indio_dev->info = &ad7746_info;
74140b5c4d5SJonathan Cameron indio_dev->channels = ad7746_channels;
74240b5c4d5SJonathan Cameron if (id->driver_data == 7746)
74340b5c4d5SJonathan Cameron indio_dev->num_channels = ARRAY_SIZE(ad7746_channels);
74440b5c4d5SJonathan Cameron else
74540b5c4d5SJonathan Cameron indio_dev->num_channels = ARRAY_SIZE(ad7746_channels) - 2;
74640b5c4d5SJonathan Cameron indio_dev->modes = INDIO_DIRECT_MODE;
74740b5c4d5SJonathan Cameron
74840b5c4d5SJonathan Cameron if (device_property_read_bool(dev, "adi,exca-output-en")) {
74940b5c4d5SJonathan Cameron if (device_property_read_bool(dev, "adi,exca-output-invert"))
75040b5c4d5SJonathan Cameron regval |= AD7746_EXCSETUP_NEXCA;
75140b5c4d5SJonathan Cameron else
75240b5c4d5SJonathan Cameron regval |= AD7746_EXCSETUP_EXCA;
75340b5c4d5SJonathan Cameron }
75440b5c4d5SJonathan Cameron
75540b5c4d5SJonathan Cameron if (device_property_read_bool(dev, "adi,excb-output-en")) {
75640b5c4d5SJonathan Cameron if (device_property_read_bool(dev, "adi,excb-output-invert"))
75740b5c4d5SJonathan Cameron regval |= AD7746_EXCSETUP_NEXCB;
75840b5c4d5SJonathan Cameron else
75940b5c4d5SJonathan Cameron regval |= AD7746_EXCSETUP_EXCB;
76040b5c4d5SJonathan Cameron }
76140b5c4d5SJonathan Cameron
76240b5c4d5SJonathan Cameron ret = device_property_read_u32(dev, "adi,excitation-vdd-permille",
76340b5c4d5SJonathan Cameron &vdd_permille);
76440b5c4d5SJonathan Cameron if (!ret) {
76540b5c4d5SJonathan Cameron switch (vdd_permille) {
76640b5c4d5SJonathan Cameron case 125:
76740b5c4d5SJonathan Cameron regval |= FIELD_PREP(AD7746_EXCSETUP_EXCLVL_MASK, 0);
76840b5c4d5SJonathan Cameron break;
76940b5c4d5SJonathan Cameron case 250:
77040b5c4d5SJonathan Cameron regval |= FIELD_PREP(AD7746_EXCSETUP_EXCLVL_MASK, 1);
77140b5c4d5SJonathan Cameron break;
77240b5c4d5SJonathan Cameron case 375:
77340b5c4d5SJonathan Cameron regval |= FIELD_PREP(AD7746_EXCSETUP_EXCLVL_MASK, 2);
77440b5c4d5SJonathan Cameron break;
77540b5c4d5SJonathan Cameron case 500:
77640b5c4d5SJonathan Cameron regval |= FIELD_PREP(AD7746_EXCSETUP_EXCLVL_MASK, 3);
77740b5c4d5SJonathan Cameron break;
77840b5c4d5SJonathan Cameron default:
77940b5c4d5SJonathan Cameron break;
78040b5c4d5SJonathan Cameron }
78140b5c4d5SJonathan Cameron }
78240b5c4d5SJonathan Cameron
78340b5c4d5SJonathan Cameron ret = i2c_smbus_write_byte_data(chip->client, AD7746_REG_EXC_SETUP,
78440b5c4d5SJonathan Cameron regval);
78540b5c4d5SJonathan Cameron if (ret < 0)
78640b5c4d5SJonathan Cameron return ret;
78740b5c4d5SJonathan Cameron
78840b5c4d5SJonathan Cameron return devm_iio_device_register(indio_dev->dev.parent, indio_dev);
78940b5c4d5SJonathan Cameron }
79040b5c4d5SJonathan Cameron
79140b5c4d5SJonathan Cameron static const struct i2c_device_id ad7746_id[] = {
79240b5c4d5SJonathan Cameron { "ad7745", 7745 },
79340b5c4d5SJonathan Cameron { "ad7746", 7746 },
79440b5c4d5SJonathan Cameron { "ad7747", 7747 },
79540b5c4d5SJonathan Cameron {}
79640b5c4d5SJonathan Cameron };
79740b5c4d5SJonathan Cameron MODULE_DEVICE_TABLE(i2c, ad7746_id);
79840b5c4d5SJonathan Cameron
79940b5c4d5SJonathan Cameron static const struct of_device_id ad7746_of_match[] = {
80040b5c4d5SJonathan Cameron { .compatible = "adi,ad7745" },
80140b5c4d5SJonathan Cameron { .compatible = "adi,ad7746" },
80240b5c4d5SJonathan Cameron { .compatible = "adi,ad7747" },
80340b5c4d5SJonathan Cameron { },
80440b5c4d5SJonathan Cameron };
80540b5c4d5SJonathan Cameron MODULE_DEVICE_TABLE(of, ad7746_of_match);
80640b5c4d5SJonathan Cameron
80740b5c4d5SJonathan Cameron static struct i2c_driver ad7746_driver = {
80840b5c4d5SJonathan Cameron .driver = {
80940b5c4d5SJonathan Cameron .name = KBUILD_MODNAME,
81040b5c4d5SJonathan Cameron .of_match_table = ad7746_of_match,
81140b5c4d5SJonathan Cameron },
8127cf15f42SUwe Kleine-König .probe = ad7746_probe,
81340b5c4d5SJonathan Cameron .id_table = ad7746_id,
81440b5c4d5SJonathan Cameron };
81540b5c4d5SJonathan Cameron module_i2c_driver(ad7746_driver);
81640b5c4d5SJonathan Cameron
81740b5c4d5SJonathan Cameron MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
81840b5c4d5SJonathan Cameron MODULE_DESCRIPTION("Analog Devices AD7746/5/7 capacitive sensor driver");
81940b5c4d5SJonathan Cameron MODULE_LICENSE("GPL v2");
820