.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * AD7303 Digital to analog converters driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright 2013 Analog Devices Inc. |
---|
5 | | - * |
---|
6 | | - * Licensed under the GPL-2. |
---|
7 | 6 | */ |
---|
8 | 7 | |
---|
9 | 8 | #include <linux/err.h> |
---|
10 | 9 | #include <linux/module.h> |
---|
| 10 | +#include <linux/mod_devicetable.h> |
---|
11 | 11 | #include <linux/kernel.h> |
---|
12 | 12 | #include <linux/spi/spi.h> |
---|
13 | 13 | #include <linux/slab.h> |
---|
14 | 14 | #include <linux/sysfs.h> |
---|
15 | 15 | #include <linux/regulator/consumer.h> |
---|
16 | | -#include <linux/of.h> |
---|
17 | 16 | |
---|
18 | 17 | #include <linux/iio/iio.h> |
---|
19 | 18 | #include <linux/iio/sysfs.h> |
---|
.. | .. |
---|
31 | 30 | * @spi: the device for this driver instance |
---|
32 | 31 | * @config: cached config register value |
---|
33 | 32 | * @dac_cache: current DAC raw value (chip does not support readback) |
---|
| 33 | + * @vdd_reg: reference to VDD regulator |
---|
| 34 | + * @vref_reg: reference to VREF regulator |
---|
| 35 | + * @lock: protect writes and cache updates |
---|
34 | 36 | * @data: spi transfer buffer |
---|
35 | 37 | */ |
---|
36 | 38 | |
---|
.. | .. |
---|
42 | 44 | struct regulator *vdd_reg; |
---|
43 | 45 | struct regulator *vref_reg; |
---|
44 | 46 | |
---|
| 47 | + struct mutex lock; |
---|
45 | 48 | /* |
---|
46 | 49 | * DMA (thus cache coherency maintenance) requires the |
---|
47 | 50 | * transfer buffers to live in their own cache lines. |
---|
.. | .. |
---|
80 | 83 | if (ret) |
---|
81 | 84 | return ret; |
---|
82 | 85 | |
---|
83 | | - mutex_lock(&indio_dev->mlock); |
---|
| 86 | + mutex_lock(&st->lock); |
---|
84 | 87 | |
---|
85 | 88 | if (pwr_down) |
---|
86 | 89 | st->config |= AD7303_CFG_POWER_DOWN(chan->channel); |
---|
.. | .. |
---|
91 | 94 | * mode, so just write one of the DAC channels again */ |
---|
92 | 95 | ad7303_write(st, chan->channel, st->dac_cache[chan->channel]); |
---|
93 | 96 | |
---|
94 | | - mutex_unlock(&indio_dev->mlock); |
---|
| 97 | + mutex_unlock(&st->lock); |
---|
95 | 98 | return len; |
---|
96 | 99 | } |
---|
97 | 100 | |
---|
.. | .. |
---|
117 | 120 | |
---|
118 | 121 | switch (info) { |
---|
119 | 122 | case IIO_CHAN_INFO_RAW: |
---|
| 123 | + mutex_lock(&st->lock); |
---|
120 | 124 | *val = st->dac_cache[chan->channel]; |
---|
| 125 | + mutex_unlock(&st->lock); |
---|
121 | 126 | return IIO_VAL_INT; |
---|
122 | 127 | case IIO_CHAN_INFO_SCALE: |
---|
123 | 128 | vref_uv = ad7303_get_vref(st, chan); |
---|
.. | .. |
---|
145 | 150 | if (val >= (1 << chan->scan_type.realbits) || val < 0) |
---|
146 | 151 | return -EINVAL; |
---|
147 | 152 | |
---|
148 | | - mutex_lock(&indio_dev->mlock); |
---|
| 153 | + mutex_lock(&st->lock); |
---|
149 | 154 | ret = ad7303_write(st, chan->address, val); |
---|
150 | 155 | if (ret == 0) |
---|
151 | 156 | st->dac_cache[chan->channel] = val; |
---|
152 | | - mutex_unlock(&indio_dev->mlock); |
---|
| 157 | + mutex_unlock(&st->lock); |
---|
153 | 158 | break; |
---|
154 | 159 | default: |
---|
155 | 160 | ret = -EINVAL; |
---|
.. | .. |
---|
200 | 205 | const struct spi_device_id *id = spi_get_device_id(spi); |
---|
201 | 206 | struct iio_dev *indio_dev; |
---|
202 | 207 | struct ad7303_state *st; |
---|
203 | | - bool ext_ref; |
---|
204 | 208 | int ret; |
---|
205 | 209 | |
---|
206 | 210 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); |
---|
.. | .. |
---|
212 | 216 | |
---|
213 | 217 | st->spi = spi; |
---|
214 | 218 | |
---|
| 219 | + mutex_init(&st->lock); |
---|
| 220 | + |
---|
215 | 221 | st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd"); |
---|
216 | 222 | if (IS_ERR(st->vdd_reg)) |
---|
217 | 223 | return PTR_ERR(st->vdd_reg); |
---|
.. | .. |
---|
220 | 226 | if (ret) |
---|
221 | 227 | return ret; |
---|
222 | 228 | |
---|
223 | | - if (spi->dev.of_node) { |
---|
224 | | - ext_ref = of_property_read_bool(spi->dev.of_node, |
---|
225 | | - "REF-supply"); |
---|
226 | | - } else { |
---|
227 | | - struct ad7303_platform_data *pdata = spi->dev.platform_data; |
---|
228 | | - if (pdata && pdata->use_external_ref) |
---|
229 | | - ext_ref = true; |
---|
230 | | - else |
---|
231 | | - ext_ref = false; |
---|
| 229 | + st->vref_reg = devm_regulator_get_optional(&spi->dev, "REF"); |
---|
| 230 | + if (IS_ERR(st->vref_reg)) { |
---|
| 231 | + ret = PTR_ERR(st->vref_reg); |
---|
| 232 | + if (ret != -ENODEV) |
---|
| 233 | + goto err_disable_vdd_reg; |
---|
| 234 | + st->vref_reg = NULL; |
---|
232 | 235 | } |
---|
233 | 236 | |
---|
234 | | - if (ext_ref) { |
---|
235 | | - st->vref_reg = devm_regulator_get(&spi->dev, "REF"); |
---|
236 | | - if (IS_ERR(st->vref_reg)) { |
---|
237 | | - ret = PTR_ERR(st->vref_reg); |
---|
238 | | - goto err_disable_vdd_reg; |
---|
239 | | - } |
---|
240 | | - |
---|
| 237 | + if (st->vref_reg) { |
---|
241 | 238 | ret = regulator_enable(st->vref_reg); |
---|
242 | 239 | if (ret) |
---|
243 | 240 | goto err_disable_vdd_reg; |
---|
.. | .. |
---|
245 | 242 | st->config |= AD7303_CFG_EXTERNAL_VREF; |
---|
246 | 243 | } |
---|
247 | 244 | |
---|
248 | | - indio_dev->dev.parent = &spi->dev; |
---|
249 | 245 | indio_dev->name = id->name; |
---|
250 | 246 | indio_dev->info = &ad7303_info; |
---|
251 | 247 | indio_dev->modes = INDIO_DIRECT_MODE; |
---|
.. | .. |
---|
295 | 291 | static struct spi_driver ad7303_driver = { |
---|
296 | 292 | .driver = { |
---|
297 | 293 | .name = "ad7303", |
---|
298 | | - .of_match_table = of_match_ptr(ad7303_spi_of_match), |
---|
| 294 | + .of_match_table = ad7303_spi_of_match, |
---|
299 | 295 | }, |
---|
300 | 296 | .probe = ad7303_probe, |
---|
301 | 297 | .remove = ad7303_remove, |
---|