1// SPDX-License-Identifier: GPL-2.0
2/*
3 * IIO DAC emulation driver using a digital potentiometer
4 *
5 * Copyright (C) 2016 Axentia Technologies AB
6 *
7 * Author: Peter Rosin <peda@axentia.se>
8 */
9
10/*
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.
14 *
15 *                   .------.
16 *    .-----------.  |      |
17 *    | vref      |--'    .---.
18 *    | regulator |--.    |   |
19 *    '-----------'  |    | d |
20 *                   |    | p |
21 *                   |    | o |  wiper
22 *                   |    | t |<---------+
23 *                   |    |   |
24 *                   |    '---'       dac output voltage
25 *                   |      |
26 *                   '------+------------+
27 */
28
29#include <linux/err.h>
30#include <linux/iio/consumer.h>
31#include <linux/iio/iio.h>
32#include <linux/module.h>
33#include <linux/mod_devicetable.h>
34#include <linux/platform_device.h>
35#include <linux/regulator/consumer.h>
36
37struct dpot_dac {
38	struct regulator *vref;
39	struct iio_channel *dpot;
40	u32 max_ohms;
41};
42
43static const struct iio_chan_spec dpot_dac_iio_channel = {
44	.type = IIO_VOLTAGE,
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),
48	.output = 1,
49	.indexed = 1,
50};
51
52static int dpot_dac_read_raw(struct iio_dev *indio_dev,
53			     struct iio_chan_spec const *chan,
54			     int *val, int *val2, long mask)
55{
56	struct dpot_dac *dac = iio_priv(indio_dev);
57	int ret;
58	unsigned long long tmp;
59
60	switch (mask) {
61	case IIO_CHAN_INFO_RAW:
62		return iio_read_channel_raw(dac->dpot, val);
63
64	case IIO_CHAN_INFO_SCALE:
65		ret = iio_read_channel_scale(dac->dpot, val, val2);
66		switch (ret) {
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);
72			*val = tmp;
73			return ret;
74		case IIO_VAL_INT:
75			/*
76			 * Convert integer scale to fractional scale by
77			 * setting the denominator (val2) to one...
78			 */
79			*val2 = 1;
80			ret = IIO_VAL_FRACTIONAL;
81			/* ...and fall through. Say it again for GCC. */
82			fallthrough;
83		case IIO_VAL_FRACTIONAL:
84			*val *= regulator_get_voltage(dac->vref) / 1000;
85			*val2 *= dac->max_ohms;
86			break;
87		}
88
89		return ret;
90	}
91
92	return -EINVAL;
93}
94
95static 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,
98			       long mask)
99{
100	struct dpot_dac *dac = iio_priv(indio_dev);
101
102	switch (mask) {
103	case IIO_CHAN_INFO_RAW:
104		*type = IIO_VAL_INT;
105		return iio_read_avail_channel_raw(dac->dpot, vals, length);
106	}
107
108	return -EINVAL;
109}
110
111static int dpot_dac_write_raw(struct iio_dev *indio_dev,
112			      struct iio_chan_spec const *chan,
113			      int val, int val2, long mask)
114{
115	struct dpot_dac *dac = iio_priv(indio_dev);
116
117	switch (mask) {
118	case IIO_CHAN_INFO_RAW:
119		return iio_write_channel_raw(dac->dpot, val);
120	}
121
122	return -EINVAL;
123}
124
125static 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,
129};
130
131static int dpot_dac_channel_max_ohms(struct iio_dev *indio_dev)
132{
133	struct device *dev = &indio_dev->dev;
134	struct dpot_dac *dac = iio_priv(indio_dev);
135	unsigned long long tmp;
136	int ret;
137	int val;
138	int val2;
139	int max;
140
141	ret = iio_read_max_channel_raw(dac->dpot, &max);
142	if (ret < 0) {
143		dev_err(dev, "dpot does not indicate its raw maximum value\n");
144		return ret;
145	}
146
147	switch (iio_read_channel_scale(dac->dpot, &val, &val2)) {
148	case IIO_VAL_INT:
149		return max * val;
150	case IIO_VAL_FRACTIONAL:
151		tmp = (unsigned long long)max * val;
152		do_div(tmp, val2);
153		return tmp;
154	case IIO_VAL_FRACTIONAL_LOG2:
155		tmp = val * 1000000000LL * max >> val2;
156		do_div(tmp, 1000000000LL);
157		return tmp;
158	default:
159		dev_err(dev, "dpot has a scale that is too weird\n");
160	}
161
162	return -EINVAL;
163}
164
165static int dpot_dac_probe(struct platform_device *pdev)
166{
167	struct device *dev = &pdev->dev;
168	struct iio_dev *indio_dev;
169	struct dpot_dac *dac;
170	enum iio_chan_type type;
171	int ret;
172
173	indio_dev = devm_iio_device_alloc(dev, sizeof(*dac));
174	if (!indio_dev)
175		return -ENOMEM;
176
177	platform_set_drvdata(pdev, indio_dev);
178	dac = iio_priv(indio_dev);
179
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;
185
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");
190
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");
195
196	ret = iio_get_channel_type(dac->dpot, &type);
197	if (ret < 0)
198		return ret;
199
200	if (type != IIO_RESISTANCE) {
201		dev_err(dev, "dpot is of the wrong type\n");
202		return -EINVAL;
203	}
204
205	ret = dpot_dac_channel_max_ohms(indio_dev);
206	if (ret < 0)
207		return ret;
208	dac->max_ohms = ret;
209
210	ret = regulator_enable(dac->vref);
211	if (ret) {
212		dev_err(dev, "failed to enable the vref regulator\n");
213		return ret;
214	}
215
216	ret = iio_device_register(indio_dev);
217	if (ret) {
218		dev_err(dev, "failed to register iio device\n");
219		goto disable_reg;
220	}
221
222	return 0;
223
224disable_reg:
225	regulator_disable(dac->vref);
226	return ret;
227}
228
229static void dpot_dac_remove(struct platform_device *pdev)
230{
231	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
232	struct dpot_dac *dac = iio_priv(indio_dev);
233
234	iio_device_unregister(indio_dev);
235	regulator_disable(dac->vref);
236}
237
238static const struct of_device_id dpot_dac_match[] = {
239	{ .compatible = "dpot-dac" },
240	{ /* sentinel */ }
241};
242MODULE_DEVICE_TABLE(of, dpot_dac_match);
243
244static struct platform_driver dpot_dac_driver = {
245	.probe = dpot_dac_probe,
246	.remove_new = dpot_dac_remove,
247	.driver = {
248		.name = "iio-dpot-dac",
249		.of_match_table = dpot_dac_match,
250	},
251};
252module_platform_driver(dpot_dac_driver);
253
254MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer");
255MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
256MODULE_LICENSE("GPL v2");
257