1
2
3
4
5
6
7
8
9
10
11#include <linux/types.h>
12#include <linux/mutex.h>
13#include <linux/device.h>
14#include <linux/spi/spi.h>
15#include <linux/slab.h>
16#include <linux/sysfs.h>
17#include <linux/module.h>
18
19#include <linux/iio/iio.h>
20#include <linux/iio/sysfs.h>
21
22#define DRV_NAME "ad9910"
23
24#define CFR1 0x0
25#define CFR2 0x1
26#define CFR3 0x2
27
28#define AUXDAC 0x3
29#define IOUPD 0x4
30#define FTW 0x7
31#define POW 0x8
32#define ASF 0x9
33#define MULTC 0x0A
34#define DIG_RAMPL 0x0B
35#define DIG_RAMPS 0x0C
36#define DIG_RAMPR 0x0D
37#define SIN_TONEP0 0x0E
38#define SIN_TONEP1 0x0F
39#define SIN_TONEP2 0x10
40#define SIN_TONEP3 0x11
41#define SIN_TONEP4 0x12
42#define SIN_TONEP5 0x13
43#define SIN_TONEP6 0x14
44#define SIN_TONEP7 0x15
45
46#define RAM_ENABLE (1 << 7)
47
48#define MANUAL_OSK (1 << 7)
49#define INVSIC (1 << 6)
50#define DDS_SINEOP (1)
51
52#define AUTO_OSK (1)
53#define OSKEN (1 << 1)
54#define LOAD_ARR (1 << 2)
55#define CLR_PHA (1 << 3)
56#define CLR_DIG (1 << 4)
57#define ACLR_PHA (1 << 5)
58#define ACLR_DIG (1 << 6)
59#define LOAD_LRR (1 << 7)
60
61#define LSB_FST (1)
62#define SDIO_IPT (1 << 1)
63#define EXT_PWD (1 << 3)
64#define ADAC_PWD (1 << 4)
65#define REFCLK_PWD (1 << 5)
66#define DAC_PWD (1 << 6)
67#define DIG_PWD (1 << 7)
68
69#define ENA_AMP (1)
70#define READ_FTW (1)
71#define DIGR_LOW (1 << 1)
72#define DIGR_HIGH (1 << 2)
73#define DIGR_ENA (1 << 3)
74#define SYNCCLK_ENA (1 << 6)
75#define ITER_IOUPD (1 << 7)
76
77#define TX_ENA (1 << 1)
78#define PDCLK_INV (1 << 2)
79#define PDCLK_ENB (1 << 3)
80
81#define PARA_ENA (1 << 4)
82#define SYNC_DIS (1 << 5)
83#define DATA_ASS (1 << 6)
84#define MATCH_ENA (1 << 7)
85
86#define PLL_ENA (1)
87#define PFD_RST (1 << 2)
88#define REFCLK_RST (1 << 6)
89#define REFCLK_BYP (1 << 7)
90
91
92struct ad9910_config {
93 u8 auxdac[5];
94 u8 ioupd[5];
95 u8 ftw[5];
96 u8 pow[3];
97 u8 asf[5];
98 u8 multc[5];
99 u8 dig_rampl[9];
100 u8 dig_ramps[9];
101 u8 dig_rampr[5];
102 u8 sin_tonep0[9];
103 u8 sin_tonep1[9];
104 u8 sin_tonep2[9];
105 u8 sin_tonep3[9];
106 u8 sin_tonep4[9];
107 u8 sin_tonep5[9];
108 u8 sin_tonep6[9];
109 u8 sin_tonep7[9];
110};
111
112struct ad9910_state {
113 struct mutex lock;
114 struct spi_device *sdev;
115};
116
117static ssize_t ad9910_set_parameter(struct device *dev,
118 struct device_attribute *attr,
119 const char *buf,
120 size_t len)
121{
122 struct spi_transfer xfer;
123 int ret;
124 struct ad9910_config *config = (struct ad9910_config *)buf;
125 struct iio_dev *idev = dev_to_iio_dev(dev);
126 struct ad9910_state *st = iio_priv(idev);
127
128 xfer.len = 5;
129 xfer.tx_buf = &config->auxdac[0];
130 mutex_lock(&st->lock);
131
132 ret = spi_sync_transfer(st->sdev, &xfer, 1);
133 if (ret)
134 goto error_ret;
135
136 xfer.len = 5;
137 xfer.tx_buf = &config->ioupd[0];
138
139 ret = spi_sync_transfer(st->sdev, &xfer, 1);
140 if (ret)
141 goto error_ret;
142
143 xfer.len = 5;
144 xfer.tx_buf = &config->ftw[0];
145
146 ret = spi_sync_transfer(st->sdev, &xfer, 1);
147 if (ret)
148 goto error_ret;
149
150 xfer.len = 3;
151 xfer.tx_buf = &config->pow[0];
152
153 ret = spi_sync_transfer(st->sdev, &xfer, 1);
154 if (ret)
155 goto error_ret;
156
157 xfer.len = 5;
158 xfer.tx_buf = &config->asf[0];
159
160 ret = spi_sync_transfer(st->sdev, &xfer, 1);
161 if (ret)
162 goto error_ret;
163
164 xfer.len = 5;
165 xfer.tx_buf = &config->multc[0];
166
167 ret = spi_sync_transfer(st->sdev, &xfer, 1);
168 if (ret)
169 goto error_ret;
170
171 xfer.len = 9;
172 xfer.tx_buf = &config->dig_rampl[0];
173
174 ret = spi_sync_transfer(st->sdev, &xfer, 1);
175 if (ret)
176 goto error_ret;
177
178 xfer.len = 9;
179 xfer.tx_buf = &config->dig_ramps[0];
180
181 ret = spi_sync_transfer(st->sdev, &xfer, 1);
182 if (ret)
183 goto error_ret;
184
185 xfer.len = 5;
186 xfer.tx_buf = &config->dig_rampr[0];
187
188 ret = spi_sync_transfer(st->sdev, &xfer, 1);
189 if (ret)
190 goto error_ret;
191
192 xfer.len = 9;
193 xfer.tx_buf = &config->sin_tonep0[0];
194
195 ret = spi_sync_transfer(st->sdev, &xfer, 1);
196 if (ret)
197 goto error_ret;
198
199 xfer.len = 9;
200 xfer.tx_buf = &config->sin_tonep1[0];
201
202 ret = spi_sync_transfer(st->sdev, &xfer, 1);
203 if (ret)
204 goto error_ret;
205
206 xfer.len = 9;
207 xfer.tx_buf = &config->sin_tonep2[0];
208
209 ret = spi_sync_transfer(st->sdev, &xfer, 1);
210 if (ret)
211 goto error_ret;
212 xfer.len = 9;
213 xfer.tx_buf = &config->sin_tonep3[0];
214
215 ret = spi_sync_transfer(st->sdev, &xfer, 1);
216 if (ret)
217 goto error_ret;
218
219 xfer.len = 9;
220 xfer.tx_buf = &config->sin_tonep4[0];
221
222 ret = spi_sync_transfer(st->sdev, &xfer, 1);
223 if (ret)
224 goto error_ret;
225
226 xfer.len = 9;
227 xfer.tx_buf = &config->sin_tonep5[0];
228
229 ret = spi_sync_transfer(st->sdev, &xfer, 1);
230 if (ret)
231 goto error_ret;
232
233 xfer.len = 9;
234 xfer.tx_buf = &config->sin_tonep6[0];
235
236 ret = spi_sync_transfer(st->sdev, &xfer, 1);
237 if (ret)
238 goto error_ret;
239
240 xfer.len = 9;
241 xfer.tx_buf = &config->sin_tonep7[0];
242
243 ret = spi_sync_transfer(st->sdev, &xfer, 1);
244 if (ret)
245 goto error_ret;
246error_ret:
247 mutex_unlock(&st->lock);
248
249 return ret ? ret : len;
250}
251
252static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0);
253
254static void ad9910_init(struct ad9910_state *st)
255{
256 struct spi_transfer xfer;
257 int ret;
258 u8 cfr[5];
259
260 cfr[0] = CFR1;
261 cfr[1] = 0;
262 cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP;
263 cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR;
264 cfr[4] = 0;
265
266 mutex_lock(&st->lock);
267
268 xfer.len = 5;
269 xfer.tx_buf = 𝔠
270
271 ret = spi_sync_transfer(st->sdev, &xfer, 1);
272 if (ret)
273 goto error_ret;
274
275 cfr[0] = CFR2;
276 cfr[1] = ENA_AMP;
277 cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD;
278 cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB;
279 cfr[4] = PARA_ENA;
280
281 xfer.len = 5;
282 xfer.tx_buf = 𝔠
283
284 ret = spi_sync_transfer(st->sdev, &xfer, 1);
285 if (ret)
286 goto error_ret;
287
288 cfr[0] = CFR3;
289 cfr[1] = PLL_ENA;
290 cfr[2] = 0;
291 cfr[3] = REFCLK_RST | REFCLK_BYP;
292 cfr[4] = 0;
293
294 xfer.len = 5;
295 xfer.tx_buf = 𝔠
296
297 ret = spi_sync_transfer(st->sdev, &xfer, 1);
298 if (ret)
299 goto error_ret;
300
301error_ret:
302 mutex_unlock(&st->lock);
303
304
305
306}
307
308static struct attribute *ad9910_attributes[] = {
309 &iio_dev_attr_dds.dev_attr.attr,
310 NULL,
311};
312
313static const struct attribute_group ad9910_attribute_group = {
314 .attrs = ad9910_attributes,
315};
316
317static const struct iio_info ad9910_info = {
318 .attrs = &ad9910_attribute_group,
319 .driver_module = THIS_MODULE,
320};
321
322static int ad9910_probe(struct spi_device *spi)
323{
324 struct ad9910_state *st;
325 struct iio_dev *idev;
326 int ret = 0;
327
328 idev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
329 if (!idev)
330 return -ENOMEM;
331 spi_set_drvdata(spi, idev);
332 st = iio_priv(idev);
333 mutex_init(&st->lock);
334 st->sdev = spi;
335
336 idev->dev.parent = &spi->dev;
337 idev->info = &ad9910_info;
338 idev->modes = INDIO_DIRECT_MODE;
339
340 ret = iio_device_register(idev);
341 if (ret)
342 return ret;
343 spi->max_speed_hz = 2000000;
344 spi->mode = SPI_MODE_3;
345 spi->bits_per_word = 8;
346 spi_setup(spi);
347 ad9910_init(st);
348 return 0;
349}
350
351static int ad9910_remove(struct spi_device *spi)
352{
353 iio_device_unregister(spi_get_drvdata(spi));
354
355 return 0;
356}
357
358static struct spi_driver ad9910_driver = {
359 .driver = {
360 .name = DRV_NAME,
361 .owner = THIS_MODULE,
362 },
363 .probe = ad9910_probe,
364 .remove = ad9910_remove,
365};
366module_spi_driver(ad9910_driver);
367
368MODULE_AUTHOR("Cliff Cai");
369MODULE_DESCRIPTION("Analog Devices ad9910 driver");
370MODULE_LICENSE("GPL v2");
371MODULE_ALIAS("spi:" DRV_NAME);
372