1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * AD5686R, AD5685R, AD5684R Digital to analog converters driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright 2011 Analog Devices Inc.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/interrupt.h>
9*4882a593Smuzhiyun #include <linux/fs.h>
10*4882a593Smuzhiyun #include <linux/device.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/sysfs.h>
15*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/iio/iio.h>
18*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include "ad5686.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static const char * const ad5686_powerdown_modes[] = {
23*4882a593Smuzhiyun "1kohm_to_gnd",
24*4882a593Smuzhiyun "100kohm_to_gnd",
25*4882a593Smuzhiyun "three_state"
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
ad5686_get_powerdown_mode(struct iio_dev * indio_dev,const struct iio_chan_spec * chan)28*4882a593Smuzhiyun static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev,
29*4882a593Smuzhiyun const struct iio_chan_spec *chan)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun struct ad5686_state *st = iio_priv(indio_dev);
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1;
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun
ad5686_set_powerdown_mode(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,unsigned int mode)36*4882a593Smuzhiyun static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev,
37*4882a593Smuzhiyun const struct iio_chan_spec *chan,
38*4882a593Smuzhiyun unsigned int mode)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun struct ad5686_state *st = iio_priv(indio_dev);
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun st->pwr_down_mode &= ~(0x3 << (chan->channel * 2));
43*4882a593Smuzhiyun st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2));
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun return 0;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun static const struct iio_enum ad5686_powerdown_mode_enum = {
49*4882a593Smuzhiyun .items = ad5686_powerdown_modes,
50*4882a593Smuzhiyun .num_items = ARRAY_SIZE(ad5686_powerdown_modes),
51*4882a593Smuzhiyun .get = ad5686_get_powerdown_mode,
52*4882a593Smuzhiyun .set = ad5686_set_powerdown_mode,
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
ad5686_read_dac_powerdown(struct iio_dev * indio_dev,uintptr_t private,const struct iio_chan_spec * chan,char * buf)55*4882a593Smuzhiyun static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev,
56*4882a593Smuzhiyun uintptr_t private, const struct iio_chan_spec *chan, char *buf)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun struct ad5686_state *st = iio_priv(indio_dev);
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun return sprintf(buf, "%d\n", !!(st->pwr_down_mask &
61*4882a593Smuzhiyun (0x3 << (chan->channel * 2))));
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
ad5686_write_dac_powerdown(struct iio_dev * indio_dev,uintptr_t private,const struct iio_chan_spec * chan,const char * buf,size_t len)64*4882a593Smuzhiyun static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
65*4882a593Smuzhiyun uintptr_t private,
66*4882a593Smuzhiyun const struct iio_chan_spec *chan,
67*4882a593Smuzhiyun const char *buf,
68*4882a593Smuzhiyun size_t len)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun bool readin;
71*4882a593Smuzhiyun int ret;
72*4882a593Smuzhiyun struct ad5686_state *st = iio_priv(indio_dev);
73*4882a593Smuzhiyun unsigned int val, ref_bit_msk;
74*4882a593Smuzhiyun u8 shift, address = 0;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun ret = strtobool(buf, &readin);
77*4882a593Smuzhiyun if (ret)
78*4882a593Smuzhiyun return ret;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if (readin)
81*4882a593Smuzhiyun st->pwr_down_mask |= (0x3 << (chan->channel * 2));
82*4882a593Smuzhiyun else
83*4882a593Smuzhiyun st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun switch (st->chip_info->regmap_type) {
86*4882a593Smuzhiyun case AD5310_REGMAP:
87*4882a593Smuzhiyun shift = 9;
88*4882a593Smuzhiyun ref_bit_msk = AD5310_REF_BIT_MSK;
89*4882a593Smuzhiyun break;
90*4882a593Smuzhiyun case AD5683_REGMAP:
91*4882a593Smuzhiyun shift = 13;
92*4882a593Smuzhiyun ref_bit_msk = AD5683_REF_BIT_MSK;
93*4882a593Smuzhiyun break;
94*4882a593Smuzhiyun case AD5686_REGMAP:
95*4882a593Smuzhiyun shift = 0;
96*4882a593Smuzhiyun ref_bit_msk = 0;
97*4882a593Smuzhiyun /* AD5674R/AD5679R have 16 channels and 2 powerdown registers */
98*4882a593Smuzhiyun if (chan->channel > 0x7)
99*4882a593Smuzhiyun address = 0x8;
100*4882a593Smuzhiyun break;
101*4882a593Smuzhiyun case AD5693_REGMAP:
102*4882a593Smuzhiyun shift = 13;
103*4882a593Smuzhiyun ref_bit_msk = AD5693_REF_BIT_MSK;
104*4882a593Smuzhiyun break;
105*4882a593Smuzhiyun default:
106*4882a593Smuzhiyun return -EINVAL;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun val = ((st->pwr_down_mask & st->pwr_down_mode) << shift);
110*4882a593Smuzhiyun if (!st->use_internal_vref)
111*4882a593Smuzhiyun val |= ref_bit_msk;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun ret = st->write(st, AD5686_CMD_POWERDOWN_DAC,
114*4882a593Smuzhiyun address, val >> (address * 2));
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun return ret ? ret : len;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
ad5686_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long m)119*4882a593Smuzhiyun static int ad5686_read_raw(struct iio_dev *indio_dev,
120*4882a593Smuzhiyun struct iio_chan_spec const *chan,
121*4882a593Smuzhiyun int *val,
122*4882a593Smuzhiyun int *val2,
123*4882a593Smuzhiyun long m)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct ad5686_state *st = iio_priv(indio_dev);
126*4882a593Smuzhiyun int ret;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun switch (m) {
129*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
130*4882a593Smuzhiyun mutex_lock(&st->lock);
131*4882a593Smuzhiyun ret = st->read(st, chan->address);
132*4882a593Smuzhiyun mutex_unlock(&st->lock);
133*4882a593Smuzhiyun if (ret < 0)
134*4882a593Smuzhiyun return ret;
135*4882a593Smuzhiyun *val = (ret >> chan->scan_type.shift) &
136*4882a593Smuzhiyun GENMASK(chan->scan_type.realbits - 1, 0);
137*4882a593Smuzhiyun return IIO_VAL_INT;
138*4882a593Smuzhiyun case IIO_CHAN_INFO_SCALE:
139*4882a593Smuzhiyun *val = st->vref_mv;
140*4882a593Smuzhiyun *val2 = chan->scan_type.realbits;
141*4882a593Smuzhiyun return IIO_VAL_FRACTIONAL_LOG2;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun return -EINVAL;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
ad5686_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)146*4882a593Smuzhiyun static int ad5686_write_raw(struct iio_dev *indio_dev,
147*4882a593Smuzhiyun struct iio_chan_spec const *chan,
148*4882a593Smuzhiyun int val,
149*4882a593Smuzhiyun int val2,
150*4882a593Smuzhiyun long mask)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun struct ad5686_state *st = iio_priv(indio_dev);
153*4882a593Smuzhiyun int ret;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun switch (mask) {
156*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
157*4882a593Smuzhiyun if (val > (1 << chan->scan_type.realbits) || val < 0)
158*4882a593Smuzhiyun return -EINVAL;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun mutex_lock(&st->lock);
161*4882a593Smuzhiyun ret = st->write(st,
162*4882a593Smuzhiyun AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
163*4882a593Smuzhiyun chan->address,
164*4882a593Smuzhiyun val << chan->scan_type.shift);
165*4882a593Smuzhiyun mutex_unlock(&st->lock);
166*4882a593Smuzhiyun break;
167*4882a593Smuzhiyun default:
168*4882a593Smuzhiyun ret = -EINVAL;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun return ret;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun static const struct iio_info ad5686_info = {
175*4882a593Smuzhiyun .read_raw = ad5686_read_raw,
176*4882a593Smuzhiyun .write_raw = ad5686_write_raw,
177*4882a593Smuzhiyun };
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun .name = "powerdown",
182*4882a593Smuzhiyun .read = ad5686_read_dac_powerdown,
183*4882a593Smuzhiyun .write = ad5686_write_dac_powerdown,
184*4882a593Smuzhiyun .shared = IIO_SEPARATE,
185*4882a593Smuzhiyun },
186*4882a593Smuzhiyun IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5686_powerdown_mode_enum),
187*4882a593Smuzhiyun IIO_ENUM_AVAILABLE("powerdown_mode", &ad5686_powerdown_mode_enum),
188*4882a593Smuzhiyun { },
189*4882a593Smuzhiyun };
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun #define AD5868_CHANNEL(chan, addr, bits, _shift) { \
192*4882a593Smuzhiyun .type = IIO_VOLTAGE, \
193*4882a593Smuzhiyun .indexed = 1, \
194*4882a593Smuzhiyun .output = 1, \
195*4882a593Smuzhiyun .channel = chan, \
196*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
197*4882a593Smuzhiyun .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
198*4882a593Smuzhiyun .address = addr, \
199*4882a593Smuzhiyun .scan_type = { \
200*4882a593Smuzhiyun .sign = 'u', \
201*4882a593Smuzhiyun .realbits = (bits), \
202*4882a593Smuzhiyun .storagebits = 16, \
203*4882a593Smuzhiyun .shift = (_shift), \
204*4882a593Smuzhiyun }, \
205*4882a593Smuzhiyun .ext_info = ad5686_ext_info, \
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun #define DECLARE_AD5693_CHANNELS(name, bits, _shift) \
209*4882a593Smuzhiyun static const struct iio_chan_spec name[] = { \
210*4882a593Smuzhiyun AD5868_CHANNEL(0, 0, bits, _shift), \
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun #define DECLARE_AD5686_CHANNELS(name, bits, _shift) \
214*4882a593Smuzhiyun static const struct iio_chan_spec name[] = { \
215*4882a593Smuzhiyun AD5868_CHANNEL(0, 1, bits, _shift), \
216*4882a593Smuzhiyun AD5868_CHANNEL(1, 2, bits, _shift), \
217*4882a593Smuzhiyun AD5868_CHANNEL(2, 4, bits, _shift), \
218*4882a593Smuzhiyun AD5868_CHANNEL(3, 8, bits, _shift), \
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun #define DECLARE_AD5676_CHANNELS(name, bits, _shift) \
222*4882a593Smuzhiyun static const struct iio_chan_spec name[] = { \
223*4882a593Smuzhiyun AD5868_CHANNEL(0, 0, bits, _shift), \
224*4882a593Smuzhiyun AD5868_CHANNEL(1, 1, bits, _shift), \
225*4882a593Smuzhiyun AD5868_CHANNEL(2, 2, bits, _shift), \
226*4882a593Smuzhiyun AD5868_CHANNEL(3, 3, bits, _shift), \
227*4882a593Smuzhiyun AD5868_CHANNEL(4, 4, bits, _shift), \
228*4882a593Smuzhiyun AD5868_CHANNEL(5, 5, bits, _shift), \
229*4882a593Smuzhiyun AD5868_CHANNEL(6, 6, bits, _shift), \
230*4882a593Smuzhiyun AD5868_CHANNEL(7, 7, bits, _shift), \
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun #define DECLARE_AD5679_CHANNELS(name, bits, _shift) \
234*4882a593Smuzhiyun static const struct iio_chan_spec name[] = { \
235*4882a593Smuzhiyun AD5868_CHANNEL(0, 0, bits, _shift), \
236*4882a593Smuzhiyun AD5868_CHANNEL(1, 1, bits, _shift), \
237*4882a593Smuzhiyun AD5868_CHANNEL(2, 2, bits, _shift), \
238*4882a593Smuzhiyun AD5868_CHANNEL(3, 3, bits, _shift), \
239*4882a593Smuzhiyun AD5868_CHANNEL(4, 4, bits, _shift), \
240*4882a593Smuzhiyun AD5868_CHANNEL(5, 5, bits, _shift), \
241*4882a593Smuzhiyun AD5868_CHANNEL(6, 6, bits, _shift), \
242*4882a593Smuzhiyun AD5868_CHANNEL(7, 7, bits, _shift), \
243*4882a593Smuzhiyun AD5868_CHANNEL(8, 8, bits, _shift), \
244*4882a593Smuzhiyun AD5868_CHANNEL(9, 9, bits, _shift), \
245*4882a593Smuzhiyun AD5868_CHANNEL(10, 10, bits, _shift), \
246*4882a593Smuzhiyun AD5868_CHANNEL(11, 11, bits, _shift), \
247*4882a593Smuzhiyun AD5868_CHANNEL(12, 12, bits, _shift), \
248*4882a593Smuzhiyun AD5868_CHANNEL(13, 13, bits, _shift), \
249*4882a593Smuzhiyun AD5868_CHANNEL(14, 14, bits, _shift), \
250*4882a593Smuzhiyun AD5868_CHANNEL(15, 15, bits, _shift), \
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
254*4882a593Smuzhiyun DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
255*4882a593Smuzhiyun DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
256*4882a593Smuzhiyun DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4);
257*4882a593Smuzhiyun DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
258*4882a593Smuzhiyun DECLARE_AD5679_CHANNELS(ad5679r_channels, 16, 0);
259*4882a593Smuzhiyun DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4);
260*4882a593Smuzhiyun DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2);
261*4882a593Smuzhiyun DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0);
262*4882a593Smuzhiyun DECLARE_AD5693_CHANNELS(ad5693_channels, 16, 0);
263*4882a593Smuzhiyun DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2);
264*4882a593Smuzhiyun DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
267*4882a593Smuzhiyun [ID_AD5310R] = {
268*4882a593Smuzhiyun .channels = ad5310r_channels,
269*4882a593Smuzhiyun .int_vref_mv = 2500,
270*4882a593Smuzhiyun .num_channels = 1,
271*4882a593Smuzhiyun .regmap_type = AD5310_REGMAP,
272*4882a593Smuzhiyun },
273*4882a593Smuzhiyun [ID_AD5311R] = {
274*4882a593Smuzhiyun .channels = ad5311r_channels,
275*4882a593Smuzhiyun .int_vref_mv = 2500,
276*4882a593Smuzhiyun .num_channels = 1,
277*4882a593Smuzhiyun .regmap_type = AD5693_REGMAP,
278*4882a593Smuzhiyun },
279*4882a593Smuzhiyun [ID_AD5671R] = {
280*4882a593Smuzhiyun .channels = ad5672_channels,
281*4882a593Smuzhiyun .int_vref_mv = 2500,
282*4882a593Smuzhiyun .num_channels = 8,
283*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
284*4882a593Smuzhiyun },
285*4882a593Smuzhiyun [ID_AD5672R] = {
286*4882a593Smuzhiyun .channels = ad5672_channels,
287*4882a593Smuzhiyun .int_vref_mv = 2500,
288*4882a593Smuzhiyun .num_channels = 8,
289*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
290*4882a593Smuzhiyun },
291*4882a593Smuzhiyun [ID_AD5674R] = {
292*4882a593Smuzhiyun .channels = ad5674r_channels,
293*4882a593Smuzhiyun .int_vref_mv = 2500,
294*4882a593Smuzhiyun .num_channels = 16,
295*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
296*4882a593Smuzhiyun },
297*4882a593Smuzhiyun [ID_AD5675R] = {
298*4882a593Smuzhiyun .channels = ad5676_channels,
299*4882a593Smuzhiyun .int_vref_mv = 2500,
300*4882a593Smuzhiyun .num_channels = 8,
301*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
302*4882a593Smuzhiyun },
303*4882a593Smuzhiyun [ID_AD5676] = {
304*4882a593Smuzhiyun .channels = ad5676_channels,
305*4882a593Smuzhiyun .num_channels = 8,
306*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
307*4882a593Smuzhiyun },
308*4882a593Smuzhiyun [ID_AD5676R] = {
309*4882a593Smuzhiyun .channels = ad5676_channels,
310*4882a593Smuzhiyun .int_vref_mv = 2500,
311*4882a593Smuzhiyun .num_channels = 8,
312*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
313*4882a593Smuzhiyun },
314*4882a593Smuzhiyun [ID_AD5679R] = {
315*4882a593Smuzhiyun .channels = ad5679r_channels,
316*4882a593Smuzhiyun .int_vref_mv = 2500,
317*4882a593Smuzhiyun .num_channels = 16,
318*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
319*4882a593Smuzhiyun },
320*4882a593Smuzhiyun [ID_AD5681R] = {
321*4882a593Smuzhiyun .channels = ad5691r_channels,
322*4882a593Smuzhiyun .int_vref_mv = 2500,
323*4882a593Smuzhiyun .num_channels = 1,
324*4882a593Smuzhiyun .regmap_type = AD5683_REGMAP,
325*4882a593Smuzhiyun },
326*4882a593Smuzhiyun [ID_AD5682R] = {
327*4882a593Smuzhiyun .channels = ad5692r_channels,
328*4882a593Smuzhiyun .int_vref_mv = 2500,
329*4882a593Smuzhiyun .num_channels = 1,
330*4882a593Smuzhiyun .regmap_type = AD5683_REGMAP,
331*4882a593Smuzhiyun },
332*4882a593Smuzhiyun [ID_AD5683] = {
333*4882a593Smuzhiyun .channels = ad5693_channels,
334*4882a593Smuzhiyun .num_channels = 1,
335*4882a593Smuzhiyun .regmap_type = AD5683_REGMAP,
336*4882a593Smuzhiyun },
337*4882a593Smuzhiyun [ID_AD5683R] = {
338*4882a593Smuzhiyun .channels = ad5693_channels,
339*4882a593Smuzhiyun .int_vref_mv = 2500,
340*4882a593Smuzhiyun .num_channels = 1,
341*4882a593Smuzhiyun .regmap_type = AD5683_REGMAP,
342*4882a593Smuzhiyun },
343*4882a593Smuzhiyun [ID_AD5684] = {
344*4882a593Smuzhiyun .channels = ad5684_channels,
345*4882a593Smuzhiyun .num_channels = 4,
346*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
347*4882a593Smuzhiyun },
348*4882a593Smuzhiyun [ID_AD5684R] = {
349*4882a593Smuzhiyun .channels = ad5684_channels,
350*4882a593Smuzhiyun .int_vref_mv = 2500,
351*4882a593Smuzhiyun .num_channels = 4,
352*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
353*4882a593Smuzhiyun },
354*4882a593Smuzhiyun [ID_AD5685R] = {
355*4882a593Smuzhiyun .channels = ad5685r_channels,
356*4882a593Smuzhiyun .int_vref_mv = 2500,
357*4882a593Smuzhiyun .num_channels = 4,
358*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
359*4882a593Smuzhiyun },
360*4882a593Smuzhiyun [ID_AD5686] = {
361*4882a593Smuzhiyun .channels = ad5686_channels,
362*4882a593Smuzhiyun .num_channels = 4,
363*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
364*4882a593Smuzhiyun },
365*4882a593Smuzhiyun [ID_AD5686R] = {
366*4882a593Smuzhiyun .channels = ad5686_channels,
367*4882a593Smuzhiyun .int_vref_mv = 2500,
368*4882a593Smuzhiyun .num_channels = 4,
369*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
370*4882a593Smuzhiyun },
371*4882a593Smuzhiyun [ID_AD5691R] = {
372*4882a593Smuzhiyun .channels = ad5691r_channels,
373*4882a593Smuzhiyun .int_vref_mv = 2500,
374*4882a593Smuzhiyun .num_channels = 1,
375*4882a593Smuzhiyun .regmap_type = AD5693_REGMAP,
376*4882a593Smuzhiyun },
377*4882a593Smuzhiyun [ID_AD5692R] = {
378*4882a593Smuzhiyun .channels = ad5692r_channels,
379*4882a593Smuzhiyun .int_vref_mv = 2500,
380*4882a593Smuzhiyun .num_channels = 1,
381*4882a593Smuzhiyun .regmap_type = AD5693_REGMAP,
382*4882a593Smuzhiyun },
383*4882a593Smuzhiyun [ID_AD5693] = {
384*4882a593Smuzhiyun .channels = ad5693_channels,
385*4882a593Smuzhiyun .num_channels = 1,
386*4882a593Smuzhiyun .regmap_type = AD5693_REGMAP,
387*4882a593Smuzhiyun },
388*4882a593Smuzhiyun [ID_AD5693R] = {
389*4882a593Smuzhiyun .channels = ad5693_channels,
390*4882a593Smuzhiyun .int_vref_mv = 2500,
391*4882a593Smuzhiyun .num_channels = 1,
392*4882a593Smuzhiyun .regmap_type = AD5693_REGMAP,
393*4882a593Smuzhiyun },
394*4882a593Smuzhiyun [ID_AD5694] = {
395*4882a593Smuzhiyun .channels = ad5684_channels,
396*4882a593Smuzhiyun .num_channels = 4,
397*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
398*4882a593Smuzhiyun },
399*4882a593Smuzhiyun [ID_AD5694R] = {
400*4882a593Smuzhiyun .channels = ad5684_channels,
401*4882a593Smuzhiyun .int_vref_mv = 2500,
402*4882a593Smuzhiyun .num_channels = 4,
403*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
404*4882a593Smuzhiyun },
405*4882a593Smuzhiyun [ID_AD5696] = {
406*4882a593Smuzhiyun .channels = ad5686_channels,
407*4882a593Smuzhiyun .num_channels = 4,
408*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
409*4882a593Smuzhiyun },
410*4882a593Smuzhiyun [ID_AD5696R] = {
411*4882a593Smuzhiyun .channels = ad5686_channels,
412*4882a593Smuzhiyun .int_vref_mv = 2500,
413*4882a593Smuzhiyun .num_channels = 4,
414*4882a593Smuzhiyun .regmap_type = AD5686_REGMAP,
415*4882a593Smuzhiyun },
416*4882a593Smuzhiyun };
417*4882a593Smuzhiyun
ad5686_probe(struct device * dev,enum ad5686_supported_device_ids chip_type,const char * name,ad5686_write_func write,ad5686_read_func read)418*4882a593Smuzhiyun int ad5686_probe(struct device *dev,
419*4882a593Smuzhiyun enum ad5686_supported_device_ids chip_type,
420*4882a593Smuzhiyun const char *name, ad5686_write_func write,
421*4882a593Smuzhiyun ad5686_read_func read)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun struct ad5686_state *st;
424*4882a593Smuzhiyun struct iio_dev *indio_dev;
425*4882a593Smuzhiyun unsigned int val, ref_bit_msk;
426*4882a593Smuzhiyun u8 cmd;
427*4882a593Smuzhiyun int ret, i, voltage_uv = 0;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
430*4882a593Smuzhiyun if (indio_dev == NULL)
431*4882a593Smuzhiyun return -ENOMEM;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun st = iio_priv(indio_dev);
434*4882a593Smuzhiyun dev_set_drvdata(dev, indio_dev);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun st->dev = dev;
437*4882a593Smuzhiyun st->write = write;
438*4882a593Smuzhiyun st->read = read;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun st->reg = devm_regulator_get_optional(dev, "vcc");
441*4882a593Smuzhiyun if (!IS_ERR(st->reg)) {
442*4882a593Smuzhiyun ret = regulator_enable(st->reg);
443*4882a593Smuzhiyun if (ret)
444*4882a593Smuzhiyun return ret;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun ret = regulator_get_voltage(st->reg);
447*4882a593Smuzhiyun if (ret < 0)
448*4882a593Smuzhiyun goto error_disable_reg;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun voltage_uv = ret;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun st->chip_info = &ad5686_chip_info_tbl[chip_type];
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun if (voltage_uv)
456*4882a593Smuzhiyun st->vref_mv = voltage_uv / 1000;
457*4882a593Smuzhiyun else
458*4882a593Smuzhiyun st->vref_mv = st->chip_info->int_vref_mv;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun /* Set all the power down mode for all channels to 1K pulldown */
461*4882a593Smuzhiyun for (i = 0; i < st->chip_info->num_channels; i++)
462*4882a593Smuzhiyun st->pwr_down_mode |= (0x01 << (i * 2));
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun indio_dev->name = name;
465*4882a593Smuzhiyun indio_dev->info = &ad5686_info;
466*4882a593Smuzhiyun indio_dev->modes = INDIO_DIRECT_MODE;
467*4882a593Smuzhiyun indio_dev->channels = st->chip_info->channels;
468*4882a593Smuzhiyun indio_dev->num_channels = st->chip_info->num_channels;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun mutex_init(&st->lock);
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun switch (st->chip_info->regmap_type) {
473*4882a593Smuzhiyun case AD5310_REGMAP:
474*4882a593Smuzhiyun cmd = AD5686_CMD_CONTROL_REG;
475*4882a593Smuzhiyun ref_bit_msk = AD5310_REF_BIT_MSK;
476*4882a593Smuzhiyun st->use_internal_vref = !voltage_uv;
477*4882a593Smuzhiyun break;
478*4882a593Smuzhiyun case AD5683_REGMAP:
479*4882a593Smuzhiyun cmd = AD5686_CMD_CONTROL_REG;
480*4882a593Smuzhiyun ref_bit_msk = AD5683_REF_BIT_MSK;
481*4882a593Smuzhiyun st->use_internal_vref = !voltage_uv;
482*4882a593Smuzhiyun break;
483*4882a593Smuzhiyun case AD5686_REGMAP:
484*4882a593Smuzhiyun cmd = AD5686_CMD_INTERNAL_REFER_SETUP;
485*4882a593Smuzhiyun ref_bit_msk = 0;
486*4882a593Smuzhiyun break;
487*4882a593Smuzhiyun case AD5693_REGMAP:
488*4882a593Smuzhiyun cmd = AD5686_CMD_CONTROL_REG;
489*4882a593Smuzhiyun ref_bit_msk = AD5693_REF_BIT_MSK;
490*4882a593Smuzhiyun st->use_internal_vref = !voltage_uv;
491*4882a593Smuzhiyun break;
492*4882a593Smuzhiyun default:
493*4882a593Smuzhiyun ret = -EINVAL;
494*4882a593Smuzhiyun goto error_disable_reg;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun val = (voltage_uv | ref_bit_msk);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun ret = st->write(st, cmd, 0, !!val);
500*4882a593Smuzhiyun if (ret)
501*4882a593Smuzhiyun goto error_disable_reg;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun ret = iio_device_register(indio_dev);
504*4882a593Smuzhiyun if (ret)
505*4882a593Smuzhiyun goto error_disable_reg;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun return 0;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun error_disable_reg:
510*4882a593Smuzhiyun if (!IS_ERR(st->reg))
511*4882a593Smuzhiyun regulator_disable(st->reg);
512*4882a593Smuzhiyun return ret;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ad5686_probe);
515*4882a593Smuzhiyun
ad5686_remove(struct device * dev)516*4882a593Smuzhiyun int ad5686_remove(struct device *dev)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun struct iio_dev *indio_dev = dev_get_drvdata(dev);
519*4882a593Smuzhiyun struct ad5686_state *st = iio_priv(indio_dev);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun iio_device_unregister(indio_dev);
522*4882a593Smuzhiyun if (!IS_ERR(st->reg))
523*4882a593Smuzhiyun regulator_disable(st->reg);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun return 0;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ad5686_remove);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
530*4882a593Smuzhiyun MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
531*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
532