1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * AD7303 Digital to analog converters driver |
4 | * |
5 | * Copyright 2013 Analog Devices Inc. |
6 | */ |
7 | |
8 | #include <linux/err.h> |
9 | #include <linux/module.h> |
10 | #include <linux/mod_devicetable.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/spi/spi.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/sysfs.h> |
15 | #include <linux/regulator/consumer.h> |
16 | |
17 | #include <linux/iio/iio.h> |
18 | #include <linux/iio/sysfs.h> |
19 | |
20 | #define AD7303_CFG_EXTERNAL_VREF BIT(15) |
21 | #define AD7303_CFG_POWER_DOWN(ch) BIT(11 + (ch)) |
22 | #define AD7303_CFG_ADDR_OFFSET 10 |
23 | |
24 | #define AD7303_CMD_UPDATE_DAC (0x3 << 8) |
25 | |
26 | /** |
27 | * struct ad7303_state - driver instance specific data |
28 | * @spi: the device for this driver instance |
29 | * @config: cached config register value |
30 | * @dac_cache: current DAC raw value (chip does not support readback) |
31 | * @vdd_reg: reference to VDD regulator |
32 | * @vref_reg: reference to VREF regulator |
33 | * @lock: protect writes and cache updates |
34 | * @data: spi transfer buffer |
35 | */ |
36 | |
37 | struct ad7303_state { |
38 | struct spi_device *spi; |
39 | uint16_t config; |
40 | uint8_t dac_cache[2]; |
41 | |
42 | struct regulator *vdd_reg; |
43 | struct regulator *vref_reg; |
44 | |
45 | struct mutex lock; |
46 | /* |
47 | * DMA (thus cache coherency maintenance) may require the |
48 | * transfer buffers to live in their own cache lines. |
49 | */ |
50 | __be16 data __aligned(IIO_DMA_MINALIGN); |
51 | }; |
52 | |
53 | static int ad7303_write(struct ad7303_state *st, unsigned int chan, |
54 | uint8_t val) |
55 | { |
56 | st->data = cpu_to_be16(AD7303_CMD_UPDATE_DAC | |
57 | (chan << AD7303_CFG_ADDR_OFFSET) | |
58 | st->config | val); |
59 | |
60 | return spi_write(spi: st->spi, buf: &st->data, len: sizeof(st->data)); |
61 | } |
62 | |
63 | static ssize_t ad7303_read_dac_powerdown(struct iio_dev *indio_dev, |
64 | uintptr_t private, const struct iio_chan_spec *chan, char *buf) |
65 | { |
66 | struct ad7303_state *st = iio_priv(indio_dev); |
67 | |
68 | return sysfs_emit(buf, fmt: "%d\n" , (bool)(st->config & |
69 | AD7303_CFG_POWER_DOWN(chan->channel))); |
70 | } |
71 | |
72 | static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev, |
73 | uintptr_t private, const struct iio_chan_spec *chan, const char *buf, |
74 | size_t len) |
75 | { |
76 | struct ad7303_state *st = iio_priv(indio_dev); |
77 | bool pwr_down; |
78 | int ret; |
79 | |
80 | ret = kstrtobool(s: buf, res: &pwr_down); |
81 | if (ret) |
82 | return ret; |
83 | |
84 | mutex_lock(&st->lock); |
85 | |
86 | if (pwr_down) |
87 | st->config |= AD7303_CFG_POWER_DOWN(chan->channel); |
88 | else |
89 | st->config &= ~AD7303_CFG_POWER_DOWN(chan->channel); |
90 | |
91 | /* There is no noop cmd which allows us to only update the powerdown |
92 | * mode, so just write one of the DAC channels again */ |
93 | ad7303_write(st, chan: chan->channel, val: st->dac_cache[chan->channel]); |
94 | |
95 | mutex_unlock(lock: &st->lock); |
96 | return len; |
97 | } |
98 | |
99 | static int ad7303_get_vref(struct ad7303_state *st, |
100 | struct iio_chan_spec const *chan) |
101 | { |
102 | int ret; |
103 | |
104 | if (st->config & AD7303_CFG_EXTERNAL_VREF) |
105 | return regulator_get_voltage(regulator: st->vref_reg); |
106 | |
107 | ret = regulator_get_voltage(regulator: st->vdd_reg); |
108 | if (ret < 0) |
109 | return ret; |
110 | return ret / 2; |
111 | } |
112 | |
113 | static int ad7303_read_raw(struct iio_dev *indio_dev, |
114 | struct iio_chan_spec const *chan, int *val, int *val2, long info) |
115 | { |
116 | struct ad7303_state *st = iio_priv(indio_dev); |
117 | int vref_uv; |
118 | |
119 | switch (info) { |
120 | case IIO_CHAN_INFO_RAW: |
121 | mutex_lock(&st->lock); |
122 | *val = st->dac_cache[chan->channel]; |
123 | mutex_unlock(lock: &st->lock); |
124 | return IIO_VAL_INT; |
125 | case IIO_CHAN_INFO_SCALE: |
126 | vref_uv = ad7303_get_vref(st, chan); |
127 | if (vref_uv < 0) |
128 | return vref_uv; |
129 | |
130 | *val = 2 * vref_uv / 1000; |
131 | *val2 = chan->scan_type.realbits; |
132 | |
133 | return IIO_VAL_FRACTIONAL_LOG2; |
134 | default: |
135 | break; |
136 | } |
137 | return -EINVAL; |
138 | } |
139 | |
140 | static int ad7303_write_raw(struct iio_dev *indio_dev, |
141 | struct iio_chan_spec const *chan, int val, int val2, long mask) |
142 | { |
143 | struct ad7303_state *st = iio_priv(indio_dev); |
144 | int ret; |
145 | |
146 | switch (mask) { |
147 | case IIO_CHAN_INFO_RAW: |
148 | if (val >= (1 << chan->scan_type.realbits) || val < 0) |
149 | return -EINVAL; |
150 | |
151 | mutex_lock(&st->lock); |
152 | ret = ad7303_write(st, chan: chan->address, val); |
153 | if (ret == 0) |
154 | st->dac_cache[chan->channel] = val; |
155 | mutex_unlock(lock: &st->lock); |
156 | break; |
157 | default: |
158 | ret = -EINVAL; |
159 | } |
160 | |
161 | return ret; |
162 | } |
163 | |
164 | static const struct iio_info ad7303_info = { |
165 | .read_raw = ad7303_read_raw, |
166 | .write_raw = ad7303_write_raw, |
167 | }; |
168 | |
169 | static const struct iio_chan_spec_ext_info ad7303_ext_info[] = { |
170 | { |
171 | .name = "powerdown" , |
172 | .read = ad7303_read_dac_powerdown, |
173 | .write = ad7303_write_dac_powerdown, |
174 | .shared = IIO_SEPARATE, |
175 | }, |
176 | { }, |
177 | }; |
178 | |
179 | #define AD7303_CHANNEL(chan) { \ |
180 | .type = IIO_VOLTAGE, \ |
181 | .indexed = 1, \ |
182 | .output = 1, \ |
183 | .channel = (chan), \ |
184 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
185 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
186 | .address = (chan), \ |
187 | .scan_type = { \ |
188 | .sign = 'u', \ |
189 | .realbits = 8, \ |
190 | .storagebits = 8, \ |
191 | .shift = 0, \ |
192 | }, \ |
193 | .ext_info = ad7303_ext_info, \ |
194 | } |
195 | |
196 | static const struct iio_chan_spec ad7303_channels[] = { |
197 | AD7303_CHANNEL(0), |
198 | AD7303_CHANNEL(1), |
199 | }; |
200 | |
201 | static void ad7303_reg_disable(void *reg) |
202 | { |
203 | regulator_disable(regulator: reg); |
204 | } |
205 | |
206 | static int ad7303_probe(struct spi_device *spi) |
207 | { |
208 | const struct spi_device_id *id = spi_get_device_id(sdev: spi); |
209 | struct iio_dev *indio_dev; |
210 | struct ad7303_state *st; |
211 | int ret; |
212 | |
213 | indio_dev = devm_iio_device_alloc(parent: &spi->dev, sizeof_priv: sizeof(*st)); |
214 | if (indio_dev == NULL) |
215 | return -ENOMEM; |
216 | |
217 | st = iio_priv(indio_dev); |
218 | |
219 | st->spi = spi; |
220 | |
221 | mutex_init(&st->lock); |
222 | |
223 | st->vdd_reg = devm_regulator_get(dev: &spi->dev, id: "Vdd" ); |
224 | if (IS_ERR(ptr: st->vdd_reg)) |
225 | return PTR_ERR(ptr: st->vdd_reg); |
226 | |
227 | ret = regulator_enable(regulator: st->vdd_reg); |
228 | if (ret) |
229 | return ret; |
230 | |
231 | ret = devm_add_action_or_reset(&spi->dev, ad7303_reg_disable, st->vdd_reg); |
232 | if (ret) |
233 | return ret; |
234 | |
235 | st->vref_reg = devm_regulator_get_optional(dev: &spi->dev, id: "REF" ); |
236 | if (IS_ERR(ptr: st->vref_reg)) { |
237 | ret = PTR_ERR(ptr: st->vref_reg); |
238 | if (ret != -ENODEV) |
239 | return ret; |
240 | st->vref_reg = NULL; |
241 | } |
242 | |
243 | if (st->vref_reg) { |
244 | ret = regulator_enable(regulator: st->vref_reg); |
245 | if (ret) |
246 | return ret; |
247 | |
248 | ret = devm_add_action_or_reset(&spi->dev, ad7303_reg_disable, |
249 | st->vref_reg); |
250 | if (ret) |
251 | return ret; |
252 | |
253 | st->config |= AD7303_CFG_EXTERNAL_VREF; |
254 | } |
255 | |
256 | indio_dev->name = id->name; |
257 | indio_dev->info = &ad7303_info; |
258 | indio_dev->modes = INDIO_DIRECT_MODE; |
259 | indio_dev->channels = ad7303_channels; |
260 | indio_dev->num_channels = ARRAY_SIZE(ad7303_channels); |
261 | |
262 | return devm_iio_device_register(&spi->dev, indio_dev); |
263 | } |
264 | |
265 | static const struct of_device_id ad7303_spi_of_match[] = { |
266 | { .compatible = "adi,ad7303" , }, |
267 | { /* sentinel */ }, |
268 | }; |
269 | MODULE_DEVICE_TABLE(of, ad7303_spi_of_match); |
270 | |
271 | static const struct spi_device_id ad7303_spi_ids[] = { |
272 | { "ad7303" , 0 }, |
273 | {} |
274 | }; |
275 | MODULE_DEVICE_TABLE(spi, ad7303_spi_ids); |
276 | |
277 | static struct spi_driver ad7303_driver = { |
278 | .driver = { |
279 | .name = "ad7303" , |
280 | .of_match_table = ad7303_spi_of_match, |
281 | }, |
282 | .probe = ad7303_probe, |
283 | .id_table = ad7303_spi_ids, |
284 | }; |
285 | module_spi_driver(ad7303_driver); |
286 | |
287 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>" ); |
288 | MODULE_DESCRIPTION("Analog Devices AD7303 DAC driver" ); |
289 | MODULE_LICENSE("GPL v2" ); |
290 | |