1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * ti-dac082s085.c - Texas Instruments 8/10/12-bit 2/4-channel DAC driver |
4 | * |
5 | * Copyright (C) 2017 KUNBUS GmbH |
6 | * |
7 | * https://www.ti.com/lit/ds/symlink/dac082s085.pdf |
8 | * https://www.ti.com/lit/ds/symlink/dac102s085.pdf |
9 | * https://www.ti.com/lit/ds/symlink/dac122s085.pdf |
10 | * https://www.ti.com/lit/ds/symlink/dac084s085.pdf |
11 | * https://www.ti.com/lit/ds/symlink/dac104s085.pdf |
12 | * https://www.ti.com/lit/ds/symlink/dac124s085.pdf |
13 | */ |
14 | |
15 | #include <linux/iio/iio.h> |
16 | #include <linux/module.h> |
17 | #include <linux/mod_devicetable.h> |
18 | #include <linux/regulator/consumer.h> |
19 | #include <linux/spi/spi.h> |
20 | |
21 | enum { dual_8bit, dual_10bit, dual_12bit, quad_8bit, quad_10bit, quad_12bit }; |
22 | |
23 | struct ti_dac_spec { |
24 | u8 num_channels; |
25 | u8 resolution; |
26 | }; |
27 | |
28 | static const struct ti_dac_spec ti_dac_spec[] = { |
29 | [dual_8bit] = { .num_channels = 2, .resolution = 8 }, |
30 | [dual_10bit] = { .num_channels = 2, .resolution = 10 }, |
31 | [dual_12bit] = { .num_channels = 2, .resolution = 12 }, |
32 | [quad_8bit] = { .num_channels = 4, .resolution = 8 }, |
33 | [quad_10bit] = { .num_channels = 4, .resolution = 10 }, |
34 | [quad_12bit] = { .num_channels = 4, .resolution = 12 }, |
35 | }; |
36 | |
37 | /** |
38 | * struct ti_dac_chip - TI DAC chip |
39 | * @lock: protects write sequences |
40 | * @vref: regulator generating Vref |
41 | * @mesg: SPI message to perform a write |
42 | * @xfer: SPI transfer used by @mesg |
43 | * @val: cached value of each output |
44 | * @powerdown: whether the chip is powered down |
45 | * @powerdown_mode: selected by the user |
46 | * @resolution: resolution of the chip |
47 | * @buf: buffer for @xfer |
48 | */ |
49 | struct ti_dac_chip { |
50 | struct mutex lock; |
51 | struct regulator *vref; |
52 | struct spi_message mesg; |
53 | struct spi_transfer xfer; |
54 | u16 val[4]; |
55 | bool powerdown; |
56 | u8 powerdown_mode; |
57 | u8 resolution; |
58 | u8 buf[2] __aligned(IIO_DMA_MINALIGN); |
59 | }; |
60 | |
61 | #define WRITE_NOT_UPDATE(chan) (0x00 | (chan) << 6) |
62 | #define WRITE_AND_UPDATE(chan) (0x10 | (chan) << 6) |
63 | #define WRITE_ALL_UPDATE 0x20 |
64 | #define POWERDOWN(mode) (0x30 | ((mode) + 1) << 6) |
65 | |
66 | static int ti_dac_cmd(struct ti_dac_chip *ti_dac, u8 cmd, u16 val) |
67 | { |
68 | u8 shift = 12 - ti_dac->resolution; |
69 | |
70 | ti_dac->buf[0] = cmd | (val >> (8 - shift)); |
71 | ti_dac->buf[1] = (val << shift) & 0xff; |
72 | return spi_sync(spi: ti_dac->mesg.spi, message: &ti_dac->mesg); |
73 | } |
74 | |
75 | static const char * const ti_dac_powerdown_modes[] = { |
76 | "2.5kohm_to_gnd" , "100kohm_to_gnd" , "three_state" , |
77 | }; |
78 | |
79 | static int ti_dac_get_powerdown_mode(struct iio_dev *indio_dev, |
80 | const struct iio_chan_spec *chan) |
81 | { |
82 | struct ti_dac_chip *ti_dac = iio_priv(indio_dev); |
83 | |
84 | return ti_dac->powerdown_mode; |
85 | } |
86 | |
87 | static int ti_dac_set_powerdown_mode(struct iio_dev *indio_dev, |
88 | const struct iio_chan_spec *chan, |
89 | unsigned int mode) |
90 | { |
91 | struct ti_dac_chip *ti_dac = iio_priv(indio_dev); |
92 | int ret = 0; |
93 | |
94 | if (ti_dac->powerdown_mode == mode) |
95 | return 0; |
96 | |
97 | mutex_lock(&ti_dac->lock); |
98 | if (ti_dac->powerdown) { |
99 | ret = ti_dac_cmd(ti_dac, POWERDOWN(mode), val: 0); |
100 | if (ret) |
101 | goto out; |
102 | } |
103 | ti_dac->powerdown_mode = mode; |
104 | |
105 | out: |
106 | mutex_unlock(lock: &ti_dac->lock); |
107 | return ret; |
108 | } |
109 | |
110 | static const struct iio_enum ti_dac_powerdown_mode = { |
111 | .items = ti_dac_powerdown_modes, |
112 | .num_items = ARRAY_SIZE(ti_dac_powerdown_modes), |
113 | .get = ti_dac_get_powerdown_mode, |
114 | .set = ti_dac_set_powerdown_mode, |
115 | }; |
116 | |
117 | static ssize_t ti_dac_read_powerdown(struct iio_dev *indio_dev, |
118 | uintptr_t private, |
119 | const struct iio_chan_spec *chan, |
120 | char *buf) |
121 | { |
122 | struct ti_dac_chip *ti_dac = iio_priv(indio_dev); |
123 | |
124 | return sysfs_emit(buf, fmt: "%d\n" , ti_dac->powerdown); |
125 | } |
126 | |
127 | static ssize_t ti_dac_write_powerdown(struct iio_dev *indio_dev, |
128 | uintptr_t private, |
129 | const struct iio_chan_spec *chan, |
130 | const char *buf, size_t len) |
131 | { |
132 | struct ti_dac_chip *ti_dac = iio_priv(indio_dev); |
133 | bool powerdown; |
134 | int ret; |
135 | |
136 | ret = kstrtobool(s: buf, res: &powerdown); |
137 | if (ret) |
138 | return ret; |
139 | |
140 | if (ti_dac->powerdown == powerdown) |
141 | return len; |
142 | |
143 | mutex_lock(&ti_dac->lock); |
144 | if (powerdown) |
145 | ret = ti_dac_cmd(ti_dac, POWERDOWN(ti_dac->powerdown_mode), val: 0); |
146 | else |
147 | ret = ti_dac_cmd(ti_dac, WRITE_AND_UPDATE(0), val: ti_dac->val[0]); |
148 | if (!ret) |
149 | ti_dac->powerdown = powerdown; |
150 | mutex_unlock(lock: &ti_dac->lock); |
151 | |
152 | return ret ? ret : len; |
153 | } |
154 | |
155 | static const struct iio_chan_spec_ext_info ti_dac_ext_info[] = { |
156 | { |
157 | .name = "powerdown" , |
158 | .read = ti_dac_read_powerdown, |
159 | .write = ti_dac_write_powerdown, |
160 | .shared = IIO_SHARED_BY_TYPE, |
161 | }, |
162 | IIO_ENUM("powerdown_mode" , IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode), |
163 | IIO_ENUM_AVAILABLE("powerdown_mode" , IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode), |
164 | { }, |
165 | }; |
166 | |
167 | #define TI_DAC_CHANNEL(chan) { \ |
168 | .type = IIO_VOLTAGE, \ |
169 | .channel = (chan), \ |
170 | .address = (chan), \ |
171 | .indexed = true, \ |
172 | .output = true, \ |
173 | .datasheet_name = (const char[]){ 'A' + (chan), 0 }, \ |
174 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
175 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
176 | .ext_info = ti_dac_ext_info, \ |
177 | } |
178 | |
179 | static const struct iio_chan_spec ti_dac_channels[] = { |
180 | TI_DAC_CHANNEL(0), |
181 | TI_DAC_CHANNEL(1), |
182 | TI_DAC_CHANNEL(2), |
183 | TI_DAC_CHANNEL(3), |
184 | }; |
185 | |
186 | static int ti_dac_read_raw(struct iio_dev *indio_dev, |
187 | struct iio_chan_spec const *chan, |
188 | int *val, int *val2, long mask) |
189 | { |
190 | struct ti_dac_chip *ti_dac = iio_priv(indio_dev); |
191 | int ret; |
192 | |
193 | switch (mask) { |
194 | case IIO_CHAN_INFO_RAW: |
195 | *val = ti_dac->val[chan->channel]; |
196 | ret = IIO_VAL_INT; |
197 | break; |
198 | |
199 | case IIO_CHAN_INFO_SCALE: |
200 | ret = regulator_get_voltage(regulator: ti_dac->vref); |
201 | if (ret < 0) |
202 | return ret; |
203 | |
204 | *val = ret / 1000; |
205 | *val2 = ti_dac->resolution; |
206 | ret = IIO_VAL_FRACTIONAL_LOG2; |
207 | break; |
208 | |
209 | default: |
210 | ret = -EINVAL; |
211 | } |
212 | |
213 | return ret; |
214 | } |
215 | |
216 | static int ti_dac_write_raw(struct iio_dev *indio_dev, |
217 | struct iio_chan_spec const *chan, |
218 | int val, int val2, long mask) |
219 | { |
220 | struct ti_dac_chip *ti_dac = iio_priv(indio_dev); |
221 | int ret; |
222 | |
223 | switch (mask) { |
224 | case IIO_CHAN_INFO_RAW: |
225 | if (ti_dac->val[chan->channel] == val) |
226 | return 0; |
227 | |
228 | if (val >= (1 << ti_dac->resolution) || val < 0) |
229 | return -EINVAL; |
230 | |
231 | if (ti_dac->powerdown) |
232 | return -EBUSY; |
233 | |
234 | mutex_lock(&ti_dac->lock); |
235 | ret = ti_dac_cmd(ti_dac, WRITE_AND_UPDATE(chan->channel), val); |
236 | if (!ret) |
237 | ti_dac->val[chan->channel] = val; |
238 | mutex_unlock(lock: &ti_dac->lock); |
239 | break; |
240 | |
241 | default: |
242 | ret = -EINVAL; |
243 | } |
244 | |
245 | return ret; |
246 | } |
247 | |
248 | static int ti_dac_write_raw_get_fmt(struct iio_dev *indio_dev, |
249 | struct iio_chan_spec const *chan, long mask) |
250 | { |
251 | return IIO_VAL_INT; |
252 | } |
253 | |
254 | static const struct iio_info ti_dac_info = { |
255 | .read_raw = ti_dac_read_raw, |
256 | .write_raw = ti_dac_write_raw, |
257 | .write_raw_get_fmt = ti_dac_write_raw_get_fmt, |
258 | }; |
259 | |
260 | static int ti_dac_probe(struct spi_device *spi) |
261 | { |
262 | struct device *dev = &spi->dev; |
263 | const struct ti_dac_spec *spec; |
264 | struct ti_dac_chip *ti_dac; |
265 | struct iio_dev *indio_dev; |
266 | int ret; |
267 | |
268 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*ti_dac)); |
269 | if (!indio_dev) |
270 | return -ENOMEM; |
271 | |
272 | indio_dev->info = &ti_dac_info; |
273 | indio_dev->name = spi->modalias; |
274 | indio_dev->modes = INDIO_DIRECT_MODE; |
275 | indio_dev->channels = ti_dac_channels; |
276 | spi_set_drvdata(spi, data: indio_dev); |
277 | |
278 | ti_dac = iio_priv(indio_dev); |
279 | ti_dac->xfer.tx_buf = &ti_dac->buf; |
280 | ti_dac->xfer.len = sizeof(ti_dac->buf); |
281 | spi_message_init_with_transfers(m: &ti_dac->mesg, xfers: &ti_dac->xfer, num_xfers: 1); |
282 | ti_dac->mesg.spi = spi; |
283 | |
284 | spec = &ti_dac_spec[spi_get_device_id(sdev: spi)->driver_data]; |
285 | indio_dev->num_channels = spec->num_channels; |
286 | ti_dac->resolution = spec->resolution; |
287 | |
288 | ti_dac->vref = devm_regulator_get(dev, id: "vref" ); |
289 | if (IS_ERR(ptr: ti_dac->vref)) |
290 | return PTR_ERR(ptr: ti_dac->vref); |
291 | |
292 | ret = regulator_enable(regulator: ti_dac->vref); |
293 | if (ret < 0) |
294 | return ret; |
295 | |
296 | mutex_init(&ti_dac->lock); |
297 | |
298 | ret = ti_dac_cmd(ti_dac, WRITE_ALL_UPDATE, val: 0); |
299 | if (ret) { |
300 | dev_err(dev, "failed to initialize outputs to 0\n" ); |
301 | goto err; |
302 | } |
303 | |
304 | ret = iio_device_register(indio_dev); |
305 | if (ret) |
306 | goto err; |
307 | |
308 | return 0; |
309 | |
310 | err: |
311 | mutex_destroy(lock: &ti_dac->lock); |
312 | regulator_disable(regulator: ti_dac->vref); |
313 | return ret; |
314 | } |
315 | |
316 | static void ti_dac_remove(struct spi_device *spi) |
317 | { |
318 | struct iio_dev *indio_dev = spi_get_drvdata(spi); |
319 | struct ti_dac_chip *ti_dac = iio_priv(indio_dev); |
320 | |
321 | iio_device_unregister(indio_dev); |
322 | mutex_destroy(lock: &ti_dac->lock); |
323 | regulator_disable(regulator: ti_dac->vref); |
324 | } |
325 | |
326 | static const struct of_device_id ti_dac_of_id[] = { |
327 | { .compatible = "ti,dac082s085" }, |
328 | { .compatible = "ti,dac102s085" }, |
329 | { .compatible = "ti,dac122s085" }, |
330 | { .compatible = "ti,dac084s085" }, |
331 | { .compatible = "ti,dac104s085" }, |
332 | { .compatible = "ti,dac124s085" }, |
333 | { } |
334 | }; |
335 | MODULE_DEVICE_TABLE(of, ti_dac_of_id); |
336 | |
337 | static const struct spi_device_id ti_dac_spi_id[] = { |
338 | { "dac082s085" , dual_8bit }, |
339 | { "dac102s085" , dual_10bit }, |
340 | { "dac122s085" , dual_12bit }, |
341 | { "dac084s085" , quad_8bit }, |
342 | { "dac104s085" , quad_10bit }, |
343 | { "dac124s085" , quad_12bit }, |
344 | { } |
345 | }; |
346 | MODULE_DEVICE_TABLE(spi, ti_dac_spi_id); |
347 | |
348 | static struct spi_driver ti_dac_driver = { |
349 | .driver = { |
350 | .name = "ti-dac082s085" , |
351 | .of_match_table = ti_dac_of_id, |
352 | }, |
353 | .probe = ti_dac_probe, |
354 | .remove = ti_dac_remove, |
355 | .id_table = ti_dac_spi_id, |
356 | }; |
357 | module_spi_driver(ti_dac_driver); |
358 | |
359 | MODULE_AUTHOR("Lukas Wunner <lukas@wunner.de>" ); |
360 | MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 2/4-channel DAC driver" ); |
361 | MODULE_LICENSE("GPL v2" ); |
362 | |