1b581f748SAlexandru Tachici // SPDX-License-Identifier: GPL-2.0
2b581f748SAlexandru Tachici /*
3b581f748SAlexandru Tachici * AD7190 AD7192 AD7193 AD7195 SPI ADC driver
4b581f748SAlexandru Tachici *
5b581f748SAlexandru Tachici * Copyright 2011-2015 Analog Devices Inc.
6b581f748SAlexandru Tachici */
7b581f748SAlexandru Tachici
8b581f748SAlexandru Tachici #include <linux/interrupt.h>
9b581f748SAlexandru Tachici #include <linux/clk.h>
10b581f748SAlexandru Tachici #include <linux/device.h>
11b581f748SAlexandru Tachici #include <linux/kernel.h>
12b581f748SAlexandru Tachici #include <linux/slab.h>
13b581f748SAlexandru Tachici #include <linux/sysfs.h>
14b581f748SAlexandru Tachici #include <linux/spi/spi.h>
15b581f748SAlexandru Tachici #include <linux/regulator/consumer.h>
16b581f748SAlexandru Tachici #include <linux/err.h>
17b581f748SAlexandru Tachici #include <linux/sched.h>
18b581f748SAlexandru Tachici #include <linux/delay.h>
19843b5d16SJonathan Cameron #include <linux/module.h>
20843b5d16SJonathan Cameron #include <linux/mod_devicetable.h>
21843b5d16SJonathan Cameron #include <linux/property.h>
22b581f748SAlexandru Tachici
23b581f748SAlexandru Tachici #include <linux/iio/iio.h>
24b581f748SAlexandru Tachici #include <linux/iio/sysfs.h>
25b581f748SAlexandru Tachici #include <linux/iio/buffer.h>
26b581f748SAlexandru Tachici #include <linux/iio/trigger.h>
27b581f748SAlexandru Tachici #include <linux/iio/trigger_consumer.h>
28b581f748SAlexandru Tachici #include <linux/iio/triggered_buffer.h>
29b581f748SAlexandru Tachici #include <linux/iio/adc/ad_sigma_delta.h>
30b581f748SAlexandru Tachici
31b581f748SAlexandru Tachici /* Registers */
32b581f748SAlexandru Tachici #define AD7192_REG_COMM 0 /* Communications Register (WO, 8-bit) */
33b581f748SAlexandru Tachici #define AD7192_REG_STAT 0 /* Status Register (RO, 8-bit) */
34b581f748SAlexandru Tachici #define AD7192_REG_MODE 1 /* Mode Register (RW, 24-bit */
35b581f748SAlexandru Tachici #define AD7192_REG_CONF 2 /* Configuration Register (RW, 24-bit) */
36b581f748SAlexandru Tachici #define AD7192_REG_DATA 3 /* Data Register (RO, 24/32-bit) */
37b581f748SAlexandru Tachici #define AD7192_REG_ID 4 /* ID Register (RO, 8-bit) */
38b581f748SAlexandru Tachici #define AD7192_REG_GPOCON 5 /* GPOCON Register (RO, 8-bit) */
39b581f748SAlexandru Tachici #define AD7192_REG_OFFSET 6 /* Offset Register (RW, 16-bit */
40b581f748SAlexandru Tachici /* (AD7792)/24-bit (AD7192)) */
41b581f748SAlexandru Tachici #define AD7192_REG_FULLSALE 7 /* Full-Scale Register */
42b581f748SAlexandru Tachici /* (RW, 16-bit (AD7792)/24-bit (AD7192)) */
43b581f748SAlexandru Tachici
44b581f748SAlexandru Tachici /* Communications Register Bit Designations (AD7192_REG_COMM) */
45b581f748SAlexandru Tachici #define AD7192_COMM_WEN BIT(7) /* Write Enable */
46b581f748SAlexandru Tachici #define AD7192_COMM_WRITE 0 /* Write Operation */
47b581f748SAlexandru Tachici #define AD7192_COMM_READ BIT(6) /* Read Operation */
48b581f748SAlexandru Tachici #define AD7192_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */
49b581f748SAlexandru Tachici #define AD7192_COMM_CREAD BIT(2) /* Continuous Read of Data Register */
50b581f748SAlexandru Tachici
51b581f748SAlexandru Tachici /* Status Register Bit Designations (AD7192_REG_STAT) */
52b581f748SAlexandru Tachici #define AD7192_STAT_RDY BIT(7) /* Ready */
53b581f748SAlexandru Tachici #define AD7192_STAT_ERR BIT(6) /* Error (Overrange, Underrange) */
54b581f748SAlexandru Tachici #define AD7192_STAT_NOREF BIT(5) /* Error no external reference */
55b581f748SAlexandru Tachici #define AD7192_STAT_PARITY BIT(4) /* Parity */
56b581f748SAlexandru Tachici #define AD7192_STAT_CH3 BIT(2) /* Channel 3 */
57b581f748SAlexandru Tachici #define AD7192_STAT_CH2 BIT(1) /* Channel 2 */
58b581f748SAlexandru Tachici #define AD7192_STAT_CH1 BIT(0) /* Channel 1 */
59b581f748SAlexandru Tachici
60b581f748SAlexandru Tachici /* Mode Register Bit Designations (AD7192_REG_MODE) */
61b581f748SAlexandru Tachici #define AD7192_MODE_SEL(x) (((x) & 0x7) << 21) /* Operation Mode Select */
62b581f748SAlexandru Tachici #define AD7192_MODE_SEL_MASK (0x7 << 21) /* Operation Mode Select Mask */
6344b0be6eSAlexandru Tachici #define AD7192_MODE_STA(x) (((x) & 0x1) << 20) /* Status Register transmission */
6444b0be6eSAlexandru Tachici #define AD7192_MODE_STA_MASK BIT(20) /* Status Register transmission Mask */
65b581f748SAlexandru Tachici #define AD7192_MODE_CLKSRC(x) (((x) & 0x3) << 18) /* Clock Source Select */
66b581f748SAlexandru Tachici #define AD7192_MODE_SINC3 BIT(15) /* SINC3 Filter Select */
67b581f748SAlexandru Tachici #define AD7192_MODE_ENPAR BIT(13) /* Parity Enable */
68b581f748SAlexandru Tachici #define AD7192_MODE_CLKDIV BIT(12) /* Clock divide by 2 (AD7190/2 only)*/
69b581f748SAlexandru Tachici #define AD7192_MODE_SCYCLE BIT(11) /* Single cycle conversion */
70b581f748SAlexandru Tachici #define AD7192_MODE_REJ60 BIT(10) /* 50/60Hz notch filter */
71b581f748SAlexandru Tachici #define AD7192_MODE_RATE(x) ((x) & 0x3FF) /* Filter Update Rate Select */
72b581f748SAlexandru Tachici
73b581f748SAlexandru Tachici /* Mode Register: AD7192_MODE_SEL options */
74b581f748SAlexandru Tachici #define AD7192_MODE_CONT 0 /* Continuous Conversion Mode */
75b581f748SAlexandru Tachici #define AD7192_MODE_SINGLE 1 /* Single Conversion Mode */
76b581f748SAlexandru Tachici #define AD7192_MODE_IDLE 2 /* Idle Mode */
77b581f748SAlexandru Tachici #define AD7192_MODE_PWRDN 3 /* Power-Down Mode */
78b581f748SAlexandru Tachici #define AD7192_MODE_CAL_INT_ZERO 4 /* Internal Zero-Scale Calibration */
79b581f748SAlexandru Tachici #define AD7192_MODE_CAL_INT_FULL 5 /* Internal Full-Scale Calibration */
80b581f748SAlexandru Tachici #define AD7192_MODE_CAL_SYS_ZERO 6 /* System Zero-Scale Calibration */
81b581f748SAlexandru Tachici #define AD7192_MODE_CAL_SYS_FULL 7 /* System Full-Scale Calibration */
82b581f748SAlexandru Tachici
83b581f748SAlexandru Tachici /* Mode Register: AD7192_MODE_CLKSRC options */
84b581f748SAlexandru Tachici #define AD7192_CLK_EXT_MCLK1_2 0 /* External 4.92 MHz Clock connected*/
85b581f748SAlexandru Tachici /* from MCLK1 to MCLK2 */
86b581f748SAlexandru Tachici #define AD7192_CLK_EXT_MCLK2 1 /* External Clock applied to MCLK2 */
87b581f748SAlexandru Tachici #define AD7192_CLK_INT 2 /* Internal 4.92 MHz Clock not */
88b581f748SAlexandru Tachici /* available at the MCLK2 pin */
89b581f748SAlexandru Tachici #define AD7192_CLK_INT_CO 3 /* Internal 4.92 MHz Clock available*/
90b581f748SAlexandru Tachici /* at the MCLK2 pin */
91b581f748SAlexandru Tachici
92b581f748SAlexandru Tachici /* Configuration Register Bit Designations (AD7192_REG_CONF) */
93b581f748SAlexandru Tachici
94b581f748SAlexandru Tachici #define AD7192_CONF_CHOP BIT(23) /* CHOP enable */
956bc471b6SAlisa Roman #define AD7192_CONF_ACX BIT(22) /* AC excitation enable(AD7195 only) */
96b581f748SAlexandru Tachici #define AD7192_CONF_REFSEL BIT(20) /* REFIN1/REFIN2 Reference Select */
97b581f748SAlexandru Tachici #define AD7192_CONF_CHAN(x) ((x) << 8) /* Channel select */
98b581f748SAlexandru Tachici #define AD7192_CONF_CHAN_MASK (0x7FF << 8) /* Channel select mask */
99b581f748SAlexandru Tachici #define AD7192_CONF_BURN BIT(7) /* Burnout current enable */
100b581f748SAlexandru Tachici #define AD7192_CONF_REFDET BIT(6) /* Reference detect enable */
101b581f748SAlexandru Tachici #define AD7192_CONF_BUF BIT(4) /* Buffered Mode Enable */
102b581f748SAlexandru Tachici #define AD7192_CONF_UNIPOLAR BIT(3) /* Unipolar/Bipolar Enable */
103b581f748SAlexandru Tachici #define AD7192_CONF_GAIN(x) ((x) & 0x7) /* Gain Select */
104b581f748SAlexandru Tachici
105b581f748SAlexandru Tachici #define AD7192_CH_AIN1P_AIN2M BIT(0) /* AIN1(+) - AIN2(-) */
106b581f748SAlexandru Tachici #define AD7192_CH_AIN3P_AIN4M BIT(1) /* AIN3(+) - AIN4(-) */
107b581f748SAlexandru Tachici #define AD7192_CH_TEMP BIT(2) /* Temp Sensor */
108b581f748SAlexandru Tachici #define AD7192_CH_AIN2P_AIN2M BIT(3) /* AIN2(+) - AIN2(-) */
109b581f748SAlexandru Tachici #define AD7192_CH_AIN1 BIT(4) /* AIN1 - AINCOM */
110b581f748SAlexandru Tachici #define AD7192_CH_AIN2 BIT(5) /* AIN2 - AINCOM */
111b581f748SAlexandru Tachici #define AD7192_CH_AIN3 BIT(6) /* AIN3 - AINCOM */
112b581f748SAlexandru Tachici #define AD7192_CH_AIN4 BIT(7) /* AIN4 - AINCOM */
113b581f748SAlexandru Tachici
114b581f748SAlexandru Tachici #define AD7193_CH_AIN1P_AIN2M 0x001 /* AIN1(+) - AIN2(-) */
115b581f748SAlexandru Tachici #define AD7193_CH_AIN3P_AIN4M 0x002 /* AIN3(+) - AIN4(-) */
116b581f748SAlexandru Tachici #define AD7193_CH_AIN5P_AIN6M 0x004 /* AIN5(+) - AIN6(-) */
117b581f748SAlexandru Tachici #define AD7193_CH_AIN7P_AIN8M 0x008 /* AIN7(+) - AIN8(-) */
118b581f748SAlexandru Tachici #define AD7193_CH_TEMP 0x100 /* Temp senseor */
119b581f748SAlexandru Tachici #define AD7193_CH_AIN2P_AIN2M 0x200 /* AIN2(+) - AIN2(-) */
120b581f748SAlexandru Tachici #define AD7193_CH_AIN1 0x401 /* AIN1 - AINCOM */
121b581f748SAlexandru Tachici #define AD7193_CH_AIN2 0x402 /* AIN2 - AINCOM */
122b581f748SAlexandru Tachici #define AD7193_CH_AIN3 0x404 /* AIN3 - AINCOM */
123b581f748SAlexandru Tachici #define AD7193_CH_AIN4 0x408 /* AIN4 - AINCOM */
124b581f748SAlexandru Tachici #define AD7193_CH_AIN5 0x410 /* AIN5 - AINCOM */
125b581f748SAlexandru Tachici #define AD7193_CH_AIN6 0x420 /* AIN6 - AINCOM */
126b581f748SAlexandru Tachici #define AD7193_CH_AIN7 0x440 /* AIN7 - AINCOM */
127b581f748SAlexandru Tachici #define AD7193_CH_AIN8 0x480 /* AIN7 - AINCOM */
128b581f748SAlexandru Tachici #define AD7193_CH_AINCOM 0x600 /* AINCOM - AINCOM */
129b581f748SAlexandru Tachici
130b581f748SAlexandru Tachici /* ID Register Bit Designations (AD7192_REG_ID) */
1318f2273b1SAlexandru Ardelean #define CHIPID_AD7190 0x4
1328f2273b1SAlexandru Ardelean #define CHIPID_AD7192 0x0
1338f2273b1SAlexandru Ardelean #define CHIPID_AD7193 0x2
1348f2273b1SAlexandru Ardelean #define CHIPID_AD7195 0x6
135b581f748SAlexandru Tachici #define AD7192_ID_MASK 0x0F
136b581f748SAlexandru Tachici
137b581f748SAlexandru Tachici /* GPOCON Register Bit Designations (AD7192_REG_GPOCON) */
138b581f748SAlexandru Tachici #define AD7192_GPOCON_BPDSW BIT(6) /* Bridge power-down switch enable */
139b581f748SAlexandru Tachici #define AD7192_GPOCON_GP32EN BIT(5) /* Digital Output P3 and P2 enable */
140b581f748SAlexandru Tachici #define AD7192_GPOCON_GP10EN BIT(4) /* Digital Output P1 and P0 enable */
141b581f748SAlexandru Tachici #define AD7192_GPOCON_P3DAT BIT(3) /* P3 state */
142b581f748SAlexandru Tachici #define AD7192_GPOCON_P2DAT BIT(2) /* P2 state */
143b581f748SAlexandru Tachici #define AD7192_GPOCON_P1DAT BIT(1) /* P1 state */
144b581f748SAlexandru Tachici #define AD7192_GPOCON_P0DAT BIT(0) /* P0 state */
145b581f748SAlexandru Tachici
146b581f748SAlexandru Tachici #define AD7192_EXT_FREQ_MHZ_MIN 2457600
147b581f748SAlexandru Tachici #define AD7192_EXT_FREQ_MHZ_MAX 5120000
148b581f748SAlexandru Tachici #define AD7192_INT_FREQ_MHZ 4915200
149b581f748SAlexandru Tachici
150b581f748SAlexandru Tachici #define AD7192_NO_SYNC_FILTER 1
151b581f748SAlexandru Tachici #define AD7192_SYNC3_FILTER 3
152b581f748SAlexandru Tachici #define AD7192_SYNC4_FILTER 4
153b581f748SAlexandru Tachici
154b581f748SAlexandru Tachici /* NOTE:
155b581f748SAlexandru Tachici * The AD7190/2/5 features a dual use data out ready DOUT/RDY output.
156b581f748SAlexandru Tachici * In order to avoid contentions on the SPI bus, it's therefore necessary
157b581f748SAlexandru Tachici * to use spi bus locking.
158b581f748SAlexandru Tachici *
159b581f748SAlexandru Tachici * The DOUT/RDY output must also be wired to an interrupt capable GPIO.
160b581f748SAlexandru Tachici */
161b581f748SAlexandru Tachici
162b581f748SAlexandru Tachici enum {
163b581f748SAlexandru Tachici AD7192_SYSCALIB_ZERO_SCALE,
164b581f748SAlexandru Tachici AD7192_SYSCALIB_FULL_SCALE,
165b581f748SAlexandru Tachici };
166b581f748SAlexandru Tachici
1678f2273b1SAlexandru Ardelean enum {
1688f2273b1SAlexandru Ardelean ID_AD7190,
1698f2273b1SAlexandru Ardelean ID_AD7192,
1708f2273b1SAlexandru Ardelean ID_AD7193,
1718f2273b1SAlexandru Ardelean ID_AD7195,
1728f2273b1SAlexandru Ardelean };
1738f2273b1SAlexandru Ardelean
1748f2273b1SAlexandru Ardelean struct ad7192_chip_info {
1758f2273b1SAlexandru Ardelean unsigned int chip_id;
1768f2273b1SAlexandru Ardelean const char *name;
1778f2273b1SAlexandru Ardelean };
1788f2273b1SAlexandru Ardelean
179b581f748SAlexandru Tachici struct ad7192_state {
1808f2273b1SAlexandru Ardelean const struct ad7192_chip_info *chip_info;
181b581f748SAlexandru Tachici struct regulator *avdd;
1827e7dcab6SAlisa-Dariana Roman struct regulator *vref;
183b581f748SAlexandru Tachici struct clk *mclk;
184b581f748SAlexandru Tachici u16 int_vref_mv;
185b581f748SAlexandru Tachici u32 fclk;
186b581f748SAlexandru Tachici u32 f_order;
187b581f748SAlexandru Tachici u32 mode;
188b581f748SAlexandru Tachici u32 conf;
189b581f748SAlexandru Tachici u32 scale_avail[8][2];
190b581f748SAlexandru Tachici u8 gpocon;
191b581f748SAlexandru Tachici u8 clock_sel;
192b581f748SAlexandru Tachici struct mutex lock; /* protect sensor state */
193b581f748SAlexandru Tachici u8 syscalib_mode[8];
194b581f748SAlexandru Tachici
195b581f748SAlexandru Tachici struct ad_sigma_delta sd;
196b581f748SAlexandru Tachici };
197b581f748SAlexandru Tachici
198b581f748SAlexandru Tachici static const char * const ad7192_syscalib_modes[] = {
199b581f748SAlexandru Tachici [AD7192_SYSCALIB_ZERO_SCALE] = "zero_scale",
200b581f748SAlexandru Tachici [AD7192_SYSCALIB_FULL_SCALE] = "full_scale",
201b581f748SAlexandru Tachici };
202b581f748SAlexandru Tachici
ad7192_set_syscalib_mode(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,unsigned int mode)203b581f748SAlexandru Tachici static int ad7192_set_syscalib_mode(struct iio_dev *indio_dev,
204b581f748SAlexandru Tachici const struct iio_chan_spec *chan,
205b581f748SAlexandru Tachici unsigned int mode)
206b581f748SAlexandru Tachici {
207b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
208b581f748SAlexandru Tachici
209b581f748SAlexandru Tachici st->syscalib_mode[chan->channel] = mode;
210b581f748SAlexandru Tachici
211b581f748SAlexandru Tachici return 0;
212b581f748SAlexandru Tachici }
213b581f748SAlexandru Tachici
ad7192_get_syscalib_mode(struct iio_dev * indio_dev,const struct iio_chan_spec * chan)214b581f748SAlexandru Tachici static int ad7192_get_syscalib_mode(struct iio_dev *indio_dev,
215b581f748SAlexandru Tachici const struct iio_chan_spec *chan)
216b581f748SAlexandru Tachici {
217b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
218b581f748SAlexandru Tachici
219b581f748SAlexandru Tachici return st->syscalib_mode[chan->channel];
220b581f748SAlexandru Tachici }
221b581f748SAlexandru Tachici
ad7192_write_syscalib(struct iio_dev * indio_dev,uintptr_t private,const struct iio_chan_spec * chan,const char * buf,size_t len)222b581f748SAlexandru Tachici static ssize_t ad7192_write_syscalib(struct iio_dev *indio_dev,
223b581f748SAlexandru Tachici uintptr_t private,
224b581f748SAlexandru Tachici const struct iio_chan_spec *chan,
225b581f748SAlexandru Tachici const char *buf, size_t len)
226b581f748SAlexandru Tachici {
227b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
228b581f748SAlexandru Tachici bool sys_calib;
229b581f748SAlexandru Tachici int ret, temp;
230b581f748SAlexandru Tachici
23174f582ecSLars-Peter Clausen ret = kstrtobool(buf, &sys_calib);
232b581f748SAlexandru Tachici if (ret)
233b581f748SAlexandru Tachici return ret;
234b581f748SAlexandru Tachici
235b581f748SAlexandru Tachici temp = st->syscalib_mode[chan->channel];
236b581f748SAlexandru Tachici if (sys_calib) {
237b581f748SAlexandru Tachici if (temp == AD7192_SYSCALIB_ZERO_SCALE)
238b581f748SAlexandru Tachici ret = ad_sd_calibrate(&st->sd, AD7192_MODE_CAL_SYS_ZERO,
239b581f748SAlexandru Tachici chan->address);
240b581f748SAlexandru Tachici else
241b581f748SAlexandru Tachici ret = ad_sd_calibrate(&st->sd, AD7192_MODE_CAL_SYS_FULL,
242b581f748SAlexandru Tachici chan->address);
243b581f748SAlexandru Tachici }
244b581f748SAlexandru Tachici
245b581f748SAlexandru Tachici return ret ? ret : len;
246b581f748SAlexandru Tachici }
247b581f748SAlexandru Tachici
248b581f748SAlexandru Tachici static const struct iio_enum ad7192_syscalib_mode_enum = {
249b581f748SAlexandru Tachici .items = ad7192_syscalib_modes,
250b581f748SAlexandru Tachici .num_items = ARRAY_SIZE(ad7192_syscalib_modes),
251b581f748SAlexandru Tachici .set = ad7192_set_syscalib_mode,
252b581f748SAlexandru Tachici .get = ad7192_get_syscalib_mode
253b581f748SAlexandru Tachici };
254b581f748SAlexandru Tachici
255b581f748SAlexandru Tachici static const struct iio_chan_spec_ext_info ad7192_calibsys_ext_info[] = {
256b581f748SAlexandru Tachici {
257b581f748SAlexandru Tachici .name = "sys_calibration",
258b581f748SAlexandru Tachici .write = ad7192_write_syscalib,
259b581f748SAlexandru Tachici .shared = IIO_SEPARATE,
260b581f748SAlexandru Tachici },
261b581f748SAlexandru Tachici IIO_ENUM("sys_calibration_mode", IIO_SEPARATE,
262b581f748SAlexandru Tachici &ad7192_syscalib_mode_enum),
263ffc7c517SAntoniu Miclaus IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE,
264ffc7c517SAntoniu Miclaus &ad7192_syscalib_mode_enum),
265b581f748SAlexandru Tachici {}
266b581f748SAlexandru Tachici };
267b581f748SAlexandru Tachici
ad_sigma_delta_to_ad7192(struct ad_sigma_delta * sd)268b581f748SAlexandru Tachici static struct ad7192_state *ad_sigma_delta_to_ad7192(struct ad_sigma_delta *sd)
269b581f748SAlexandru Tachici {
270b581f748SAlexandru Tachici return container_of(sd, struct ad7192_state, sd);
271b581f748SAlexandru Tachici }
272b581f748SAlexandru Tachici
ad7192_set_channel(struct ad_sigma_delta * sd,unsigned int channel)273b581f748SAlexandru Tachici static int ad7192_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
274b581f748SAlexandru Tachici {
275b581f748SAlexandru Tachici struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
276b581f748SAlexandru Tachici
277b581f748SAlexandru Tachici st->conf &= ~AD7192_CONF_CHAN_MASK;
278b581f748SAlexandru Tachici st->conf |= AD7192_CONF_CHAN(channel);
279b581f748SAlexandru Tachici
280b581f748SAlexandru Tachici return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
281b581f748SAlexandru Tachici }
282b581f748SAlexandru Tachici
ad7192_set_mode(struct ad_sigma_delta * sd,enum ad_sigma_delta_mode mode)283b581f748SAlexandru Tachici static int ad7192_set_mode(struct ad_sigma_delta *sd,
284b581f748SAlexandru Tachici enum ad_sigma_delta_mode mode)
285b581f748SAlexandru Tachici {
286b581f748SAlexandru Tachici struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
287b581f748SAlexandru Tachici
288b581f748SAlexandru Tachici st->mode &= ~AD7192_MODE_SEL_MASK;
289b581f748SAlexandru Tachici st->mode |= AD7192_MODE_SEL(mode);
290b581f748SAlexandru Tachici
291b581f748SAlexandru Tachici return ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
292b581f748SAlexandru Tachici }
293b581f748SAlexandru Tachici
ad7192_append_status(struct ad_sigma_delta * sd,bool append)29444b0be6eSAlexandru Tachici static int ad7192_append_status(struct ad_sigma_delta *sd, bool append)
29544b0be6eSAlexandru Tachici {
29644b0be6eSAlexandru Tachici struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
29744b0be6eSAlexandru Tachici unsigned int mode = st->mode;
29844b0be6eSAlexandru Tachici int ret;
29944b0be6eSAlexandru Tachici
30044b0be6eSAlexandru Tachici mode &= ~AD7192_MODE_STA_MASK;
30144b0be6eSAlexandru Tachici mode |= AD7192_MODE_STA(append);
30244b0be6eSAlexandru Tachici
30344b0be6eSAlexandru Tachici ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, mode);
30444b0be6eSAlexandru Tachici if (ret < 0)
30544b0be6eSAlexandru Tachici return ret;
30644b0be6eSAlexandru Tachici
30744b0be6eSAlexandru Tachici st->mode = mode;
30844b0be6eSAlexandru Tachici
30944b0be6eSAlexandru Tachici return 0;
31044b0be6eSAlexandru Tachici }
31144b0be6eSAlexandru Tachici
ad7192_disable_all(struct ad_sigma_delta * sd)31244b0be6eSAlexandru Tachici static int ad7192_disable_all(struct ad_sigma_delta *sd)
31344b0be6eSAlexandru Tachici {
31444b0be6eSAlexandru Tachici struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
31544b0be6eSAlexandru Tachici u32 conf = st->conf;
31644b0be6eSAlexandru Tachici int ret;
31744b0be6eSAlexandru Tachici
31844b0be6eSAlexandru Tachici conf &= ~AD7192_CONF_CHAN_MASK;
31944b0be6eSAlexandru Tachici
32044b0be6eSAlexandru Tachici ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, conf);
32144b0be6eSAlexandru Tachici if (ret < 0)
32244b0be6eSAlexandru Tachici return ret;
32344b0be6eSAlexandru Tachici
32444b0be6eSAlexandru Tachici st->conf = conf;
32544b0be6eSAlexandru Tachici
32644b0be6eSAlexandru Tachici return 0;
32744b0be6eSAlexandru Tachici }
32844b0be6eSAlexandru Tachici
329b581f748SAlexandru Tachici static const struct ad_sigma_delta_info ad7192_sigma_delta_info = {
330b581f748SAlexandru Tachici .set_channel = ad7192_set_channel,
33144b0be6eSAlexandru Tachici .append_status = ad7192_append_status,
33244b0be6eSAlexandru Tachici .disable_all = ad7192_disable_all,
333b581f748SAlexandru Tachici .set_mode = ad7192_set_mode,
334b581f748SAlexandru Tachici .has_registers = true,
335b581f748SAlexandru Tachici .addr_shift = 3,
336b581f748SAlexandru Tachici .read_mask = BIT(6),
33744b0be6eSAlexandru Tachici .status_ch_mask = GENMASK(3, 0),
33844b0be6eSAlexandru Tachici .num_slots = 4,
33989a86da5SAlexandru Tachici .irq_flags = IRQF_TRIGGER_FALLING,
340b581f748SAlexandru Tachici };
341b581f748SAlexandru Tachici
342b581f748SAlexandru Tachici static const struct ad_sd_calib_data ad7192_calib_arr[8] = {
343b581f748SAlexandru Tachici {AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN1},
344b581f748SAlexandru Tachici {AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN1},
345b581f748SAlexandru Tachici {AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN2},
346b581f748SAlexandru Tachici {AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN2},
347b581f748SAlexandru Tachici {AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN3},
348b581f748SAlexandru Tachici {AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN3},
349b581f748SAlexandru Tachici {AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN4},
350b581f748SAlexandru Tachici {AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN4}
351b581f748SAlexandru Tachici };
352b581f748SAlexandru Tachici
ad7192_calibrate_all(struct ad7192_state * st)353b581f748SAlexandru Tachici static int ad7192_calibrate_all(struct ad7192_state *st)
354b581f748SAlexandru Tachici {
355b581f748SAlexandru Tachici return ad_sd_calibrate_all(&st->sd, ad7192_calib_arr,
356b581f748SAlexandru Tachici ARRAY_SIZE(ad7192_calib_arr));
357b581f748SAlexandru Tachici }
358b581f748SAlexandru Tachici
ad7192_valid_external_frequency(u32 freq)359b581f748SAlexandru Tachici static inline bool ad7192_valid_external_frequency(u32 freq)
360b581f748SAlexandru Tachici {
361b581f748SAlexandru Tachici return (freq >= AD7192_EXT_FREQ_MHZ_MIN &&
362b581f748SAlexandru Tachici freq <= AD7192_EXT_FREQ_MHZ_MAX);
363b581f748SAlexandru Tachici }
364b581f748SAlexandru Tachici
ad7192_clock_select(struct ad7192_state * st)365843b5d16SJonathan Cameron static int ad7192_clock_select(struct ad7192_state *st)
366b581f748SAlexandru Tachici {
367843b5d16SJonathan Cameron struct device *dev = &st->sd.spi->dev;
368b581f748SAlexandru Tachici unsigned int clock_sel;
369b581f748SAlexandru Tachici
370b581f748SAlexandru Tachici clock_sel = AD7192_CLK_INT;
371b581f748SAlexandru Tachici
372b581f748SAlexandru Tachici /* use internal clock */
373f7d9e21dSFabrizio Lamarque if (!st->mclk) {
374843b5d16SJonathan Cameron if (device_property_read_bool(dev, "adi,int-clock-output-enable"))
375b581f748SAlexandru Tachici clock_sel = AD7192_CLK_INT_CO;
376b581f748SAlexandru Tachici } else {
377843b5d16SJonathan Cameron if (device_property_read_bool(dev, "adi,clock-xtal"))
378b581f748SAlexandru Tachici clock_sel = AD7192_CLK_EXT_MCLK1_2;
379b581f748SAlexandru Tachici else
380b581f748SAlexandru Tachici clock_sel = AD7192_CLK_EXT_MCLK2;
381b581f748SAlexandru Tachici }
382b581f748SAlexandru Tachici
383b581f748SAlexandru Tachici return clock_sel;
384b581f748SAlexandru Tachici }
385b581f748SAlexandru Tachici
ad7192_setup(struct iio_dev * indio_dev,struct device * dev)386843b5d16SJonathan Cameron static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev)
387b581f748SAlexandru Tachici {
3889e58e3a6SFabrizio Lamarque struct ad7192_state *st = iio_priv(indio_dev);
389b581f748SAlexandru Tachici bool rej60_en, refin2_en;
390b581f748SAlexandru Tachici bool buf_en, bipolar, burnout_curr_en;
391b581f748SAlexandru Tachici unsigned long long scale_uv;
392b581f748SAlexandru Tachici int i, ret, id;
393b581f748SAlexandru Tachici
394b581f748SAlexandru Tachici /* reset the serial interface */
395b581f748SAlexandru Tachici ret = ad_sd_reset(&st->sd, 48);
396b581f748SAlexandru Tachici if (ret < 0)
397b581f748SAlexandru Tachici return ret;
398b581f748SAlexandru Tachici usleep_range(500, 1000); /* Wait for at least 500us */
399b581f748SAlexandru Tachici
400b581f748SAlexandru Tachici /* write/read test for device presence */
401b581f748SAlexandru Tachici ret = ad_sd_read_reg(&st->sd, AD7192_REG_ID, 1, &id);
402b581f748SAlexandru Tachici if (ret)
403b581f748SAlexandru Tachici return ret;
404b581f748SAlexandru Tachici
405b581f748SAlexandru Tachici id &= AD7192_ID_MASK;
406b581f748SAlexandru Tachici
4078f2273b1SAlexandru Ardelean if (id != st->chip_info->chip_id)
408843b5d16SJonathan Cameron dev_warn(dev, "device ID query failed (0x%X != 0x%X)\n",
409f41f4443SMarkus Burri id, st->chip_info->chip_id);
410b581f748SAlexandru Tachici
411b581f748SAlexandru Tachici st->mode = AD7192_MODE_SEL(AD7192_MODE_IDLE) |
412b581f748SAlexandru Tachici AD7192_MODE_CLKSRC(st->clock_sel) |
413b581f748SAlexandru Tachici AD7192_MODE_RATE(480);
414b581f748SAlexandru Tachici
415b581f748SAlexandru Tachici st->conf = AD7192_CONF_GAIN(0);
416b581f748SAlexandru Tachici
417843b5d16SJonathan Cameron rej60_en = device_property_read_bool(dev, "adi,rejection-60-Hz-enable");
418b581f748SAlexandru Tachici if (rej60_en)
419b581f748SAlexandru Tachici st->mode |= AD7192_MODE_REJ60;
420b581f748SAlexandru Tachici
421843b5d16SJonathan Cameron refin2_en = device_property_read_bool(dev, "adi,refin2-pins-enable");
4228f2273b1SAlexandru Ardelean if (refin2_en && st->chip_info->chip_id != CHIPID_AD7195)
423b581f748SAlexandru Tachici st->conf |= AD7192_CONF_REFSEL;
424b581f748SAlexandru Tachici
425b581f748SAlexandru Tachici st->conf &= ~AD7192_CONF_CHOP;
426b581f748SAlexandru Tachici st->f_order = AD7192_NO_SYNC_FILTER;
427b581f748SAlexandru Tachici
428843b5d16SJonathan Cameron buf_en = device_property_read_bool(dev, "adi,buffer-enable");
429b581f748SAlexandru Tachici if (buf_en)
430b581f748SAlexandru Tachici st->conf |= AD7192_CONF_BUF;
431b581f748SAlexandru Tachici
432843b5d16SJonathan Cameron bipolar = device_property_read_bool(dev, "bipolar");
433b581f748SAlexandru Tachici if (!bipolar)
434b581f748SAlexandru Tachici st->conf |= AD7192_CONF_UNIPOLAR;
435b581f748SAlexandru Tachici
436843b5d16SJonathan Cameron burnout_curr_en = device_property_read_bool(dev,
437b581f748SAlexandru Tachici "adi,burnout-currents-enable");
438b581f748SAlexandru Tachici if (burnout_curr_en && buf_en) {
439b581f748SAlexandru Tachici st->conf |= AD7192_CONF_BURN;
440b581f748SAlexandru Tachici } else if (burnout_curr_en) {
441843b5d16SJonathan Cameron dev_warn(dev,
442b581f748SAlexandru Tachici "Can't enable burnout currents: see CHOP or buffer\n");
443b581f748SAlexandru Tachici }
444b581f748SAlexandru Tachici
445b581f748SAlexandru Tachici ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
446b581f748SAlexandru Tachici if (ret)
447b581f748SAlexandru Tachici return ret;
448b581f748SAlexandru Tachici
449b581f748SAlexandru Tachici ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
450b581f748SAlexandru Tachici if (ret)
451b581f748SAlexandru Tachici return ret;
452b581f748SAlexandru Tachici
453b581f748SAlexandru Tachici ret = ad7192_calibrate_all(st);
454b581f748SAlexandru Tachici if (ret)
455b581f748SAlexandru Tachici return ret;
456b581f748SAlexandru Tachici
457b581f748SAlexandru Tachici /* Populate available ADC input ranges */
458b581f748SAlexandru Tachici for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) {
459b581f748SAlexandru Tachici scale_uv = ((u64)st->int_vref_mv * 100000000)
460b581f748SAlexandru Tachici >> (indio_dev->channels[0].scan_type.realbits -
461b581f748SAlexandru Tachici ((st->conf & AD7192_CONF_UNIPOLAR) ? 0 : 1));
462b581f748SAlexandru Tachici scale_uv >>= i;
463b581f748SAlexandru Tachici
464b581f748SAlexandru Tachici st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10;
465b581f748SAlexandru Tachici st->scale_avail[i][0] = scale_uv;
466b581f748SAlexandru Tachici }
467b581f748SAlexandru Tachici
468b581f748SAlexandru Tachici return 0;
469b581f748SAlexandru Tachici }
470b581f748SAlexandru Tachici
ad7192_show_ac_excitation(struct device * dev,struct device_attribute * attr,char * buf)471b581f748SAlexandru Tachici static ssize_t ad7192_show_ac_excitation(struct device *dev,
472b581f748SAlexandru Tachici struct device_attribute *attr,
473b581f748SAlexandru Tachici char *buf)
474b581f748SAlexandru Tachici {
475b581f748SAlexandru Tachici struct iio_dev *indio_dev = dev_to_iio_dev(dev);
476b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
477b581f748SAlexandru Tachici
4786bc471b6SAlisa Roman return sysfs_emit(buf, "%d\n", !!(st->conf & AD7192_CONF_ACX));
479b581f748SAlexandru Tachici }
480b581f748SAlexandru Tachici
ad7192_show_bridge_switch(struct device * dev,struct device_attribute * attr,char * buf)481b581f748SAlexandru Tachici static ssize_t ad7192_show_bridge_switch(struct device *dev,
482b581f748SAlexandru Tachici struct device_attribute *attr,
483b581f748SAlexandru Tachici char *buf)
484b581f748SAlexandru Tachici {
485b581f748SAlexandru Tachici struct iio_dev *indio_dev = dev_to_iio_dev(dev);
486b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
487b581f748SAlexandru Tachici
4889d5fcb8fSLars-Peter Clausen return sysfs_emit(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW));
489b581f748SAlexandru Tachici }
490b581f748SAlexandru Tachici
ad7192_set(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)491b581f748SAlexandru Tachici static ssize_t ad7192_set(struct device *dev,
492b581f748SAlexandru Tachici struct device_attribute *attr,
493b581f748SAlexandru Tachici const char *buf,
494b581f748SAlexandru Tachici size_t len)
495b581f748SAlexandru Tachici {
496b581f748SAlexandru Tachici struct iio_dev *indio_dev = dev_to_iio_dev(dev);
497b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
498b581f748SAlexandru Tachici struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
499b581f748SAlexandru Tachici int ret;
500b581f748SAlexandru Tachici bool val;
501b581f748SAlexandru Tachici
50274f582ecSLars-Peter Clausen ret = kstrtobool(buf, &val);
503b581f748SAlexandru Tachici if (ret < 0)
504b581f748SAlexandru Tachici return ret;
505b581f748SAlexandru Tachici
506b581f748SAlexandru Tachici ret = iio_device_claim_direct_mode(indio_dev);
507b581f748SAlexandru Tachici if (ret)
508b581f748SAlexandru Tachici return ret;
509b581f748SAlexandru Tachici
510b581f748SAlexandru Tachici switch ((u32)this_attr->address) {
511b581f748SAlexandru Tachici case AD7192_REG_GPOCON:
512b581f748SAlexandru Tachici if (val)
513b581f748SAlexandru Tachici st->gpocon |= AD7192_GPOCON_BPDSW;
514b581f748SAlexandru Tachici else
515b581f748SAlexandru Tachici st->gpocon &= ~AD7192_GPOCON_BPDSW;
516b581f748SAlexandru Tachici
517b581f748SAlexandru Tachici ad_sd_write_reg(&st->sd, AD7192_REG_GPOCON, 1, st->gpocon);
518b581f748SAlexandru Tachici break;
5196bc471b6SAlisa Roman case AD7192_REG_CONF:
520b581f748SAlexandru Tachici if (val)
5216bc471b6SAlisa Roman st->conf |= AD7192_CONF_ACX;
522b581f748SAlexandru Tachici else
5236bc471b6SAlisa Roman st->conf &= ~AD7192_CONF_ACX;
524b581f748SAlexandru Tachici
5256bc471b6SAlisa Roman ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
526b581f748SAlexandru Tachici break;
527b581f748SAlexandru Tachici default:
528b581f748SAlexandru Tachici ret = -EINVAL;
529b581f748SAlexandru Tachici }
530b581f748SAlexandru Tachici
531b581f748SAlexandru Tachici iio_device_release_direct_mode(indio_dev);
532b581f748SAlexandru Tachici
533b581f748SAlexandru Tachici return ret ? ret : len;
534b581f748SAlexandru Tachici }
535b581f748SAlexandru Tachici
ad7192_get_available_filter_freq(struct ad7192_state * st,int * freq)536b581f748SAlexandru Tachici static void ad7192_get_available_filter_freq(struct ad7192_state *st,
537b581f748SAlexandru Tachici int *freq)
538b581f748SAlexandru Tachici {
539b581f748SAlexandru Tachici unsigned int fadc;
540b581f748SAlexandru Tachici
541b581f748SAlexandru Tachici /* Formulas for filter at page 25 of the datasheet */
542b581f748SAlexandru Tachici fadc = DIV_ROUND_CLOSEST(st->fclk,
543b581f748SAlexandru Tachici AD7192_SYNC4_FILTER * AD7192_MODE_RATE(st->mode));
544b581f748SAlexandru Tachici freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
545b581f748SAlexandru Tachici
546b581f748SAlexandru Tachici fadc = DIV_ROUND_CLOSEST(st->fclk,
547b581f748SAlexandru Tachici AD7192_SYNC3_FILTER * AD7192_MODE_RATE(st->mode));
548b581f748SAlexandru Tachici freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
549b581f748SAlexandru Tachici
550b581f748SAlexandru Tachici fadc = DIV_ROUND_CLOSEST(st->fclk, AD7192_MODE_RATE(st->mode));
551b581f748SAlexandru Tachici freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
552b581f748SAlexandru Tachici freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
553b581f748SAlexandru Tachici }
554b581f748SAlexandru Tachici
ad7192_show_filter_avail(struct device * dev,struct device_attribute * attr,char * buf)555b581f748SAlexandru Tachici static ssize_t ad7192_show_filter_avail(struct device *dev,
556b581f748SAlexandru Tachici struct device_attribute *attr,
557b581f748SAlexandru Tachici char *buf)
558b581f748SAlexandru Tachici {
559b581f748SAlexandru Tachici struct iio_dev *indio_dev = dev_to_iio_dev(dev);
560b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
561b581f748SAlexandru Tachici unsigned int freq_avail[4], i;
562b581f748SAlexandru Tachici size_t len = 0;
563b581f748SAlexandru Tachici
564b581f748SAlexandru Tachici ad7192_get_available_filter_freq(st, freq_avail);
565b581f748SAlexandru Tachici
566b581f748SAlexandru Tachici for (i = 0; i < ARRAY_SIZE(freq_avail); i++)
5671cbf2c4bSAlisa Roman len += sysfs_emit_at(buf, len, "%d.%03d ", freq_avail[i] / 1000,
568b581f748SAlexandru Tachici freq_avail[i] % 1000);
569b581f748SAlexandru Tachici
570b581f748SAlexandru Tachici buf[len - 1] = '\n';
571b581f748SAlexandru Tachici
572b581f748SAlexandru Tachici return len;
573b581f748SAlexandru Tachici }
574b581f748SAlexandru Tachici
575b581f748SAlexandru Tachici static IIO_DEVICE_ATTR(filter_low_pass_3db_frequency_available,
576b581f748SAlexandru Tachici 0444, ad7192_show_filter_avail, NULL, 0);
577b581f748SAlexandru Tachici
578b581f748SAlexandru Tachici static IIO_DEVICE_ATTR(bridge_switch_en, 0644,
579b581f748SAlexandru Tachici ad7192_show_bridge_switch, ad7192_set,
580b581f748SAlexandru Tachici AD7192_REG_GPOCON);
581b581f748SAlexandru Tachici
582b581f748SAlexandru Tachici static IIO_DEVICE_ATTR(ac_excitation_en, 0644,
583b581f748SAlexandru Tachici ad7192_show_ac_excitation, ad7192_set,
5846bc471b6SAlisa Roman AD7192_REG_CONF);
585b581f748SAlexandru Tachici
586b581f748SAlexandru Tachici static struct attribute *ad7192_attributes[] = {
587b581f748SAlexandru Tachici &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
588b581f748SAlexandru Tachici &iio_dev_attr_bridge_switch_en.dev_attr.attr,
589b581f748SAlexandru Tachici NULL
590b581f748SAlexandru Tachici };
591b581f748SAlexandru Tachici
592b581f748SAlexandru Tachici static const struct attribute_group ad7192_attribute_group = {
593b581f748SAlexandru Tachici .attrs = ad7192_attributes,
594b581f748SAlexandru Tachici };
595b581f748SAlexandru Tachici
596b581f748SAlexandru Tachici static struct attribute *ad7195_attributes[] = {
597b581f748SAlexandru Tachici &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
598b581f748SAlexandru Tachici &iio_dev_attr_bridge_switch_en.dev_attr.attr,
5996bc471b6SAlisa Roman &iio_dev_attr_ac_excitation_en.dev_attr.attr,
600b581f748SAlexandru Tachici NULL
601b581f748SAlexandru Tachici };
602b581f748SAlexandru Tachici
603b581f748SAlexandru Tachici static const struct attribute_group ad7195_attribute_group = {
604b581f748SAlexandru Tachici .attrs = ad7195_attributes,
605b581f748SAlexandru Tachici };
606b581f748SAlexandru Tachici
ad7192_get_temp_scale(bool unipolar)607b581f748SAlexandru Tachici static unsigned int ad7192_get_temp_scale(bool unipolar)
608b581f748SAlexandru Tachici {
609b581f748SAlexandru Tachici return unipolar ? 2815 * 2 : 2815;
610b581f748SAlexandru Tachici }
611b581f748SAlexandru Tachici
ad7192_set_3db_filter_freq(struct ad7192_state * st,int val,int val2)612b581f748SAlexandru Tachici static int ad7192_set_3db_filter_freq(struct ad7192_state *st,
613b581f748SAlexandru Tachici int val, int val2)
614b581f748SAlexandru Tachici {
615b581f748SAlexandru Tachici int freq_avail[4], i, ret, freq;
616b581f748SAlexandru Tachici unsigned int diff_new, diff_old;
617b581f748SAlexandru Tachici int idx = 0;
618b581f748SAlexandru Tachici
619b581f748SAlexandru Tachici diff_old = U32_MAX;
620b581f748SAlexandru Tachici freq = val * 1000 + val2;
621b581f748SAlexandru Tachici
622b581f748SAlexandru Tachici ad7192_get_available_filter_freq(st, freq_avail);
623b581f748SAlexandru Tachici
624b581f748SAlexandru Tachici for (i = 0; i < ARRAY_SIZE(freq_avail); i++) {
625b581f748SAlexandru Tachici diff_new = abs(freq - freq_avail[i]);
626b581f748SAlexandru Tachici if (diff_new < diff_old) {
627b581f748SAlexandru Tachici diff_old = diff_new;
628b581f748SAlexandru Tachici idx = i;
629b581f748SAlexandru Tachici }
630b581f748SAlexandru Tachici }
631b581f748SAlexandru Tachici
632b581f748SAlexandru Tachici switch (idx) {
633b581f748SAlexandru Tachici case 0:
634b581f748SAlexandru Tachici st->f_order = AD7192_SYNC4_FILTER;
635b581f748SAlexandru Tachici st->mode &= ~AD7192_MODE_SINC3;
636b581f748SAlexandru Tachici
637b581f748SAlexandru Tachici st->conf |= AD7192_CONF_CHOP;
638b581f748SAlexandru Tachici break;
639b581f748SAlexandru Tachici case 1:
640b581f748SAlexandru Tachici st->f_order = AD7192_SYNC3_FILTER;
641b581f748SAlexandru Tachici st->mode |= AD7192_MODE_SINC3;
642b581f748SAlexandru Tachici
643b581f748SAlexandru Tachici st->conf |= AD7192_CONF_CHOP;
644b581f748SAlexandru Tachici break;
645b581f748SAlexandru Tachici case 2:
646b581f748SAlexandru Tachici st->f_order = AD7192_NO_SYNC_FILTER;
647b581f748SAlexandru Tachici st->mode &= ~AD7192_MODE_SINC3;
648b581f748SAlexandru Tachici
649b581f748SAlexandru Tachici st->conf &= ~AD7192_CONF_CHOP;
650b581f748SAlexandru Tachici break;
651b581f748SAlexandru Tachici case 3:
652b581f748SAlexandru Tachici st->f_order = AD7192_NO_SYNC_FILTER;
653b581f748SAlexandru Tachici st->mode |= AD7192_MODE_SINC3;
654b581f748SAlexandru Tachici
655b581f748SAlexandru Tachici st->conf &= ~AD7192_CONF_CHOP;
656b581f748SAlexandru Tachici break;
657b581f748SAlexandru Tachici }
658b581f748SAlexandru Tachici
659b581f748SAlexandru Tachici ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
660b581f748SAlexandru Tachici if (ret < 0)
661b581f748SAlexandru Tachici return ret;
662b581f748SAlexandru Tachici
663b581f748SAlexandru Tachici return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
664b581f748SAlexandru Tachici }
665b581f748SAlexandru Tachici
ad7192_get_3db_filter_freq(struct ad7192_state * st)666b581f748SAlexandru Tachici static int ad7192_get_3db_filter_freq(struct ad7192_state *st)
667b581f748SAlexandru Tachici {
668b581f748SAlexandru Tachici unsigned int fadc;
669b581f748SAlexandru Tachici
670b581f748SAlexandru Tachici fadc = DIV_ROUND_CLOSEST(st->fclk,
671b581f748SAlexandru Tachici st->f_order * AD7192_MODE_RATE(st->mode));
672b581f748SAlexandru Tachici
673b581f748SAlexandru Tachici if (st->conf & AD7192_CONF_CHOP)
674b581f748SAlexandru Tachici return DIV_ROUND_CLOSEST(fadc * 240, 1024);
675b581f748SAlexandru Tachici if (st->mode & AD7192_MODE_SINC3)
676b581f748SAlexandru Tachici return DIV_ROUND_CLOSEST(fadc * 272, 1024);
677b581f748SAlexandru Tachici else
678b581f748SAlexandru Tachici return DIV_ROUND_CLOSEST(fadc * 230, 1024);
679b581f748SAlexandru Tachici }
680b581f748SAlexandru Tachici
ad7192_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long m)681b581f748SAlexandru Tachici static int ad7192_read_raw(struct iio_dev *indio_dev,
682b581f748SAlexandru Tachici struct iio_chan_spec const *chan,
683b581f748SAlexandru Tachici int *val,
684b581f748SAlexandru Tachici int *val2,
685b581f748SAlexandru Tachici long m)
686b581f748SAlexandru Tachici {
687b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
688b581f748SAlexandru Tachici bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR);
689b581f748SAlexandru Tachici
690b581f748SAlexandru Tachici switch (m) {
691b581f748SAlexandru Tachici case IIO_CHAN_INFO_RAW:
692b581f748SAlexandru Tachici return ad_sigma_delta_single_conversion(indio_dev, chan, val);
693b581f748SAlexandru Tachici case IIO_CHAN_INFO_SCALE:
694b581f748SAlexandru Tachici switch (chan->type) {
695b581f748SAlexandru Tachici case IIO_VOLTAGE:
696b581f748SAlexandru Tachici mutex_lock(&st->lock);
697b581f748SAlexandru Tachici *val = st->scale_avail[AD7192_CONF_GAIN(st->conf)][0];
698b581f748SAlexandru Tachici *val2 = st->scale_avail[AD7192_CONF_GAIN(st->conf)][1];
699b581f748SAlexandru Tachici mutex_unlock(&st->lock);
700b581f748SAlexandru Tachici return IIO_VAL_INT_PLUS_NANO;
701b581f748SAlexandru Tachici case IIO_TEMP:
702b581f748SAlexandru Tachici *val = 0;
703b581f748SAlexandru Tachici *val2 = 1000000000 / ad7192_get_temp_scale(unipolar);
704b581f748SAlexandru Tachici return IIO_VAL_INT_PLUS_NANO;
705b581f748SAlexandru Tachici default:
706b581f748SAlexandru Tachici return -EINVAL;
707b581f748SAlexandru Tachici }
708b581f748SAlexandru Tachici case IIO_CHAN_INFO_OFFSET:
709b581f748SAlexandru Tachici if (!unipolar)
710b581f748SAlexandru Tachici *val = -(1 << (chan->scan_type.realbits - 1));
711b581f748SAlexandru Tachici else
712b581f748SAlexandru Tachici *val = 0;
713b581f748SAlexandru Tachici /* Kelvin to Celsius */
714b581f748SAlexandru Tachici if (chan->type == IIO_TEMP)
715b581f748SAlexandru Tachici *val -= 273 * ad7192_get_temp_scale(unipolar);
716b581f748SAlexandru Tachici return IIO_VAL_INT;
717b581f748SAlexandru Tachici case IIO_CHAN_INFO_SAMP_FREQ:
718b581f748SAlexandru Tachici *val = st->fclk /
719b581f748SAlexandru Tachici (st->f_order * 1024 * AD7192_MODE_RATE(st->mode));
720b581f748SAlexandru Tachici return IIO_VAL_INT;
721b581f748SAlexandru Tachici case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
722b581f748SAlexandru Tachici *val = ad7192_get_3db_filter_freq(st);
723b581f748SAlexandru Tachici *val2 = 1000;
724b581f748SAlexandru Tachici return IIO_VAL_FRACTIONAL;
725b581f748SAlexandru Tachici }
726b581f748SAlexandru Tachici
727b581f748SAlexandru Tachici return -EINVAL;
728b581f748SAlexandru Tachici }
729b581f748SAlexandru Tachici
ad7192_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)730b581f748SAlexandru Tachici static int ad7192_write_raw(struct iio_dev *indio_dev,
731b581f748SAlexandru Tachici struct iio_chan_spec const *chan,
732b581f748SAlexandru Tachici int val,
733b581f748SAlexandru Tachici int val2,
734b581f748SAlexandru Tachici long mask)
735b581f748SAlexandru Tachici {
736b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
737b581f748SAlexandru Tachici int ret, i, div;
738b581f748SAlexandru Tachici unsigned int tmp;
739b581f748SAlexandru Tachici
740b581f748SAlexandru Tachici ret = iio_device_claim_direct_mode(indio_dev);
741b581f748SAlexandru Tachici if (ret)
742b581f748SAlexandru Tachici return ret;
743b581f748SAlexandru Tachici
744b581f748SAlexandru Tachici switch (mask) {
745b581f748SAlexandru Tachici case IIO_CHAN_INFO_SCALE:
746b581f748SAlexandru Tachici ret = -EINVAL;
747b581f748SAlexandru Tachici mutex_lock(&st->lock);
748b581f748SAlexandru Tachici for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
749b581f748SAlexandru Tachici if (val2 == st->scale_avail[i][1]) {
750b581f748SAlexandru Tachici ret = 0;
751b581f748SAlexandru Tachici tmp = st->conf;
752b581f748SAlexandru Tachici st->conf &= ~AD7192_CONF_GAIN(-1);
753b581f748SAlexandru Tachici st->conf |= AD7192_CONF_GAIN(i);
754b581f748SAlexandru Tachici if (tmp == st->conf)
755b581f748SAlexandru Tachici break;
756b581f748SAlexandru Tachici ad_sd_write_reg(&st->sd, AD7192_REG_CONF,
757b581f748SAlexandru Tachici 3, st->conf);
758b581f748SAlexandru Tachici ad7192_calibrate_all(st);
759b581f748SAlexandru Tachici break;
760b581f748SAlexandru Tachici }
761b581f748SAlexandru Tachici mutex_unlock(&st->lock);
762b581f748SAlexandru Tachici break;
763b581f748SAlexandru Tachici case IIO_CHAN_INFO_SAMP_FREQ:
764b581f748SAlexandru Tachici if (!val) {
765b581f748SAlexandru Tachici ret = -EINVAL;
766b581f748SAlexandru Tachici break;
767b581f748SAlexandru Tachici }
768b581f748SAlexandru Tachici
769b581f748SAlexandru Tachici div = st->fclk / (val * st->f_order * 1024);
770b581f748SAlexandru Tachici if (div < 1 || div > 1023) {
771b581f748SAlexandru Tachici ret = -EINVAL;
772b581f748SAlexandru Tachici break;
773b581f748SAlexandru Tachici }
774b581f748SAlexandru Tachici
775b581f748SAlexandru Tachici st->mode &= ~AD7192_MODE_RATE(-1);
776b581f748SAlexandru Tachici st->mode |= AD7192_MODE_RATE(div);
777b581f748SAlexandru Tachici ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
778b581f748SAlexandru Tachici break;
779b581f748SAlexandru Tachici case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
780b581f748SAlexandru Tachici ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000);
781b581f748SAlexandru Tachici break;
782b581f748SAlexandru Tachici default:
783b581f748SAlexandru Tachici ret = -EINVAL;
784b581f748SAlexandru Tachici }
785b581f748SAlexandru Tachici
786b581f748SAlexandru Tachici iio_device_release_direct_mode(indio_dev);
787b581f748SAlexandru Tachici
788b581f748SAlexandru Tachici return ret;
789b581f748SAlexandru Tachici }
790b581f748SAlexandru Tachici
ad7192_write_raw_get_fmt(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,long mask)791b581f748SAlexandru Tachici static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev,
792b581f748SAlexandru Tachici struct iio_chan_spec const *chan,
793b581f748SAlexandru Tachici long mask)
794b581f748SAlexandru Tachici {
795b581f748SAlexandru Tachici switch (mask) {
796b581f748SAlexandru Tachici case IIO_CHAN_INFO_SCALE:
797b581f748SAlexandru Tachici return IIO_VAL_INT_PLUS_NANO;
798b581f748SAlexandru Tachici case IIO_CHAN_INFO_SAMP_FREQ:
799b581f748SAlexandru Tachici return IIO_VAL_INT;
800b581f748SAlexandru Tachici case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
801b581f748SAlexandru Tachici return IIO_VAL_INT_PLUS_MICRO;
802b581f748SAlexandru Tachici default:
803b581f748SAlexandru Tachici return -EINVAL;
804b581f748SAlexandru Tachici }
805b581f748SAlexandru Tachici }
806b581f748SAlexandru Tachici
ad7192_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)807b581f748SAlexandru Tachici static int ad7192_read_avail(struct iio_dev *indio_dev,
808b581f748SAlexandru Tachici struct iio_chan_spec const *chan,
809b581f748SAlexandru Tachici const int **vals, int *type, int *length,
810b581f748SAlexandru Tachici long mask)
811b581f748SAlexandru Tachici {
812b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
813b581f748SAlexandru Tachici
814b581f748SAlexandru Tachici switch (mask) {
815b581f748SAlexandru Tachici case IIO_CHAN_INFO_SCALE:
816b581f748SAlexandru Tachici *vals = (int *)st->scale_avail;
817b581f748SAlexandru Tachici *type = IIO_VAL_INT_PLUS_NANO;
818b581f748SAlexandru Tachici /* Values are stored in a 2D matrix */
819b581f748SAlexandru Tachici *length = ARRAY_SIZE(st->scale_avail) * 2;
820b581f748SAlexandru Tachici
821b581f748SAlexandru Tachici return IIO_AVAIL_LIST;
822b581f748SAlexandru Tachici }
823b581f748SAlexandru Tachici
824b581f748SAlexandru Tachici return -EINVAL;
825b581f748SAlexandru Tachici }
826b581f748SAlexandru Tachici
ad7192_update_scan_mode(struct iio_dev * indio_dev,const unsigned long * scan_mask)827fe7d929aSAlexandru Tachici static int ad7192_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask)
828fe7d929aSAlexandru Tachici {
829fe7d929aSAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
830fe7d929aSAlexandru Tachici u32 conf = st->conf;
831fe7d929aSAlexandru Tachici int ret;
832fe7d929aSAlexandru Tachici int i;
833fe7d929aSAlexandru Tachici
834fe7d929aSAlexandru Tachici conf &= ~AD7192_CONF_CHAN_MASK;
835fe7d929aSAlexandru Tachici for_each_set_bit(i, scan_mask, 8)
836fe7d929aSAlexandru Tachici conf |= AD7192_CONF_CHAN(i);
837fe7d929aSAlexandru Tachici
838fe7d929aSAlexandru Tachici ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, conf);
839fe7d929aSAlexandru Tachici if (ret < 0)
840fe7d929aSAlexandru Tachici return ret;
841fe7d929aSAlexandru Tachici
842fe7d929aSAlexandru Tachici st->conf = conf;
843fe7d929aSAlexandru Tachici
844fe7d929aSAlexandru Tachici return 0;
845fe7d929aSAlexandru Tachici }
846fe7d929aSAlexandru Tachici
847b581f748SAlexandru Tachici static const struct iio_info ad7192_info = {
848b581f748SAlexandru Tachici .read_raw = ad7192_read_raw,
849b581f748SAlexandru Tachici .write_raw = ad7192_write_raw,
850b581f748SAlexandru Tachici .write_raw_get_fmt = ad7192_write_raw_get_fmt,
851b581f748SAlexandru Tachici .read_avail = ad7192_read_avail,
852b581f748SAlexandru Tachici .attrs = &ad7192_attribute_group,
853b581f748SAlexandru Tachici .validate_trigger = ad_sd_validate_trigger,
854fe7d929aSAlexandru Tachici .update_scan_mode = ad7192_update_scan_mode,
855b581f748SAlexandru Tachici };
856b581f748SAlexandru Tachici
857b581f748SAlexandru Tachici static const struct iio_info ad7195_info = {
858b581f748SAlexandru Tachici .read_raw = ad7192_read_raw,
859b581f748SAlexandru Tachici .write_raw = ad7192_write_raw,
860b581f748SAlexandru Tachici .write_raw_get_fmt = ad7192_write_raw_get_fmt,
861b581f748SAlexandru Tachici .read_avail = ad7192_read_avail,
862b581f748SAlexandru Tachici .attrs = &ad7195_attribute_group,
863b581f748SAlexandru Tachici .validate_trigger = ad_sd_validate_trigger,
864fe7d929aSAlexandru Tachici .update_scan_mode = ad7192_update_scan_mode,
865b581f748SAlexandru Tachici };
866b581f748SAlexandru Tachici
867b581f748SAlexandru Tachici #define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _extend_name, \
868b581f748SAlexandru Tachici _type, _mask_type_av, _ext_info) \
869b581f748SAlexandru Tachici { \
870b581f748SAlexandru Tachici .type = (_type), \
871b581f748SAlexandru Tachici .differential = ((_channel2) == -1 ? 0 : 1), \
872b581f748SAlexandru Tachici .indexed = 1, \
873b581f748SAlexandru Tachici .channel = (_channel1), \
874b581f748SAlexandru Tachici .channel2 = (_channel2), \
875b581f748SAlexandru Tachici .address = (_address), \
876b581f748SAlexandru Tachici .extend_name = (_extend_name), \
877b581f748SAlexandru Tachici .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
878b581f748SAlexandru Tachici BIT(IIO_CHAN_INFO_OFFSET), \
879b581f748SAlexandru Tachici .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
880b581f748SAlexandru Tachici .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
881b581f748SAlexandru Tachici BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
882b581f748SAlexandru Tachici .info_mask_shared_by_type_available = (_mask_type_av), \
883b581f748SAlexandru Tachici .ext_info = (_ext_info), \
884b581f748SAlexandru Tachici .scan_index = (_si), \
885b581f748SAlexandru Tachici .scan_type = { \
886b581f748SAlexandru Tachici .sign = 'u', \
887b581f748SAlexandru Tachici .realbits = 24, \
888b581f748SAlexandru Tachici .storagebits = 32, \
889b581f748SAlexandru Tachici .endianness = IIO_BE, \
890b581f748SAlexandru Tachici }, \
891b581f748SAlexandru Tachici }
892b581f748SAlexandru Tachici
893b581f748SAlexandru Tachici #define AD719x_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \
894b581f748SAlexandru Tachici __AD719x_CHANNEL(_si, _channel1, _channel2, _address, NULL, \
895b581f748SAlexandru Tachici IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE), \
896b581f748SAlexandru Tachici ad7192_calibsys_ext_info)
897b581f748SAlexandru Tachici
898b581f748SAlexandru Tachici #define AD719x_CHANNEL(_si, _channel1, _address) \
899b581f748SAlexandru Tachici __AD719x_CHANNEL(_si, _channel1, -1, _address, NULL, IIO_VOLTAGE, \
900b581f748SAlexandru Tachici BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info)
901b581f748SAlexandru Tachici
902b581f748SAlexandru Tachici #define AD719x_TEMP_CHANNEL(_si, _address) \
903b581f748SAlexandru Tachici __AD719x_CHANNEL(_si, 0, -1, _address, NULL, IIO_TEMP, 0, NULL)
904b581f748SAlexandru Tachici
905b581f748SAlexandru Tachici static const struct iio_chan_spec ad7192_channels[] = {
906b581f748SAlexandru Tachici AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M),
907b581f748SAlexandru Tachici AD719x_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M),
908b581f748SAlexandru Tachici AD719x_TEMP_CHANNEL(2, AD7192_CH_TEMP),
909e55245d1SPaul Cercueil AD719x_DIFF_CHANNEL(3, 2, 2, AD7192_CH_AIN2P_AIN2M),
910b581f748SAlexandru Tachici AD719x_CHANNEL(4, 1, AD7192_CH_AIN1),
911b581f748SAlexandru Tachici AD719x_CHANNEL(5, 2, AD7192_CH_AIN2),
912b581f748SAlexandru Tachici AD719x_CHANNEL(6, 3, AD7192_CH_AIN3),
913b581f748SAlexandru Tachici AD719x_CHANNEL(7, 4, AD7192_CH_AIN4),
914b581f748SAlexandru Tachici IIO_CHAN_SOFT_TIMESTAMP(8),
915b581f748SAlexandru Tachici };
916b581f748SAlexandru Tachici
917b581f748SAlexandru Tachici static const struct iio_chan_spec ad7193_channels[] = {
918b581f748SAlexandru Tachici AD719x_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M),
919b581f748SAlexandru Tachici AD719x_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M),
920b581f748SAlexandru Tachici AD719x_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M),
921b581f748SAlexandru Tachici AD719x_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M),
922b581f748SAlexandru Tachici AD719x_TEMP_CHANNEL(4, AD7193_CH_TEMP),
923e55245d1SPaul Cercueil AD719x_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M),
924b581f748SAlexandru Tachici AD719x_CHANNEL(6, 1, AD7193_CH_AIN1),
925b581f748SAlexandru Tachici AD719x_CHANNEL(7, 2, AD7193_CH_AIN2),
926b581f748SAlexandru Tachici AD719x_CHANNEL(8, 3, AD7193_CH_AIN3),
927b581f748SAlexandru Tachici AD719x_CHANNEL(9, 4, AD7193_CH_AIN4),
928b581f748SAlexandru Tachici AD719x_CHANNEL(10, 5, AD7193_CH_AIN5),
929b581f748SAlexandru Tachici AD719x_CHANNEL(11, 6, AD7193_CH_AIN6),
930b581f748SAlexandru Tachici AD719x_CHANNEL(12, 7, AD7193_CH_AIN7),
931b581f748SAlexandru Tachici AD719x_CHANNEL(13, 8, AD7193_CH_AIN8),
932b581f748SAlexandru Tachici IIO_CHAN_SOFT_TIMESTAMP(14),
933b581f748SAlexandru Tachici };
934b581f748SAlexandru Tachici
9358f2273b1SAlexandru Ardelean static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
9368f2273b1SAlexandru Ardelean [ID_AD7190] = {
9378f2273b1SAlexandru Ardelean .chip_id = CHIPID_AD7190,
9388f2273b1SAlexandru Ardelean .name = "ad7190",
9398f2273b1SAlexandru Ardelean },
9408f2273b1SAlexandru Ardelean [ID_AD7192] = {
9418f2273b1SAlexandru Ardelean .chip_id = CHIPID_AD7192,
9428f2273b1SAlexandru Ardelean .name = "ad7192",
9438f2273b1SAlexandru Ardelean },
9448f2273b1SAlexandru Ardelean [ID_AD7193] = {
9458f2273b1SAlexandru Ardelean .chip_id = CHIPID_AD7193,
9468f2273b1SAlexandru Ardelean .name = "ad7193",
9478f2273b1SAlexandru Ardelean },
9488f2273b1SAlexandru Ardelean [ID_AD7195] = {
9498f2273b1SAlexandru Ardelean .chip_id = CHIPID_AD7195,
9508f2273b1SAlexandru Ardelean .name = "ad7195",
9518f2273b1SAlexandru Ardelean },
9528f2273b1SAlexandru Ardelean };
9538f2273b1SAlexandru Ardelean
ad7192_channels_config(struct iio_dev * indio_dev)954b581f748SAlexandru Tachici static int ad7192_channels_config(struct iio_dev *indio_dev)
955b581f748SAlexandru Tachici {
956b581f748SAlexandru Tachici struct ad7192_state *st = iio_priv(indio_dev);
957b581f748SAlexandru Tachici
9588f2273b1SAlexandru Ardelean switch (st->chip_info->chip_id) {
9598f2273b1SAlexandru Ardelean case CHIPID_AD7193:
960b581f748SAlexandru Tachici indio_dev->channels = ad7193_channels;
961b581f748SAlexandru Tachici indio_dev->num_channels = ARRAY_SIZE(ad7193_channels);
962b581f748SAlexandru Tachici break;
963b581f748SAlexandru Tachici default:
964b581f748SAlexandru Tachici indio_dev->channels = ad7192_channels;
965b581f748SAlexandru Tachici indio_dev->num_channels = ARRAY_SIZE(ad7192_channels);
966b581f748SAlexandru Tachici break;
967b581f748SAlexandru Tachici }
968b581f748SAlexandru Tachici
969b581f748SAlexandru Tachici return 0;
970b581f748SAlexandru Tachici }
971b581f748SAlexandru Tachici
ad7192_reg_disable(void * reg)972bd5dcdebSAlexandru Ardelean static void ad7192_reg_disable(void *reg)
973bd5dcdebSAlexandru Ardelean {
974bd5dcdebSAlexandru Ardelean regulator_disable(reg);
975bd5dcdebSAlexandru Ardelean }
976bd5dcdebSAlexandru Ardelean
ad7192_probe(struct spi_device * spi)977b581f748SAlexandru Tachici static int ad7192_probe(struct spi_device *spi)
978b581f748SAlexandru Tachici {
979b581f748SAlexandru Tachici struct ad7192_state *st;
980b581f748SAlexandru Tachici struct iio_dev *indio_dev;
981b0f27fcaSAlexandru Ardelean int ret;
982b581f748SAlexandru Tachici
983b581f748SAlexandru Tachici if (!spi->irq) {
984b581f748SAlexandru Tachici dev_err(&spi->dev, "no IRQ?\n");
985b581f748SAlexandru Tachici return -ENODEV;
986b581f748SAlexandru Tachici }
987b581f748SAlexandru Tachici
988b581f748SAlexandru Tachici indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
989b581f748SAlexandru Tachici if (!indio_dev)
990b581f748SAlexandru Tachici return -ENOMEM;
991b581f748SAlexandru Tachici
992b581f748SAlexandru Tachici st = iio_priv(indio_dev);
993b581f748SAlexandru Tachici
994b581f748SAlexandru Tachici mutex_init(&st->lock);
995b581f748SAlexandru Tachici
996b581f748SAlexandru Tachici st->avdd = devm_regulator_get(&spi->dev, "avdd");
997b581f748SAlexandru Tachici if (IS_ERR(st->avdd))
998b581f748SAlexandru Tachici return PTR_ERR(st->avdd);
999b581f748SAlexandru Tachici
1000b581f748SAlexandru Tachici ret = regulator_enable(st->avdd);
1001b581f748SAlexandru Tachici if (ret) {
1002b581f748SAlexandru Tachici dev_err(&spi->dev, "Failed to enable specified AVdd supply\n");
1003b581f748SAlexandru Tachici return ret;
1004b581f748SAlexandru Tachici }
1005b581f748SAlexandru Tachici
1006bd5dcdebSAlexandru Ardelean ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->avdd);
1007bd5dcdebSAlexandru Ardelean if (ret)
1008bd5dcdebSAlexandru Ardelean return ret;
1009bd5dcdebSAlexandru Ardelean
10101ccef2e6SMatti Vaittinen ret = devm_regulator_get_enable(&spi->dev, "dvdd");
1011bd5dcdebSAlexandru Ardelean if (ret)
10121ccef2e6SMatti Vaittinen return dev_err_probe(&spi->dev, ret, "Failed to enable specified DVdd supply\n");
1013bd5dcdebSAlexandru Ardelean
10147e7dcab6SAlisa-Dariana Roman st->vref = devm_regulator_get_optional(&spi->dev, "vref");
10157e7dcab6SAlisa-Dariana Roman if (IS_ERR(st->vref)) {
10167e7dcab6SAlisa-Dariana Roman if (PTR_ERR(st->vref) != -ENODEV)
10177e7dcab6SAlisa-Dariana Roman return PTR_ERR(st->vref);
10187e7dcab6SAlisa-Dariana Roman
1019b0f27fcaSAlexandru Ardelean ret = regulator_get_voltage(st->avdd);
10207e7dcab6SAlisa-Dariana Roman if (ret < 0)
10217e7dcab6SAlisa-Dariana Roman return dev_err_probe(&spi->dev, ret,
10227e7dcab6SAlisa-Dariana Roman "Device tree error, AVdd voltage undefined\n");
10237e7dcab6SAlisa-Dariana Roman } else {
10247e7dcab6SAlisa-Dariana Roman ret = regulator_enable(st->vref);
10257e7dcab6SAlisa-Dariana Roman if (ret) {
10267e7dcab6SAlisa-Dariana Roman dev_err(&spi->dev, "Failed to enable specified Vref supply\n");
1027bd5dcdebSAlexandru Ardelean return ret;
1028b581f748SAlexandru Tachici }
10297e7dcab6SAlisa-Dariana Roman
10307e7dcab6SAlisa-Dariana Roman ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->vref);
10317e7dcab6SAlisa-Dariana Roman if (ret)
10327e7dcab6SAlisa-Dariana Roman return ret;
10337e7dcab6SAlisa-Dariana Roman
10347e7dcab6SAlisa-Dariana Roman ret = regulator_get_voltage(st->vref);
10357e7dcab6SAlisa-Dariana Roman if (ret < 0)
10367e7dcab6SAlisa-Dariana Roman return dev_err_probe(&spi->dev, ret,
10377e7dcab6SAlisa-Dariana Roman "Device tree error, Vref voltage undefined\n");
10387e7dcab6SAlisa-Dariana Roman }
1039b0f27fcaSAlexandru Ardelean st->int_vref_mv = ret / 1000;
1040b581f748SAlexandru Tachici
1041843b5d16SJonathan Cameron st->chip_info = spi_get_device_match_data(spi);
1042*c47940e8SNuno Sa if (!st->chip_info)
1043*c47940e8SNuno Sa return -ENODEV;
1044*c47940e8SNuno Sa
10458f2273b1SAlexandru Ardelean indio_dev->name = st->chip_info->name;
1046b581f748SAlexandru Tachici indio_dev->modes = INDIO_DIRECT_MODE;
1047b581f748SAlexandru Tachici
1048b581f748SAlexandru Tachici ret = ad7192_channels_config(indio_dev);
1049b581f748SAlexandru Tachici if (ret < 0)
1050bd5dcdebSAlexandru Ardelean return ret;
1051b581f748SAlexandru Tachici
10528f2273b1SAlexandru Ardelean if (st->chip_info->chip_id == CHIPID_AD7195)
1053b581f748SAlexandru Tachici indio_dev->info = &ad7195_info;
1054b581f748SAlexandru Tachici else
1055b581f748SAlexandru Tachici indio_dev->info = &ad7192_info;
1056b581f748SAlexandru Tachici
1057f41f4443SMarkus Burri ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info);
1058f41f4443SMarkus Burri if (ret)
1059f41f4443SMarkus Burri return ret;
1060b581f748SAlexandru Tachici
1061bd5dcdebSAlexandru Ardelean ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
1062b581f748SAlexandru Tachici if (ret)
1063bd5dcdebSAlexandru Ardelean return ret;
1064b581f748SAlexandru Tachici
1065b581f748SAlexandru Tachici st->fclk = AD7192_INT_FREQ_MHZ;
1066b581f748SAlexandru Tachici
1067478baae9SChristophe JAILLET st->mclk = devm_clk_get_optional_enabled(&spi->dev, "mclk");
1068bd5dcdebSAlexandru Ardelean if (IS_ERR(st->mclk))
1069bd5dcdebSAlexandru Ardelean return PTR_ERR(st->mclk);
1070b581f748SAlexandru Tachici
1071843b5d16SJonathan Cameron st->clock_sel = ad7192_clock_select(st);
1072b581f748SAlexandru Tachici
1073b581f748SAlexandru Tachici if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 ||
1074b581f748SAlexandru Tachici st->clock_sel == AD7192_CLK_EXT_MCLK2) {
1075b581f748SAlexandru Tachici st->fclk = clk_get_rate(st->mclk);
1076b581f748SAlexandru Tachici if (!ad7192_valid_external_frequency(st->fclk)) {
1077b581f748SAlexandru Tachici dev_err(&spi->dev,
1078b581f748SAlexandru Tachici "External clock frequency out of bounds\n");
1079bd5dcdebSAlexandru Ardelean return -EINVAL;
1080b581f748SAlexandru Tachici }
1081b581f748SAlexandru Tachici }
1082b581f748SAlexandru Tachici
1083843b5d16SJonathan Cameron ret = ad7192_setup(indio_dev, &spi->dev);
1084b581f748SAlexandru Tachici if (ret)
1085b581f748SAlexandru Tachici return ret;
1086b581f748SAlexandru Tachici
1087bd5dcdebSAlexandru Ardelean return devm_iio_device_register(&spi->dev, indio_dev);
1088b581f748SAlexandru Tachici }
1089b581f748SAlexandru Tachici
10903eca1d26SAlexandru Ardelean static const struct of_device_id ad7192_of_match[] = {
10913eca1d26SAlexandru Ardelean { .compatible = "adi,ad7190", .data = &ad7192_chip_info_tbl[ID_AD7190] },
10923eca1d26SAlexandru Ardelean { .compatible = "adi,ad7192", .data = &ad7192_chip_info_tbl[ID_AD7192] },
10933eca1d26SAlexandru Ardelean { .compatible = "adi,ad7193", .data = &ad7192_chip_info_tbl[ID_AD7193] },
10943eca1d26SAlexandru Ardelean { .compatible = "adi,ad7195", .data = &ad7192_chip_info_tbl[ID_AD7195] },
10953eca1d26SAlexandru Ardelean {}
10963eca1d26SAlexandru Ardelean };
10973eca1d26SAlexandru Ardelean MODULE_DEVICE_TABLE(of, ad7192_of_match);
10983eca1d26SAlexandru Ardelean
1099935779eaSWei Yongjun static const struct spi_device_id ad7192_ids[] = {
1100935779eaSWei Yongjun { "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] },
1101935779eaSWei Yongjun { "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] },
1102935779eaSWei Yongjun { "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] },
1103935779eaSWei Yongjun { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
1104935779eaSWei Yongjun {}
1105935779eaSWei Yongjun };
1106935779eaSWei Yongjun MODULE_DEVICE_TABLE(spi, ad7192_ids);
1107935779eaSWei Yongjun
1108b581f748SAlexandru Tachici static struct spi_driver ad7192_driver = {
1109b581f748SAlexandru Tachici .driver = {
1110b581f748SAlexandru Tachici .name = "ad7192",
1111b581f748SAlexandru Tachici .of_match_table = ad7192_of_match,
1112b581f748SAlexandru Tachici },
1113b581f748SAlexandru Tachici .probe = ad7192_probe,
1114935779eaSWei Yongjun .id_table = ad7192_ids,
1115b581f748SAlexandru Tachici };
1116b581f748SAlexandru Tachici module_spi_driver(ad7192_driver);
1117b581f748SAlexandru Tachici
1118b581f748SAlexandru Tachici MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
1119b581f748SAlexandru Tachici MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC");
1120b581f748SAlexandru Tachici MODULE_LICENSE("GPL v2");
1121ef807729SJonathan Cameron MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
1122