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...
80 ret
= IIO_VAL_FRACTIONAL
;
81 /* ...and fall through. Say it again for GCC. */
83 case IIO_VAL_FRACTIONAL
:
84 *val
*= regulator_get_voltage(dac
->vref
) / 1000;
85 *val2
*= dac
->max_ohms
;
95 static int dpot_dac_read_avail(struct iio_dev
*indio_dev
,
96 struct iio_chan_spec
const *chan
,
97 const int **vals
, int *type
, int *length
,
100 struct dpot_dac
*dac
= iio_priv(indio_dev
);
103 case IIO_CHAN_INFO_RAW
:
105 return iio_read_avail_channel_raw(dac
->dpot
, vals
, length
);
111 static int dpot_dac_write_raw(struct iio_dev
*indio_dev
,
112 struct iio_chan_spec
const *chan
,
113 int val
, int val2
, long mask
)
115 struct dpot_dac
*dac
= iio_priv(indio_dev
);
118 case IIO_CHAN_INFO_RAW
:
119 return iio_write_channel_raw(dac
->dpot
, val
);
125 static const struct iio_info dpot_dac_info
= {
126 .read_raw
= dpot_dac_read_raw
,
127 .read_avail
= dpot_dac_read_avail
,
128 .write_raw
= dpot_dac_write_raw
,
131 static int dpot_dac_channel_max_ohms(struct iio_dev
*indio_dev
)
133 struct device
*dev
= &indio_dev
->dev
;
134 struct dpot_dac
*dac
= iio_priv(indio_dev
);
135 unsigned long long tmp
;
141 ret
= iio_read_max_channel_raw(dac
->dpot
, &max
);
143 dev_err(dev
, "dpot does not indicate its raw maximum value\n");
147 switch (iio_read_channel_scale(dac
->dpot
, &val
, &val2
)) {
150 case IIO_VAL_FRACTIONAL
:
151 tmp
= (unsigned long long)max
* val
;
154 case IIO_VAL_FRACTIONAL_LOG2
:
155 tmp
= val
* 1000000000LL * max
>> val2
;
156 do_div(tmp
, 1000000000LL);
159 dev_err(dev
, "dpot has a scale that is too weird\n");
165 static int dpot_dac_probe(struct platform_device
*pdev
)
167 struct device
*dev
= &pdev
->dev
;
168 struct iio_dev
*indio_dev
;
169 struct dpot_dac
*dac
;
170 enum iio_chan_type type
;
173 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*dac
));
177 platform_set_drvdata(pdev
, indio_dev
);
178 dac
= iio_priv(indio_dev
);
180 indio_dev
->name
= dev_name(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 return dev_err_probe(&pdev
->dev
, PTR_ERR(dac
->vref
),
189 "failed to get vref regulator\n");
191 dac
->dpot
= devm_iio_channel_get(dev
, "dpot");
192 if (IS_ERR(dac
->dpot
))
193 return dev_err_probe(&pdev
->dev
, PTR_ERR(dac
->dpot
),
194 "failed to get dpot input channel\n");
196 ret
= iio_get_channel_type(dac
->dpot
, &type
);
200 if (type
!= IIO_RESISTANCE
) {
201 dev_err(dev
, "dpot is of the wrong type\n");
205 ret
= dpot_dac_channel_max_ohms(indio_dev
);
210 ret
= regulator_enable(dac
->vref
);
212 dev_err(dev
, "failed to enable the vref regulator\n");
216 ret
= iio_device_register(indio_dev
);
218 dev_err(dev
, "failed to register iio device\n");
225 regulator_disable(dac
->vref
);
229 static int dpot_dac_remove(struct platform_device
*pdev
)
231 struct iio_dev
*indio_dev
= platform_get_drvdata(pdev
);
232 struct dpot_dac
*dac
= iio_priv(indio_dev
);
234 iio_device_unregister(indio_dev
);
235 regulator_disable(dac
->vref
);
240 static const struct of_device_id dpot_dac_match
[] = {
241 { .compatible
= "dpot-dac" },
244 MODULE_DEVICE_TABLE(of
, dpot_dac_match
);
246 static struct platform_driver dpot_dac_driver
= {
247 .probe
= dpot_dac_probe
,
248 .remove
= dpot_dac_remove
,
250 .name
= "iio-dpot-dac",
251 .of_match_table
= dpot_dac_match
,
254 module_platform_driver(dpot_dac_driver
);
256 MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer");
257 MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
258 MODULE_LICENSE("GPL v2");