1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * AD5504, AD5501 High Voltage Digital to Analog Converter |
4 | * |
5 | * Copyright 2011 Analog Devices Inc. |
6 | */ |
7 | |
8 | #include <linux/interrupt.h> |
9 | #include <linux/fs.h> |
10 | #include <linux/device.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 | #include <linux/module.h> |
17 | #include <linux/bitops.h> |
18 | |
19 | #include <linux/iio/iio.h> |
20 | #include <linux/iio/sysfs.h> |
21 | #include <linux/iio/events.h> |
22 | #include <linux/iio/dac/ad5504.h> |
23 | |
24 | #define AD5504_RES_MASK GENMASK(11, 0) |
25 | #define AD5504_CMD_READ BIT(15) |
26 | #define AD5504_CMD_WRITE 0 |
27 | #define AD5504_ADDR(addr) ((addr) << 12) |
28 | |
29 | /* Registers */ |
30 | #define AD5504_ADDR_NOOP 0 |
31 | #define AD5504_ADDR_DAC(x) ((x) + 1) |
32 | #define AD5504_ADDR_ALL_DAC 5 |
33 | #define AD5504_ADDR_CTRL 7 |
34 | |
35 | /* Control Register */ |
36 | #define AD5504_DAC_PWR(ch) ((ch) << 2) |
37 | #define AD5504_DAC_PWRDWN_MODE(mode) ((mode) << 6) |
38 | #define AD5504_DAC_PWRDN_20K 0 |
39 | #define AD5504_DAC_PWRDN_3STATE 1 |
40 | |
41 | /** |
42 | * struct ad5504_state - driver instance specific data |
43 | * @spi: spi_device |
44 | * @reg: supply regulator |
45 | * @vref_mv: actual reference voltage used |
46 | * @pwr_down_mask: power down mask |
47 | * @pwr_down_mode: current power down mode |
48 | * @data: transfer buffer |
49 | */ |
50 | struct ad5504_state { |
51 | struct spi_device *spi; |
52 | struct regulator *reg; |
53 | unsigned short vref_mv; |
54 | unsigned pwr_down_mask; |
55 | unsigned pwr_down_mode; |
56 | |
57 | __be16 data[2] __aligned(IIO_DMA_MINALIGN); |
58 | }; |
59 | |
60 | /* |
61 | * ad5504_supported_device_ids: |
62 | */ |
63 | enum ad5504_supported_device_ids { |
64 | ID_AD5504, |
65 | ID_AD5501, |
66 | }; |
67 | |
68 | static int ad5504_spi_write(struct ad5504_state *st, u8 addr, u16 val) |
69 | { |
70 | st->data[0] = cpu_to_be16(AD5504_CMD_WRITE | AD5504_ADDR(addr) | |
71 | (val & AD5504_RES_MASK)); |
72 | |
73 | return spi_write(spi: st->spi, buf: &st->data[0], len: 2); |
74 | } |
75 | |
76 | static int ad5504_spi_read(struct ad5504_state *st, u8 addr) |
77 | { |
78 | int ret; |
79 | struct spi_transfer t = { |
80 | .tx_buf = &st->data[0], |
81 | .rx_buf = &st->data[1], |
82 | .len = 2, |
83 | }; |
84 | |
85 | st->data[0] = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr)); |
86 | ret = spi_sync_transfer(spi: st->spi, xfers: &t, num_xfers: 1); |
87 | if (ret < 0) |
88 | return ret; |
89 | |
90 | return be16_to_cpu(st->data[1]) & AD5504_RES_MASK; |
91 | } |
92 | |
93 | static int ad5504_read_raw(struct iio_dev *indio_dev, |
94 | struct iio_chan_spec const *chan, |
95 | int *val, |
96 | int *val2, |
97 | long m) |
98 | { |
99 | struct ad5504_state *st = iio_priv(indio_dev); |
100 | int ret; |
101 | |
102 | switch (m) { |
103 | case IIO_CHAN_INFO_RAW: |
104 | ret = ad5504_spi_read(st, addr: chan->address); |
105 | if (ret < 0) |
106 | return ret; |
107 | |
108 | *val = ret; |
109 | |
110 | return IIO_VAL_INT; |
111 | case IIO_CHAN_INFO_SCALE: |
112 | *val = st->vref_mv; |
113 | *val2 = chan->scan_type.realbits; |
114 | return IIO_VAL_FRACTIONAL_LOG2; |
115 | } |
116 | return -EINVAL; |
117 | } |
118 | |
119 | static int ad5504_write_raw(struct iio_dev *indio_dev, |
120 | struct iio_chan_spec const *chan, |
121 | int val, |
122 | int val2, |
123 | long mask) |
124 | { |
125 | struct ad5504_state *st = iio_priv(indio_dev); |
126 | |
127 | switch (mask) { |
128 | case IIO_CHAN_INFO_RAW: |
129 | if (val >= (1 << chan->scan_type.realbits) || val < 0) |
130 | return -EINVAL; |
131 | |
132 | return ad5504_spi_write(st, addr: chan->address, val); |
133 | default: |
134 | return -EINVAL; |
135 | } |
136 | } |
137 | |
138 | static const char * const ad5504_powerdown_modes[] = { |
139 | "20kohm_to_gnd" , |
140 | "three_state" , |
141 | }; |
142 | |
143 | static int ad5504_get_powerdown_mode(struct iio_dev *indio_dev, |
144 | const struct iio_chan_spec *chan) |
145 | { |
146 | struct ad5504_state *st = iio_priv(indio_dev); |
147 | |
148 | return st->pwr_down_mode; |
149 | } |
150 | |
151 | static int ad5504_set_powerdown_mode(struct iio_dev *indio_dev, |
152 | const struct iio_chan_spec *chan, unsigned int mode) |
153 | { |
154 | struct ad5504_state *st = iio_priv(indio_dev); |
155 | |
156 | st->pwr_down_mode = mode; |
157 | |
158 | return 0; |
159 | } |
160 | |
161 | static const struct iio_enum ad5504_powerdown_mode_enum = { |
162 | .items = ad5504_powerdown_modes, |
163 | .num_items = ARRAY_SIZE(ad5504_powerdown_modes), |
164 | .get = ad5504_get_powerdown_mode, |
165 | .set = ad5504_set_powerdown_mode, |
166 | }; |
167 | |
168 | static ssize_t ad5504_read_dac_powerdown(struct iio_dev *indio_dev, |
169 | uintptr_t private, const struct iio_chan_spec *chan, char *buf) |
170 | { |
171 | struct ad5504_state *st = iio_priv(indio_dev); |
172 | |
173 | return sysfs_emit(buf, fmt: "%d\n" , |
174 | !(st->pwr_down_mask & (1 << chan->channel))); |
175 | } |
176 | |
177 | static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev, |
178 | uintptr_t private, const struct iio_chan_spec *chan, const char *buf, |
179 | size_t len) |
180 | { |
181 | bool pwr_down; |
182 | int ret; |
183 | struct ad5504_state *st = iio_priv(indio_dev); |
184 | |
185 | ret = kstrtobool(s: buf, res: &pwr_down); |
186 | if (ret) |
187 | return ret; |
188 | |
189 | if (pwr_down) |
190 | st->pwr_down_mask &= ~(1 << chan->channel); |
191 | else |
192 | st->pwr_down_mask |= (1 << chan->channel); |
193 | |
194 | ret = ad5504_spi_write(st, AD5504_ADDR_CTRL, |
195 | AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) | |
196 | AD5504_DAC_PWR(st->pwr_down_mask)); |
197 | |
198 | /* writes to the CTRL register must be followed by a NOOP */ |
199 | ad5504_spi_write(st, AD5504_ADDR_NOOP, val: 0); |
200 | |
201 | return ret ? ret : len; |
202 | } |
203 | |
204 | static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000" ); |
205 | static IIO_CONST_ATTR(temp0_thresh_rising_en, "1" ); |
206 | |
207 | static struct attribute *ad5504_ev_attributes[] = { |
208 | &iio_const_attr_temp0_thresh_rising_value.dev_attr.attr, |
209 | &iio_const_attr_temp0_thresh_rising_en.dev_attr.attr, |
210 | NULL, |
211 | }; |
212 | |
213 | static const struct attribute_group ad5504_ev_attribute_group = { |
214 | .attrs = ad5504_ev_attributes, |
215 | }; |
216 | |
217 | static irqreturn_t ad5504_event_handler(int irq, void *private) |
218 | { |
219 | iio_push_event(indio_dev: private, |
220 | IIO_UNMOD_EVENT_CODE(IIO_TEMP, |
221 | 0, |
222 | IIO_EV_TYPE_THRESH, |
223 | IIO_EV_DIR_RISING), |
224 | timestamp: iio_get_time_ns(indio_dev: private)); |
225 | |
226 | return IRQ_HANDLED; |
227 | } |
228 | |
229 | static const struct iio_info ad5504_info = { |
230 | .write_raw = ad5504_write_raw, |
231 | .read_raw = ad5504_read_raw, |
232 | .event_attrs = &ad5504_ev_attribute_group, |
233 | }; |
234 | |
235 | static const struct iio_chan_spec_ext_info ad5504_ext_info[] = { |
236 | { |
237 | .name = "powerdown" , |
238 | .read = ad5504_read_dac_powerdown, |
239 | .write = ad5504_write_dac_powerdown, |
240 | .shared = IIO_SEPARATE, |
241 | }, |
242 | IIO_ENUM("powerdown_mode" , IIO_SHARED_BY_TYPE, |
243 | &ad5504_powerdown_mode_enum), |
244 | IIO_ENUM_AVAILABLE("powerdown_mode" , IIO_SHARED_BY_TYPE, &ad5504_powerdown_mode_enum), |
245 | { }, |
246 | }; |
247 | |
248 | #define AD5504_CHANNEL(_chan) { \ |
249 | .type = IIO_VOLTAGE, \ |
250 | .indexed = 1, \ |
251 | .output = 1, \ |
252 | .channel = (_chan), \ |
253 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
254 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
255 | .address = AD5504_ADDR_DAC(_chan), \ |
256 | .scan_type = { \ |
257 | .sign = 'u', \ |
258 | .realbits = 12, \ |
259 | .storagebits = 16, \ |
260 | }, \ |
261 | .ext_info = ad5504_ext_info, \ |
262 | } |
263 | |
264 | static const struct iio_chan_spec ad5504_channels[] = { |
265 | AD5504_CHANNEL(0), |
266 | AD5504_CHANNEL(1), |
267 | AD5504_CHANNEL(2), |
268 | AD5504_CHANNEL(3), |
269 | }; |
270 | |
271 | static int ad5504_probe(struct spi_device *spi) |
272 | { |
273 | struct ad5504_platform_data *pdata = spi->dev.platform_data; |
274 | struct iio_dev *indio_dev; |
275 | struct ad5504_state *st; |
276 | struct regulator *reg; |
277 | int ret, voltage_uv = 0; |
278 | |
279 | indio_dev = devm_iio_device_alloc(parent: &spi->dev, sizeof_priv: sizeof(*st)); |
280 | if (!indio_dev) |
281 | return -ENOMEM; |
282 | reg = devm_regulator_get(dev: &spi->dev, id: "vcc" ); |
283 | if (!IS_ERR(ptr: reg)) { |
284 | ret = regulator_enable(regulator: reg); |
285 | if (ret) |
286 | return ret; |
287 | |
288 | ret = regulator_get_voltage(regulator: reg); |
289 | if (ret < 0) |
290 | goto error_disable_reg; |
291 | |
292 | voltage_uv = ret; |
293 | } |
294 | |
295 | spi_set_drvdata(spi, data: indio_dev); |
296 | st = iio_priv(indio_dev); |
297 | if (voltage_uv) |
298 | st->vref_mv = voltage_uv / 1000; |
299 | else if (pdata) |
300 | st->vref_mv = pdata->vref_mv; |
301 | else |
302 | dev_warn(&spi->dev, "reference voltage unspecified\n" ); |
303 | |
304 | st->reg = reg; |
305 | st->spi = spi; |
306 | indio_dev->name = spi_get_device_id(sdev: st->spi)->name; |
307 | indio_dev->info = &ad5504_info; |
308 | if (spi_get_device_id(sdev: st->spi)->driver_data == ID_AD5501) |
309 | indio_dev->num_channels = 1; |
310 | else |
311 | indio_dev->num_channels = 4; |
312 | indio_dev->channels = ad5504_channels; |
313 | indio_dev->modes = INDIO_DIRECT_MODE; |
314 | |
315 | if (spi->irq) { |
316 | ret = devm_request_threaded_irq(dev: &spi->dev, irq: spi->irq, |
317 | NULL, |
318 | thread_fn: &ad5504_event_handler, |
319 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
320 | devname: spi_get_device_id(sdev: st->spi)->name, |
321 | dev_id: indio_dev); |
322 | if (ret) |
323 | goto error_disable_reg; |
324 | } |
325 | |
326 | ret = iio_device_register(indio_dev); |
327 | if (ret) |
328 | goto error_disable_reg; |
329 | |
330 | return 0; |
331 | |
332 | error_disable_reg: |
333 | if (!IS_ERR(ptr: reg)) |
334 | regulator_disable(regulator: reg); |
335 | |
336 | return ret; |
337 | } |
338 | |
339 | static void ad5504_remove(struct spi_device *spi) |
340 | { |
341 | struct iio_dev *indio_dev = spi_get_drvdata(spi); |
342 | struct ad5504_state *st = iio_priv(indio_dev); |
343 | |
344 | iio_device_unregister(indio_dev); |
345 | |
346 | if (!IS_ERR(ptr: st->reg)) |
347 | regulator_disable(regulator: st->reg); |
348 | } |
349 | |
350 | static const struct spi_device_id ad5504_id[] = { |
351 | {"ad5504" , ID_AD5504}, |
352 | {"ad5501" , ID_AD5501}, |
353 | {} |
354 | }; |
355 | MODULE_DEVICE_TABLE(spi, ad5504_id); |
356 | |
357 | static struct spi_driver ad5504_driver = { |
358 | .driver = { |
359 | .name = "ad5504" , |
360 | }, |
361 | .probe = ad5504_probe, |
362 | .remove = ad5504_remove, |
363 | .id_table = ad5504_id, |
364 | }; |
365 | module_spi_driver(ad5504_driver); |
366 | |
367 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>" ); |
368 | MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC" ); |
369 | MODULE_LICENSE("GPL v2" ); |
370 | |