xref: /linux/drivers/iio/cdc/ad7746.c (revision 7ec462100ef9142344ddbf86f2c3008b97acddbe)
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