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
,
131 .driver_module
= THIS_MODULE
,
134 static int dpot_dac_channel_max_ohms(struct iio_dev
*indio_dev
)
136 struct device
*dev
= &indio_dev
->dev
;
137 struct dpot_dac
*dac
= iio_priv(indio_dev
);
138 unsigned long long tmp
;
144 ret
= iio_read_max_channel_raw(dac
->dpot
, &max
);
146 dev_err(dev
, "dpot does not indicate its raw maximum value\n");
150 switch (iio_read_channel_scale(dac
->dpot
, &val
, &val2
)) {
153 case IIO_VAL_FRACTIONAL
:
154 tmp
= (unsigned long long)max
* val
;
157 case IIO_VAL_FRACTIONAL_LOG2
:
158 tmp
= val
* 1000000000LL * max
>> val2
;
159 do_div(tmp
, 1000000000LL);
162 dev_err(dev
, "dpot has a scale that is too weird\n");
168 static int dpot_dac_probe(struct platform_device
*pdev
)
170 struct device
*dev
= &pdev
->dev
;
171 struct iio_dev
*indio_dev
;
172 struct dpot_dac
*dac
;
173 enum iio_chan_type type
;
176 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*dac
));
180 platform_set_drvdata(pdev
, indio_dev
);
181 dac
= iio_priv(indio_dev
);
183 indio_dev
->name
= dev_name(dev
);
184 indio_dev
->dev
.parent
= dev
;
185 indio_dev
->info
= &dpot_dac_info
;
186 indio_dev
->modes
= INDIO_DIRECT_MODE
;
187 indio_dev
->channels
= &dpot_dac_iio_channel
;
188 indio_dev
->num_channels
= 1;
190 dac
->vref
= devm_regulator_get(dev
, "vref");
191 if (IS_ERR(dac
->vref
)) {
192 if (PTR_ERR(dac
->vref
) != -EPROBE_DEFER
)
193 dev_err(&pdev
->dev
, "failed to get vref regulator\n");
194 return PTR_ERR(dac
->vref
);
197 dac
->dpot
= devm_iio_channel_get(dev
, "dpot");
198 if (IS_ERR(dac
->dpot
)) {
199 if (PTR_ERR(dac
->dpot
) != -EPROBE_DEFER
)
200 dev_err(dev
, "failed to get dpot input channel\n");
201 return PTR_ERR(dac
->dpot
);
204 ret
= iio_get_channel_type(dac
->dpot
, &type
);
208 if (type
!= IIO_RESISTANCE
) {
209 dev_err(dev
, "dpot is of the wrong type\n");
213 ret
= dpot_dac_channel_max_ohms(indio_dev
);
218 ret
= regulator_enable(dac
->vref
);
220 dev_err(dev
, "failed to enable the vref regulator\n");
224 ret
= iio_device_register(indio_dev
);
226 dev_err(dev
, "failed to register iio device\n");
233 regulator_disable(dac
->vref
);
237 static int dpot_dac_remove(struct platform_device
*pdev
)
239 struct iio_dev
*indio_dev
= platform_get_drvdata(pdev
);
240 struct dpot_dac
*dac
= iio_priv(indio_dev
);
242 iio_device_unregister(indio_dev
);
243 regulator_disable(dac
->vref
);
248 static const struct of_device_id dpot_dac_match
[] = {
249 { .compatible
= "dpot-dac" },
252 MODULE_DEVICE_TABLE(of
, dpot_dac_match
);
254 static struct platform_driver dpot_dac_driver
= {
255 .probe
= dpot_dac_probe
,
256 .remove
= dpot_dac_remove
,
258 .name
= "iio-dpot-dac",
259 .of_match_table
= dpot_dac_match
,
262 module_platform_driver(dpot_dac_driver
);
264 MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer");
265 MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
266 MODULE_LICENSE("GPL v2");