diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-14 16:26:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-14 16:26:07 -0400 |
commit | b5cf43c47b05c8deb10f9674d541dddbdec0e341 (patch) | |
tree | 41c9b71c40f5f0d3cd702f0b602254867630e6a1 /sound/soc/at32/playpaq_wm8510.c | |
parent | b7f80afa28866c257876c272d6c013e0dbed3c31 (diff) | |
parent | fe0a3fe324811385b64790d42079bf534798a0cd (diff) |
Merge branch 'for-linus' of git://git.alsa-project.org/alsa-kernel
* 'for-linus' of git://git.alsa-project.org/alsa-kernel: (179 commits)
ALSA: Release v1.0.17
ALSA: correct kcalloc usage
ALSA: ALSA driver for SGI O2 audio board
ALSA: asoc: kbuild - only show menus for the current ASoC CPU platform.
ALSA: ALSA driver for SGI HAL2 audio device
ALSA: hda - Fix FSC V5505 model
ALSA: hda - Fix missing init for unsol events on micsense model
ALSA: hda - Fix internal mic vref pin setup
ALSA: hda: 92hd71bxx PC Beep
ALSA: HDA - HP dc7600 with pci sub IDs 0x103c/0x3011 belongs to hp-3013 model
ALSA: usb-audio: add some Yamaha USB MIDI quirks
ALSA: usb-audio: fix Yamaha KX quirk
ALSA: ASoC: Au12x0/Au1550 PSC Audio support
ALSA: Add Yamaha KX49 (USB MIDI controller) to usbquirks.h
ALSA: ASoC: pxa2xx-ac97: fix warning due to missing argument in fuction declaration
ALSA: tosa: fix compilation with new DAPM API
ALSA: wavefront - add const
ALSA: remove CONFIG_KMOD from sound
ALSA: Fix a const to non-const assignment in the Digigram VXpocket sound driver
ALSA: Fix a const pointer usage warning in the Digigram VX soundcard driver
...
Diffstat (limited to 'sound/soc/at32/playpaq_wm8510.c')
-rw-r--r-- | sound/soc/at32/playpaq_wm8510.c | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c new file mode 100644 index 000000000000..fee5f8e58957 --- /dev/null +++ b/sound/soc/at32/playpaq_wm8510.c | |||
@@ -0,0 +1,522 @@ | |||
1 | /* sound/soc/at32/playpaq_wm8510.c | ||
2 | * ASoC machine driver for PlayPaq using WM8510 codec | ||
3 | * | ||
4 | * Copyright (C) 2008 Long Range Systems | ||
5 | * Geoffrey Wossum <gwossum@acm.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c | ||
12 | * | ||
13 | * NOTE: If you don't have the AT32 enhanced portmux configured (which | ||
14 | * isn't currently in the mainline or Atmel patched kernel), you will | ||
15 | * need to set the MCLK pin (PA30) to peripheral A in your board initialization | ||
16 | * code. Something like: | ||
17 | * at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | /* #define DEBUG */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/version.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/clk.h> | ||
29 | #include <linux/timer.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | |||
33 | #include <sound/core.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/pcm_params.h> | ||
36 | #include <sound/soc.h> | ||
37 | #include <sound/soc-dapm.h> | ||
38 | |||
39 | #include <asm/arch/at32ap700x.h> | ||
40 | #include <asm/arch/portmux.h> | ||
41 | |||
42 | #include "../codecs/wm8510.h" | ||
43 | #include "at32-pcm.h" | ||
44 | #include "at32-ssc.h" | ||
45 | |||
46 | |||
47 | /*-------------------------------------------------------------------------*\ | ||
48 | * constants | ||
49 | \*-------------------------------------------------------------------------*/ | ||
50 | #define MCLK_PIN GPIO_PIN_PA(30) | ||
51 | #define MCLK_PERIPH GPIO_PERIPH_A | ||
52 | |||
53 | |||
54 | /*-------------------------------------------------------------------------*\ | ||
55 | * data types | ||
56 | \*-------------------------------------------------------------------------*/ | ||
57 | /* SSC clocking data */ | ||
58 | struct ssc_clock_data { | ||
59 | /* CMR div */ | ||
60 | unsigned int cmr_div; | ||
61 | |||
62 | /* Frame period (as needed by xCMR.PERIOD) */ | ||
63 | unsigned int period; | ||
64 | |||
65 | /* The SSC clock rate these settings where calculated for */ | ||
66 | unsigned long ssc_rate; | ||
67 | }; | ||
68 | |||
69 | |||
70 | /*-------------------------------------------------------------------------*\ | ||
71 | * module data | ||
72 | \*-------------------------------------------------------------------------*/ | ||
73 | static struct clk *_gclk0; | ||
74 | static struct clk *_pll0; | ||
75 | |||
76 | #define CODEC_CLK (_gclk0) | ||
77 | |||
78 | |||
79 | /*-------------------------------------------------------------------------*\ | ||
80 | * Sound SOC operations | ||
81 | \*-------------------------------------------------------------------------*/ | ||
82 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
83 | static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( | ||
84 | struct snd_pcm_hw_params *params, | ||
85 | struct snd_soc_dai *cpu_dai) | ||
86 | { | ||
87 | struct at32_ssc_info *ssc_p = cpu_dai->private_data; | ||
88 | struct ssc_device *ssc = ssc_p->ssc; | ||
89 | struct ssc_clock_data cd; | ||
90 | unsigned int rate, width_bits, channels; | ||
91 | unsigned int bitrate, ssc_div; | ||
92 | unsigned actual_rate; | ||
93 | |||
94 | |||
95 | /* | ||
96 | * Figure out required bitrate | ||
97 | */ | ||
98 | rate = params_rate(params); | ||
99 | channels = params_channels(params); | ||
100 | width_bits = snd_pcm_format_physical_width(params_format(params)); | ||
101 | bitrate = rate * width_bits * channels; | ||
102 | |||
103 | |||
104 | /* | ||
105 | * Figure out required SSC divider and period for required bitrate | ||
106 | */ | ||
107 | cd.ssc_rate = clk_get_rate(ssc->clk); | ||
108 | ssc_div = cd.ssc_rate / bitrate; | ||
109 | cd.cmr_div = ssc_div / 2; | ||
110 | if (ssc_div & 1) { | ||
111 | /* round cmr_div up */ | ||
112 | cd.cmr_div++; | ||
113 | } | ||
114 | cd.period = width_bits - 1; | ||
115 | |||
116 | |||
117 | /* | ||
118 | * Find actual rate, compare to requested rate | ||
119 | */ | ||
120 | actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); | ||
121 | pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n", | ||
122 | rate, actual_rate); | ||
123 | |||
124 | |||
125 | return cd; | ||
126 | } | ||
127 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | ||
128 | |||
129 | |||
130 | |||
131 | static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, | ||
132 | struct snd_pcm_hw_params *params) | ||
133 | { | ||
134 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
135 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
136 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
137 | struct at32_ssc_info *ssc_p = cpu_dai->private_data; | ||
138 | struct ssc_device *ssc = ssc_p->ssc; | ||
139 | unsigned int pll_out = 0, bclk = 0, mclk_div = 0; | ||
140 | int ret; | ||
141 | |||
142 | |||
143 | /* Due to difficulties with getting the correct clocks from the AT32's | ||
144 | * PLL0, we're going to let the CODEC be in charge of all the clocks | ||
145 | */ | ||
146 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
147 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | | ||
148 | SND_SOC_DAIFMT_NB_NF | | ||
149 | SND_SOC_DAIFMT_CBM_CFM); | ||
150 | #else | ||
151 | struct ssc_clock_data cd; | ||
152 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | | ||
153 | SND_SOC_DAIFMT_NB_NF | | ||
154 | SND_SOC_DAIFMT_CBS_CFS); | ||
155 | #endif | ||
156 | |||
157 | if (ssc == NULL) { | ||
158 | pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n"); | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | |||
163 | /* | ||
164 | * Figure out PLL and BCLK dividers for WM8510 | ||
165 | */ | ||
166 | switch (params_rate(params)) { | ||
167 | case 48000: | ||
168 | pll_out = 12288000; | ||
169 | mclk_div = WM8510_MCLKDIV_1; | ||
170 | bclk = WM8510_BCLKDIV_8; | ||
171 | break; | ||
172 | |||
173 | case 44100: | ||
174 | pll_out = 11289600; | ||
175 | mclk_div = WM8510_MCLKDIV_1; | ||
176 | bclk = WM8510_BCLKDIV_8; | ||
177 | break; | ||
178 | |||
179 | case 22050: | ||
180 | pll_out = 11289600; | ||
181 | mclk_div = WM8510_MCLKDIV_2; | ||
182 | bclk = WM8510_BCLKDIV_8; | ||
183 | break; | ||
184 | |||
185 | case 16000: | ||
186 | pll_out = 12288000; | ||
187 | mclk_div = WM8510_MCLKDIV_3; | ||
188 | bclk = WM8510_BCLKDIV_8; | ||
189 | break; | ||
190 | |||
191 | case 11025: | ||
192 | pll_out = 11289600; | ||
193 | mclk_div = WM8510_MCLKDIV_4; | ||
194 | bclk = WM8510_BCLKDIV_8; | ||
195 | break; | ||
196 | |||
197 | case 8000: | ||
198 | pll_out = 12288000; | ||
199 | mclk_div = WM8510_MCLKDIV_6; | ||
200 | bclk = WM8510_BCLKDIV_8; | ||
201 | break; | ||
202 | |||
203 | default: | ||
204 | pr_warning("playpaq_wm8510: Unsupported sample rate %d\n", | ||
205 | params_rate(params)); | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | |||
210 | /* | ||
211 | * set CPU and CODEC DAI configuration | ||
212 | */ | ||
213 | ret = snd_soc_dai_set_fmt(codec_dai, fmt); | ||
214 | if (ret < 0) { | ||
215 | pr_warning("playpaq_wm8510: " | ||
216 | "Failed to set CODEC DAI format (%d)\n", | ||
217 | ret); | ||
218 | return ret; | ||
219 | } | ||
220 | ret = snd_soc_dai_set_fmt(cpu_dai, fmt); | ||
221 | if (ret < 0) { | ||
222 | pr_warning("playpaq_wm8510: " | ||
223 | "Failed to set CPU DAI format (%d)\n", | ||
224 | ret); | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | |||
229 | /* | ||
230 | * Set CPU clock configuration | ||
231 | */ | ||
232 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
233 | cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai); | ||
234 | pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n", | ||
235 | cd.cmr_div, cd.period); | ||
236 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div); | ||
237 | if (ret < 0) { | ||
238 | pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n", | ||
239 | ret); | ||
240 | return ret; | ||
241 | } | ||
242 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD, | ||
243 | cd.period); | ||
244 | if (ret < 0) { | ||
245 | pr_warning("playpaq_wm8510: " | ||
246 | "Failed to set CPU transmit period (%d)\n", | ||
247 | ret); | ||
248 | return ret; | ||
249 | } | ||
250 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | ||
251 | |||
252 | |||
253 | /* | ||
254 | * Set CODEC clock configuration | ||
255 | */ | ||
256 | pr_debug("playpaq_wm8510: " | ||
257 | "pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n", | ||
258 | clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div); | ||
259 | |||
260 | |||
261 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
262 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk); | ||
263 | if (ret < 0) { | ||
264 | pr_warning | ||
265 | ("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n", | ||
266 | ret); | ||
267 | return ret; | ||
268 | } | ||
269 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | ||
270 | |||
271 | |||
272 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
273 | clk_get_rate(CODEC_CLK), pll_out); | ||
274 | if (ret < 0) { | ||
275 | pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", | ||
276 | ret); | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | |||
281 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div); | ||
282 | if (ret < 0) { | ||
283 | pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n", | ||
284 | ret); | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | |||
293 | |||
294 | static struct snd_soc_ops playpaq_wm8510_ops = { | ||
295 | .hw_params = playpaq_wm8510_hw_params, | ||
296 | }; | ||
297 | |||
298 | |||
299 | |||
300 | static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = { | ||
301 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
302 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
303 | }; | ||
304 | |||
305 | |||
306 | |||
307 | static const char *intercon[][3] = { | ||
308 | /* speaker connected to SPKOUT */ | ||
309 | {"Ext Spk", NULL, "SPKOUTP"}, | ||
310 | {"Ext Spk", NULL, "SPKOUTN"}, | ||
311 | |||
312 | {"Mic Bias", NULL, "Int Mic"}, | ||
313 | {"MICN", NULL, "Mic Bias"}, | ||
314 | {"MICP", NULL, "Mic Bias"}, | ||
315 | |||
316 | /* Terminator */ | ||
317 | {NULL, NULL, NULL}, | ||
318 | }; | ||
319 | |||
320 | |||
321 | |||
322 | static int playpaq_wm8510_init(struct snd_soc_codec *codec) | ||
323 | { | ||
324 | int i; | ||
325 | |||
326 | /* | ||
327 | * Add DAPM widgets | ||
328 | */ | ||
329 | for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++) | ||
330 | snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]); | ||
331 | |||
332 | |||
333 | |||
334 | /* | ||
335 | * Setup audio path interconnects | ||
336 | */ | ||
337 | for (i = 0; intercon[i][0] != NULL; i++) { | ||
338 | snd_soc_dapm_connect_input(codec, | ||
339 | intercon[i][0], | ||
340 | intercon[i][1], intercon[i][2]); | ||
341 | } | ||
342 | |||
343 | |||
344 | /* always connected pins */ | ||
345 | snd_soc_dapm_enable_pin(codec, "Int Mic"); | ||
346 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
347 | snd_soc_dapm_sync(codec); | ||
348 | |||
349 | |||
350 | |||
351 | /* Make CSB show PLL rate */ | ||
352 | snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV, | ||
353 | WM8510_OPCLKDIV_1 | 4); | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | |||
359 | |||
360 | static struct snd_soc_dai_link playpaq_wm8510_dai = { | ||
361 | .name = "WM8510", | ||
362 | .stream_name = "WM8510 PCM", | ||
363 | .cpu_dai = &at32_ssc_dai[0], | ||
364 | .codec_dai = &wm8510_dai, | ||
365 | .init = playpaq_wm8510_init, | ||
366 | .ops = &playpaq_wm8510_ops, | ||
367 | }; | ||
368 | |||
369 | |||
370 | |||
371 | static struct snd_soc_machine snd_soc_machine_playpaq = { | ||
372 | .name = "LRS_PlayPaq_WM8510", | ||
373 | .dai_link = &playpaq_wm8510_dai, | ||
374 | .num_links = 1, | ||
375 | }; | ||
376 | |||
377 | |||
378 | |||
379 | static struct wm8510_setup_data playpaq_wm8510_setup = { | ||
380 | .i2c_address = 0x1a, | ||
381 | }; | ||
382 | |||
383 | |||
384 | |||
385 | static struct snd_soc_device playpaq_wm8510_snd_devdata = { | ||
386 | .machine = &snd_soc_machine_playpaq, | ||
387 | .platform = &at32_soc_platform, | ||
388 | .codec_dev = &soc_codec_dev_wm8510, | ||
389 | .codec_data = &playpaq_wm8510_setup, | ||
390 | }; | ||
391 | |||
392 | static struct platform_device *playpaq_snd_device; | ||
393 | |||
394 | |||
395 | static int __init playpaq_asoc_init(void) | ||
396 | { | ||
397 | int ret = 0; | ||
398 | struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; | ||
399 | struct ssc_device *ssc = NULL; | ||
400 | |||
401 | |||
402 | /* | ||
403 | * Request SSC device | ||
404 | */ | ||
405 | ssc = ssc_request(0); | ||
406 | if (IS_ERR(ssc)) { | ||
407 | ret = PTR_ERR(ssc); | ||
408 | ssc = NULL; | ||
409 | goto err_ssc; | ||
410 | } | ||
411 | ssc_p->ssc = ssc; | ||
412 | |||
413 | |||
414 | /* | ||
415 | * Configure MCLK for WM8510 | ||
416 | */ | ||
417 | _gclk0 = clk_get(NULL, "gclk0"); | ||
418 | if (IS_ERR(_gclk0)) { | ||
419 | _gclk0 = NULL; | ||
420 | goto err_gclk0; | ||
421 | } | ||
422 | _pll0 = clk_get(NULL, "pll0"); | ||
423 | if (IS_ERR(_pll0)) { | ||
424 | _pll0 = NULL; | ||
425 | goto err_pll0; | ||
426 | } | ||
427 | if (clk_set_parent(_gclk0, _pll0)) { | ||
428 | pr_warning("snd-soc-playpaq: " | ||
429 | "Failed to set PLL0 as parent for DAC clock\n"); | ||
430 | goto err_set_clk; | ||
431 | } | ||
432 | clk_set_rate(CODEC_CLK, 12000000); | ||
433 | clk_enable(CODEC_CLK); | ||
434 | |||
435 | #if defined CONFIG_AT32_ENHANCED_PORTMUX | ||
436 | at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0); | ||
437 | #endif | ||
438 | |||
439 | |||
440 | /* | ||
441 | * Create and register platform device | ||
442 | */ | ||
443 | playpaq_snd_device = platform_device_alloc("soc-audio", 0); | ||
444 | if (playpaq_snd_device == NULL) { | ||
445 | ret = -ENOMEM; | ||
446 | goto err_device_alloc; | ||
447 | } | ||
448 | |||
449 | platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata); | ||
450 | playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev; | ||
451 | |||
452 | ret = platform_device_add(playpaq_snd_device); | ||
453 | if (ret) { | ||
454 | pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n", | ||
455 | ret); | ||
456 | goto err_device_add; | ||
457 | } | ||
458 | |||
459 | return 0; | ||
460 | |||
461 | |||
462 | err_device_add: | ||
463 | if (playpaq_snd_device != NULL) { | ||
464 | platform_device_put(playpaq_snd_device); | ||
465 | playpaq_snd_device = NULL; | ||
466 | } | ||
467 | err_device_alloc: | ||
468 | err_set_clk: | ||
469 | if (_pll0 != NULL) { | ||
470 | clk_put(_pll0); | ||
471 | _pll0 = NULL; | ||
472 | } | ||
473 | err_pll0: | ||
474 | if (_gclk0 != NULL) { | ||
475 | clk_put(_gclk0); | ||
476 | _gclk0 = NULL; | ||
477 | } | ||
478 | err_gclk0: | ||
479 | if (ssc != NULL) { | ||
480 | ssc_free(ssc); | ||
481 | ssc = NULL; | ||
482 | } | ||
483 | err_ssc: | ||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | |||
488 | static void __exit playpaq_asoc_exit(void) | ||
489 | { | ||
490 | struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; | ||
491 | struct ssc_device *ssc; | ||
492 | |||
493 | if (ssc_p != NULL) { | ||
494 | ssc = ssc_p->ssc; | ||
495 | if (ssc != NULL) | ||
496 | ssc_free(ssc); | ||
497 | ssc_p->ssc = NULL; | ||
498 | } | ||
499 | |||
500 | if (_gclk0 != NULL) { | ||
501 | clk_put(_gclk0); | ||
502 | _gclk0 = NULL; | ||
503 | } | ||
504 | if (_pll0 != NULL) { | ||
505 | clk_put(_pll0); | ||
506 | _pll0 = NULL; | ||
507 | } | ||
508 | |||
509 | #if defined CONFIG_AT32_ENHANCED_PORTMUX | ||
510 | at32_free_pin(MCLK_PIN); | ||
511 | #endif | ||
512 | |||
513 | platform_device_unregister(playpaq_snd_device); | ||
514 | playpaq_snd_device = NULL; | ||
515 | } | ||
516 | |||
517 | module_init(playpaq_asoc_init); | ||
518 | module_exit(playpaq_asoc_exit); | ||
519 | |||
520 | MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); | ||
521 | MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq"); | ||
522 | MODULE_LICENSE("GPL"); | ||