[brcm63xx] boards: Added GW6x00 fixups and GPIOs. The GW6200 GPIOs are different...
[openwrt.git] / target / linux / xburst / patches-2.6.35 / 060-jzcodec.patch
1 From 382d2274cfd8fc22064a33681e45668cfb6f91ad Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Sun, 1 Aug 2010 21:14:09 +0200
4 Subject: [PATCH] ASoC: Add JZ4740 codec driver
5
6 This patch adds support for the JZ4740 internal codec.
7
8 Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
9 Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
10 Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
11 ---
12 sound/soc/codecs/Kconfig | 4 +
13 sound/soc/codecs/Makefile | 2 +
14 sound/soc/codecs/jz4740.c | 511 +++++++++++++++++++++++++++++++++++++++++++++
15 sound/soc/codecs/jz4740.h | 20 ++
16 4 files changed, 537 insertions(+), 0 deletions(-)
17 create mode 100644 sound/soc/codecs/jz4740.c
18 create mode 100644 sound/soc/codecs/jz4740.h
19
20 --- a/sound/soc/codecs/Kconfig
21 +++ b/sound/soc/codecs/Kconfig
22 @@ -23,6 +23,7 @@ config SND_SOC_ALL_CODECS
23 select SND_SOC_AK4671 if I2C
24 select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
25 select SND_SOC_CS4270 if I2C
26 + select SND_SOC_JZ4740 if SOC_JZ4740
27 select SND_SOC_MAX9877 if I2C
28 select SND_SOC_DA7210 if I2C
29 select SND_SOC_PCM3008
30 @@ -138,6 +139,9 @@ config SND_SOC_CS4270_VD33_ERRATA
31 config SND_SOC_CX20442
32 tristate
33
34 +config SND_SOC_JZ4740_CODEC
35 + tristate
36 +
37 config SND_SOC_L3
38 tristate
39
40 --- a/sound/soc/codecs/Makefile
41 +++ b/sound/soc/codecs/Makefile
42 @@ -56,6 +56,7 @@ snd-soc-wm9705-objs := wm9705.o
43 snd-soc-wm9712-objs := wm9712.o
44 snd-soc-wm9713-objs := wm9713.o
45 snd-soc-wm-hubs-objs := wm_hubs.o
46 +snd-soc-jz4740-codec-objs := jz4740.o
47
48 # Amp
49 snd-soc-max9877-objs := max9877.o
50 @@ -78,6 +79,7 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-
51 obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
52 obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
53 obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
54 +obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
55 obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
56 obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
57 obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
58 --- /dev/null
59 +++ b/sound/soc/codecs/jz4740.c
60 @@ -0,0 +1,511 @@
61 +/*
62 + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
63 + *
64 + * This program is free software; you can redistribute it and/or modify
65 + * it under the terms of the GNU General Public License version 2 as
66 + * published by the Free Software Foundation.
67 + *
68 + * You should have received a copy of the GNU General Public License along
69 + * with this program; if not, write to the Free Software Foundation, Inc.,
70 + * 675 Mass Ave, Cambridge, MA 02139, USA.
71 + *
72 + */
73 +
74 +#include <linux/kernel.h>
75 +#include <linux/module.h>
76 +#include <linux/platform_device.h>
77 +#include <linux/slab.h>
78 +
79 +#include <linux/delay.h>
80 +
81 +#include <sound/core.h>
82 +#include <sound/pcm.h>
83 +#include <sound/pcm_params.h>
84 +#include <sound/initval.h>
85 +#include <sound/soc-dapm.h>
86 +#include <sound/soc.h>
87 +
88 +#define JZ4740_REG_CODEC_1 0x0
89 +#define JZ4740_REG_CODEC_2 0x1
90 +
91 +#define JZ4740_CODEC_1_LINE_ENABLE BIT(29)
92 +#define JZ4740_CODEC_1_MIC_ENABLE BIT(28)
93 +#define JZ4740_CODEC_1_SW1_ENABLE BIT(27)
94 +#define JZ4740_CODEC_1_ADC_ENABLE BIT(26)
95 +#define JZ4740_CODEC_1_SW2_ENABLE BIT(25)
96 +#define JZ4740_CODEC_1_DAC_ENABLE BIT(24)
97 +#define JZ4740_CODEC_1_VREF_DISABLE BIT(20)
98 +#define JZ4740_CODEC_1_VREF_AMP_DISABLE BIT(19)
99 +#define JZ4740_CODEC_1_VREF_PULLDOWN BIT(18)
100 +#define JZ4740_CODEC_1_VREF_LOW_CURRENT BIT(17)
101 +#define JZ4740_CODEC_1_VREF_HIGH_CURRENT BIT(16)
102 +#define JZ4740_CODEC_1_HEADPHONE_DISABLE BIT(14)
103 +#define JZ4740_CODEC_1_HEADPHONE_AMP_CHANGE_ANY BIT(13)
104 +#define JZ4740_CODEC_1_HEADPHONE_CHARGE BIT(12)
105 +#define JZ4740_CODEC_1_HEADPHONE_PULLDOWN (BIT(11) | BIT(10))
106 +#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M BIT(9)
107 +#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN BIT(8)
108 +#define JZ4740_CODEC_1_SUSPEND BIT(1)
109 +#define JZ4740_CODEC_1_RESET BIT(0)
110 +
111 +#define JZ4740_CODEC_1_LINE_ENABLE_OFFSET 29
112 +#define JZ4740_CODEC_1_MIC_ENABLE_OFFSET 28
113 +#define JZ4740_CODEC_1_SW1_ENABLE_OFFSET 27
114 +#define JZ4740_CODEC_1_ADC_ENABLE_OFFSET 26
115 +#define JZ4740_CODEC_1_SW2_ENABLE_OFFSET 25
116 +#define JZ4740_CODEC_1_DAC_ENABLE_OFFSET 24
117 +#define JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET 14
118 +#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET 8
119 +
120 +#define JZ4740_CODEC_2_INPUT_VOLUME_MASK 0x1f0000
121 +#define JZ4740_CODEC_2_SAMPLE_RATE_MASK 0x000f00
122 +#define JZ4740_CODEC_2_MIC_BOOST_GAIN_MASK 0x000030
123 +#define JZ4740_CODEC_2_HEADPHONE_VOLUME_MASK 0x000003
124 +
125 +#define JZ4740_CODEC_2_INPUT_VOLUME_OFFSET 16
126 +#define JZ4740_CODEC_2_SAMPLE_RATE_OFFSET 8
127 +#define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET 4
128 +#define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET 0
129 +
130 +static const uint32_t jz4740_codec_regs[] = {
131 + 0x021b2302, 0x00170803,
132 +};
133 +
134 +struct jz4740_codec {
135 + void __iomem *base;
136 + struct resource *mem;
137 +
138 + uint32_t reg_cache[2];
139 + struct snd_soc_codec codec;
140 +};
141 +
142 +static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec)
143 +{
144 + return container_of(codec, struct jz4740_codec, codec);
145 +}
146 +
147 +static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
148 + unsigned int reg)
149 +{
150 + struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
151 + return readl(jz4740_codec->base + (reg << 2));
152 +}
153 +
154 +static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
155 + unsigned int val)
156 +{
157 + struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
158 +
159 + jz4740_codec->reg_cache[reg] = val;
160 + writel(val, jz4740_codec->base + (reg << 2));
161 +
162 + return 0;
163 +}
164 +
165 +static const struct snd_kcontrol_new jz4740_codec_controls[] = {
166 + SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2,
167 + JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0),
168 + SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2,
169 + JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0),
170 + SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1,
171 + JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1),
172 + SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2,
173 + JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0),
174 +};
175 +
176 +static const struct snd_kcontrol_new jz4740_codec_output_controls[] = {
177 + SOC_DAPM_SINGLE("Bypass Switch", JZ4740_REG_CODEC_1,
178 + JZ4740_CODEC_1_SW1_ENABLE_OFFSET, 1, 0),
179 + SOC_DAPM_SINGLE("DAC Switch", JZ4740_REG_CODEC_1,
180 + JZ4740_CODEC_1_SW2_ENABLE_OFFSET, 1, 0),
181 +};
182 +
183 +static const struct snd_kcontrol_new jz4740_codec_input_controls[] = {
184 + SOC_DAPM_SINGLE("Line Capture Switch", JZ4740_REG_CODEC_1,
185 + JZ4740_CODEC_1_LINE_ENABLE_OFFSET, 1, 0),
186 + SOC_DAPM_SINGLE("Mic Capture Switch", JZ4740_REG_CODEC_1,
187 + JZ4740_CODEC_1_MIC_ENABLE_OFFSET, 1, 0),
188 +};
189 +
190 +static const struct snd_soc_dapm_widget jz4740_codec_dapm_widgets[] = {
191 + SND_SOC_DAPM_ADC("ADC", "Capture", JZ4740_REG_CODEC_1,
192 + JZ4740_CODEC_1_ADC_ENABLE_OFFSET, 0),
193 + SND_SOC_DAPM_DAC("DAC", "Playback", JZ4740_REG_CODEC_1,
194 + JZ4740_CODEC_1_DAC_ENABLE_OFFSET, 0),
195 +
196 + SND_SOC_DAPM_MIXER("Output Mixer", JZ4740_REG_CODEC_1,
197 + JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET, 1,
198 + jz4740_codec_output_controls,
199 + ARRAY_SIZE(jz4740_codec_output_controls)),
200 +
201 + SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
202 + jz4740_codec_input_controls,
203 + ARRAY_SIZE(jz4740_codec_input_controls)),
204 + SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0),
205 +
206 + SND_SOC_DAPM_OUTPUT("LOUT"),
207 + SND_SOC_DAPM_OUTPUT("ROUT"),
208 +
209 + SND_SOC_DAPM_INPUT("MIC"),
210 + SND_SOC_DAPM_INPUT("LIN"),
211 + SND_SOC_DAPM_INPUT("RIN"),
212 +};
213 +
214 +static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = {
215 + {"Line Input", NULL, "LIN"},
216 + {"Line Input", NULL, "RIN"},
217 +
218 + {"Input Mixer", "Line Capture Switch", "Line Input"},
219 + {"Input Mixer", "Mic Capture Switch", "MIC"},
220 +
221 + {"ADC", NULL, "Input Mixer"},
222 +
223 + {"Output Mixer", "Bypass Switch", "Input Mixer"},
224 + {"Output Mixer", "DAC Switch", "DAC"},
225 +
226 + {"LOUT", NULL, "Output Mixer"},
227 + {"ROUT", NULL, "Output Mixer"},
228 +};
229 +
230 +static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
231 + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
232 +{
233 + uint32_t val;
234 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
235 + struct snd_soc_device *socdev = rtd->socdev;
236 + struct snd_soc_codec *codec = socdev->card->codec;
237 +
238 + switch (params_rate(params)) {
239 + case 8000:
240 + val = 0;
241 + break;
242 + case 11025:
243 + val = 1;
244 + break;
245 + case 12000:
246 + val = 2;
247 + break;
248 + case 16000:
249 + val = 3;
250 + break;
251 + case 22050:
252 + val = 4;
253 + break;
254 + case 24000:
255 + val = 5;
256 + break;
257 + case 32000:
258 + val = 6;
259 + break;
260 + case 44100:
261 + val = 7;
262 + break;
263 + case 48000:
264 + val = 8;
265 + break;
266 + default:
267 + return -EINVAL;
268 + }
269 +
270 + val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET;
271 +
272 + snd_soc_update_bits(codec, JZ4740_REG_CODEC_2,
273 + JZ4740_CODEC_2_SAMPLE_RATE_MASK, val);
274 +
275 + return 0;
276 +}
277 +
278 +static struct snd_soc_dai_ops jz4740_codec_dai_ops = {
279 + .hw_params = jz4740_codec_hw_params,
280 +};
281 +
282 +struct snd_soc_dai jz4740_codec_dai = {
283 + .name = "jz4740",
284 + .playback = {
285 + .stream_name = "Playback",
286 + .channels_min = 2,
287 + .channels_max = 2,
288 + .rates = SNDRV_PCM_RATE_8000_48000,
289 + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
290 + },
291 + .capture = {
292 + .stream_name = "Capture",
293 + .channels_min = 2,
294 + .channels_max = 2,
295 + .rates = SNDRV_PCM_RATE_8000_48000,
296 + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
297 + },
298 + .ops = &jz4740_codec_dai_ops,
299 + .symmetric_rates = 1,
300 +};
301 +EXPORT_SYMBOL_GPL(jz4740_codec_dai);
302 +
303 +static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
304 +{
305 + int i;
306 + uint32_t *cache = codec->reg_cache;
307 +
308 + snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
309 + JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);
310 + udelay(2);
311 +
312 + snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
313 + JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0);
314 +
315 + for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i)
316 + jz4740_codec_write(codec, i, cache[i]);
317 +}
318 +
319 +static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
320 + enum snd_soc_bias_level level)
321 +{
322 + unsigned int mask;
323 + unsigned int value;
324 +
325 + switch (level) {
326 + case SND_SOC_BIAS_ON:
327 + break;
328 + case SND_SOC_BIAS_PREPARE:
329 + mask = JZ4740_CODEC_1_VREF_DISABLE |
330 + JZ4740_CODEC_1_VREF_AMP_DISABLE |
331 + JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
332 + value = 0;
333 +
334 + snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
335 + break;
336 + case SND_SOC_BIAS_STANDBY:
337 + /* The only way to clear the suspend flag is to reset the codec */
338 + if (codec->bias_level == SND_SOC_BIAS_OFF)
339 + jz4740_codec_wakeup(codec);
340 +
341 + mask = JZ4740_CODEC_1_VREF_DISABLE |
342 + JZ4740_CODEC_1_VREF_AMP_DISABLE |
343 + JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
344 + value = JZ4740_CODEC_1_VREF_DISABLE |
345 + JZ4740_CODEC_1_VREF_AMP_DISABLE |
346 + JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
347 +
348 + snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
349 + break;
350 + case SND_SOC_BIAS_OFF:
351 + mask = JZ4740_CODEC_1_SUSPEND;
352 + value = JZ4740_CODEC_1_SUSPEND;
353 +
354 + snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
355 + break;
356 + default:
357 + break;
358 + }
359 +
360 + codec->bias_level = level;
361 +
362 + return 0;
363 +}
364 +
365 +static struct snd_soc_codec *jz4740_codec_codec;
366 +
367 +static int jz4740_codec_dev_probe(struct platform_device *pdev)
368 +{
369 + int ret;
370 + struct snd_soc_device *socdev = platform_get_drvdata(pdev);
371 + struct snd_soc_codec *codec = jz4740_codec_codec;
372 +
373 + BUG_ON(!codec);
374 +
375 + socdev->card->codec = codec;
376 +
377 + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
378 + if (ret) {
379 + dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret);
380 + return ret;
381 + }
382 +
383 + snd_soc_add_controls(codec, jz4740_codec_controls,
384 + ARRAY_SIZE(jz4740_codec_controls));
385 +
386 + snd_soc_dapm_new_controls(codec, jz4740_codec_dapm_widgets,
387 + ARRAY_SIZE(jz4740_codec_dapm_widgets));
388 +
389 + snd_soc_dapm_add_routes(codec, jz4740_codec_dapm_routes,
390 + ARRAY_SIZE(jz4740_codec_dapm_routes));
391 +
392 + snd_soc_dapm_new_widgets(codec);
393 +
394 + return 0;
395 +}
396 +
397 +static int jz4740_codec_dev_remove(struct platform_device *pdev)
398 +{
399 + struct snd_soc_device *socdev = platform_get_drvdata(pdev);
400 +
401 + snd_soc_free_pcms(socdev);
402 + snd_soc_dapm_free(socdev);
403 +
404 + return 0;
405 +}
406 +
407 +#ifdef CONFIG_PM_SLEEP
408 +
409 +static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state)
410 +{
411 + struct snd_soc_device *socdev = platform_get_drvdata(pdev);
412 + struct snd_soc_codec *codec = socdev->card->codec;
413 +
414 + return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
415 +}
416 +
417 +static int jz4740_codec_resume(struct platform_device *pdev)
418 +{
419 + struct snd_soc_device *socdev = platform_get_drvdata(pdev);
420 + struct snd_soc_codec *codec = socdev->card->codec;
421 +
422 + return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
423 +}
424 +
425 +#else
426 +#define jz4740_codec_suspend NULL
427 +#define jz4740_codec_resume NULL
428 +#endif
429 +
430 +struct snd_soc_codec_device soc_codec_dev_jz4740_codec = {
431 + .probe = jz4740_codec_dev_probe,
432 + .remove = jz4740_codec_dev_remove,
433 + .suspend = jz4740_codec_suspend,
434 + .resume = jz4740_codec_resume,
435 +};
436 +EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec);
437 +
438 +static int __devinit jz4740_codec_probe(struct platform_device *pdev)
439 +{
440 + int ret;
441 + struct jz4740_codec *jz4740_codec;
442 + struct snd_soc_codec *codec;
443 + struct resource *mem;
444 +
445 + jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
446 + if (!jz4740_codec)
447 + return -ENOMEM;
448 +
449 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
450 + if (!mem) {
451 + dev_err(&pdev->dev, "Failed to get mmio memory resource\n");
452 + ret = -ENOENT;
453 + goto err_free_codec;
454 + }
455 +
456 + mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
457 + if (!mem) {
458 + dev_err(&pdev->dev, "Failed to request mmio memory region\n");
459 + ret = -EBUSY;
460 + goto err_free_codec;
461 + }
462 +
463 + jz4740_codec->base = ioremap(mem->start, resource_size(mem));
464 + if (!jz4740_codec->base) {
465 + dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
466 + ret = -EBUSY;
467 + goto err_release_mem_region;
468 + }
469 + jz4740_codec->mem = mem;
470 +
471 + jz4740_codec_dai.dev = &pdev->dev;
472 +
473 + codec = &jz4740_codec->codec;
474 +
475 + codec->dev = &pdev->dev;
476 + codec->name = "jz4740";
477 + codec->owner = THIS_MODULE;
478 +
479 + codec->read = jz4740_codec_read;
480 + codec->write = jz4740_codec_write;
481 + codec->set_bias_level = jz4740_codec_set_bias_level;
482 + codec->bias_level = SND_SOC_BIAS_OFF;
483 +
484 + codec->dai = &jz4740_codec_dai;
485 + codec->num_dai = 1;
486 +
487 + codec->reg_cache = jz4740_codec->reg_cache;
488 + codec->reg_cache_size = 2;
489 + memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs));
490 +
491 + mutex_init(&codec->mutex);
492 + INIT_LIST_HEAD(&codec->dapm_widgets);
493 + INIT_LIST_HEAD(&codec->dapm_paths);
494 +
495 + jz4740_codec_codec = codec;
496 +
497 + snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
498 + JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
499 +
500 + platform_set_drvdata(pdev, jz4740_codec);
501 +
502 + ret = snd_soc_register_codec(codec);
503 + if (ret) {
504 + dev_err(&pdev->dev, "Failed to register codec\n");
505 + goto err_iounmap;
506 + }
507 +
508 + ret = snd_soc_register_dai(&jz4740_codec_dai);
509 + if (ret) {
510 + dev_err(&pdev->dev, "Failed to register codec dai\n");
511 + goto err_unregister_codec;
512 + }
513 +
514 + jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
515 +
516 + return 0;
517 +
518 +err_unregister_codec:
519 + snd_soc_unregister_codec(codec);
520 +err_iounmap:
521 + iounmap(jz4740_codec->base);
522 +err_release_mem_region:
523 + release_mem_region(mem->start, resource_size(mem));
524 +err_free_codec:
525 + kfree(jz4740_codec);
526 +
527 + return ret;
528 +}
529 +
530 +static int __devexit jz4740_codec_remove(struct platform_device *pdev)
531 +{
532 + struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
533 + struct resource *mem = jz4740_codec->mem;
534 +
535 + snd_soc_unregister_dai(&jz4740_codec_dai);
536 + snd_soc_unregister_codec(&jz4740_codec->codec);
537 +
538 + iounmap(jz4740_codec->base);
539 + release_mem_region(mem->start, resource_size(mem));
540 +
541 + platform_set_drvdata(pdev, NULL);
542 + kfree(jz4740_codec);
543 +
544 + return 0;
545 +}
546 +
547 +static struct platform_driver jz4740_codec_driver = {
548 + .probe = jz4740_codec_probe,
549 + .remove = __devexit_p(jz4740_codec_remove),
550 + .driver = {
551 + .name = "jz4740-codec",
552 + .owner = THIS_MODULE,
553 + },
554 +};
555 +
556 +static int __init jz4740_codec_init(void)
557 +{
558 + return platform_driver_register(&jz4740_codec_driver);
559 +}
560 +module_init(jz4740_codec_init);
561 +
562 +static void __exit jz4740_codec_exit(void)
563 +{
564 + platform_driver_unregister(&jz4740_codec_driver);
565 +}
566 +module_exit(jz4740_codec_exit);
567 +
568 +MODULE_DESCRIPTION("JZ4740 SoC internal codec driver");
569 +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
570 +MODULE_LICENSE("GPL v2");
571 +MODULE_ALIAS("platform:jz4740-codec");
572 --- /dev/null
573 +++ b/sound/soc/codecs/jz4740.h
574 @@ -0,0 +1,20 @@
575 +/*
576 + * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
577 + *
578 + * This program is free software; you can redistribute it and/or modify
579 + * it under the terms of the GNU General Public License version 2 as
580 + * published by the Free Software Foundation.
581 + *
582 + * You should have received a copy of the GNU General Public License along
583 + * with this program; if not, write to the Free Software Foundation, Inc.,
584 + * 675 Mass Ave, Cambridge, MA 02139, USA.
585 + *
586 + */
587 +
588 +#ifndef __SND_SOC_CODECS_JZ4740_CODEC_H__
589 +#define __SND_SOC_CODECS_JZ4740_CODEC_H__
590 +
591 +extern struct snd_soc_dai jz4740_codec_dai;
592 +extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec;
593 +
594 +#endif
This page took 0.072066 seconds and 5 git commands to generate.