1 // SPDX-License-Identifier: GPL-2.0
3 * IIO DAC emulation driver using a digital potentiometer
5 * Copyright (C) 2016 Axentia Technologies AB
7 * Author: Peter Rosin <peda@axentia.se>
11 * It is assumed that the dpot is used as a voltage divider between the
12 * current dpot wiper setting and the maximum resistance of the dpot. The
13 * divided voltage is provided by a vref regulator.
18 * | regulator |--. | |
19 * '-----------' | | d |
24 * | '---' dac output voltage
26 * '------+------------+
29 #include <linux/err.h>
30 #include <linux/iio/consumer.h>
31 #include <linux/iio/iio.h>
32 #include <linux/module.h>
34 #include <linux/platform_device.h>
35 #include <linux/regulator/consumer.h>
38 struct regulator
*vref
;
39 struct iio_channel
*dpot
;
43 static const struct iio_chan_spec dpot_dac_iio_channel
= {
45 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
)
46 | BIT(IIO_CHAN_INFO_SCALE
),
47 .info_mask_separate_available
= BIT(IIO_CHAN_INFO_RAW
),
52 static int dpot_dac_read_raw(struct iio_dev
*indio_dev
,
53 struct iio_chan_spec
const *chan
,
54 int *val
, int *val2
, long mask
)
56 struct dpot_dac
*dac
= iio_priv(indio_dev
);
58 unsigned long long tmp
;
61 case IIO_CHAN_INFO_RAW
:
62 return iio_read_channel_raw(dac
->dpot
, val
);
64 case IIO_CHAN_INFO_SCALE
:
65 ret
= iio_read_channel_scale(dac
->dpot
, val
, val2
);
67 case IIO_VAL_FRACTIONAL_LOG2
:
68 tmp
= *val
* 1000000000LL;
69 do_div(tmp
, dac
->max_ohms
);
70 tmp
*= regulator_get_voltage(dac
->vref
) / 1000;
71 do_div(tmp
, 1000000000LL);
76 * Convert integer scale to fractional scale by
77 * setting the denominator (val2) to one, and...
80 ret
= IIO_VAL_FRACTIONAL
;
82 case IIO_VAL_FRACTIONAL
:
83 *val
*= regulator_get_voltage(dac
->vref
) / 1000;
84 *val2
*= dac
->max_ohms
;
94 static int dpot_dac_read_avail(struct iio_dev
*indio_dev
,
95 struct iio_chan_spec
const *chan
,
96 const int **vals
, int *type
, int *length
,
99 struct dpot_dac
*dac
= iio_priv(indio_dev
);
102 case IIO_CHAN_INFO_RAW
:
104 return iio_read_avail_channel_raw(dac
->dpot
, vals
, length
);
110 static int dpot_dac_write_raw(struct iio_dev
*indio_dev
,
111 struct iio_chan_spec
const *chan
,
112 int val
, int val2
, long mask
)
114 struct dpot_dac
*dac
= iio_priv(indio_dev
);
117 case IIO_CHAN_INFO_RAW
:
118 return iio_write_channel_raw(dac
->dpot
, val
);
124 static const struct iio_info dpot_dac_info
= {
125 .read_raw
= dpot_dac_read_raw
,
126 .read_avail
= dpot_dac_read_avail
,
127 .write_raw
= dpot_dac_write_raw
,
130 static int dpot_dac_channel_max_ohms(struct iio_dev
*indio_dev
)
132 struct device
*dev
= &indio_dev
->dev
;
133 struct dpot_dac
*dac
= iio_priv(indio_dev
);
134 unsigned long long tmp
;
140 ret
= iio_read_max_channel_raw(dac
->dpot
, &max
);
142 dev_err(dev
, "dpot does not indicate its raw maximum value\n");
146 switch (iio_read_channel_scale(dac
->dpot
, &val
, &val2
)) {
149 case IIO_VAL_FRACTIONAL
:
150 tmp
= (unsigned long long)max
* val
;
153 case IIO_VAL_FRACTIONAL_LOG2
:
154 tmp
= val
* 1000000000LL * max
>> val2
;
155 do_div(tmp
, 1000000000LL);
158 dev_err(dev
, "dpot has a scale that is too weird\n");
164 static int dpot_dac_probe(struct platform_device
*pdev
)
166 struct device
*dev
= &pdev
->dev
;
167 struct iio_dev
*indio_dev
;
168 struct dpot_dac
*dac
;
169 enum iio_chan_type type
;
172 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*dac
));
176 platform_set_drvdata(pdev
, indio_dev
);
177 dac
= iio_priv(indio_dev
);
179 indio_dev
->name
= dev_name(dev
);
180 indio_dev
->dev
.parent
= dev
;
181 indio_dev
->info
= &dpot_dac_info
;
182 indio_dev
->modes
= INDIO_DIRECT_MODE
;
183 indio_dev
->channels
= &dpot_dac_iio_channel
;
184 indio_dev
->num_channels
= 1;
186 dac
->vref
= devm_regulator_get(dev
, "vref");
187 if (IS_ERR(dac
->vref
)) {
188 if (PTR_ERR(dac
->vref
) != -EPROBE_DEFER
)
189 dev_err(&pdev
->dev
, "failed to get vref regulator\n");
190 return PTR_ERR(dac
->vref
);
193 dac
->dpot
= devm_iio_channel_get(dev
, "dpot");
194 if (IS_ERR(dac
->dpot
)) {
195 if (PTR_ERR(dac
->dpot
) != -EPROBE_DEFER
)
196 dev_err(dev
, "failed to get dpot input channel\n");
197 return PTR_ERR(dac
->dpot
);
200 ret
= iio_get_channel_type(dac
->dpot
, &type
);
204 if (type
!= IIO_RESISTANCE
) {
205 dev_err(dev
, "dpot is of the wrong type\n");
209 ret
= dpot_dac_channel_max_ohms(indio_dev
);
214 ret
= regulator_enable(dac
->vref
);
216 dev_err(dev
, "failed to enable the vref regulator\n");
220 ret
= iio_device_register(indio_dev
);
222 dev_err(dev
, "failed to register iio device\n");
229 regulator_disable(dac
->vref
);
233 static int dpot_dac_remove(struct platform_device
*pdev
)
235 struct iio_dev
*indio_dev
= platform_get_drvdata(pdev
);
236 struct dpot_dac
*dac
= iio_priv(indio_dev
);
238 iio_device_unregister(indio_dev
);
239 regulator_disable(dac
->vref
);
244 static const struct of_device_id dpot_dac_match
[] = {
245 { .compatible
= "dpot-dac" },
248 MODULE_DEVICE_TABLE(of
, dpot_dac_match
);
250 static struct platform_driver dpot_dac_driver
= {
251 .probe
= dpot_dac_probe
,
252 .remove
= dpot_dac_remove
,
254 .name
= "iio-dpot-dac",
255 .of_match_table
= dpot_dac_match
,
258 module_platform_driver(dpot_dac_driver
);
260 MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer");
261 MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
262 MODULE_LICENSE("GPL v2");