diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2012-05-29 06:41:20 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-06-05 00:19:40 -0400 |
commit | e31166f0fd48478866ee9661c36789126435ebe8 (patch) | |
tree | c5a7b345c3331935318376558429ff6e2e092aef /drivers/iio/frequency | |
parent | cd1678f963298a9e777f3edb72d28bc18a3a32c2 (diff) |
iio: frequency: New driver for Analog Devices ADF4350/ADF4351 Wideband Synthesizers
Changes since V1:
Apply Jonathan's review feedback:
Introduce and use IIO_ALTVOLTAGE.
Fix up comments and documentation.
Remove dead code.
Reorder some code fragments.
Add missing iio_device_free.
Convert to new API.
Fix-up out of staging includes.
Removed pll_locked attribute.
Changes since V2:
Use module_spi_driver.
adf4350_remove: move gpio_free after regulator.
target patch to drivers/iio
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/iio/frequency')
-rw-r--r-- | drivers/iio/frequency/Kconfig | 18 | ||||
-rw-r--r-- | drivers/iio/frequency/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/frequency/adf4350.c | 478 |
3 files changed, 497 insertions, 0 deletions
diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index 0458c92464a3..6aaa33ef4544 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig | |||
@@ -20,4 +20,22 @@ config AD9523 | |||
20 | module will be called ad9523. | 20 | module will be called ad9523. |
21 | 21 | ||
22 | endmenu | 22 | endmenu |
23 | |||
24 | # | ||
25 | # Phase-Locked Loop (PLL) frequency synthesizers | ||
26 | # | ||
27 | |||
28 | menu "Phase-Locked Loop (PLL) frequency synthesizers" | ||
29 | |||
30 | config ADF4350 | ||
31 | tristate "Analog Devices ADF4350/ADF4351 Wideband Synthesizers" | ||
32 | depends on SPI | ||
33 | help | ||
34 | Say yes here to build support for Analog Devices ADF4350/ADF4351 | ||
35 | Wideband Synthesizers. The driver provides direct access via sysfs. | ||
36 | |||
37 | To compile this driver as a module, choose M here: the | ||
38 | module will be called adf4350. | ||
39 | |||
40 | endmenu | ||
23 | endmenu | 41 | endmenu |
diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index 1b5b22417da1..00d26e5d1dc2 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile | |||
@@ -3,3 +3,4 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_AD9523) += ad9523.o | 5 | obj-$(CONFIG_AD9523) += ad9523.o |
6 | obj-$(CONFIG_ADF4350) += adf4350.o | ||
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c new file mode 100644 index 000000000000..fd4c8501aba9 --- /dev/null +++ b/drivers/iio/frequency/adf4350.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * ADF4350/ADF4351 SPI Wideband Synthesizer driver | ||
3 | * | ||
4 | * Copyright 2012 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/device.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/sysfs.h> | ||
13 | #include <linux/spi/spi.h> | ||
14 | #include <linux/regulator/consumer.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/gcd.h> | ||
18 | #include <linux/gpio.h> | ||
19 | #include <asm/div64.h> | ||
20 | |||
21 | #include <linux/iio/iio.h> | ||
22 | #include <linux/iio/sysfs.h> | ||
23 | #include <linux/iio/frequency/adf4350.h> | ||
24 | |||
25 | enum { | ||
26 | ADF4350_FREQ, | ||
27 | ADF4350_FREQ_REFIN, | ||
28 | ADF4350_FREQ_RESOLUTION, | ||
29 | ADF4350_PWRDOWN, | ||
30 | }; | ||
31 | |||
32 | struct adf4350_state { | ||
33 | struct spi_device *spi; | ||
34 | struct regulator *reg; | ||
35 | struct adf4350_platform_data *pdata; | ||
36 | unsigned long clkin; | ||
37 | unsigned long chspc; /* Channel Spacing */ | ||
38 | unsigned long fpfd; /* Phase Frequency Detector */ | ||
39 | unsigned long min_out_freq; | ||
40 | unsigned r0_fract; | ||
41 | unsigned r0_int; | ||
42 | unsigned r1_mod; | ||
43 | unsigned r4_rf_div_sel; | ||
44 | unsigned long regs[6]; | ||
45 | unsigned long regs_hw[6]; | ||
46 | |||
47 | /* | ||
48 | * DMA (thus cache coherency maintenance) requires the | ||
49 | * transfer buffers to live in their own cache lines. | ||
50 | */ | ||
51 | __be32 val ____cacheline_aligned; | ||
52 | }; | ||
53 | |||
54 | static struct adf4350_platform_data default_pdata = { | ||
55 | .clkin = 122880000, | ||
56 | .channel_spacing = 10000, | ||
57 | .r2_user_settings = ADF4350_REG2_PD_POLARITY_POS, | ||
58 | ADF4350_REG2_CHARGE_PUMP_CURR_uA(2500), | ||
59 | .r3_user_settings = ADF4350_REG3_12BIT_CLKDIV_MODE(0), | ||
60 | .r4_user_settings = ADF4350_REG4_OUTPUT_PWR(3) | | ||
61 | ADF4350_REG4_MUTE_TILL_LOCK_EN, | ||
62 | .gpio_lock_detect = -1, | ||
63 | }; | ||
64 | |||
65 | static int adf4350_sync_config(struct adf4350_state *st) | ||
66 | { | ||
67 | int ret, i, doublebuf = 0; | ||
68 | |||
69 | for (i = ADF4350_REG5; i >= ADF4350_REG0; i--) { | ||
70 | if ((st->regs_hw[i] != st->regs[i]) || | ||
71 | ((i == ADF4350_REG0) && doublebuf)) { | ||
72 | |||
73 | switch (i) { | ||
74 | case ADF4350_REG1: | ||
75 | case ADF4350_REG4: | ||
76 | doublebuf = 1; | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | st->val = cpu_to_be32(st->regs[i] | i); | ||
81 | ret = spi_write(st->spi, &st->val, 4); | ||
82 | if (ret < 0) | ||
83 | return ret; | ||
84 | st->regs_hw[i] = st->regs[i]; | ||
85 | dev_dbg(&st->spi->dev, "[%d] 0x%X\n", | ||
86 | i, (u32)st->regs[i] | i); | ||
87 | } | ||
88 | } | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int adf4350_reg_access(struct iio_dev *indio_dev, | ||
93 | unsigned reg, unsigned writeval, | ||
94 | unsigned *readval) | ||
95 | { | ||
96 | struct adf4350_state *st = iio_priv(indio_dev); | ||
97 | int ret; | ||
98 | |||
99 | if (reg > ADF4350_REG5) | ||
100 | return -EINVAL; | ||
101 | |||
102 | mutex_lock(&indio_dev->mlock); | ||
103 | if (readval == NULL) { | ||
104 | st->regs[reg] = writeval & ~(BIT(0) | BIT(1) | BIT(2)); | ||
105 | ret = adf4350_sync_config(st); | ||
106 | } else { | ||
107 | *readval = st->regs_hw[reg]; | ||
108 | ret = 0; | ||
109 | } | ||
110 | mutex_unlock(&indio_dev->mlock); | ||
111 | |||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | static int adf4350_tune_r_cnt(struct adf4350_state *st, unsigned short r_cnt) | ||
116 | { | ||
117 | struct adf4350_platform_data *pdata = st->pdata; | ||
118 | |||
119 | do { | ||
120 | r_cnt++; | ||
121 | st->fpfd = (st->clkin * (pdata->ref_doubler_en ? 2 : 1)) / | ||
122 | (r_cnt * (pdata->ref_div2_en ? 2 : 1)); | ||
123 | } while (st->fpfd > ADF4350_MAX_FREQ_PFD); | ||
124 | |||
125 | return r_cnt; | ||
126 | } | ||
127 | |||
128 | static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq) | ||
129 | { | ||
130 | struct adf4350_platform_data *pdata = st->pdata; | ||
131 | u64 tmp; | ||
132 | u32 div_gcd, prescaler; | ||
133 | u16 mdiv, r_cnt = 0; | ||
134 | u8 band_sel_div; | ||
135 | |||
136 | if (freq > ADF4350_MAX_OUT_FREQ || freq < st->min_out_freq) | ||
137 | return -EINVAL; | ||
138 | |||
139 | if (freq > ADF4350_MAX_FREQ_45_PRESC) { | ||
140 | prescaler = ADF4350_REG1_PRESCALER; | ||
141 | mdiv = 75; | ||
142 | } else { | ||
143 | prescaler = 0; | ||
144 | mdiv = 23; | ||
145 | } | ||
146 | |||
147 | st->r4_rf_div_sel = 0; | ||
148 | |||
149 | while (freq < ADF4350_MIN_VCO_FREQ) { | ||
150 | freq <<= 1; | ||
151 | st->r4_rf_div_sel++; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Allow a predefined reference division factor | ||
156 | * if not set, compute our own | ||
157 | */ | ||
158 | if (pdata->ref_div_factor) | ||
159 | r_cnt = pdata->ref_div_factor - 1; | ||
160 | |||
161 | do { | ||
162 | r_cnt = adf4350_tune_r_cnt(st, r_cnt); | ||
163 | |||
164 | st->r1_mod = st->fpfd / st->chspc; | ||
165 | while (st->r1_mod > ADF4350_MAX_MODULUS) { | ||
166 | r_cnt = adf4350_tune_r_cnt(st, r_cnt); | ||
167 | st->r1_mod = st->fpfd / st->chspc; | ||
168 | } | ||
169 | |||
170 | tmp = freq * (u64)st->r1_mod + (st->fpfd > 1); | ||
171 | do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */ | ||
172 | st->r0_fract = do_div(tmp, st->r1_mod); | ||
173 | st->r0_int = tmp; | ||
174 | } while (mdiv > st->r0_int); | ||
175 | |||
176 | band_sel_div = DIV_ROUND_UP(st->fpfd, ADF4350_MAX_BANDSEL_CLK); | ||
177 | |||
178 | if (st->r0_fract && st->r1_mod) { | ||
179 | div_gcd = gcd(st->r1_mod, st->r0_fract); | ||
180 | st->r1_mod /= div_gcd; | ||
181 | st->r0_fract /= div_gcd; | ||
182 | } else { | ||
183 | st->r0_fract = 0; | ||
184 | st->r1_mod = 1; | ||
185 | } | ||
186 | |||
187 | dev_dbg(&st->spi->dev, "VCO: %llu Hz, PFD %lu Hz\n" | ||
188 | "REF_DIV %d, R0_INT %d, R0_FRACT %d\n" | ||
189 | "R1_MOD %d, RF_DIV %d\nPRESCALER %s, BAND_SEL_DIV %d\n", | ||
190 | freq, st->fpfd, r_cnt, st->r0_int, st->r0_fract, st->r1_mod, | ||
191 | 1 << st->r4_rf_div_sel, prescaler ? "8/9" : "4/5", | ||
192 | band_sel_div); | ||
193 | |||
194 | st->regs[ADF4350_REG0] = ADF4350_REG0_INT(st->r0_int) | | ||
195 | ADF4350_REG0_FRACT(st->r0_fract); | ||
196 | |||
197 | st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(0) | | ||
198 | ADF4350_REG1_MOD(st->r1_mod) | | ||
199 | prescaler; | ||
200 | |||
201 | st->regs[ADF4350_REG2] = | ||
202 | ADF4350_REG2_10BIT_R_CNT(r_cnt) | | ||
203 | ADF4350_REG2_DOUBLE_BUFF_EN | | ||
204 | (pdata->ref_doubler_en ? ADF4350_REG2_RMULT2_EN : 0) | | ||
205 | (pdata->ref_div2_en ? ADF4350_REG2_RDIV2_EN : 0) | | ||
206 | (pdata->r2_user_settings & (ADF4350_REG2_PD_POLARITY_POS | | ||
207 | ADF4350_REG2_LDP_6ns | ADF4350_REG2_LDF_INT_N | | ||
208 | ADF4350_REG2_CHARGE_PUMP_CURR_uA(5000) | | ||
209 | ADF4350_REG2_MUXOUT(0x7) | ADF4350_REG2_NOISE_MODE(0x9))); | ||
210 | |||
211 | st->regs[ADF4350_REG3] = pdata->r3_user_settings & | ||
212 | (ADF4350_REG3_12BIT_CLKDIV(0xFFF) | | ||
213 | ADF4350_REG3_12BIT_CLKDIV_MODE(0x3) | | ||
214 | ADF4350_REG3_12BIT_CSR_EN | | ||
215 | ADF4351_REG3_CHARGE_CANCELLATION_EN | | ||
216 | ADF4351_REG3_ANTI_BACKLASH_3ns_EN | | ||
217 | ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH); | ||
218 | |||
219 | st->regs[ADF4350_REG4] = | ||
220 | ADF4350_REG4_FEEDBACK_FUND | | ||
221 | ADF4350_REG4_RF_DIV_SEL(st->r4_rf_div_sel) | | ||
222 | ADF4350_REG4_8BIT_BAND_SEL_CLKDIV(band_sel_div) | | ||
223 | ADF4350_REG4_RF_OUT_EN | | ||
224 | (pdata->r4_user_settings & | ||
225 | (ADF4350_REG4_OUTPUT_PWR(0x3) | | ||
226 | ADF4350_REG4_AUX_OUTPUT_PWR(0x3) | | ||
227 | ADF4350_REG4_AUX_OUTPUT_EN | | ||
228 | ADF4350_REG4_AUX_OUTPUT_FUND | | ||
229 | ADF4350_REG4_MUTE_TILL_LOCK_EN)); | ||
230 | |||
231 | st->regs[ADF4350_REG5] = ADF4350_REG5_LD_PIN_MODE_DIGITAL; | ||
232 | |||
233 | return adf4350_sync_config(st); | ||
234 | } | ||
235 | |||
236 | static ssize_t adf4350_write(struct iio_dev *indio_dev, | ||
237 | uintptr_t private, | ||
238 | const struct iio_chan_spec *chan, | ||
239 | const char *buf, size_t len) | ||
240 | { | ||
241 | struct adf4350_state *st = iio_priv(indio_dev); | ||
242 | unsigned long long readin; | ||
243 | int ret; | ||
244 | |||
245 | ret = kstrtoull(buf, 10, &readin); | ||
246 | if (ret) | ||
247 | return ret; | ||
248 | |||
249 | mutex_lock(&indio_dev->mlock); | ||
250 | switch ((u32)private) { | ||
251 | case ADF4350_FREQ: | ||
252 | ret = adf4350_set_freq(st, readin); | ||
253 | break; | ||
254 | case ADF4350_FREQ_REFIN: | ||
255 | if (readin > ADF4350_MAX_FREQ_REFIN) | ||
256 | ret = -EINVAL; | ||
257 | else | ||
258 | st->clkin = readin; | ||
259 | break; | ||
260 | case ADF4350_FREQ_RESOLUTION: | ||
261 | if (readin == 0) | ||
262 | ret = -EINVAL; | ||
263 | else | ||
264 | st->chspc = readin; | ||
265 | break; | ||
266 | case ADF4350_PWRDOWN: | ||
267 | if (readin) | ||
268 | st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN; | ||
269 | else | ||
270 | st->regs[ADF4350_REG2] &= ~ADF4350_REG2_POWER_DOWN_EN; | ||
271 | |||
272 | adf4350_sync_config(st); | ||
273 | break; | ||
274 | default: | ||
275 | ret = -ENODEV; | ||
276 | } | ||
277 | mutex_unlock(&indio_dev->mlock); | ||
278 | |||
279 | return ret ? ret : len; | ||
280 | } | ||
281 | |||
282 | static ssize_t adf4350_read(struct iio_dev *indio_dev, | ||
283 | uintptr_t private, | ||
284 | const struct iio_chan_spec *chan, | ||
285 | char *buf) | ||
286 | { | ||
287 | struct adf4350_state *st = iio_priv(indio_dev); | ||
288 | unsigned long long val; | ||
289 | int ret = 0; | ||
290 | |||
291 | mutex_lock(&indio_dev->mlock); | ||
292 | switch ((u32)private) { | ||
293 | case ADF4350_FREQ: | ||
294 | val = (u64)((st->r0_int * st->r1_mod) + st->r0_fract) * | ||
295 | (u64)st->fpfd; | ||
296 | do_div(val, st->r1_mod * (1 << st->r4_rf_div_sel)); | ||
297 | /* PLL unlocked? return error */ | ||
298 | if (gpio_is_valid(st->pdata->gpio_lock_detect)) | ||
299 | if (!gpio_get_value(st->pdata->gpio_lock_detect)) { | ||
300 | dev_dbg(&st->spi->dev, "PLL un-locked\n"); | ||
301 | ret = -EBUSY; | ||
302 | } | ||
303 | break; | ||
304 | case ADF4350_FREQ_REFIN: | ||
305 | val = st->clkin; | ||
306 | break; | ||
307 | case ADF4350_FREQ_RESOLUTION: | ||
308 | val = st->chspc; | ||
309 | break; | ||
310 | case ADF4350_PWRDOWN: | ||
311 | val = !!(st->regs[ADF4350_REG2] & ADF4350_REG2_POWER_DOWN_EN); | ||
312 | break; | ||
313 | } | ||
314 | mutex_unlock(&indio_dev->mlock); | ||
315 | |||
316 | return ret < 0 ? ret : sprintf(buf, "%llu\n", val); | ||
317 | } | ||
318 | |||
319 | #define _ADF4350_EXT_INFO(_name, _ident) { \ | ||
320 | .name = _name, \ | ||
321 | .read = adf4350_read, \ | ||
322 | .write = adf4350_write, \ | ||
323 | .private = _ident, \ | ||
324 | } | ||
325 | |||
326 | static const struct iio_chan_spec_ext_info adf4350_ext_info[] = { | ||
327 | /* Ideally we use IIO_CHAN_INFO_FREQUENCY, but there are | ||
328 | * values > 2^32 in order to support the entire frequency range | ||
329 | * in Hz. Using scale is a bit ugly. | ||
330 | */ | ||
331 | _ADF4350_EXT_INFO("frequency", ADF4350_FREQ), | ||
332 | _ADF4350_EXT_INFO("frequency_resolution", ADF4350_FREQ_RESOLUTION), | ||
333 | _ADF4350_EXT_INFO("refin_frequency", ADF4350_FREQ_REFIN), | ||
334 | _ADF4350_EXT_INFO("powerdown", ADF4350_PWRDOWN), | ||
335 | { }, | ||
336 | }; | ||
337 | |||
338 | static const struct iio_chan_spec adf4350_chan = { | ||
339 | .type = IIO_ALTVOLTAGE, | ||
340 | .indexed = 1, | ||
341 | .output = 1, | ||
342 | .ext_info = adf4350_ext_info, | ||
343 | }; | ||
344 | |||
345 | static const struct iio_info adf4350_info = { | ||
346 | .debugfs_reg_access = &adf4350_reg_access, | ||
347 | .driver_module = THIS_MODULE, | ||
348 | }; | ||
349 | |||
350 | static int __devinit adf4350_probe(struct spi_device *spi) | ||
351 | { | ||
352 | struct adf4350_platform_data *pdata = spi->dev.platform_data; | ||
353 | struct iio_dev *indio_dev; | ||
354 | struct adf4350_state *st; | ||
355 | int ret; | ||
356 | |||
357 | if (!pdata) { | ||
358 | dev_warn(&spi->dev, "no platform data? using default\n"); | ||
359 | |||
360 | pdata = &default_pdata; | ||
361 | } | ||
362 | |||
363 | indio_dev = iio_device_alloc(sizeof(*st)); | ||
364 | if (indio_dev == NULL) | ||
365 | return -ENOMEM; | ||
366 | |||
367 | st = iio_priv(indio_dev); | ||
368 | |||
369 | st->reg = regulator_get(&spi->dev, "vcc"); | ||
370 | if (!IS_ERR(st->reg)) { | ||
371 | ret = regulator_enable(st->reg); | ||
372 | if (ret) | ||
373 | goto error_put_reg; | ||
374 | } | ||
375 | |||
376 | spi_set_drvdata(spi, indio_dev); | ||
377 | st->spi = spi; | ||
378 | st->pdata = pdata; | ||
379 | |||
380 | indio_dev->dev.parent = &spi->dev; | ||
381 | indio_dev->name = (pdata->name[0] != 0) ? pdata->name : | ||
382 | spi_get_device_id(spi)->name; | ||
383 | |||
384 | indio_dev->info = &adf4350_info; | ||
385 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
386 | indio_dev->channels = &adf4350_chan; | ||
387 | indio_dev->num_channels = 1; | ||
388 | |||
389 | st->chspc = pdata->channel_spacing; | ||
390 | st->clkin = pdata->clkin; | ||
391 | |||
392 | st->min_out_freq = spi_get_device_id(spi)->driver_data == 4351 ? | ||
393 | ADF4351_MIN_OUT_FREQ : ADF4350_MIN_OUT_FREQ; | ||
394 | |||
395 | memset(st->regs_hw, 0xFF, sizeof(st->regs_hw)); | ||
396 | |||
397 | if (gpio_is_valid(pdata->gpio_lock_detect)) { | ||
398 | ret = gpio_request(pdata->gpio_lock_detect, indio_dev->name); | ||
399 | if (ret) { | ||
400 | dev_err(&spi->dev, "fail to request lock detect GPIO-%d", | ||
401 | pdata->gpio_lock_detect); | ||
402 | goto error_disable_reg; | ||
403 | } | ||
404 | gpio_direction_input(pdata->gpio_lock_detect); | ||
405 | } | ||
406 | |||
407 | if (pdata->power_up_frequency) { | ||
408 | ret = adf4350_set_freq(st, pdata->power_up_frequency); | ||
409 | if (ret) | ||
410 | goto error_free_gpio; | ||
411 | } | ||
412 | |||
413 | ret = iio_device_register(indio_dev); | ||
414 | if (ret) | ||
415 | goto error_free_gpio; | ||
416 | |||
417 | return 0; | ||
418 | |||
419 | error_free_gpio: | ||
420 | if (gpio_is_valid(pdata->gpio_lock_detect)) | ||
421 | gpio_free(pdata->gpio_lock_detect); | ||
422 | |||
423 | error_disable_reg: | ||
424 | if (!IS_ERR(st->reg)) | ||
425 | regulator_disable(st->reg); | ||
426 | error_put_reg: | ||
427 | if (!IS_ERR(st->reg)) | ||
428 | regulator_put(st->reg); | ||
429 | |||
430 | iio_device_free(indio_dev); | ||
431 | |||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | static int __devexit adf4350_remove(struct spi_device *spi) | ||
436 | { | ||
437 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
438 | struct adf4350_state *st = iio_priv(indio_dev); | ||
439 | struct regulator *reg = st->reg; | ||
440 | |||
441 | st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN; | ||
442 | adf4350_sync_config(st); | ||
443 | |||
444 | iio_device_unregister(indio_dev); | ||
445 | |||
446 | if (!IS_ERR(reg)) { | ||
447 | regulator_disable(reg); | ||
448 | regulator_put(reg); | ||
449 | } | ||
450 | |||
451 | if (gpio_is_valid(st->pdata->gpio_lock_detect)) | ||
452 | gpio_free(st->pdata->gpio_lock_detect); | ||
453 | |||
454 | iio_device_free(indio_dev); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static const struct spi_device_id adf4350_id[] = { | ||
460 | {"adf4350", 4350}, | ||
461 | {"adf4351", 4351}, | ||
462 | {} | ||
463 | }; | ||
464 | |||
465 | static struct spi_driver adf4350_driver = { | ||
466 | .driver = { | ||
467 | .name = "adf4350", | ||
468 | .owner = THIS_MODULE, | ||
469 | }, | ||
470 | .probe = adf4350_probe, | ||
471 | .remove = __devexit_p(adf4350_remove), | ||
472 | .id_table = adf4350_id, | ||
473 | }; | ||
474 | module_spi_driver(adf4350_driver); | ||
475 | |||
476 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
477 | MODULE_DESCRIPTION("Analog Devices ADF4350/ADF4351 PLL"); | ||
478 | MODULE_LICENSE("GPL v2"); | ||