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