diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2009-03-28 16:29:51 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-03-28 16:29:51 -0400 |
commit | ed40d0c472b136682b2fcba05f89762859c7374f (patch) | |
tree | 076b83a26bcd63d6158463735dd34c10bbc591dc /sound/soc/pxa | |
parent | 9e495834e59ca9b29f1a1f63b9f5533bb022ac49 (diff) | |
parent | 5d80f8e5a9dc9c9a94d4aeaa567e219a808b8a4a (diff) |
Merge branch 'origin' into devel
Conflicts:
sound/soc/pxa/pxa2xx-i2s.c
Diffstat (limited to 'sound/soc/pxa')
-rw-r--r-- | sound/soc/pxa/Kconfig | 27 | ||||
-rw-r--r-- | sound/soc/pxa/Makefile | 6 | ||||
-rw-r--r-- | sound/soc/pxa/corgi.c | 58 | ||||
-rw-r--r-- | sound/soc/pxa/e740_wm9705.c | 211 | ||||
-rw-r--r-- | sound/soc/pxa/e750_wm9705.c | 187 | ||||
-rw-r--r-- | sound/soc/pxa/e800_wm9712.c | 113 | ||||
-rw-r--r-- | sound/soc/pxa/mioa701_wm9713.c | 250 | ||||
-rw-r--r-- | sound/soc/pxa/palm27x.c | 15 | ||||
-rw-r--r-- | sound/soc/pxa/poodle.c | 56 | ||||
-rw-r--r-- | sound/soc/pxa/pxa-ssp.c | 150 | ||||
-rw-r--r-- | sound/soc/pxa/pxa2xx-ac97.c | 59 | ||||
-rw-r--r-- | sound/soc/pxa/pxa2xx-i2s.c | 54 | ||||
-rw-r--r-- | sound/soc/pxa/spitz.c | 14 | ||||
-rw-r--r-- | sound/soc/pxa/tosa.c | 14 | ||||
-rw-r--r-- | sound/soc/pxa/zylonite.c | 132 |
15 files changed, 1126 insertions, 220 deletions
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index f82e10699471..5998ab366e83 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -61,6 +61,24 @@ config SND_PXA2XX_SOC_TOSA | |||
61 | Say Y if you want to add support for SoC audio on Sharp | 61 | Say Y if you want to add support for SoC audio on Sharp |
62 | Zaurus SL-C6000x models (Tosa). | 62 | Zaurus SL-C6000x models (Tosa). |
63 | 63 | ||
64 | config SND_PXA2XX_SOC_E740 | ||
65 | tristate "SoC AC97 Audio support for e740" | ||
66 | depends on SND_PXA2XX_SOC && MACH_E740 | ||
67 | select SND_SOC_WM9705 | ||
68 | select SND_PXA2XX_SOC_AC97 | ||
69 | help | ||
70 | Say Y if you want to add support for SoC audio on the | ||
71 | toshiba e740 PDA | ||
72 | |||
73 | config SND_PXA2XX_SOC_E750 | ||
74 | tristate "SoC AC97 Audio support for e750" | ||
75 | depends on SND_PXA2XX_SOC && MACH_E750 | ||
76 | select SND_SOC_WM9705 | ||
77 | select SND_PXA2XX_SOC_AC97 | ||
78 | help | ||
79 | Say Y if you want to add support for SoC audio on the | ||
80 | toshiba e750 PDA | ||
81 | |||
64 | config SND_PXA2XX_SOC_E800 | 82 | config SND_PXA2XX_SOC_E800 |
65 | tristate "SoC AC97 Audio support for e800" | 83 | tristate "SoC AC97 Audio support for e800" |
66 | depends on SND_PXA2XX_SOC && MACH_E800 | 84 | depends on SND_PXA2XX_SOC && MACH_E800 |
@@ -97,3 +115,12 @@ config SND_SOC_ZYLONITE | |||
97 | help | 115 | help |
98 | Say Y if you want to add support for SoC audio on the | 116 | Say Y if you want to add support for SoC audio on the |
99 | Marvell Zylonite reference platform. | 117 | Marvell Zylonite reference platform. |
118 | |||
119 | config SND_PXA2XX_SOC_MIOA701 | ||
120 | tristate "SoC Audio support for MIO A701" | ||
121 | depends on SND_PXA2XX_SOC && MACH_MIOA701 | ||
122 | select SND_PXA2XX_SOC_AC97 | ||
123 | select SND_SOC_WM9713 | ||
124 | help | ||
125 | Say Y if you want to add support for SoC audio on the | ||
126 | MIO A701. | ||
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 08a9f2797729..8ed881c5e5cc 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile | |||
@@ -13,17 +13,23 @@ obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o | |||
13 | snd-soc-corgi-objs := corgi.o | 13 | snd-soc-corgi-objs := corgi.o |
14 | snd-soc-poodle-objs := poodle.o | 14 | snd-soc-poodle-objs := poodle.o |
15 | snd-soc-tosa-objs := tosa.o | 15 | snd-soc-tosa-objs := tosa.o |
16 | snd-soc-e740-objs := e740_wm9705.o | ||
17 | snd-soc-e750-objs := e750_wm9705.o | ||
16 | snd-soc-e800-objs := e800_wm9712.o | 18 | snd-soc-e800-objs := e800_wm9712.o |
17 | snd-soc-spitz-objs := spitz.o | 19 | snd-soc-spitz-objs := spitz.o |
18 | snd-soc-em-x270-objs := em-x270.o | 20 | snd-soc-em-x270-objs := em-x270.o |
19 | snd-soc-palm27x-objs := palm27x.o | 21 | snd-soc-palm27x-objs := palm27x.o |
20 | snd-soc-zylonite-objs := zylonite.o | 22 | snd-soc-zylonite-objs := zylonite.o |
23 | snd-soc-mioa701-objs := mioa701_wm9713.o | ||
21 | 24 | ||
22 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o | 25 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o |
23 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o | 26 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o |
24 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o | 27 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o |
28 | obj-$(CONFIG_SND_PXA2XX_SOC_E740) += snd-soc-e740.o | ||
29 | obj-$(CONFIG_SND_PXA2XX_SOC_E750) += snd-soc-e750.o | ||
25 | obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o | 30 | obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o |
26 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o | 31 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o |
27 | obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o | 32 | obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o |
28 | obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o | 33 | obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o |
34 | obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o | ||
29 | obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o | 35 | obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o |
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index ec930667feff..d5be2b30cda5 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/moduleparam.h> | 17 | #include <linux/moduleparam.h> |
18 | #include <linux/timer.h> | 18 | #include <linux/timer.h> |
19 | #include <linux/i2c.h> | ||
19 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
21 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
@@ -98,7 +99,7 @@ static void corgi_ext_control(struct snd_soc_codec *codec) | |||
98 | static int corgi_startup(struct snd_pcm_substream *substream) | 99 | static int corgi_startup(struct snd_pcm_substream *substream) |
99 | { | 100 | { |
100 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 101 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
101 | struct snd_soc_codec *codec = rtd->socdev->codec; | 102 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
102 | 103 | ||
103 | /* check the jack status at stream startup */ | 104 | /* check the jack status at stream startup */ |
104 | corgi_ext_control(codec); | 105 | corgi_ext_control(codec); |
@@ -273,18 +274,16 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = { | |||
273 | */ | 274 | */ |
274 | static int corgi_wm8731_init(struct snd_soc_codec *codec) | 275 | static int corgi_wm8731_init(struct snd_soc_codec *codec) |
275 | { | 276 | { |
276 | int i, err; | 277 | int err; |
277 | 278 | ||
278 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); | 279 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); |
279 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); | 280 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); |
280 | 281 | ||
281 | /* Add corgi specific controls */ | 282 | /* Add corgi specific controls */ |
282 | for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { | 283 | err = snd_soc_add_controls(codec, wm8731_corgi_controls, |
283 | err = snd_ctl_add(codec->card, | 284 | ARRAY_SIZE(wm8731_corgi_controls)); |
284 | snd_soc_cnew(&wm8731_corgi_controls[i], codec, NULL)); | 285 | if (err < 0) |
285 | if (err < 0) | 286 | return err; |
286 | return err; | ||
287 | } | ||
288 | 287 | ||
289 | /* Add corgi specific widgets */ | 288 | /* Add corgi specific widgets */ |
290 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, | 289 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
@@ -315,19 +314,44 @@ static struct snd_soc_card snd_soc_corgi = { | |||
315 | .num_links = 1, | 314 | .num_links = 1, |
316 | }; | 315 | }; |
317 | 316 | ||
318 | /* corgi audio private data */ | ||
319 | static struct wm8731_setup_data corgi_wm8731_setup = { | ||
320 | .i2c_bus = 0, | ||
321 | .i2c_address = 0x1b, | ||
322 | }; | ||
323 | |||
324 | /* corgi audio subsystem */ | 317 | /* corgi audio subsystem */ |
325 | static struct snd_soc_device corgi_snd_devdata = { | 318 | static struct snd_soc_device corgi_snd_devdata = { |
326 | .card = &snd_soc_corgi, | 319 | .card = &snd_soc_corgi, |
327 | .codec_dev = &soc_codec_dev_wm8731, | 320 | .codec_dev = &soc_codec_dev_wm8731, |
328 | .codec_data = &corgi_wm8731_setup, | ||
329 | }; | 321 | }; |
330 | 322 | ||
323 | /* | ||
324 | * FIXME: This is a temporary bodge to avoid cross-tree merge issues. | ||
325 | * New drivers should register the wm8731 I2C device in the machine | ||
326 | * setup code (under arch/arm for ARM systems). | ||
327 | */ | ||
328 | static int wm8731_i2c_register(void) | ||
329 | { | ||
330 | struct i2c_board_info info; | ||
331 | struct i2c_adapter *adapter; | ||
332 | struct i2c_client *client; | ||
333 | |||
334 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
335 | info.addr = 0x1b; | ||
336 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
337 | |||
338 | adapter = i2c_get_adapter(0); | ||
339 | if (!adapter) { | ||
340 | printk(KERN_ERR "can't get i2c adapter 0\n"); | ||
341 | return -ENODEV; | ||
342 | } | ||
343 | |||
344 | client = i2c_new_device(adapter, &info); | ||
345 | i2c_put_adapter(adapter); | ||
346 | if (!client) { | ||
347 | printk(KERN_ERR "can't add i2c device at 0x%x\n", | ||
348 | (unsigned int)info.addr); | ||
349 | return -ENODEV; | ||
350 | } | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
331 | static struct platform_device *corgi_snd_device; | 355 | static struct platform_device *corgi_snd_device; |
332 | 356 | ||
333 | static int __init corgi_init(void) | 357 | static int __init corgi_init(void) |
@@ -338,6 +362,10 @@ static int __init corgi_init(void) | |||
338 | machine_is_husky())) | 362 | machine_is_husky())) |
339 | return -ENODEV; | 363 | return -ENODEV; |
340 | 364 | ||
365 | ret = wm8731_i2c_register(); | ||
366 | if (ret != 0) | ||
367 | return ret; | ||
368 | |||
341 | corgi_snd_device = platform_device_alloc("soc-audio", -1); | 369 | corgi_snd_device = platform_device_alloc("soc-audio", -1); |
342 | if (!corgi_snd_device) | 370 | if (!corgi_snd_device) |
343 | return -ENOMEM; | 371 | return -ENOMEM; |
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c new file mode 100644 index 000000000000..7cd2f89d7b10 --- /dev/null +++ b/sound/soc/pxa/e740_wm9705.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * e740-wm9705.c -- SoC audio for e740 | ||
3 | * | ||
4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; version 2 ONLY. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/gpio.h> | ||
15 | |||
16 | #include <sound/core.h> | ||
17 | #include <sound/pcm.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | |||
21 | #include <mach/audio.h> | ||
22 | #include <mach/eseries-gpio.h> | ||
23 | |||
24 | #include <asm/mach-types.h> | ||
25 | |||
26 | #include "../codecs/wm9705.h" | ||
27 | #include "pxa2xx-pcm.h" | ||
28 | #include "pxa2xx-ac97.h" | ||
29 | |||
30 | |||
31 | #define E740_AUDIO_OUT 1 | ||
32 | #define E740_AUDIO_IN 2 | ||
33 | |||
34 | static int e740_audio_power; | ||
35 | |||
36 | static void e740_sync_audio_power(int status) | ||
37 | { | ||
38 | gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status); | ||
39 | gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0); | ||
40 | gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0); | ||
41 | } | ||
42 | |||
43 | static int e740_mic_amp_event(struct snd_soc_dapm_widget *w, | ||
44 | struct snd_kcontrol *kcontrol, int event) | ||
45 | { | ||
46 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
47 | e740_audio_power |= E740_AUDIO_IN; | ||
48 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
49 | e740_audio_power &= ~E740_AUDIO_IN; | ||
50 | |||
51 | e740_sync_audio_power(e740_audio_power); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static int e740_output_amp_event(struct snd_soc_dapm_widget *w, | ||
57 | struct snd_kcontrol *kcontrol, int event) | ||
58 | { | ||
59 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
60 | e740_audio_power |= E740_AUDIO_OUT; | ||
61 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
62 | e740_audio_power &= ~E740_AUDIO_OUT; | ||
63 | |||
64 | e740_sync_audio_power(e740_audio_power); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static const struct snd_soc_dapm_widget e740_dapm_widgets[] = { | ||
70 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
71 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
72 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), | ||
73 | SND_SOC_DAPM_PGA_E("Output Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
74 | e740_output_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
75 | SND_SOC_DAPM_POST_PMD), | ||
76 | SND_SOC_DAPM_PGA_E("Mic Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
77 | e740_mic_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
78 | SND_SOC_DAPM_POST_PMD), | ||
79 | }; | ||
80 | |||
81 | static const struct snd_soc_dapm_route audio_map[] = { | ||
82 | {"Output Amp", NULL, "LOUT"}, | ||
83 | {"Output Amp", NULL, "ROUT"}, | ||
84 | {"Output Amp", NULL, "MONOOUT"}, | ||
85 | |||
86 | {"Speaker", NULL, "Output Amp"}, | ||
87 | {"Headphone Jack", NULL, "Output Amp"}, | ||
88 | |||
89 | {"MIC1", NULL, "Mic Amp"}, | ||
90 | {"Mic Amp", NULL, "Mic (Internal)"}, | ||
91 | }; | ||
92 | |||
93 | static int e740_ac97_init(struct snd_soc_codec *codec) | ||
94 | { | ||
95 | snd_soc_dapm_nc_pin(codec, "HPOUTL"); | ||
96 | snd_soc_dapm_nc_pin(codec, "HPOUTR"); | ||
97 | snd_soc_dapm_nc_pin(codec, "PHONE"); | ||
98 | snd_soc_dapm_nc_pin(codec, "LINEINL"); | ||
99 | snd_soc_dapm_nc_pin(codec, "LINEINR"); | ||
100 | snd_soc_dapm_nc_pin(codec, "CDINL"); | ||
101 | snd_soc_dapm_nc_pin(codec, "CDINR"); | ||
102 | snd_soc_dapm_nc_pin(codec, "PCBEEP"); | ||
103 | snd_soc_dapm_nc_pin(codec, "MIC2"); | ||
104 | |||
105 | snd_soc_dapm_new_controls(codec, e740_dapm_widgets, | ||
106 | ARRAY_SIZE(e740_dapm_widgets)); | ||
107 | |||
108 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
109 | |||
110 | snd_soc_dapm_sync(codec); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static struct snd_soc_dai_link e740_dai[] = { | ||
116 | { | ||
117 | .name = "AC97", | ||
118 | .stream_name = "AC97 HiFi", | ||
119 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
120 | .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI], | ||
121 | .init = e740_ac97_init, | ||
122 | }, | ||
123 | { | ||
124 | .name = "AC97 Aux", | ||
125 | .stream_name = "AC97 Aux", | ||
126 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
127 | .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX], | ||
128 | }, | ||
129 | }; | ||
130 | |||
131 | static struct snd_soc_card e740 = { | ||
132 | .name = "Toshiba e740", | ||
133 | .platform = &pxa2xx_soc_platform, | ||
134 | .dai_link = e740_dai, | ||
135 | .num_links = ARRAY_SIZE(e740_dai), | ||
136 | }; | ||
137 | |||
138 | static struct snd_soc_device e740_snd_devdata = { | ||
139 | .card = &e740, | ||
140 | .codec_dev = &soc_codec_dev_wm9705, | ||
141 | }; | ||
142 | |||
143 | static struct platform_device *e740_snd_device; | ||
144 | |||
145 | static int __init e740_init(void) | ||
146 | { | ||
147 | int ret; | ||
148 | |||
149 | if (!machine_is_e740()) | ||
150 | return -ENODEV; | ||
151 | |||
152 | ret = gpio_request(GPIO_E740_MIC_ON, "Mic amp"); | ||
153 | if (ret) | ||
154 | return ret; | ||
155 | |||
156 | ret = gpio_request(GPIO_E740_AMP_ON, "Output amp"); | ||
157 | if (ret) | ||
158 | goto free_mic_amp_gpio; | ||
159 | |||
160 | ret = gpio_request(GPIO_E740_WM9705_nAVDD2, "Audio power"); | ||
161 | if (ret) | ||
162 | goto free_op_amp_gpio; | ||
163 | |||
164 | /* Disable audio */ | ||
165 | ret = gpio_direction_output(GPIO_E740_MIC_ON, 0); | ||
166 | if (ret) | ||
167 | goto free_apwr_gpio; | ||
168 | ret = gpio_direction_output(GPIO_E740_AMP_ON, 0); | ||
169 | if (ret) | ||
170 | goto free_apwr_gpio; | ||
171 | ret = gpio_direction_output(GPIO_E740_WM9705_nAVDD2, 1); | ||
172 | if (ret) | ||
173 | goto free_apwr_gpio; | ||
174 | |||
175 | e740_snd_device = platform_device_alloc("soc-audio", -1); | ||
176 | if (!e740_snd_device) { | ||
177 | ret = -ENOMEM; | ||
178 | goto free_apwr_gpio; | ||
179 | } | ||
180 | |||
181 | platform_set_drvdata(e740_snd_device, &e740_snd_devdata); | ||
182 | e740_snd_devdata.dev = &e740_snd_device->dev; | ||
183 | ret = platform_device_add(e740_snd_device); | ||
184 | |||
185 | if (!ret) | ||
186 | return 0; | ||
187 | |||
188 | /* Fail gracefully */ | ||
189 | platform_device_put(e740_snd_device); | ||
190 | free_apwr_gpio: | ||
191 | gpio_free(GPIO_E740_WM9705_nAVDD2); | ||
192 | free_op_amp_gpio: | ||
193 | gpio_free(GPIO_E740_AMP_ON); | ||
194 | free_mic_amp_gpio: | ||
195 | gpio_free(GPIO_E740_MIC_ON); | ||
196 | |||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | static void __exit e740_exit(void) | ||
201 | { | ||
202 | platform_device_unregister(e740_snd_device); | ||
203 | } | ||
204 | |||
205 | module_init(e740_init); | ||
206 | module_exit(e740_exit); | ||
207 | |||
208 | /* Module information */ | ||
209 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | ||
210 | MODULE_DESCRIPTION("ALSA SoC driver for e740"); | ||
211 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c new file mode 100644 index 000000000000..8dceccc5e059 --- /dev/null +++ b/sound/soc/pxa/e750_wm9705.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * e750-wm9705.c -- SoC audio for e750 | ||
3 | * | ||
4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; version 2 ONLY. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/gpio.h> | ||
15 | |||
16 | #include <sound/core.h> | ||
17 | #include <sound/pcm.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | |||
21 | #include <mach/audio.h> | ||
22 | #include <mach/eseries-gpio.h> | ||
23 | |||
24 | #include <asm/mach-types.h> | ||
25 | |||
26 | #include "../codecs/wm9705.h" | ||
27 | #include "pxa2xx-pcm.h" | ||
28 | #include "pxa2xx-ac97.h" | ||
29 | |||
30 | static int e750_spk_amp_event(struct snd_soc_dapm_widget *w, | ||
31 | struct snd_kcontrol *kcontrol, int event) | ||
32 | { | ||
33 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
34 | gpio_set_value(GPIO_E750_SPK_AMP_OFF, 0); | ||
35 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
36 | gpio_set_value(GPIO_E750_SPK_AMP_OFF, 1); | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int e750_hp_amp_event(struct snd_soc_dapm_widget *w, | ||
42 | struct snd_kcontrol *kcontrol, int event) | ||
43 | { | ||
44 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
45 | gpio_set_value(GPIO_E750_HP_AMP_OFF, 0); | ||
46 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
47 | gpio_set_value(GPIO_E750_HP_AMP_OFF, 1); | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static const struct snd_soc_dapm_widget e750_dapm_widgets[] = { | ||
53 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
54 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
55 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), | ||
56 | SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
57 | e750_hp_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
58 | SND_SOC_DAPM_POST_PMD), | ||
59 | SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
60 | e750_spk_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
61 | SND_SOC_DAPM_POST_PMD), | ||
62 | }; | ||
63 | |||
64 | static const struct snd_soc_dapm_route audio_map[] = { | ||
65 | {"Headphone Amp", NULL, "HPOUTL"}, | ||
66 | {"Headphone Amp", NULL, "HPOUTR"}, | ||
67 | {"Headphone Jack", NULL, "Headphone Amp"}, | ||
68 | |||
69 | {"Speaker Amp", NULL, "MONOOUT"}, | ||
70 | {"Speaker", NULL, "Speaker Amp"}, | ||
71 | |||
72 | {"MIC1", NULL, "Mic (Internal)"}, | ||
73 | }; | ||
74 | |||
75 | static int e750_ac97_init(struct snd_soc_codec *codec) | ||
76 | { | ||
77 | snd_soc_dapm_nc_pin(codec, "LOUT"); | ||
78 | snd_soc_dapm_nc_pin(codec, "ROUT"); | ||
79 | snd_soc_dapm_nc_pin(codec, "PHONE"); | ||
80 | snd_soc_dapm_nc_pin(codec, "LINEINL"); | ||
81 | snd_soc_dapm_nc_pin(codec, "LINEINR"); | ||
82 | snd_soc_dapm_nc_pin(codec, "CDINL"); | ||
83 | snd_soc_dapm_nc_pin(codec, "CDINR"); | ||
84 | snd_soc_dapm_nc_pin(codec, "PCBEEP"); | ||
85 | snd_soc_dapm_nc_pin(codec, "MIC2"); | ||
86 | |||
87 | snd_soc_dapm_new_controls(codec, e750_dapm_widgets, | ||
88 | ARRAY_SIZE(e750_dapm_widgets)); | ||
89 | |||
90 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
91 | |||
92 | snd_soc_dapm_sync(codec); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static struct snd_soc_dai_link e750_dai[] = { | ||
98 | { | ||
99 | .name = "AC97", | ||
100 | .stream_name = "AC97 HiFi", | ||
101 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
102 | .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI], | ||
103 | .init = e750_ac97_init, | ||
104 | /* use ops to check startup state */ | ||
105 | }, | ||
106 | { | ||
107 | .name = "AC97 Aux", | ||
108 | .stream_name = "AC97 Aux", | ||
109 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
110 | .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX], | ||
111 | }, | ||
112 | }; | ||
113 | |||
114 | static struct snd_soc_card e750 = { | ||
115 | .name = "Toshiba e750", | ||
116 | .platform = &pxa2xx_soc_platform, | ||
117 | .dai_link = e750_dai, | ||
118 | .num_links = ARRAY_SIZE(e750_dai), | ||
119 | }; | ||
120 | |||
121 | static struct snd_soc_device e750_snd_devdata = { | ||
122 | .card = &e750, | ||
123 | .codec_dev = &soc_codec_dev_wm9705, | ||
124 | }; | ||
125 | |||
126 | static struct platform_device *e750_snd_device; | ||
127 | |||
128 | static int __init e750_init(void) | ||
129 | { | ||
130 | int ret; | ||
131 | |||
132 | if (!machine_is_e750()) | ||
133 | return -ENODEV; | ||
134 | |||
135 | ret = gpio_request(GPIO_E750_HP_AMP_OFF, "Headphone amp"); | ||
136 | if (ret) | ||
137 | return ret; | ||
138 | |||
139 | ret = gpio_request(GPIO_E750_SPK_AMP_OFF, "Speaker amp"); | ||
140 | if (ret) | ||
141 | goto free_hp_amp_gpio; | ||
142 | |||
143 | ret = gpio_direction_output(GPIO_E750_HP_AMP_OFF, 1); | ||
144 | if (ret) | ||
145 | goto free_spk_amp_gpio; | ||
146 | |||
147 | ret = gpio_direction_output(GPIO_E750_SPK_AMP_OFF, 1); | ||
148 | if (ret) | ||
149 | goto free_spk_amp_gpio; | ||
150 | |||
151 | e750_snd_device = platform_device_alloc("soc-audio", -1); | ||
152 | if (!e750_snd_device) { | ||
153 | ret = -ENOMEM; | ||
154 | goto free_spk_amp_gpio; | ||
155 | } | ||
156 | |||
157 | platform_set_drvdata(e750_snd_device, &e750_snd_devdata); | ||
158 | e750_snd_devdata.dev = &e750_snd_device->dev; | ||
159 | ret = platform_device_add(e750_snd_device); | ||
160 | |||
161 | if (!ret) | ||
162 | return 0; | ||
163 | |||
164 | /* Fail gracefully */ | ||
165 | platform_device_put(e750_snd_device); | ||
166 | free_spk_amp_gpio: | ||
167 | gpio_free(GPIO_E750_SPK_AMP_OFF); | ||
168 | free_hp_amp_gpio: | ||
169 | gpio_free(GPIO_E750_HP_AMP_OFF); | ||
170 | |||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | static void __exit e750_exit(void) | ||
175 | { | ||
176 | platform_device_unregister(e750_snd_device); | ||
177 | gpio_free(GPIO_E750_SPK_AMP_OFF); | ||
178 | gpio_free(GPIO_E750_HP_AMP_OFF); | ||
179 | } | ||
180 | |||
181 | module_init(e750_init); | ||
182 | module_exit(e750_exit); | ||
183 | |||
184 | /* Module information */ | ||
185 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | ||
186 | MODULE_DESCRIPTION("ALSA SoC driver for e750"); | ||
187 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index ac294c797b7d..bc019cdce429 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * e800-wm9712.c -- SoC audio for e800 | 2 | * e800-wm9712.c -- SoC audio for e800 |
3 | * | 3 | * |
4 | * Based on tosa.c | ||
5 | * | ||
6 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | 4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> |
7 | * | 5 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
@@ -13,7 +11,7 @@ | |||
13 | 11 | ||
14 | #include <linux/module.h> | 12 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
16 | #include <linux/device.h> | 14 | #include <linux/gpio.h> |
17 | 15 | ||
18 | #include <sound/core.h> | 16 | #include <sound/core.h> |
19 | #include <sound/pcm.h> | 17 | #include <sound/pcm.h> |
@@ -22,20 +20,84 @@ | |||
22 | 20 | ||
23 | #include <asm/mach-types.h> | 21 | #include <asm/mach-types.h> |
24 | #include <mach/audio.h> | 22 | #include <mach/audio.h> |
23 | #include <mach/eseries-gpio.h> | ||
25 | 24 | ||
26 | #include "../codecs/wm9712.h" | 25 | #include "../codecs/wm9712.h" |
27 | #include "pxa2xx-pcm.h" | 26 | #include "pxa2xx-pcm.h" |
28 | #include "pxa2xx-ac97.h" | 27 | #include "pxa2xx-ac97.h" |
29 | 28 | ||
30 | static struct snd_soc_card e800; | 29 | static int e800_spk_amp_event(struct snd_soc_dapm_widget *w, |
30 | struct snd_kcontrol *kcontrol, int event) | ||
31 | { | ||
32 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
33 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 1); | ||
34 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
35 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 0); | ||
31 | 36 | ||
32 | static struct snd_soc_dai_link e800_dai[] = { | 37 | return 0; |
38 | } | ||
39 | |||
40 | static int e800_hp_amp_event(struct snd_soc_dapm_widget *w, | ||
41 | struct snd_kcontrol *kcontrol, int event) | ||
42 | { | ||
43 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
44 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 0); | ||
45 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
46 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 1); | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static const struct snd_soc_dapm_widget e800_dapm_widgets[] = { | ||
52 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
53 | SND_SOC_DAPM_MIC("Mic (Internal1)", NULL), | ||
54 | SND_SOC_DAPM_MIC("Mic (Internal2)", NULL), | ||
55 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
56 | SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
57 | e800_hp_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
58 | SND_SOC_DAPM_POST_PMD), | ||
59 | SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
60 | e800_spk_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
61 | SND_SOC_DAPM_POST_PMD), | ||
62 | }; | ||
63 | |||
64 | static const struct snd_soc_dapm_route audio_map[] = { | ||
65 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
66 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
67 | {"Headphone Jack", NULL, "Headphone Amp"}, | ||
68 | |||
69 | {"Speaker Amp", NULL, "MONOOUT"}, | ||
70 | {"Speaker", NULL, "Speaker Amp"}, | ||
71 | |||
72 | {"MIC1", NULL, "Mic (Internal1)"}, | ||
73 | {"MIC2", NULL, "Mic (Internal2)"}, | ||
74 | }; | ||
75 | |||
76 | static int e800_ac97_init(struct snd_soc_codec *codec) | ||
33 | { | 77 | { |
34 | .name = "AC97 Aux", | 78 | snd_soc_dapm_new_controls(codec, e800_dapm_widgets, |
35 | .stream_name = "AC97 Aux", | 79 | ARRAY_SIZE(e800_dapm_widgets)); |
36 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | 80 | |
37 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | 81 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
38 | }, | 82 | snd_soc_dapm_sync(codec); |
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static struct snd_soc_dai_link e800_dai[] = { | ||
88 | { | ||
89 | .name = "AC97", | ||
90 | .stream_name = "AC97 HiFi", | ||
91 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
92 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], | ||
93 | .init = e800_ac97_init, | ||
94 | }, | ||
95 | { | ||
96 | .name = "AC97 Aux", | ||
97 | .stream_name = "AC97 Aux", | ||
98 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
99 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | ||
100 | }, | ||
39 | }; | 101 | }; |
40 | 102 | ||
41 | static struct snd_soc_card e800 = { | 103 | static struct snd_soc_card e800 = { |
@@ -59,6 +121,22 @@ static int __init e800_init(void) | |||
59 | if (!machine_is_e800()) | 121 | if (!machine_is_e800()) |
60 | return -ENODEV; | 122 | return -ENODEV; |
61 | 123 | ||
124 | ret = gpio_request(GPIO_E800_HP_AMP_OFF, "Headphone amp"); | ||
125 | if (ret) | ||
126 | return ret; | ||
127 | |||
128 | ret = gpio_request(GPIO_E800_SPK_AMP_ON, "Speaker amp"); | ||
129 | if (ret) | ||
130 | goto free_hp_amp_gpio; | ||
131 | |||
132 | ret = gpio_direction_output(GPIO_E800_HP_AMP_OFF, 1); | ||
133 | if (ret) | ||
134 | goto free_spk_amp_gpio; | ||
135 | |||
136 | ret = gpio_direction_output(GPIO_E800_SPK_AMP_ON, 1); | ||
137 | if (ret) | ||
138 | goto free_spk_amp_gpio; | ||
139 | |||
62 | e800_snd_device = platform_device_alloc("soc-audio", -1); | 140 | e800_snd_device = platform_device_alloc("soc-audio", -1); |
63 | if (!e800_snd_device) | 141 | if (!e800_snd_device) |
64 | return -ENOMEM; | 142 | return -ENOMEM; |
@@ -67,8 +145,15 @@ static int __init e800_init(void) | |||
67 | e800_snd_devdata.dev = &e800_snd_device->dev; | 145 | e800_snd_devdata.dev = &e800_snd_device->dev; |
68 | ret = platform_device_add(e800_snd_device); | 146 | ret = platform_device_add(e800_snd_device); |
69 | 147 | ||
70 | if (ret) | 148 | if (!ret) |
71 | platform_device_put(e800_snd_device); | 149 | return 0; |
150 | |||
151 | /* Fail gracefully */ | ||
152 | platform_device_put(e800_snd_device); | ||
153 | free_spk_amp_gpio: | ||
154 | gpio_free(GPIO_E800_SPK_AMP_ON); | ||
155 | free_hp_amp_gpio: | ||
156 | gpio_free(GPIO_E800_HP_AMP_OFF); | ||
72 | 157 | ||
73 | return ret; | 158 | return ret; |
74 | } | 159 | } |
@@ -76,6 +161,8 @@ static int __init e800_init(void) | |||
76 | static void __exit e800_exit(void) | 161 | static void __exit e800_exit(void) |
77 | { | 162 | { |
78 | platform_device_unregister(e800_snd_device); | 163 | platform_device_unregister(e800_snd_device); |
164 | gpio_free(GPIO_E800_SPK_AMP_ON); | ||
165 | gpio_free(GPIO_E800_HP_AMP_OFF); | ||
79 | } | 166 | } |
80 | 167 | ||
81 | module_init(e800_init); | 168 | module_init(e800_init); |
@@ -84,4 +171,4 @@ module_exit(e800_exit); | |||
84 | /* Module information */ | 171 | /* Module information */ |
85 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | 172 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); |
86 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); | 173 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); |
87 | MODULE_LICENSE("GPL"); | 174 | MODULE_LICENSE("GPL v2"); |
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c new file mode 100644 index 000000000000..19eda8bbfdaf --- /dev/null +++ b/sound/soc/pxa/mioa701_wm9713.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * Handles the Mitac mioa701 SoC system | ||
3 | * | ||
4 | * Copyright (C) 2008 Robert Jarzmik | ||
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 as published by | ||
8 | * the Free Software Foundation in version 2 of the License. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | * This is a little schema of the sound interconnections : | ||
20 | * | ||
21 | * Sagem X200 Wolfson WM9713 | ||
22 | * +--------+ +-------------------+ Rear Speaker | ||
23 | * | | | | /-+ | ||
24 | * | +--->----->---+MONOIN SPKL+--->----+-+ | | ||
25 | * | GSM | | | | | | | ||
26 | * | +--->----->---+PCBEEP SPKR+--->----+-+ | | ||
27 | * | CHIP | | | \-+ | ||
28 | * | +---<-----<---+MONO | | ||
29 | * | | | | Front Speaker | ||
30 | * +--------+ | | /-+ | ||
31 | * | HPL+--->----+-+ | | ||
32 | * | | | | | | ||
33 | * | OUT3+--->----+-+ | | ||
34 | * | | \-+ | ||
35 | * | | | ||
36 | * | | Front Micro | ||
37 | * | | + | ||
38 | * | MIC1+-----<--+o+ | ||
39 | * | | + | ||
40 | * +-------------------+ --- | ||
41 | */ | ||
42 | |||
43 | #include <linux/module.h> | ||
44 | #include <linux/moduleparam.h> | ||
45 | #include <linux/platform_device.h> | ||
46 | |||
47 | #include <asm/mach-types.h> | ||
48 | #include <mach/audio.h> | ||
49 | |||
50 | #include <sound/core.h> | ||
51 | #include <sound/pcm.h> | ||
52 | #include <sound/soc.h> | ||
53 | #include <sound/soc-dapm.h> | ||
54 | #include <sound/initval.h> | ||
55 | #include <sound/ac97_codec.h> | ||
56 | |||
57 | #include "pxa2xx-pcm.h" | ||
58 | #include "pxa2xx-ac97.h" | ||
59 | #include "../codecs/wm9713.h" | ||
60 | |||
61 | #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) | ||
62 | |||
63 | #define AC97_GPIO_PULL 0x58 | ||
64 | |||
65 | /* Use GPIO8 for rear speaker amplifier */ | ||
66 | static int rear_amp_power(struct snd_soc_codec *codec, int power) | ||
67 | { | ||
68 | unsigned short reg; | ||
69 | |||
70 | if (power) { | ||
71 | reg = snd_soc_read(codec, AC97_GPIO_CFG); | ||
72 | snd_soc_write(codec, AC97_GPIO_CFG, reg | 0x0100); | ||
73 | reg = snd_soc_read(codec, AC97_GPIO_PULL); | ||
74 | snd_soc_write(codec, AC97_GPIO_PULL, reg | (1<<15)); | ||
75 | } else { | ||
76 | reg = snd_soc_read(codec, AC97_GPIO_CFG); | ||
77 | snd_soc_write(codec, AC97_GPIO_CFG, reg & ~0x0100); | ||
78 | reg = snd_soc_read(codec, AC97_GPIO_PULL); | ||
79 | snd_soc_write(codec, AC97_GPIO_PULL, reg & ~(1<<15)); | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int rear_amp_event(struct snd_soc_dapm_widget *widget, | ||
86 | struct snd_kcontrol *kctl, int event) | ||
87 | { | ||
88 | struct snd_soc_codec *codec = widget->codec; | ||
89 | |||
90 | return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event)); | ||
91 | } | ||
92 | |||
93 | /* mioa701 machine dapm widgets */ | ||
94 | static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = { | ||
95 | SND_SOC_DAPM_SPK("Front Speaker", NULL), | ||
96 | SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event), | ||
97 | SND_SOC_DAPM_MIC("Headset", NULL), | ||
98 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | ||
99 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | ||
100 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
101 | SND_SOC_DAPM_MIC("Front Mic", NULL), | ||
102 | }; | ||
103 | |||
104 | static const struct snd_soc_dapm_route audio_map[] = { | ||
105 | /* Call Mic */ | ||
106 | {"Mic Bias", NULL, "Front Mic"}, | ||
107 | {"MIC1", NULL, "Mic Bias"}, | ||
108 | |||
109 | /* Headset Mic */ | ||
110 | {"LINEL", NULL, "Headset Mic"}, | ||
111 | {"LINER", NULL, "Headset Mic"}, | ||
112 | |||
113 | /* GSM Module */ | ||
114 | {"MONOIN", NULL, "GSM Line Out"}, | ||
115 | {"PCBEEP", NULL, "GSM Line Out"}, | ||
116 | {"GSM Line In", NULL, "MONO"}, | ||
117 | |||
118 | /* headphone connected to HPL, HPR */ | ||
119 | {"Headset", NULL, "HPL"}, | ||
120 | {"Headset", NULL, "HPR"}, | ||
121 | |||
122 | /* front speaker connected to HPL, OUT3 */ | ||
123 | {"Front Speaker", NULL, "HPL"}, | ||
124 | {"Front Speaker", NULL, "OUT3"}, | ||
125 | |||
126 | /* rear speaker connected to SPKL, SPKR */ | ||
127 | {"Rear Speaker", NULL, "SPKL"}, | ||
128 | {"Rear Speaker", NULL, "SPKR"}, | ||
129 | }; | ||
130 | |||
131 | static int mioa701_wm9713_init(struct snd_soc_codec *codec) | ||
132 | { | ||
133 | unsigned short reg; | ||
134 | |||
135 | /* Add mioa701 specific widgets */ | ||
136 | snd_soc_dapm_new_controls(codec, ARRAY_AND_SIZE(mioa701_dapm_widgets)); | ||
137 | |||
138 | /* Set up mioa701 specific audio path audio_mapnects */ | ||
139 | snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map)); | ||
140 | |||
141 | /* Prepare GPIO8 for rear speaker amplifier */ | ||
142 | reg = codec->read(codec, AC97_GPIO_CFG); | ||
143 | codec->write(codec, AC97_GPIO_CFG, reg | 0x0100); | ||
144 | |||
145 | /* Prepare MIC input */ | ||
146 | reg = codec->read(codec, AC97_3D_CONTROL); | ||
147 | codec->write(codec, AC97_3D_CONTROL, reg | 0xc000); | ||
148 | |||
149 | snd_soc_dapm_enable_pin(codec, "Front Speaker"); | ||
150 | snd_soc_dapm_enable_pin(codec, "Rear Speaker"); | ||
151 | snd_soc_dapm_enable_pin(codec, "Front Mic"); | ||
152 | snd_soc_dapm_enable_pin(codec, "GSM Line In"); | ||
153 | snd_soc_dapm_enable_pin(codec, "GSM Line Out"); | ||
154 | snd_soc_dapm_sync(codec); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static struct snd_soc_ops mioa701_ops; | ||
160 | |||
161 | static struct snd_soc_dai_link mioa701_dai[] = { | ||
162 | { | ||
163 | .name = "AC97", | ||
164 | .stream_name = "AC97 HiFi", | ||
165 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
166 | .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI], | ||
167 | .init = mioa701_wm9713_init, | ||
168 | .ops = &mioa701_ops, | ||
169 | }, | ||
170 | { | ||
171 | .name = "AC97 Aux", | ||
172 | .stream_name = "AC97 Aux", | ||
173 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
174 | .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX], | ||
175 | .ops = &mioa701_ops, | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | static struct snd_soc_card mioa701 = { | ||
180 | .name = "MioA701", | ||
181 | .platform = &pxa2xx_soc_platform, | ||
182 | .dai_link = mioa701_dai, | ||
183 | .num_links = ARRAY_SIZE(mioa701_dai), | ||
184 | }; | ||
185 | |||
186 | static struct snd_soc_device mioa701_snd_devdata = { | ||
187 | .card = &mioa701, | ||
188 | .codec_dev = &soc_codec_dev_wm9713, | ||
189 | }; | ||
190 | |||
191 | static struct platform_device *mioa701_snd_device; | ||
192 | |||
193 | static int mioa701_wm9713_probe(struct platform_device *pdev) | ||
194 | { | ||
195 | int ret; | ||
196 | |||
197 | if (!machine_is_mioa701()) | ||
198 | return -ENODEV; | ||
199 | |||
200 | dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will" | ||
201 | "lead to overheating and possible destruction of your device." | ||
202 | "Do not use without a good knowledge of mio's board design!\n"); | ||
203 | |||
204 | mioa701_snd_device = platform_device_alloc("soc-audio", -1); | ||
205 | if (!mioa701_snd_device) | ||
206 | return -ENOMEM; | ||
207 | |||
208 | platform_set_drvdata(mioa701_snd_device, &mioa701_snd_devdata); | ||
209 | mioa701_snd_devdata.dev = &mioa701_snd_device->dev; | ||
210 | |||
211 | ret = platform_device_add(mioa701_snd_device); | ||
212 | if (!ret) | ||
213 | return 0; | ||
214 | |||
215 | platform_device_put(mioa701_snd_device); | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static int __devexit mioa701_wm9713_remove(struct platform_device *pdev) | ||
220 | { | ||
221 | platform_device_unregister(mioa701_snd_device); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static struct platform_driver mioa701_wm9713_driver = { | ||
226 | .probe = mioa701_wm9713_probe, | ||
227 | .remove = __devexit_p(mioa701_wm9713_remove), | ||
228 | .driver = { | ||
229 | .name = "mioa701-wm9713", | ||
230 | .owner = THIS_MODULE, | ||
231 | }, | ||
232 | }; | ||
233 | |||
234 | static int __init mioa701_asoc_init(void) | ||
235 | { | ||
236 | return platform_driver_register(&mioa701_wm9713_driver); | ||
237 | } | ||
238 | |||
239 | static void __exit mioa701_asoc_exit(void) | ||
240 | { | ||
241 | platform_driver_unregister(&mioa701_wm9713_driver); | ||
242 | } | ||
243 | |||
244 | module_init(mioa701_asoc_init); | ||
245 | module_exit(mioa701_asoc_exit); | ||
246 | |||
247 | /* Module information */ | ||
248 | MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); | ||
249 | MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); | ||
250 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 4a9cf3083af0..48a73f64500b 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c | |||
@@ -55,7 +55,7 @@ static void palm27x_ext_control(struct snd_soc_codec *codec) | |||
55 | static int palm27x_startup(struct snd_pcm_substream *substream) | 55 | static int palm27x_startup(struct snd_pcm_substream *substream) |
56 | { | 56 | { |
57 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 57 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
58 | struct snd_soc_codec *codec = rtd->socdev->codec; | 58 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
59 | 59 | ||
60 | /* check the jack status at stream startup */ | 60 | /* check the jack status at stream startup */ |
61 | palm27x_ext_control(codec); | 61 | palm27x_ext_control(codec); |
@@ -146,19 +146,16 @@ static const struct snd_kcontrol_new palm27x_controls[] = { | |||
146 | 146 | ||
147 | static int palm27x_ac97_init(struct snd_soc_codec *codec) | 147 | static int palm27x_ac97_init(struct snd_soc_codec *codec) |
148 | { | 148 | { |
149 | int i, err; | 149 | int err; |
150 | 150 | ||
151 | snd_soc_dapm_nc_pin(codec, "OUT3"); | 151 | snd_soc_dapm_nc_pin(codec, "OUT3"); |
152 | snd_soc_dapm_nc_pin(codec, "MONOOUT"); | 152 | snd_soc_dapm_nc_pin(codec, "MONOOUT"); |
153 | 153 | ||
154 | /* add palm27x specific controls */ | 154 | /* add palm27x specific controls */ |
155 | for (i = 0; i < ARRAY_SIZE(palm27x_controls); i++) { | 155 | err = snd_soc_add_controls(codec, palm27x_controls, |
156 | err = snd_ctl_add(codec->card, | 156 | ARRAY_SIZE(palm27x_controls)); |
157 | snd_soc_cnew(&palm27x_controls[i], | 157 | if (err < 0) |
158 | codec, NULL)); | 158 | return err; |
159 | if (err < 0) | ||
160 | return err; | ||
161 | } | ||
162 | 159 | ||
163 | /* add palm27x specific widgets */ | 160 | /* add palm27x specific widgets */ |
164 | snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets, | 161 | snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets, |
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index cad2c4c0ac95..a51058f66747 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/moduleparam.h> | 18 | #include <linux/moduleparam.h> |
19 | #include <linux/timer.h> | 19 | #include <linux/timer.h> |
20 | #include <linux/i2c.h> | ||
20 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
21 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
22 | #include <sound/core.h> | 23 | #include <sound/core.h> |
@@ -75,7 +76,7 @@ static void poodle_ext_control(struct snd_soc_codec *codec) | |||
75 | static int poodle_startup(struct snd_pcm_substream *substream) | 76 | static int poodle_startup(struct snd_pcm_substream *substream) |
76 | { | 77 | { |
77 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 78 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
78 | struct snd_soc_codec *codec = rtd->socdev->codec; | 79 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
79 | 80 | ||
80 | /* check the jack status at stream startup */ | 81 | /* check the jack status at stream startup */ |
81 | poodle_ext_control(codec); | 82 | poodle_ext_control(codec); |
@@ -238,19 +239,17 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = { | |||
238 | */ | 239 | */ |
239 | static int poodle_wm8731_init(struct snd_soc_codec *codec) | 240 | static int poodle_wm8731_init(struct snd_soc_codec *codec) |
240 | { | 241 | { |
241 | int i, err; | 242 | int err; |
242 | 243 | ||
243 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); | 244 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); |
244 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); | 245 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); |
245 | snd_soc_dapm_enable_pin(codec, "MICIN"); | 246 | snd_soc_dapm_enable_pin(codec, "MICIN"); |
246 | 247 | ||
247 | /* Add poodle specific controls */ | 248 | /* Add poodle specific controls */ |
248 | for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) { | 249 | err = snd_soc_add_controls(codec, wm8731_poodle_controls, |
249 | err = snd_ctl_add(codec->card, | 250 | ARRAY_SIZE(wm8731_poodle_controls)); |
250 | snd_soc_cnew(&wm8731_poodle_controls[i], codec, NULL)); | 251 | if (err < 0) |
251 | if (err < 0) | 252 | return err; |
252 | return err; | ||
253 | } | ||
254 | 253 | ||
255 | /* Add poodle specific widgets */ | 254 | /* Add poodle specific widgets */ |
256 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, | 255 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
@@ -281,17 +280,42 @@ static struct snd_soc_card snd_soc_poodle = { | |||
281 | .num_links = 1, | 280 | .num_links = 1, |
282 | }; | 281 | }; |
283 | 282 | ||
284 | /* poodle audio private data */ | 283 | /* |
285 | static struct wm8731_setup_data poodle_wm8731_setup = { | 284 | * FIXME: This is a temporary bodge to avoid cross-tree merge issues. |
286 | .i2c_bus = 0, | 285 | * New drivers should register the wm8731 I2C device in the machine |
287 | .i2c_address = 0x1b, | 286 | * setup code (under arch/arm for ARM systems). |
288 | }; | 287 | */ |
288 | static int wm8731_i2c_register(void) | ||
289 | { | ||
290 | struct i2c_board_info info; | ||
291 | struct i2c_adapter *adapter; | ||
292 | struct i2c_client *client; | ||
293 | |||
294 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
295 | info.addr = 0x1b; | ||
296 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
297 | |||
298 | adapter = i2c_get_adapter(0); | ||
299 | if (!adapter) { | ||
300 | printk(KERN_ERR "can't get i2c adapter 0\n"); | ||
301 | return -ENODEV; | ||
302 | } | ||
303 | |||
304 | client = i2c_new_device(adapter, &info); | ||
305 | i2c_put_adapter(adapter); | ||
306 | if (!client) { | ||
307 | printk(KERN_ERR "can't add i2c device at 0x%x\n", | ||
308 | (unsigned int)info.addr); | ||
309 | return -ENODEV; | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | } | ||
289 | 314 | ||
290 | /* poodle audio subsystem */ | 315 | /* poodle audio subsystem */ |
291 | static struct snd_soc_device poodle_snd_devdata = { | 316 | static struct snd_soc_device poodle_snd_devdata = { |
292 | .card = &snd_soc_poodle, | 317 | .card = &snd_soc_poodle, |
293 | .codec_dev = &soc_codec_dev_wm8731, | 318 | .codec_dev = &soc_codec_dev_wm8731, |
294 | .codec_data = &poodle_wm8731_setup, | ||
295 | }; | 319 | }; |
296 | 320 | ||
297 | static struct platform_device *poodle_snd_device; | 321 | static struct platform_device *poodle_snd_device; |
@@ -303,6 +327,10 @@ static int __init poodle_init(void) | |||
303 | if (!machine_is_poodle()) | 327 | if (!machine_is_poodle()) |
304 | return -ENODEV; | 328 | return -ENODEV; |
305 | 329 | ||
330 | ret = wm8731_i2c_register(); | ||
331 | if (ret != 0) | ||
332 | return ret; | ||
333 | |||
306 | locomo_gpio_set_dir(&poodle_locomo_device.dev, | 334 | locomo_gpio_set_dir(&poodle_locomo_device.dev, |
307 | POODLE_LOCOMO_GPIO_AMP_ON, 0); | 335 | POODLE_LOCOMO_GPIO_AMP_ON, 0); |
308 | /* should we mute HP at startup - burning power ?*/ | 336 | /* should we mute HP at startup - burning power ?*/ |
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 1dfdf66fb1f3..7acd3febf8b0 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define DEBUG | ||
2 | /* | 1 | /* |
3 | * pxa-ssp.c -- ALSA Soc Audio Layer | 2 | * pxa-ssp.c -- ALSA Soc Audio Layer |
4 | * | 3 | * |
@@ -21,6 +20,8 @@ | |||
21 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
22 | #include <linux/io.h> | 21 | #include <linux/io.h> |
23 | 22 | ||
23 | #include <asm/irq.h> | ||
24 | |||
24 | #include <sound/core.h> | 25 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
26 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
@@ -221,9 +222,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, | |||
221 | int ret = 0; | 222 | int ret = 0; |
222 | 223 | ||
223 | if (!cpu_dai->active) { | 224 | if (!cpu_dai->active) { |
224 | ret = ssp_init(&priv->dev, cpu_dai->id + 1, SSP_NO_IRQ); | 225 | priv->dev.port = cpu_dai->id + 1; |
225 | if (ret < 0) | 226 | priv->dev.irq = NO_IRQ; |
226 | return ret; | 227 | clk_enable(priv->dev.ssp->clk); |
227 | ssp_disable(&priv->dev); | 228 | ssp_disable(&priv->dev); |
228 | } | 229 | } |
229 | return ret; | 230 | return ret; |
@@ -238,7 +239,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, | |||
238 | 239 | ||
239 | if (!cpu_dai->active) { | 240 | if (!cpu_dai->active) { |
240 | ssp_disable(&priv->dev); | 241 | ssp_disable(&priv->dev); |
241 | ssp_exit(&priv->dev); | 242 | clk_disable(priv->dev.ssp->clk); |
242 | } | 243 | } |
243 | } | 244 | } |
244 | 245 | ||
@@ -298,7 +299,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
298 | int val; | 299 | int val; |
299 | 300 | ||
300 | u32 sscr0 = ssp_read_reg(ssp, SSCR0) & | 301 | u32 sscr0 = ssp_read_reg(ssp, SSCR0) & |
301 | ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); | 302 | ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS); |
302 | 303 | ||
303 | dev_dbg(&ssp->pdev->dev, | 304 | dev_dbg(&ssp->pdev->dev, |
304 | "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", | 305 | "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", |
@@ -326,7 +327,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
326 | case PXA_SSP_CLK_AUDIO: | 327 | case PXA_SSP_CLK_AUDIO: |
327 | priv->sysclk = 0; | 328 | priv->sysclk = 0; |
328 | ssp_set_scr(&priv->dev, 1); | 329 | ssp_set_scr(&priv->dev, 1); |
329 | sscr0 |= SSCR0_ADC; | 330 | sscr0 |= SSCR0_ACS; |
330 | break; | 331 | break; |
331 | default: | 332 | default: |
332 | return -ENODEV; | 333 | return -ENODEV; |
@@ -520,9 +521,20 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
520 | u32 sscr1; | 521 | u32 sscr1; |
521 | u32 sspsp; | 522 | u32 sspsp; |
522 | 523 | ||
524 | /* check if we need to change anything at all */ | ||
525 | if (priv->dai_fmt == fmt) | ||
526 | return 0; | ||
527 | |||
528 | /* we can only change the settings if the port is not in use */ | ||
529 | if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) { | ||
530 | dev_err(&ssp->pdev->dev, | ||
531 | "can't change hardware dai format: stream is in use"); | ||
532 | return -EINVAL; | ||
533 | } | ||
534 | |||
523 | /* reset port settings */ | 535 | /* reset port settings */ |
524 | sscr0 = ssp_read_reg(ssp, SSCR0) & | 536 | sscr0 = ssp_read_reg(ssp, SSCR0) & |
525 | (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); | 537 | (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS); |
526 | sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); | 538 | sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); |
527 | sspsp = 0; | 539 | sspsp = 0; |
528 | 540 | ||
@@ -545,18 +557,18 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
545 | 557 | ||
546 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 558 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
547 | case SND_SOC_DAIFMT_I2S: | 559 | case SND_SOC_DAIFMT_I2S: |
548 | sscr0 |= SSCR0_MOD | SSCR0_PSP; | 560 | sscr0 |= SSCR0_PSP; |
549 | sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; | 561 | sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; |
550 | 562 | ||
563 | /* See hw_params() */ | ||
551 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 564 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
552 | case SND_SOC_DAIFMT_NB_NF: | 565 | case SND_SOC_DAIFMT_NB_NF: |
553 | sspsp |= SSPSP_FSRT; | 566 | sspsp |= SSPSP_SFRMP; |
554 | break; | 567 | break; |
555 | case SND_SOC_DAIFMT_NB_IF: | 568 | case SND_SOC_DAIFMT_NB_IF: |
556 | sspsp |= SSPSP_SFRMP | SSPSP_FSRT; | ||
557 | break; | 569 | break; |
558 | case SND_SOC_DAIFMT_IB_IF: | 570 | case SND_SOC_DAIFMT_IB_IF: |
559 | sspsp |= SSPSP_SFRMP; | 571 | sspsp |= SSPSP_SCMODE(3); |
560 | break; | 572 | break; |
561 | default: | 573 | default: |
562 | return -EINVAL; | 574 | return -EINVAL; |
@@ -642,34 +654,65 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, | |||
642 | sscr0 |= SSCR0_FPCKE; | 654 | sscr0 |= SSCR0_FPCKE; |
643 | #endif | 655 | #endif |
644 | sscr0 |= SSCR0_DataSize(16); | 656 | sscr0 |= SSCR0_DataSize(16); |
645 | if (params_channels(params) > 1) | ||
646 | sscr0 |= SSCR0_EDSS; | ||
647 | break; | 657 | break; |
648 | case SNDRV_PCM_FORMAT_S24_LE: | 658 | case SNDRV_PCM_FORMAT_S24_LE: |
649 | sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); | 659 | sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); |
650 | /* we must be in network mode (2 slots) for 24 bit stereo */ | ||
651 | break; | 660 | break; |
652 | case SNDRV_PCM_FORMAT_S32_LE: | 661 | case SNDRV_PCM_FORMAT_S32_LE: |
653 | sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); | 662 | sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); |
654 | /* we must be in network mode (2 slots) for 32 bit stereo */ | ||
655 | break; | 663 | break; |
656 | } | 664 | } |
657 | ssp_write_reg(ssp, SSCR0, sscr0); | 665 | ssp_write_reg(ssp, SSCR0, sscr0); |
658 | 666 | ||
659 | switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 667 | switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
660 | case SND_SOC_DAIFMT_I2S: | 668 | case SND_SOC_DAIFMT_I2S: |
661 | /* Cleared when the DAI format is set */ | 669 | sspsp = ssp_read_reg(ssp, SSPSP); |
662 | sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width); | 670 | |
671 | if (((sscr0 & SSCR0_SCR) == SSCR0_SerClkDiv(4)) && | ||
672 | (width == 16)) { | ||
673 | /* This is a special case where the bitclk is 64fs | ||
674 | * and we're not dealing with 2*32 bits of audio | ||
675 | * samples. | ||
676 | * | ||
677 | * The SSP values used for that are all found out by | ||
678 | * trying and failing a lot; some of the registers | ||
679 | * needed for that mode are only available on PXA3xx. | ||
680 | */ | ||
681 | |||
682 | #ifdef CONFIG_PXA3xx | ||
683 | if (!cpu_is_pxa3xx()) | ||
684 | return -EINVAL; | ||
685 | |||
686 | sspsp |= SSPSP_SFRMWDTH(width * 2); | ||
687 | sspsp |= SSPSP_SFRMDLY(width * 4); | ||
688 | sspsp |= SSPSP_EDMYSTOP(3); | ||
689 | sspsp |= SSPSP_DMYSTOP(3); | ||
690 | sspsp |= SSPSP_DMYSTRT(1); | ||
691 | #else | ||
692 | return -EINVAL; | ||
693 | #endif | ||
694 | } else { | ||
695 | /* The frame width is the width the LRCLK is | ||
696 | * asserted for; the delay is expressed in | ||
697 | * half cycle units. We need the extra cycle | ||
698 | * because the data starts clocking out one BCLK | ||
699 | * after LRCLK changes polarity. | ||
700 | */ | ||
701 | sspsp |= SSPSP_SFRMWDTH(width + 1); | ||
702 | sspsp |= SSPSP_SFRMDLY((width + 1) * 2); | ||
703 | sspsp |= SSPSP_DMYSTRT(1); | ||
704 | } | ||
705 | |||
663 | ssp_write_reg(ssp, SSPSP, sspsp); | 706 | ssp_write_reg(ssp, SSPSP, sspsp); |
664 | break; | 707 | break; |
665 | default: | 708 | default: |
666 | break; | 709 | break; |
667 | } | 710 | } |
668 | 711 | ||
669 | /* We always use a network mode so we always require TDM slots | 712 | /* When we use a network mode, we always require TDM slots |
670 | * - complain loudly and fail if they've not been set up yet. | 713 | * - complain loudly and fail if they've not been set up yet. |
671 | */ | 714 | */ |
672 | if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) { | 715 | if ((sscr0 & SSCR0_MOD) && !(ssp_read_reg(ssp, SSTSA) & 0xf)) { |
673 | dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); | 716 | dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); |
674 | return -EINVAL; | 717 | return -EINVAL; |
675 | } | 718 | } |
@@ -751,7 +794,7 @@ static int pxa_ssp_probe(struct platform_device *pdev, | |||
751 | if (!priv) | 794 | if (!priv) |
752 | return -ENOMEM; | 795 | return -ENOMEM; |
753 | 796 | ||
754 | priv->dev.ssp = ssp_request(dai->id, "SoC audio"); | 797 | priv->dev.ssp = ssp_request(dai->id + 1, "SoC audio"); |
755 | if (priv->dev.ssp == NULL) { | 798 | if (priv->dev.ssp == NULL) { |
756 | ret = -ENODEV; | 799 | ret = -ENODEV; |
757 | goto err_priv; | 800 | goto err_priv; |
@@ -782,6 +825,19 @@ static void pxa_ssp_remove(struct platform_device *pdev, | |||
782 | SNDRV_PCM_FMTBIT_S24_LE | \ | 825 | SNDRV_PCM_FMTBIT_S24_LE | \ |
783 | SNDRV_PCM_FMTBIT_S32_LE) | 826 | SNDRV_PCM_FMTBIT_S32_LE) |
784 | 827 | ||
828 | static struct snd_soc_dai_ops pxa_ssp_dai_ops = { | ||
829 | .startup = pxa_ssp_startup, | ||
830 | .shutdown = pxa_ssp_shutdown, | ||
831 | .trigger = pxa_ssp_trigger, | ||
832 | .hw_params = pxa_ssp_hw_params, | ||
833 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
834 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
835 | .set_pll = pxa_ssp_set_dai_pll, | ||
836 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
837 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
838 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
839 | }; | ||
840 | |||
785 | struct snd_soc_dai pxa_ssp_dai[] = { | 841 | struct snd_soc_dai pxa_ssp_dai[] = { |
786 | { | 842 | { |
787 | .name = "pxa2xx-ssp1", | 843 | .name = "pxa2xx-ssp1", |
@@ -802,18 +858,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
802 | .rates = PXA_SSP_RATES, | 858 | .rates = PXA_SSP_RATES, |
803 | .formats = PXA_SSP_FORMATS, | 859 | .formats = PXA_SSP_FORMATS, |
804 | }, | 860 | }, |
805 | .ops = { | 861 | .ops = &pxa_ssp_dai_ops, |
806 | .startup = pxa_ssp_startup, | ||
807 | .shutdown = pxa_ssp_shutdown, | ||
808 | .trigger = pxa_ssp_trigger, | ||
809 | .hw_params = pxa_ssp_hw_params, | ||
810 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
811 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
812 | .set_pll = pxa_ssp_set_dai_pll, | ||
813 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
814 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
815 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
816 | }, | ||
817 | }, | 862 | }, |
818 | { .name = "pxa2xx-ssp2", | 863 | { .name = "pxa2xx-ssp2", |
819 | .id = 1, | 864 | .id = 1, |
@@ -833,18 +878,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
833 | .rates = PXA_SSP_RATES, | 878 | .rates = PXA_SSP_RATES, |
834 | .formats = PXA_SSP_FORMATS, | 879 | .formats = PXA_SSP_FORMATS, |
835 | }, | 880 | }, |
836 | .ops = { | 881 | .ops = &pxa_ssp_dai_ops, |
837 | .startup = pxa_ssp_startup, | ||
838 | .shutdown = pxa_ssp_shutdown, | ||
839 | .trigger = pxa_ssp_trigger, | ||
840 | .hw_params = pxa_ssp_hw_params, | ||
841 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
842 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
843 | .set_pll = pxa_ssp_set_dai_pll, | ||
844 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
845 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
846 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
847 | }, | ||
848 | }, | 882 | }, |
849 | { | 883 | { |
850 | .name = "pxa2xx-ssp3", | 884 | .name = "pxa2xx-ssp3", |
@@ -865,18 +899,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
865 | .rates = PXA_SSP_RATES, | 899 | .rates = PXA_SSP_RATES, |
866 | .formats = PXA_SSP_FORMATS, | 900 | .formats = PXA_SSP_FORMATS, |
867 | }, | 901 | }, |
868 | .ops = { | 902 | .ops = &pxa_ssp_dai_ops, |
869 | .startup = pxa_ssp_startup, | ||
870 | .shutdown = pxa_ssp_shutdown, | ||
871 | .trigger = pxa_ssp_trigger, | ||
872 | .hw_params = pxa_ssp_hw_params, | ||
873 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
874 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
875 | .set_pll = pxa_ssp_set_dai_pll, | ||
876 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
877 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
878 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
879 | }, | ||
880 | }, | 903 | }, |
881 | { | 904 | { |
882 | .name = "pxa2xx-ssp4", | 905 | .name = "pxa2xx-ssp4", |
@@ -897,18 +920,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
897 | .rates = PXA_SSP_RATES, | 920 | .rates = PXA_SSP_RATES, |
898 | .formats = PXA_SSP_FORMATS, | 921 | .formats = PXA_SSP_FORMATS, |
899 | }, | 922 | }, |
900 | .ops = { | 923 | .ops = &pxa_ssp_dai_ops, |
901 | .startup = pxa_ssp_startup, | ||
902 | .shutdown = pxa_ssp_shutdown, | ||
903 | .trigger = pxa_ssp_trigger, | ||
904 | .hw_params = pxa_ssp_hw_params, | ||
905 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
906 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
907 | .set_pll = pxa_ssp_set_dai_pll, | ||
908 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
909 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
910 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
911 | }, | ||
912 | }, | 924 | }, |
913 | }; | 925 | }; |
914 | EXPORT_SYMBOL_GPL(pxa_ssp_dai); | 926 | EXPORT_SYMBOL_GPL(pxa_ssp_dai); |
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index a4a655f7e304..d9c94d71fa61 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -106,13 +106,13 @@ static int pxa2xx_ac97_resume(struct snd_soc_dai *dai) | |||
106 | static int pxa2xx_ac97_probe(struct platform_device *pdev, | 106 | static int pxa2xx_ac97_probe(struct platform_device *pdev, |
107 | struct snd_soc_dai *dai) | 107 | struct snd_soc_dai *dai) |
108 | { | 108 | { |
109 | return pxa2xx_ac97_hw_probe(pdev); | 109 | return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev)); |
110 | } | 110 | } |
111 | 111 | ||
112 | static void pxa2xx_ac97_remove(struct platform_device *pdev, | 112 | static void pxa2xx_ac97_remove(struct platform_device *pdev, |
113 | struct snd_soc_dai *dai) | 113 | struct snd_soc_dai *dai) |
114 | { | 114 | { |
115 | pxa2xx_ac97_hw_remove(pdev); | 115 | pxa2xx_ac97_hw_remove(to_platform_device(dai->dev)); |
116 | } | 116 | } |
117 | 117 | ||
118 | static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, | 118 | static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, |
@@ -164,6 +164,18 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, | |||
164 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | 164 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ |
165 | SNDRV_PCM_RATE_48000) | 165 | SNDRV_PCM_RATE_48000) |
166 | 166 | ||
167 | static struct snd_soc_dai_ops pxa_ac97_hifi_dai_ops = { | ||
168 | .hw_params = pxa2xx_ac97_hw_params, | ||
169 | }; | ||
170 | |||
171 | static struct snd_soc_dai_ops pxa_ac97_aux_dai_ops = { | ||
172 | .hw_params = pxa2xx_ac97_hw_aux_params, | ||
173 | }; | ||
174 | |||
175 | static struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = { | ||
176 | .hw_params = pxa2xx_ac97_hw_mic_params, | ||
177 | }; | ||
178 | |||
167 | /* | 179 | /* |
168 | * There is only 1 physical AC97 interface for pxa2xx, but it | 180 | * There is only 1 physical AC97 interface for pxa2xx, but it |
169 | * has extra fifo's that can be used for aux DACs and ADCs. | 181 | * has extra fifo's that can be used for aux DACs and ADCs. |
@@ -189,8 +201,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { | |||
189 | .channels_max = 2, | 201 | .channels_max = 2, |
190 | .rates = PXA2XX_AC97_RATES, | 202 | .rates = PXA2XX_AC97_RATES, |
191 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 203 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
192 | .ops = { | 204 | .ops = &pxa_ac97_hifi_dai_ops, |
193 | .hw_params = pxa2xx_ac97_hw_params,}, | ||
194 | }, | 205 | }, |
195 | { | 206 | { |
196 | .name = "pxa2xx-ac97-aux", | 207 | .name = "pxa2xx-ac97-aux", |
@@ -208,8 +219,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { | |||
208 | .channels_max = 1, | 219 | .channels_max = 1, |
209 | .rates = PXA2XX_AC97_RATES, | 220 | .rates = PXA2XX_AC97_RATES, |
210 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 221 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
211 | .ops = { | 222 | .ops = &pxa_ac97_aux_dai_ops, |
212 | .hw_params = pxa2xx_ac97_hw_aux_params,}, | ||
213 | }, | 223 | }, |
214 | { | 224 | { |
215 | .name = "pxa2xx-ac97-mic", | 225 | .name = "pxa2xx-ac97-mic", |
@@ -221,23 +231,52 @@ struct snd_soc_dai pxa_ac97_dai[] = { | |||
221 | .channels_max = 1, | 231 | .channels_max = 1, |
222 | .rates = PXA2XX_AC97_RATES, | 232 | .rates = PXA2XX_AC97_RATES, |
223 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 233 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
224 | .ops = { | 234 | .ops = &pxa_ac97_mic_dai_ops, |
225 | .hw_params = pxa2xx_ac97_hw_mic_params,}, | ||
226 | }, | 235 | }, |
227 | }; | 236 | }; |
228 | 237 | ||
229 | EXPORT_SYMBOL_GPL(pxa_ac97_dai); | 238 | EXPORT_SYMBOL_GPL(pxa_ac97_dai); |
230 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | 239 | EXPORT_SYMBOL_GPL(soc_ac97_ops); |
231 | 240 | ||
232 | static int __init pxa_ac97_init(void) | 241 | static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev) |
233 | { | 242 | { |
243 | int i; | ||
244 | |||
245 | for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) | ||
246 | pxa_ac97_dai[i].dev = &pdev->dev; | ||
247 | |||
248 | /* Punt most of the init to the SoC probe; we may need the machine | ||
249 | * driver to do interesting things with the clocking to get us up | ||
250 | * and running. | ||
251 | */ | ||
234 | return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); | 252 | return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); |
235 | } | 253 | } |
254 | |||
255 | static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev) | ||
256 | { | ||
257 | snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static struct platform_driver pxa2xx_ac97_driver = { | ||
263 | .probe = pxa2xx_ac97_dev_probe, | ||
264 | .remove = __devexit_p(pxa2xx_ac97_dev_remove), | ||
265 | .driver = { | ||
266 | .name = "pxa2xx-ac97", | ||
267 | .owner = THIS_MODULE, | ||
268 | }, | ||
269 | }; | ||
270 | |||
271 | static int __init pxa_ac97_init(void) | ||
272 | { | ||
273 | return platform_driver_register(&pxa2xx_ac97_driver); | ||
274 | } | ||
236 | module_init(pxa_ac97_init); | 275 | module_init(pxa_ac97_init); |
237 | 276 | ||
238 | static void __exit pxa_ac97_exit(void) | 277 | static void __exit pxa_ac97_exit(void) |
239 | { | 278 | { |
240 | snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); | 279 | platform_driver_unregister(&pxa2xx_ac97_driver); |
241 | } | 280 | } |
242 | module_exit(pxa_ac97_exit); | 281 | module_exit(pxa_ac97_exit); |
243 | 282 | ||
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 223de890259e..2f4b6e489b78 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
@@ -25,20 +25,11 @@ | |||
25 | 25 | ||
26 | #include <mach/hardware.h> | 26 | #include <mach/hardware.h> |
27 | #include <mach/dma.h> | 27 | #include <mach/dma.h> |
28 | #include <mach/pxa2xx-gpio.h> | ||
29 | #include <mach/audio.h> | 28 | #include <mach/audio.h> |
30 | 29 | ||
31 | #include "pxa2xx-pcm.h" | 30 | #include "pxa2xx-pcm.h" |
32 | #include "pxa2xx-i2s.h" | 31 | #include "pxa2xx-i2s.h" |
33 | 32 | ||
34 | struct pxa2xx_gpio { | ||
35 | u32 sys; | ||
36 | u32 rx; | ||
37 | u32 tx; | ||
38 | u32 clk; | ||
39 | u32 frm; | ||
40 | }; | ||
41 | |||
42 | /* | 33 | /* |
43 | * I2S Controller Register and Bit Definitions | 34 | * I2S Controller Register and Bit Definitions |
44 | */ | 35 | */ |
@@ -106,21 +97,6 @@ static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = { | |||
106 | DCMD_BURST32 | DCMD_WIDTH4, | 97 | DCMD_BURST32 | DCMD_WIDTH4, |
107 | }; | 98 | }; |
108 | 99 | ||
109 | static struct pxa2xx_gpio gpio_bus[] = { | ||
110 | { /* I2S SoC Slave */ | ||
111 | .rx = GPIO29_SDATA_IN_I2S_MD, | ||
112 | .tx = GPIO30_SDATA_OUT_I2S_MD, | ||
113 | .clk = GPIO28_BITCLK_IN_I2S_MD, | ||
114 | .frm = GPIO31_SYNC_I2S_MD, | ||
115 | }, | ||
116 | { /* I2S SoC Master */ | ||
117 | .rx = GPIO29_SDATA_IN_I2S_MD, | ||
118 | .tx = GPIO30_SDATA_OUT_I2S_MD, | ||
119 | .clk = GPIO28_BITCLK_OUT_I2S_MD, | ||
120 | .frm = GPIO31_SYNC_I2S_MD, | ||
121 | }, | ||
122 | }; | ||
123 | |||
124 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, | 100 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, |
125 | struct snd_soc_dai *dai) | 101 | struct snd_soc_dai *dai) |
126 | { | 102 | { |
@@ -181,9 +157,6 @@ static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
181 | if (clk_id != PXA2XX_I2S_SYSCLK) | 157 | if (clk_id != PXA2XX_I2S_SYSCLK) |
182 | return -ENODEV; | 158 | return -ENODEV; |
183 | 159 | ||
184 | if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT) | ||
185 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys); | ||
186 | |||
187 | return 0; | 160 | return 0; |
188 | } | 161 | } |
189 | 162 | ||
@@ -194,10 +167,6 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
194 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 167 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
195 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 168 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
196 | 169 | ||
197 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); | ||
198 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); | ||
199 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm); | ||
200 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk); | ||
201 | BUG_ON(IS_ERR(clk_i2s)); | 170 | BUG_ON(IS_ERR(clk_i2s)); |
202 | clk_enable(clk_i2s); | 171 | clk_enable(clk_i2s); |
203 | pxa_i2s_wait(); | 172 | pxa_i2s_wait(); |
@@ -335,6 +304,15 @@ static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) | |||
335 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | 304 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ |
336 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | 305 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) |
337 | 306 | ||
307 | static struct snd_soc_dai_ops pxa_i2s_dai_ops = { | ||
308 | .startup = pxa2xx_i2s_startup, | ||
309 | .shutdown = pxa2xx_i2s_shutdown, | ||
310 | .trigger = pxa2xx_i2s_trigger, | ||
311 | .hw_params = pxa2xx_i2s_hw_params, | ||
312 | .set_fmt = pxa2xx_i2s_set_dai_fmt, | ||
313 | .set_sysclk = pxa2xx_i2s_set_dai_sysclk, | ||
314 | }; | ||
315 | |||
338 | struct snd_soc_dai pxa_i2s_dai = { | 316 | struct snd_soc_dai pxa_i2s_dai = { |
339 | .name = "pxa2xx-i2s", | 317 | .name = "pxa2xx-i2s", |
340 | .id = 0, | 318 | .id = 0, |
@@ -350,14 +328,7 @@ struct snd_soc_dai pxa_i2s_dai = { | |||
350 | .channels_max = 2, | 328 | .channels_max = 2, |
351 | .rates = PXA2XX_I2S_RATES, | 329 | .rates = PXA2XX_I2S_RATES, |
352 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 330 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
353 | .ops = { | 331 | .ops = &pxa_i2s_dai_ops, |
354 | .startup = pxa2xx_i2s_startup, | ||
355 | .shutdown = pxa2xx_i2s_shutdown, | ||
356 | .trigger = pxa2xx_i2s_trigger, | ||
357 | .hw_params = pxa2xx_i2s_hw_params, | ||
358 | .set_fmt = pxa2xx_i2s_set_dai_fmt, | ||
359 | .set_sysclk = pxa2xx_i2s_set_dai_sysclk, | ||
360 | }, | ||
361 | }; | 332 | }; |
362 | 333 | ||
363 | EXPORT_SYMBOL_GPL(pxa_i2s_dai); | 334 | EXPORT_SYMBOL_GPL(pxa_i2s_dai); |
@@ -398,11 +369,6 @@ static struct platform_driver pxa2xx_i2s_driver = { | |||
398 | 369 | ||
399 | static int __init pxa2xx_i2s_init(void) | 370 | static int __init pxa2xx_i2s_init(void) |
400 | { | 371 | { |
401 | if (cpu_is_pxa27x()) | ||
402 | gpio_bus[1].sys = GPIO113_I2S_SYSCLK_MD; | ||
403 | else | ||
404 | gpio_bus[1].sys = GPIO32_SYSCLK_I2S_MD; | ||
405 | |||
406 | clk_i2s = ERR_PTR(-ENOENT); | 372 | clk_i2s = ERR_PTR(-ENOENT); |
407 | return platform_driver_register(&pxa2xx_i2s_driver); | 373 | return platform_driver_register(&pxa2xx_i2s_driver); |
408 | } | 374 | } |
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index de8778fa8729..c4cd2acaacb4 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
@@ -107,7 +107,7 @@ static void spitz_ext_control(struct snd_soc_codec *codec) | |||
107 | static int spitz_startup(struct snd_pcm_substream *substream) | 107 | static int spitz_startup(struct snd_pcm_substream *substream) |
108 | { | 108 | { |
109 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 109 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
110 | struct snd_soc_codec *codec = rtd->socdev->codec; | 110 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
111 | 111 | ||
112 | /* check the jack status at stream startup */ | 112 | /* check the jack status at stream startup */ |
113 | spitz_ext_control(codec); | 113 | spitz_ext_control(codec); |
@@ -276,7 +276,7 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = { | |||
276 | */ | 276 | */ |
277 | static int spitz_wm8750_init(struct snd_soc_codec *codec) | 277 | static int spitz_wm8750_init(struct snd_soc_codec *codec) |
278 | { | 278 | { |
279 | int i, err; | 279 | int err; |
280 | 280 | ||
281 | /* NC codec pins */ | 281 | /* NC codec pins */ |
282 | snd_soc_dapm_nc_pin(codec, "RINPUT1"); | 282 | snd_soc_dapm_nc_pin(codec, "RINPUT1"); |
@@ -288,12 +288,10 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) | |||
288 | snd_soc_dapm_nc_pin(codec, "MONO1"); | 288 | snd_soc_dapm_nc_pin(codec, "MONO1"); |
289 | 289 | ||
290 | /* Add spitz specific controls */ | 290 | /* Add spitz specific controls */ |
291 | for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { | 291 | err = snd_soc_add_controls(codec, wm8750_spitz_controls, |
292 | err = snd_ctl_add(codec->card, | 292 | ARRAY_SIZE(wm8750_spitz_controls)); |
293 | snd_soc_cnew(&wm8750_spitz_controls[i], codec, NULL)); | 293 | if (err < 0) |
294 | if (err < 0) | 294 | return err; |
295 | return err; | ||
296 | } | ||
297 | 295 | ||
298 | /* Add spitz specific widgets */ | 296 | /* Add spitz specific widgets */ |
299 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, | 297 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, |
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 050223d04e54..dbbd3e9d1637 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
@@ -80,7 +80,7 @@ static void tosa_ext_control(struct snd_soc_codec *codec) | |||
80 | static int tosa_startup(struct snd_pcm_substream *substream) | 80 | static int tosa_startup(struct snd_pcm_substream *substream) |
81 | { | 81 | { |
82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
83 | struct snd_soc_codec *codec = rtd->socdev->codec; | 83 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
84 | 84 | ||
85 | /* check the jack status at stream startup */ | 85 | /* check the jack status at stream startup */ |
86 | tosa_ext_control(codec); | 86 | tosa_ext_control(codec); |
@@ -186,18 +186,16 @@ static const struct snd_kcontrol_new tosa_controls[] = { | |||
186 | 186 | ||
187 | static int tosa_ac97_init(struct snd_soc_codec *codec) | 187 | static int tosa_ac97_init(struct snd_soc_codec *codec) |
188 | { | 188 | { |
189 | int i, err; | 189 | int err; |
190 | 190 | ||
191 | snd_soc_dapm_nc_pin(codec, "OUT3"); | 191 | snd_soc_dapm_nc_pin(codec, "OUT3"); |
192 | snd_soc_dapm_nc_pin(codec, "MONOOUT"); | 192 | snd_soc_dapm_nc_pin(codec, "MONOOUT"); |
193 | 193 | ||
194 | /* add tosa specific controls */ | 194 | /* add tosa specific controls */ |
195 | for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { | 195 | err = snd_soc_add_controls(codec, tosa_controls, |
196 | err = snd_ctl_add(codec->card, | 196 | ARRAY_SIZE(tosa_controls)); |
197 | snd_soc_cnew(&tosa_controls[i],codec, NULL)); | 197 | if (err < 0) |
198 | if (err < 0) | 198 | return err; |
199 | return err; | ||
200 | } | ||
201 | 199 | ||
202 | /* add tosa specific widgets */ | 200 | /* add tosa specific widgets */ |
203 | snd_soc_dapm_new_controls(codec, tosa_dapm_widgets, | 201 | snd_soc_dapm_new_controls(codec, tosa_dapm_widgets, |
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index f8e9ecd589d3..9a386b4c4ed1 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/clk.h> | ||
17 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
18 | #include <sound/core.h> | 19 | #include <sound/core.h> |
19 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
@@ -26,6 +27,17 @@ | |||
26 | #include "pxa2xx-ac97.h" | 27 | #include "pxa2xx-ac97.h" |
27 | #include "pxa-ssp.h" | 28 | #include "pxa-ssp.h" |
28 | 29 | ||
30 | /* | ||
31 | * There is a physical switch SW15 on the board which changes the MCLK | ||
32 | * for the WM9713 between the standard AC97 master clock and the | ||
33 | * output of the CLK_POUT signal from the PXA. | ||
34 | */ | ||
35 | static int clk_pout; | ||
36 | module_param(clk_pout, int, 0); | ||
37 | MODULE_PARM_DESC(clk_pout, "Use CLK_POUT as WM9713 MCLK (SW15 on board)."); | ||
38 | |||
39 | static struct clk *pout; | ||
40 | |||
29 | static struct snd_soc_card zylonite; | 41 | static struct snd_soc_card zylonite; |
30 | 42 | ||
31 | static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { | 43 | static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { |
@@ -61,10 +73,8 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
61 | 73 | ||
62 | static int zylonite_wm9713_init(struct snd_soc_codec *codec) | 74 | static int zylonite_wm9713_init(struct snd_soc_codec *codec) |
63 | { | 75 | { |
64 | /* Currently we only support use of the AC97 clock here. If | 76 | if (clk_pout) |
65 | * CLK_POUT is selected by SW15 then the clock API will need | 77 | snd_soc_dai_set_pll(&codec->dai[0], 0, clk_get_rate(pout), 0); |
66 | * to be used to request and enable it here. | ||
67 | */ | ||
68 | 78 | ||
69 | snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, | 79 | snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, |
70 | ARRAY_SIZE(zylonite_dapm_widgets)); | 80 | ARRAY_SIZE(zylonite_dapm_widgets)); |
@@ -86,40 +96,35 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, | |||
86 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 96 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
87 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 97 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
88 | unsigned int pll_out = 0; | 98 | unsigned int pll_out = 0; |
89 | unsigned int acds = 0; | ||
90 | unsigned int wm9713_div = 0; | 99 | unsigned int wm9713_div = 0; |
91 | int ret = 0; | 100 | int ret = 0; |
101 | int rate = params_rate(params); | ||
102 | int width = snd_pcm_format_physical_width(params_format(params)); | ||
92 | 103 | ||
93 | switch (params_rate(params)) { | 104 | /* Only support ratios that we can generate neatly from the AC97 |
105 | * based master clock - in particular, this excludes 44.1kHz. | ||
106 | * In most applications the voice DAC will be used for telephony | ||
107 | * data so multiples of 8kHz will be the common case. | ||
108 | */ | ||
109 | switch (rate) { | ||
94 | case 8000: | 110 | case 8000: |
95 | wm9713_div = 12; | 111 | wm9713_div = 12; |
96 | pll_out = 2048000; | ||
97 | break; | 112 | break; |
98 | case 16000: | 113 | case 16000: |
99 | wm9713_div = 6; | 114 | wm9713_div = 6; |
100 | pll_out = 4096000; | ||
101 | break; | 115 | break; |
102 | case 48000: | 116 | case 48000: |
103 | default: | ||
104 | wm9713_div = 2; | 117 | wm9713_div = 2; |
105 | pll_out = 12288000; | ||
106 | acds = 1; | ||
107 | break; | 118 | break; |
119 | default: | ||
120 | /* Don't support OSS emulation */ | ||
121 | return -EINVAL; | ||
108 | } | 122 | } |
109 | 123 | ||
110 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 124 | /* Add 1 to the width for the leading clock cycle */ |
111 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 125 | pll_out = rate * (width + 1) * 8; |
112 | if (ret < 0) | ||
113 | return ret; | ||
114 | |||
115 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
116 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
117 | if (ret < 0) | ||
118 | return ret; | ||
119 | 126 | ||
120 | ret = snd_soc_dai_set_tdm_slot(cpu_dai, | 127 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); |
121 | params_channels(params), | ||
122 | params_channels(params)); | ||
123 | if (ret < 0) | 128 | if (ret < 0) |
124 | return ret; | 129 | return ret; |
125 | 130 | ||
@@ -127,19 +132,22 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, | |||
127 | if (ret < 0) | 132 | if (ret < 0) |
128 | return ret; | 133 | return ret; |
129 | 134 | ||
130 | ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds); | 135 | if (clk_pout) |
136 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV, | ||
137 | WM9713_PCMDIV(wm9713_div)); | ||
138 | else | ||
139 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, | ||
140 | WM9713_PCMDIV(wm9713_div)); | ||
131 | if (ret < 0) | 141 | if (ret < 0) |
132 | return ret; | 142 | return ret; |
133 | 143 | ||
134 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); | 144 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
145 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
135 | if (ret < 0) | 146 | if (ret < 0) |
136 | return ret; | 147 | return ret; |
137 | 148 | ||
138 | /* Note that if the PLL is in use the WM9713_PCMCLK_PLL_DIV needs | 149 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
139 | * to be set instead. | 150 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
140 | */ | ||
141 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, | ||
142 | WM9713_PCMDIV(wm9713_div)); | ||
143 | if (ret < 0) | 151 | if (ret < 0) |
144 | return ret; | 152 | return ret; |
145 | 153 | ||
@@ -173,8 +181,72 @@ static struct snd_soc_dai_link zylonite_dai[] = { | |||
173 | }, | 181 | }, |
174 | }; | 182 | }; |
175 | 183 | ||
184 | static int zylonite_probe(struct platform_device *pdev) | ||
185 | { | ||
186 | int ret; | ||
187 | |||
188 | if (clk_pout) { | ||
189 | pout = clk_get(NULL, "CLK_POUT"); | ||
190 | if (IS_ERR(pout)) { | ||
191 | dev_err(&pdev->dev, "Unable to obtain CLK_POUT: %ld\n", | ||
192 | PTR_ERR(pout)); | ||
193 | return PTR_ERR(pout); | ||
194 | } | ||
195 | |||
196 | ret = clk_enable(pout); | ||
197 | if (ret != 0) { | ||
198 | dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n", | ||
199 | ret); | ||
200 | clk_put(pout); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | dev_dbg(&pdev->dev, "MCLK enabled at %luHz\n", | ||
205 | clk_get_rate(pout)); | ||
206 | } | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int zylonite_remove(struct platform_device *pdev) | ||
212 | { | ||
213 | if (clk_pout) { | ||
214 | clk_disable(pout); | ||
215 | clk_put(pout); | ||
216 | } | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int zylonite_suspend_post(struct platform_device *pdev, | ||
222 | pm_message_t state) | ||
223 | { | ||
224 | if (clk_pout) | ||
225 | clk_disable(pout); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int zylonite_resume_pre(struct platform_device *pdev) | ||
231 | { | ||
232 | int ret = 0; | ||
233 | |||
234 | if (clk_pout) { | ||
235 | ret = clk_enable(pout); | ||
236 | if (ret != 0) | ||
237 | dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n", | ||
238 | ret); | ||
239 | } | ||
240 | |||
241 | return ret; | ||
242 | } | ||
243 | |||
176 | static struct snd_soc_card zylonite = { | 244 | static struct snd_soc_card zylonite = { |
177 | .name = "Zylonite", | 245 | .name = "Zylonite", |
246 | .probe = &zylonite_probe, | ||
247 | .remove = &zylonite_remove, | ||
248 | .suspend_post = &zylonite_suspend_post, | ||
249 | .resume_pre = &zylonite_resume_pre, | ||
178 | .platform = &pxa2xx_soc_platform, | 250 | .platform = &pxa2xx_soc_platform, |
179 | .dai_link = zylonite_dai, | 251 | .dai_link = zylonite_dai, |
180 | .num_links = ARRAY_SIZE(zylonite_dai), | 252 | .num_links = ARRAY_SIZE(zylonite_dai), |