2 * IIO DAC emulation driver using a digital potentiometer
4 * Copyright (C) 2016 Axentia Technologies AB
6 * Author: Peter Rosin <peda@axentia.se>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
14 * It is assumed that the dpot is used as a voltage divider between the
15 * current dpot wiper setting and the maximum resistance of the dpot. The
16 * divided voltage is provided by a vref regulator.
21 * | regulator |--. | |
22 * '-----------' | | d |
27 * | '---' dac output voltage
29 * '------+------------+
32 #include <linux/err.h>
33 #include <linux/iio/consumer.h>
34 #include <linux/iio/iio.h>
35 #include <linux/module.h>
37 #include <linux/platform_device.h>
38 #include <linux/regulator/consumer.h>
41 struct regulator
*vref
;
42 struct iio_channel
*dpot
;
46 static const struct iio_chan_spec dpot_dac_iio_channel
= {
48 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
)
49 | BIT(IIO_CHAN_INFO_SCALE
),
50 .info_mask_separate_available
= BIT(IIO_CHAN_INFO_RAW
),
55 static int dpot_dac_read_raw(struct iio_dev
*indio_dev
,
56 struct iio_chan_spec
const *chan
,
57 int *val
, int *val2
, long mask
)
59 struct dpot_dac
*dac
= iio_priv(indio_dev
);
61 unsigned long long tmp
;
64 case IIO_CHAN_INFO_RAW
:
65 return iio_read_channel_raw(dac
->dpot
, val
);
67 case IIO_CHAN_INFO_SCALE
:
68 ret
= iio_read_channel_scale(dac
->dpot
, val
, val2
);
70 case IIO_VAL_FRACTIONAL_LOG2
:
71 tmp
= *val
* 1000000000LL;
72 do_div(tmp
, dac
->max_ohms
);
73 tmp
*= regulator_get_voltage(dac
->vref
) / 1000;
74 do_div(tmp
, 1000000000LL);
79 * Convert integer scale to fractional scale by
80 * setting the denominator (val2) to one...
83 ret
= IIO_VAL_FRACTIONAL
;
84 /* ...and fall through. */
85 case IIO_VAL_FRACTIONAL
:
86 *val
*= regulator_get_voltage(dac
->vref
) / 1000;
87 *val2
*= dac
->max_ohms
;
97 static int dpot_dac_read_avail(struct iio_dev
*indio_dev
,
98 struct iio_chan_spec
const *chan
,
99 const int **vals
, int *type
, int *length
,
102 struct dpot_dac
*dac
= iio_priv(indio_dev
);
105 case IIO_CHAN_INFO_RAW
:
107 return iio_read_avail_channel_raw(dac
->dpot
, vals
, length
);
113 static int dpot_dac_write_raw(struct iio_dev
*indio_dev
,
114 struct iio_chan_spec
const *chan
,
115 int val
, int val2
, long mask
)
117 struct dpot_dac
*dac
= iio_priv(indio_dev
);
120 case IIO_CHAN_INFO_RAW
:
121 return iio_write_channel_raw(dac
->dpot
, val
);
127 static const struct iio_info dpot_dac_info
= {
128 .read_raw
= dpot_dac_read_raw
,
129 .read_avail
= dpot_dac_read_avail
,
130 .write_raw
= dpot_dac_write_raw
,
133 static int dpot_dac_channel_max_ohms(struct iio_dev
*indio_dev
)
135 struct device
*dev
= &indio_dev
->dev
;
136 struct dpot_dac
*dac
= iio_priv(indio_dev
);
137 unsigned long long tmp
;
143 ret
= iio_read_max_channel_raw(dac
->dpot
, &max
);
145 dev_err(dev
, "dpot does not indicate its raw maximum value\n");
149 switch (iio_read_channel_scale(dac
->dpot
, &val
, &val2
)) {
152 case IIO_VAL_FRACTIONAL
:
153 tmp
= (unsigned long long)max
* val
;
156 case IIO_VAL_FRACTIONAL_LOG2
:
157 tmp
= val
* 1000000000LL * max
>> val2
;
158 do_div(tmp
, 1000000000LL);
161 dev_err(dev
, "dpot has a scale that is too weird\n");
167 static int dpot_dac_probe(struct platform_device
*pdev
)
169 struct device
*dev
= &pdev
->dev
;
170 struct iio_dev
*indio_dev
;
171 struct dpot_dac
*dac
;
172 enum iio_chan_type type
;
175 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*dac
));
179 platform_set_drvdata(pdev
, indio_dev
);
180 dac
= iio_priv(indio_dev
);
182 indio_dev
->name
= dev_name(dev
);
183 indio_dev
->dev
.parent
= dev
;
184 indio_dev
->info
= &dpot_dac_info
;
185 indio_dev
->modes
= INDIO_DIRECT_MODE
;
186 indio_dev
->channels
= &dpot_dac_iio_channel
;
187 indio_dev
->num_channels
= 1;
189 dac
->vref
= devm_regulator_get(dev
, "vref");
190 if (IS_ERR(dac
->vref
)) {
191 if (PTR_ERR(dac
->vref
) != -EPROBE_DEFER
)
192 dev_err(&pdev
->dev
, "failed to get vref regulator\n");
193 return PTR_ERR(dac
->vref
);
196 dac
->dpot
= devm_iio_channel_get(dev
, "dpot");
197 if (IS_ERR(dac
->dpot
)) {
198 if (PTR_ERR(dac
->dpot
) != -EPROBE_DEFER
)
199 dev_err(dev
, "failed to get dpot input channel\n");
200 return PTR_ERR(dac
->dpot
);
203 ret
= iio_get_channel_type(dac
->dpot
, &type
);
207 if (type
!= IIO_RESISTANCE
) {
208 dev_err(dev
, "dpot is of the wrong type\n");
212 ret
= dpot_dac_channel_max_ohms(indio_dev
);
217 ret
= regulator_enable(dac
->vref
);
219 dev_err(dev
, "failed to enable the vref regulator\n");
223 ret
= iio_device_register(indio_dev
);
225 dev_err(dev
, "failed to register iio device\n");
232 regulator_disable(dac
->vref
);
236 static int dpot_dac_remove(struct platform_device
*pdev
)
238 struct iio_dev
*indio_dev
= platform_get_drvdata(pdev
);
239 struct dpot_dac
*dac
= iio_priv(indio_dev
);
241 iio_device_unregister(indio_dev
);
242 regulator_disable(dac
->vref
);
247 static const struct of_device_id dpot_dac_match
[] = {
248 { .compatible
= "dpot-dac" },
251 MODULE_DEVICE_TABLE(of
, dpot_dac_match
);
253 static struct platform_driver dpot_dac_driver
= {
254 .probe
= dpot_dac_probe
,
255 .remove
= dpot_dac_remove
,
257 .name
= "iio-dpot-dac",
258 .of_match_table
= dpot_dac_match
,
261 module_platform_driver(dpot_dac_driver
);
263 MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer");
264 MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
265 MODULE_LICENSE("GPL v2");