Commit | Line | Data |
---|---|---|
a886689f CC |
1 | /* |
2 | * Driver for ADI Direct Digital Synthesis ad9852 | |
3 | * | |
4 | * Copyright (c) 2010 Analog Devices Inc. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
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> | |
99c97852 | 17 | #include <linux/module.h> |
a886689f | 18 | |
06458e27 JC |
19 | #include <linux/iio/iio.h> |
20 | #include <linux/iio/sysfs.h> | |
a886689f CC |
21 | |
22 | #define DRV_NAME "ad9852" | |
23 | ||
24 | #define addr_phaad1 0x0 | |
25 | #define addr_phaad2 0x1 | |
26 | #define addr_fretu1 0x2 | |
27 | #define addr_fretu2 0x3 | |
28 | #define addr_delfre 0x4 | |
29 | #define addr_updclk 0x5 | |
30 | #define addr_ramclk 0x6 | |
31 | #define addr_contrl 0x7 | |
32 | #define addr_optskm 0x8 | |
33 | #define addr_optskr 0xa | |
34 | #define addr_dacctl 0xb | |
35 | ||
36 | #define COMPPD (1 << 4) | |
37 | #define REFMULT2 (1 << 2) | |
38 | #define BYPPLL (1 << 5) | |
39 | #define PLLRANG (1 << 6) | |
40 | #define IEUPCLK (1) | |
41 | #define OSKEN (1 << 5) | |
42 | ||
43 | #define read_bit (1 << 7) | |
44 | ||
45 | /* Register format: 1 byte addr + value */ | |
46 | struct ad9852_config { | |
47 | u8 phajst0[3]; | |
48 | u8 phajst1[3]; | |
49 | u8 fretun1[6]; | |
50 | u8 fretun2[6]; | |
51 | u8 dltafre[6]; | |
52 | u8 updtclk[5]; | |
53 | u8 ramprat[4]; | |
54 | u8 control[5]; | |
55 | u8 outpskm[3]; | |
56 | u8 outpskr[2]; | |
57 | u8 daccntl[3]; | |
58 | }; | |
59 | ||
60 | struct ad9852_state { | |
61 | struct mutex lock; | |
a886689f CC |
62 | struct spi_device *sdev; |
63 | }; | |
64 | ||
65 | static ssize_t ad9852_set_parameter(struct device *dev, | |
66 | struct device_attribute *attr, | |
67 | const char *buf, | |
68 | size_t len) | |
69 | { | |
70 | struct spi_message msg; | |
71 | struct spi_transfer xfer; | |
72 | int ret; | |
73 | struct ad9852_config *config = (struct ad9852_config *)buf; | |
74 | struct iio_dev *idev = dev_get_drvdata(dev); | |
a2829911 | 75 | struct ad9852_state *st = iio_priv(idev); |
a886689f CC |
76 | |
77 | xfer.len = 3; | |
78 | xfer.tx_buf = &config->phajst0[0]; | |
79 | mutex_lock(&st->lock); | |
80 | ||
81 | spi_message_init(&msg); | |
82 | spi_message_add_tail(&xfer, &msg); | |
83 | ret = spi_sync(st->sdev, &msg); | |
84 | if (ret) | |
85 | goto error_ret; | |
86 | ||
87 | xfer.len = 3; | |
88 | xfer.tx_buf = &config->phajst1[0]; | |
a886689f CC |
89 | |
90 | spi_message_init(&msg); | |
91 | spi_message_add_tail(&xfer, &msg); | |
92 | ret = spi_sync(st->sdev, &msg); | |
93 | if (ret) | |
94 | goto error_ret; | |
95 | ||
96 | xfer.len = 6; | |
97 | xfer.tx_buf = &config->fretun1[0]; | |
a886689f CC |
98 | |
99 | spi_message_init(&msg); | |
100 | spi_message_add_tail(&xfer, &msg); | |
101 | ret = spi_sync(st->sdev, &msg); | |
102 | if (ret) | |
103 | goto error_ret; | |
104 | ||
105 | xfer.len = 6; | |
106 | xfer.tx_buf = &config->fretun2[0]; | |
a886689f CC |
107 | |
108 | spi_message_init(&msg); | |
109 | spi_message_add_tail(&xfer, &msg); | |
110 | ret = spi_sync(st->sdev, &msg); | |
111 | if (ret) | |
112 | goto error_ret; | |
113 | ||
114 | xfer.len = 6; | |
115 | xfer.tx_buf = &config->dltafre[0]; | |
a886689f CC |
116 | |
117 | spi_message_init(&msg); | |
118 | spi_message_add_tail(&xfer, &msg); | |
119 | ret = spi_sync(st->sdev, &msg); | |
120 | if (ret) | |
121 | goto error_ret; | |
122 | ||
123 | xfer.len = 5; | |
124 | xfer.tx_buf = &config->updtclk[0]; | |
a886689f CC |
125 | |
126 | spi_message_init(&msg); | |
127 | spi_message_add_tail(&xfer, &msg); | |
128 | ret = spi_sync(st->sdev, &msg); | |
129 | if (ret) | |
130 | goto error_ret; | |
131 | ||
132 | xfer.len = 4; | |
133 | xfer.tx_buf = &config->ramprat[0]; | |
a886689f CC |
134 | |
135 | spi_message_init(&msg); | |
136 | spi_message_add_tail(&xfer, &msg); | |
137 | ret = spi_sync(st->sdev, &msg); | |
138 | if (ret) | |
139 | goto error_ret; | |
140 | ||
141 | xfer.len = 5; | |
142 | xfer.tx_buf = &config->control[0]; | |
a886689f CC |
143 | |
144 | spi_message_init(&msg); | |
145 | spi_message_add_tail(&xfer, &msg); | |
146 | ret = spi_sync(st->sdev, &msg); | |
147 | if (ret) | |
148 | goto error_ret; | |
149 | ||
150 | xfer.len = 3; | |
151 | xfer.tx_buf = &config->outpskm[0]; | |
a886689f CC |
152 | |
153 | spi_message_init(&msg); | |
154 | spi_message_add_tail(&xfer, &msg); | |
155 | ret = spi_sync(st->sdev, &msg); | |
156 | if (ret) | |
157 | goto error_ret; | |
158 | ||
159 | xfer.len = 2; | |
160 | xfer.tx_buf = &config->outpskr[0]; | |
a886689f CC |
161 | |
162 | spi_message_init(&msg); | |
163 | spi_message_add_tail(&xfer, &msg); | |
164 | ret = spi_sync(st->sdev, &msg); | |
165 | if (ret) | |
166 | goto error_ret; | |
59a12641 | 167 | |
a886689f CC |
168 | xfer.len = 3; |
169 | xfer.tx_buf = &config->daccntl[0]; | |
a886689f CC |
170 | |
171 | spi_message_init(&msg); | |
172 | spi_message_add_tail(&xfer, &msg); | |
173 | ret = spi_sync(st->sdev, &msg); | |
174 | if (ret) | |
175 | goto error_ret; | |
176 | error_ret: | |
177 | mutex_unlock(&st->lock); | |
178 | ||
179 | return ret ? ret : len; | |
180 | } | |
181 | ||
182 | static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0); | |
183 | ||
184 | static void ad9852_init(struct ad9852_state *st) | |
185 | { | |
186 | struct spi_message msg; | |
187 | struct spi_transfer xfer; | |
188 | int ret; | |
189 | u8 config[5]; | |
190 | ||
191 | config[0] = addr_contrl; | |
192 | config[1] = COMPPD; | |
193 | config[2] = REFMULT2 | BYPPLL | PLLRANG; | |
194 | config[3] = IEUPCLK; | |
195 | config[4] = OSKEN; | |
196 | ||
197 | mutex_lock(&st->lock); | |
198 | ||
199 | xfer.len = 5; | |
200 | xfer.tx_buf = &config; | |
201 | ||
202 | spi_message_init(&msg); | |
203 | spi_message_add_tail(&xfer, &msg); | |
204 | ret = spi_sync(st->sdev, &msg); | |
205 | if (ret) | |
206 | goto error_ret; | |
207 | ||
208 | error_ret: | |
209 | mutex_unlock(&st->lock); | |
210 | ||
211 | ||
212 | ||
213 | } | |
214 | ||
215 | static struct attribute *ad9852_attributes[] = { | |
216 | &iio_dev_attr_dds.dev_attr.attr, | |
217 | NULL, | |
218 | }; | |
219 | ||
220 | static const struct attribute_group ad9852_attribute_group = { | |
a886689f CC |
221 | .attrs = ad9852_attributes, |
222 | }; | |
223 | ||
6fe8135f JC |
224 | static const struct iio_info ad9852_info = { |
225 | .attrs = &ad9852_attribute_group, | |
226 | .driver_module = THIS_MODULE, | |
227 | }; | |
228 | ||
a886689f CC |
229 | static int __devinit ad9852_probe(struct spi_device *spi) |
230 | { | |
231 | struct ad9852_state *st; | |
a2829911 | 232 | struct iio_dev *idev; |
a886689f CC |
233 | int ret = 0; |
234 | ||
7cbb7537 | 235 | idev = iio_device_alloc(sizeof(*st)); |
a2829911 | 236 | if (idev == NULL) { |
a886689f CC |
237 | ret = -ENOMEM; |
238 | goto error_ret; | |
239 | } | |
a2829911 JC |
240 | st = iio_priv(idev); |
241 | spi_set_drvdata(spi, idev); | |
a886689f CC |
242 | mutex_init(&st->lock); |
243 | st->sdev = spi; | |
244 | ||
a2829911 JC |
245 | idev->dev.parent = &spi->dev; |
246 | idev->info = &ad9852_info; | |
247 | idev->modes = INDIO_DIRECT_MODE; | |
a886689f | 248 | |
a2829911 | 249 | ret = iio_device_register(idev); |
a886689f CC |
250 | if (ret) |
251 | goto error_free_dev; | |
252 | spi->max_speed_hz = 2000000; | |
253 | spi->mode = SPI_MODE_3; | |
254 | spi->bits_per_word = 8; | |
255 | spi_setup(spi); | |
256 | ad9852_init(st); | |
a2829911 | 257 | |
a886689f CC |
258 | return 0; |
259 | ||
260 | error_free_dev: | |
7cbb7537 | 261 | iio_device_free(idev); |
a2829911 | 262 | |
a886689f CC |
263 | error_ret: |
264 | return ret; | |
265 | } | |
266 | ||
267 | static int __devexit ad9852_remove(struct spi_device *spi) | |
268 | { | |
a2829911 | 269 | iio_device_unregister(spi_get_drvdata(spi)); |
7cbb7537 | 270 | iio_device_free(spi_get_drvdata(spi)); |
a886689f CC |
271 | |
272 | return 0; | |
273 | } | |
274 | ||
275 | static struct spi_driver ad9852_driver = { | |
276 | .driver = { | |
277 | .name = DRV_NAME, | |
278 | .owner = THIS_MODULE, | |
279 | }, | |
280 | .probe = ad9852_probe, | |
281 | .remove = __devexit_p(ad9852_remove), | |
282 | }; | |
ae6ae6fe | 283 | module_spi_driver(ad9852_driver); |
a886689f CC |
284 | |
285 | MODULE_AUTHOR("Cliff Cai"); | |
286 | MODULE_DESCRIPTION("Analog Devices ad9852 driver"); | |
287 | MODULE_LICENSE("GPL v2"); | |
55e4390c | 288 | MODULE_ALIAS("spi:" DRV_NAME); |