1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * DAC7612 Dual, 12-Bit Serial input Digital-to-Analog Converter |
4 | * |
5 | * Copyright 2019 Qtechnology A/S |
6 | * 2019 Ricardo Ribalda <ribalda@kernel.org> |
7 | * |
8 | * Licensed under the GPL-2. |
9 | */ |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/spi/spi.h> |
13 | #include <linux/gpio/consumer.h> |
14 | #include <linux/iio/iio.h> |
15 | |
16 | #define DAC7612_RESOLUTION 12 |
17 | #define DAC7612_ADDRESS 4 |
18 | #define DAC7612_START 5 |
19 | |
20 | struct dac7612 { |
21 | struct spi_device *spi; |
22 | struct gpio_desc *loaddacs; |
23 | uint16_t cache[2]; |
24 | |
25 | /* |
26 | * Lock to protect the state of the device from potential concurrent |
27 | * write accesses from userspace. The write operation requires an |
28 | * SPI write, then toggling of a GPIO, so the lock aims to protect |
29 | * the sanity of the entire sequence of operation. |
30 | */ |
31 | struct mutex lock; |
32 | |
33 | /* |
34 | * DMA (thus cache coherency maintenance) may require the |
35 | * transfer buffers to live in their own cache lines. |
36 | */ |
37 | uint8_t data[2] __aligned(IIO_DMA_MINALIGN); |
38 | }; |
39 | |
40 | static int dac7612_cmd_single(struct dac7612 *priv, int channel, u16 val) |
41 | { |
42 | int ret; |
43 | |
44 | priv->data[0] = BIT(DAC7612_START) | (channel << DAC7612_ADDRESS); |
45 | priv->data[0] |= val >> 8; |
46 | priv->data[1] = val & 0xff; |
47 | |
48 | priv->cache[channel] = val; |
49 | |
50 | ret = spi_write(spi: priv->spi, buf: priv->data, len: sizeof(priv->data)); |
51 | if (ret) |
52 | return ret; |
53 | |
54 | gpiod_set_value(desc: priv->loaddacs, value: 1); |
55 | gpiod_set_value(desc: priv->loaddacs, value: 0); |
56 | |
57 | return 0; |
58 | } |
59 | |
60 | #define dac7612_CHANNEL(chan, name) { \ |
61 | .type = IIO_VOLTAGE, \ |
62 | .channel = (chan), \ |
63 | .indexed = 1, \ |
64 | .output = 1, \ |
65 | .datasheet_name = name, \ |
66 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
67 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
68 | } |
69 | |
70 | static const struct iio_chan_spec dac7612_channels[] = { |
71 | dac7612_CHANNEL(0, "OUTA" ), |
72 | dac7612_CHANNEL(1, "OUTB" ), |
73 | }; |
74 | |
75 | static int dac7612_read_raw(struct iio_dev *iio_dev, |
76 | const struct iio_chan_spec *chan, |
77 | int *val, int *val2, long mask) |
78 | { |
79 | struct dac7612 *priv; |
80 | |
81 | switch (mask) { |
82 | case IIO_CHAN_INFO_RAW: |
83 | priv = iio_priv(indio_dev: iio_dev); |
84 | *val = priv->cache[chan->channel]; |
85 | return IIO_VAL_INT; |
86 | |
87 | case IIO_CHAN_INFO_SCALE: |
88 | *val = 1; |
89 | return IIO_VAL_INT; |
90 | |
91 | default: |
92 | return -EINVAL; |
93 | } |
94 | } |
95 | |
96 | static int dac7612_write_raw(struct iio_dev *iio_dev, |
97 | const struct iio_chan_spec *chan, |
98 | int val, int val2, long mask) |
99 | { |
100 | struct dac7612 *priv = iio_priv(indio_dev: iio_dev); |
101 | int ret; |
102 | |
103 | if (mask != IIO_CHAN_INFO_RAW) |
104 | return -EINVAL; |
105 | |
106 | if ((val >= BIT(DAC7612_RESOLUTION)) || val < 0 || val2) |
107 | return -EINVAL; |
108 | |
109 | if (val == priv->cache[chan->channel]) |
110 | return 0; |
111 | |
112 | mutex_lock(&priv->lock); |
113 | ret = dac7612_cmd_single(priv, channel: chan->channel, val); |
114 | mutex_unlock(lock: &priv->lock); |
115 | |
116 | return ret; |
117 | } |
118 | |
119 | static const struct iio_info dac7612_info = { |
120 | .read_raw = dac7612_read_raw, |
121 | .write_raw = dac7612_write_raw, |
122 | }; |
123 | |
124 | static int dac7612_probe(struct spi_device *spi) |
125 | { |
126 | struct iio_dev *iio_dev; |
127 | struct dac7612 *priv; |
128 | int i; |
129 | int ret; |
130 | |
131 | iio_dev = devm_iio_device_alloc(parent: &spi->dev, sizeof_priv: sizeof(*priv)); |
132 | if (!iio_dev) |
133 | return -ENOMEM; |
134 | |
135 | priv = iio_priv(indio_dev: iio_dev); |
136 | /* |
137 | * LOADDACS pin can be controlled by the driver or externally. |
138 | * When controlled by the driver, the DAC value is updated after |
139 | * every write. |
140 | * When the driver does not control the PIN, the user or an external |
141 | * event can change the value of all DACs by pulsing down the LOADDACs |
142 | * pin. |
143 | */ |
144 | priv->loaddacs = devm_gpiod_get_optional(dev: &spi->dev, con_id: "ti,loaddacs" , |
145 | flags: GPIOD_OUT_LOW); |
146 | if (IS_ERR(ptr: priv->loaddacs)) |
147 | return PTR_ERR(ptr: priv->loaddacs); |
148 | priv->spi = spi; |
149 | spi_set_drvdata(spi, data: iio_dev); |
150 | iio_dev->info = &dac7612_info; |
151 | iio_dev->modes = INDIO_DIRECT_MODE; |
152 | iio_dev->channels = dac7612_channels; |
153 | iio_dev->num_channels = ARRAY_SIZE(priv->cache); |
154 | iio_dev->name = spi_get_device_id(sdev: spi)->name; |
155 | |
156 | mutex_init(&priv->lock); |
157 | |
158 | for (i = 0; i < ARRAY_SIZE(priv->cache); i++) { |
159 | ret = dac7612_cmd_single(priv, channel: i, val: 0); |
160 | if (ret) |
161 | return ret; |
162 | } |
163 | |
164 | return devm_iio_device_register(&spi->dev, iio_dev); |
165 | } |
166 | |
167 | static const struct spi_device_id dac7612_id[] = { |
168 | {"ti-dac7612" }, |
169 | {} |
170 | }; |
171 | MODULE_DEVICE_TABLE(spi, dac7612_id); |
172 | |
173 | static const struct of_device_id dac7612_of_match[] = { |
174 | { .compatible = "ti,dac7612" }, |
175 | { .compatible = "ti,dac7612u" }, |
176 | { .compatible = "ti,dac7612ub" }, |
177 | { }, |
178 | }; |
179 | MODULE_DEVICE_TABLE(of, dac7612_of_match); |
180 | |
181 | static struct spi_driver dac7612_driver = { |
182 | .driver = { |
183 | .name = "ti-dac7612" , |
184 | .of_match_table = dac7612_of_match, |
185 | }, |
186 | .probe = dac7612_probe, |
187 | .id_table = dac7612_id, |
188 | }; |
189 | module_spi_driver(dac7612_driver); |
190 | |
191 | MODULE_AUTHOR("Ricardo Ribalda <ribalda@kernel.org>" ); |
192 | MODULE_DESCRIPTION("Texas Instruments DAC7612 DAC driver" ); |
193 | MODULE_LICENSE("GPL v2" ); |
194 | |