diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-03-23 19:35:53 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-03-23 19:35:53 -0400 |
commit | b5c784894c90042f4fc6348aedc7524e899df281 (patch) | |
tree | 0db86a93d73e4aabca04e361d7e6807aa4c1d307 /sound | |
parent | ff4fc3656e489ed6ee575959b0510286aefe1e20 (diff) | |
parent | 1f2186951e02f2a5bcda9459f63136918932385a (diff) |
Merge branch 'topic/asoc' into for-linus
Diffstat (limited to 'sound')
110 files changed, 8411 insertions, 3534 deletions
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 35afd0c33be5..2e6355f4cbb9 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c | |||
@@ -31,6 +31,7 @@ static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); | |||
31 | static volatile long gsr_bits; | 31 | static volatile long gsr_bits; |
32 | static struct clk *ac97_clk; | 32 | static struct clk *ac97_clk; |
33 | static struct clk *ac97conf_clk; | 33 | static struct clk *ac97conf_clk; |
34 | static int reset_gpio; | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * Beware PXA27x bugs: | 37 | * Beware PXA27x bugs: |
@@ -42,6 +43,45 @@ static struct clk *ac97conf_clk; | |||
42 | * 1 jiffy timeout if interrupt never comes). | 43 | * 1 jiffy timeout if interrupt never comes). |
43 | */ | 44 | */ |
44 | 45 | ||
46 | enum { | ||
47 | RESETGPIO_FORCE_HIGH, | ||
48 | RESETGPIO_FORCE_LOW, | ||
49 | RESETGPIO_NORMAL_ALTFUNC | ||
50 | }; | ||
51 | |||
52 | /** | ||
53 | * set_resetgpio_mode - computes and sets the AC97_RESET gpio mode on PXA | ||
54 | * @mode: chosen action | ||
55 | * | ||
56 | * As the PXA27x CPUs suffer from a AC97 bug, a manual control of the reset line | ||
57 | * must be done to insure proper work of AC97 reset line. This function | ||
58 | * computes the correct gpio_mode for further use by reset functions, and | ||
59 | * applied the change through pxa_gpio_mode. | ||
60 | */ | ||
61 | static void set_resetgpio_mode(int resetgpio_action) | ||
62 | { | ||
63 | int mode = 0; | ||
64 | |||
65 | if (reset_gpio) | ||
66 | switch (resetgpio_action) { | ||
67 | case RESETGPIO_NORMAL_ALTFUNC: | ||
68 | if (reset_gpio == 113) | ||
69 | mode = 113 | GPIO_OUT | GPIO_DFLT_LOW; | ||
70 | if (reset_gpio == 95) | ||
71 | mode = 95 | GPIO_ALT_FN_1_OUT; | ||
72 | break; | ||
73 | case RESETGPIO_FORCE_LOW: | ||
74 | mode = reset_gpio | GPIO_OUT | GPIO_DFLT_LOW; | ||
75 | break; | ||
76 | case RESETGPIO_FORCE_HIGH: | ||
77 | mode = reset_gpio | GPIO_OUT | GPIO_DFLT_HIGH; | ||
78 | break; | ||
79 | }; | ||
80 | |||
81 | if (mode) | ||
82 | pxa_gpio_mode(mode); | ||
83 | } | ||
84 | |||
45 | unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | 85 | unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) |
46 | { | 86 | { |
47 | unsigned short val = -1; | 87 | unsigned short val = -1; |
@@ -137,10 +177,10 @@ static inline void pxa_ac97_warm_pxa27x(void) | |||
137 | 177 | ||
138 | /* warm reset broken on Bulverde, | 178 | /* warm reset broken on Bulverde, |
139 | so manually keep AC97 reset high */ | 179 | so manually keep AC97 reset high */ |
140 | pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); | 180 | set_resetgpio_mode(RESETGPIO_FORCE_HIGH); |
141 | udelay(10); | 181 | udelay(10); |
142 | GCR |= GCR_WARM_RST; | 182 | GCR |= GCR_WARM_RST; |
143 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | 183 | set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); |
144 | udelay(500); | 184 | udelay(500); |
145 | } | 185 | } |
146 | 186 | ||
@@ -308,8 +348,8 @@ int pxa2xx_ac97_hw_resume(void) | |||
308 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); | 348 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); |
309 | } | 349 | } |
310 | if (cpu_is_pxa27x()) { | 350 | if (cpu_is_pxa27x()) { |
311 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | 351 | /* Use GPIO 113 or 95 as AC97 Reset on Bulverde */ |
312 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | 352 | set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); |
313 | } | 353 | } |
314 | clk_enable(ac97_clk); | 354 | clk_enable(ac97_clk); |
315 | return 0; | 355 | return 0; |
@@ -320,6 +360,27 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); | |||
320 | int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) | 360 | int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) |
321 | { | 361 | { |
322 | int ret; | 362 | int ret; |
363 | struct pxa2xx_ac97_platform_data *pdata = dev->dev.platform_data; | ||
364 | |||
365 | if (pdata) { | ||
366 | switch (pdata->reset_gpio) { | ||
367 | case 95: | ||
368 | case 113: | ||
369 | reset_gpio = pdata->reset_gpio; | ||
370 | break; | ||
371 | case 0: | ||
372 | reset_gpio = 113; | ||
373 | break; | ||
374 | case -1: | ||
375 | break; | ||
376 | default: | ||
377 | dev_err(&dev->dev, "Invalid reset GPIO %d\n", | ||
378 | pdata->reset_gpio); | ||
379 | } | ||
380 | } else { | ||
381 | if (cpu_is_pxa27x()) | ||
382 | reset_gpio = 113; | ||
383 | } | ||
323 | 384 | ||
324 | if (cpu_is_pxa25x() || cpu_is_pxa27x()) { | 385 | if (cpu_is_pxa25x() || cpu_is_pxa27x()) { |
325 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | 386 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); |
@@ -330,7 +391,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) | |||
330 | 391 | ||
331 | if (cpu_is_pxa27x()) { | 392 | if (cpu_is_pxa27x()) { |
332 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | 393 | /* Use GPIO 113 as AC97 Reset on Bulverde */ |
333 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | 394 | set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); |
334 | ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); | 395 | ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); |
335 | if (IS_ERR(ac97conf_clk)) { | 396 | if (IS_ERR(ac97conf_clk)) { |
336 | ret = PTR_ERR(ac97conf_clk); | 397 | ret = PTR_ERR(ac97conf_clk); |
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index ef025c66cc66..3d2bb6fc6dcc 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -6,6 +6,7 @@ menuconfig SND_SOC | |||
6 | tristate "ALSA for SoC audio support" | 6 | tristate "ALSA for SoC audio support" |
7 | select SND_PCM | 7 | select SND_PCM |
8 | select AC97_BUS if SND_SOC_AC97_BUS | 8 | select AC97_BUS if SND_SOC_AC97_BUS |
9 | select SND_JACK if INPUT=y || INPUT=SND | ||
9 | ---help--- | 10 | ---help--- |
10 | 11 | ||
11 | If you want ASoC support, you should say Y here and also to the | 12 | If you want ASoC support, you should say Y here and also to the |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 86a9b1f5b0f3..0237879fd412 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o |
2 | 2 | ||
3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o | 3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o |
4 | obj-$(CONFIG_SND_SOC) += codecs/ | 4 | obj-$(CONFIG_SND_SOC) += codecs/ |
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 3dcdc4e3cfa0..9ef6b96373f5 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c | |||
@@ -347,7 +347,7 @@ static int atmel_pcm_mmap(struct snd_pcm_substream *substream, | |||
347 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | 347 | vma->vm_end - vma->vm_start, vma->vm_page_prot); |
348 | } | 348 | } |
349 | 349 | ||
350 | struct snd_pcm_ops atmel_pcm_ops = { | 350 | static struct snd_pcm_ops atmel_pcm_ops = { |
351 | .open = atmel_pcm_open, | 351 | .open = atmel_pcm_open, |
352 | .close = atmel_pcm_close, | 352 | .close = atmel_pcm_close, |
353 | .ioctl = snd_pcm_lib_ioctl, | 353 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index ff0054b76502..e588e63f18d2 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -697,6 +697,15 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) | |||
697 | #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ | 697 | #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ |
698 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 698 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
699 | 699 | ||
700 | static struct snd_soc_dai_ops atmel_ssc_dai_ops = { | ||
701 | .startup = atmel_ssc_startup, | ||
702 | .shutdown = atmel_ssc_shutdown, | ||
703 | .prepare = atmel_ssc_prepare, | ||
704 | .hw_params = atmel_ssc_hw_params, | ||
705 | .set_fmt = atmel_ssc_set_dai_fmt, | ||
706 | .set_clkdiv = atmel_ssc_set_dai_clkdiv, | ||
707 | }; | ||
708 | |||
700 | struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { | 709 | struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { |
701 | { .name = "atmel-ssc0", | 710 | { .name = "atmel-ssc0", |
702 | .id = 0, | 711 | .id = 0, |
@@ -712,13 +721,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { | |||
712 | .channels_max = 2, | 721 | .channels_max = 2, |
713 | .rates = ATMEL_SSC_RATES, | 722 | .rates = ATMEL_SSC_RATES, |
714 | .formats = ATMEL_SSC_FORMATS,}, | 723 | .formats = ATMEL_SSC_FORMATS,}, |
715 | .ops = { | 724 | .ops = &atmel_ssc_dai_ops, |
716 | .startup = atmel_ssc_startup, | ||
717 | .shutdown = atmel_ssc_shutdown, | ||
718 | .prepare = atmel_ssc_prepare, | ||
719 | .hw_params = atmel_ssc_hw_params, | ||
720 | .set_fmt = atmel_ssc_set_dai_fmt, | ||
721 | .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, | ||
722 | .private_data = &ssc_info[0], | 725 | .private_data = &ssc_info[0], |
723 | }, | 726 | }, |
724 | #if NUM_SSC_DEVICES == 3 | 727 | #if NUM_SSC_DEVICES == 3 |
@@ -736,13 +739,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { | |||
736 | .channels_max = 2, | 739 | .channels_max = 2, |
737 | .rates = ATMEL_SSC_RATES, | 740 | .rates = ATMEL_SSC_RATES, |
738 | .formats = ATMEL_SSC_FORMATS,}, | 741 | .formats = ATMEL_SSC_FORMATS,}, |
739 | .ops = { | 742 | .ops = &atmel_ssc_dai_ops, |
740 | .startup = atmel_ssc_startup, | ||
741 | .shutdown = atmel_ssc_shutdown, | ||
742 | .prepare = atmel_ssc_prepare, | ||
743 | .hw_params = atmel_ssc_hw_params, | ||
744 | .set_fmt = atmel_ssc_set_dai_fmt, | ||
745 | .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, | ||
746 | .private_data = &ssc_info[1], | 743 | .private_data = &ssc_info[1], |
747 | }, | 744 | }, |
748 | { .name = "atmel-ssc2", | 745 | { .name = "atmel-ssc2", |
@@ -759,13 +756,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { | |||
759 | .channels_max = 2, | 756 | .channels_max = 2, |
760 | .rates = ATMEL_SSC_RATES, | 757 | .rates = ATMEL_SSC_RATES, |
761 | .formats = ATMEL_SSC_FORMATS,}, | 758 | .formats = ATMEL_SSC_FORMATS,}, |
762 | .ops = { | 759 | .ops = &atmel_ssc_dai_ops, |
763 | .startup = atmel_ssc_startup, | ||
764 | .shutdown = atmel_ssc_shutdown, | ||
765 | .prepare = atmel_ssc_prepare, | ||
766 | .hw_params = atmel_ssc_hw_params, | ||
767 | .set_fmt = atmel_ssc_set_dai_fmt, | ||
768 | .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, | ||
769 | .private_data = &ssc_info[2], | 760 | .private_data = &ssc_info[2], |
770 | }, | 761 | }, |
771 | #endif | 762 | #endif |
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index 43dd8cee83c6..70657534e6b1 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c | |||
@@ -164,38 +164,38 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, | |||
164 | */ | 164 | */ |
165 | switch (params_rate(params)) { | 165 | switch (params_rate(params)) { |
166 | case 48000: | 166 | case 48000: |
167 | pll_out = 12288000; | 167 | pll_out = 24576000; |
168 | mclk_div = WM8510_MCLKDIV_1; | 168 | mclk_div = WM8510_MCLKDIV_2; |
169 | bclk = WM8510_BCLKDIV_8; | 169 | bclk = WM8510_BCLKDIV_8; |
170 | break; | 170 | break; |
171 | 171 | ||
172 | case 44100: | 172 | case 44100: |
173 | pll_out = 11289600; | 173 | pll_out = 22579200; |
174 | mclk_div = WM8510_MCLKDIV_1; | 174 | mclk_div = WM8510_MCLKDIV_2; |
175 | bclk = WM8510_BCLKDIV_8; | 175 | bclk = WM8510_BCLKDIV_8; |
176 | break; | 176 | break; |
177 | 177 | ||
178 | case 22050: | 178 | case 22050: |
179 | pll_out = 11289600; | 179 | pll_out = 22579200; |
180 | mclk_div = WM8510_MCLKDIV_2; | 180 | mclk_div = WM8510_MCLKDIV_4; |
181 | bclk = WM8510_BCLKDIV_8; | 181 | bclk = WM8510_BCLKDIV_8; |
182 | break; | 182 | break; |
183 | 183 | ||
184 | case 16000: | 184 | case 16000: |
185 | pll_out = 12288000; | 185 | pll_out = 24576000; |
186 | mclk_div = WM8510_MCLKDIV_3; | 186 | mclk_div = WM8510_MCLKDIV_6; |
187 | bclk = WM8510_BCLKDIV_8; | 187 | bclk = WM8510_BCLKDIV_8; |
188 | break; | 188 | break; |
189 | 189 | ||
190 | case 11025: | 190 | case 11025: |
191 | pll_out = 11289600; | 191 | pll_out = 22579200; |
192 | mclk_div = WM8510_MCLKDIV_4; | 192 | mclk_div = WM8510_MCLKDIV_8; |
193 | bclk = WM8510_BCLKDIV_8; | 193 | bclk = WM8510_BCLKDIV_8; |
194 | break; | 194 | break; |
195 | 195 | ||
196 | case 8000: | 196 | case 8000: |
197 | pll_out = 12288000; | 197 | pll_out = 24576000; |
198 | mclk_div = WM8510_MCLKDIV_6; | 198 | mclk_div = WM8510_MCLKDIV_12; |
199 | bclk = WM8510_BCLKDIV_8; | 199 | bclk = WM8510_BCLKDIV_8; |
200 | break; | 200 | break; |
201 | 201 | ||
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 6ea04be911d0..173a239a541c 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/timer.h> | 36 | #include <linux/timer.h> |
37 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
38 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/i2c.h> | ||
39 | 40 | ||
40 | #include <linux/atmel-ssc.h> | 41 | #include <linux/atmel-ssc.h> |
41 | 42 | ||
@@ -45,6 +46,7 @@ | |||
45 | #include <sound/soc.h> | 46 | #include <sound/soc.h> |
46 | #include <sound/soc-dapm.h> | 47 | #include <sound/soc-dapm.h> |
47 | 48 | ||
49 | #include <asm/mach-types.h> | ||
48 | #include <mach/hardware.h> | 50 | #include <mach/hardware.h> |
49 | #include <mach/gpio.h> | 51 | #include <mach/gpio.h> |
50 | 52 | ||
@@ -52,6 +54,9 @@ | |||
52 | #include "atmel-pcm.h" | 54 | #include "atmel-pcm.h" |
53 | #include "atmel_ssc_dai.h" | 55 | #include "atmel_ssc_dai.h" |
54 | 56 | ||
57 | #define MCLK_RATE 12000000 | ||
58 | |||
59 | static struct clk *mclk; | ||
55 | 60 | ||
56 | static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) | 61 | static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) |
57 | { | 62 | { |
@@ -59,11 +64,12 @@ static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) | |||
59 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 64 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
60 | int ret; | 65 | int ret; |
61 | 66 | ||
62 | /* codec system clock is supplied by PCK0, set to 12MHz */ | ||
63 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, | 67 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, |
64 | 12000000, SND_SOC_CLOCK_IN); | 68 | MCLK_RATE, SND_SOC_CLOCK_IN); |
65 | if (ret < 0) | 69 | if (ret < 0) { |
70 | clk_disable(mclk); | ||
66 | return ret; | 71 | return ret; |
72 | } | ||
67 | 73 | ||
68 | return 0; | 74 | return 0; |
69 | } | 75 | } |
@@ -189,6 +195,31 @@ static struct snd_soc_ops at91sam9g20ek_ops = { | |||
189 | .shutdown = at91sam9g20ek_shutdown, | 195 | .shutdown = at91sam9g20ek_shutdown, |
190 | }; | 196 | }; |
191 | 197 | ||
198 | static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, | ||
199 | enum snd_soc_bias_level level) | ||
200 | { | ||
201 | static int mclk_on; | ||
202 | int ret = 0; | ||
203 | |||
204 | switch (level) { | ||
205 | case SND_SOC_BIAS_ON: | ||
206 | case SND_SOC_BIAS_PREPARE: | ||
207 | if (!mclk_on) | ||
208 | ret = clk_enable(mclk); | ||
209 | if (ret == 0) | ||
210 | mclk_on = 1; | ||
211 | break; | ||
212 | |||
213 | case SND_SOC_BIAS_OFF: | ||
214 | case SND_SOC_BIAS_STANDBY: | ||
215 | if (mclk_on) | ||
216 | clk_disable(mclk); | ||
217 | mclk_on = 0; | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | return ret; | ||
222 | } | ||
192 | 223 | ||
193 | static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { | 224 | static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { |
194 | SND_SOC_DAPM_MIC("Int Mic", NULL), | 225 | SND_SOC_DAPM_MIC("Int Mic", NULL), |
@@ -243,21 +274,48 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = { | |||
243 | }; | 274 | }; |
244 | 275 | ||
245 | static struct snd_soc_card snd_soc_at91sam9g20ek = { | 276 | static struct snd_soc_card snd_soc_at91sam9g20ek = { |
246 | .name = "WM8731", | 277 | .name = "AT91SAMG20-EK", |
247 | .platform = &atmel_soc_platform, | 278 | .platform = &atmel_soc_platform, |
248 | .dai_link = &at91sam9g20ek_dai, | 279 | .dai_link = &at91sam9g20ek_dai, |
249 | .num_links = 1, | 280 | .num_links = 1, |
281 | .set_bias_level = at91sam9g20ek_set_bias_level, | ||
250 | }; | 282 | }; |
251 | 283 | ||
252 | static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = { | 284 | /* |
253 | .i2c_bus = 0, | 285 | * FIXME: This is a temporary bodge to avoid cross-tree merge issues. |
254 | .i2c_address = 0x1b, | 286 | * New drivers should register the wm8731 I2C device in the machine |
255 | }; | 287 | * setup code (under arch/arm for ARM systems). |
288 | */ | ||
289 | static int wm8731_i2c_register(void) | ||
290 | { | ||
291 | struct i2c_board_info info; | ||
292 | struct i2c_adapter *adapter; | ||
293 | struct i2c_client *client; | ||
294 | |||
295 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
296 | info.addr = 0x1b; | ||
297 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
298 | |||
299 | adapter = i2c_get_adapter(0); | ||
300 | if (!adapter) { | ||
301 | printk(KERN_ERR "can't get i2c adapter 0\n"); | ||
302 | return -ENODEV; | ||
303 | } | ||
304 | |||
305 | client = i2c_new_device(adapter, &info); | ||
306 | i2c_put_adapter(adapter); | ||
307 | if (!client) { | ||
308 | printk(KERN_ERR "can't add i2c device at 0x%x\n", | ||
309 | (unsigned int)info.addr); | ||
310 | return -ENODEV; | ||
311 | } | ||
312 | |||
313 | return 0; | ||
314 | } | ||
256 | 315 | ||
257 | static struct snd_soc_device at91sam9g20ek_snd_devdata = { | 316 | static struct snd_soc_device at91sam9g20ek_snd_devdata = { |
258 | .card = &snd_soc_at91sam9g20ek, | 317 | .card = &snd_soc_at91sam9g20ek, |
259 | .codec_dev = &soc_codec_dev_wm8731, | 318 | .codec_dev = &soc_codec_dev_wm8731, |
260 | .codec_data = &at91sam9g20ek_wm8731_setup, | ||
261 | }; | 319 | }; |
262 | 320 | ||
263 | static struct platform_device *at91sam9g20ek_snd_device; | 321 | static struct platform_device *at91sam9g20ek_snd_device; |
@@ -266,23 +324,56 @@ static int __init at91sam9g20ek_init(void) | |||
266 | { | 324 | { |
267 | struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; | 325 | struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; |
268 | struct ssc_device *ssc = NULL; | 326 | struct ssc_device *ssc = NULL; |
327 | struct clk *pllb; | ||
269 | int ret; | 328 | int ret; |
270 | 329 | ||
330 | if (!machine_is_at91sam9g20ek()) | ||
331 | return -ENODEV; | ||
332 | |||
333 | /* | ||
334 | * Codec MCLK is supplied by PCK0 - set it up. | ||
335 | */ | ||
336 | mclk = clk_get(NULL, "pck0"); | ||
337 | if (IS_ERR(mclk)) { | ||
338 | printk(KERN_ERR "ASoC: Failed to get MCLK\n"); | ||
339 | ret = PTR_ERR(mclk); | ||
340 | goto err; | ||
341 | } | ||
342 | |||
343 | pllb = clk_get(NULL, "pllb"); | ||
344 | if (IS_ERR(mclk)) { | ||
345 | printk(KERN_ERR "ASoC: Failed to get PLLB\n"); | ||
346 | ret = PTR_ERR(mclk); | ||
347 | goto err_mclk; | ||
348 | } | ||
349 | ret = clk_set_parent(mclk, pllb); | ||
350 | clk_put(pllb); | ||
351 | if (ret != 0) { | ||
352 | printk(KERN_ERR "ASoC: Failed to set MCLK parent\n"); | ||
353 | goto err_mclk; | ||
354 | } | ||
355 | |||
356 | clk_set_rate(mclk, MCLK_RATE); | ||
357 | |||
271 | /* | 358 | /* |
272 | * Request SSC device | 359 | * Request SSC device |
273 | */ | 360 | */ |
274 | ssc = ssc_request(0); | 361 | ssc = ssc_request(0); |
275 | if (IS_ERR(ssc)) { | 362 | if (IS_ERR(ssc)) { |
363 | printk(KERN_ERR "ASoC: Failed to request SSC 0\n"); | ||
276 | ret = PTR_ERR(ssc); | 364 | ret = PTR_ERR(ssc); |
277 | ssc = NULL; | 365 | ssc = NULL; |
278 | goto err_ssc; | 366 | goto err_ssc; |
279 | } | 367 | } |
280 | ssc_p->ssc = ssc; | 368 | ssc_p->ssc = ssc; |
281 | 369 | ||
370 | ret = wm8731_i2c_register(); | ||
371 | if (ret != 0) | ||
372 | goto err_ssc; | ||
373 | |||
282 | at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); | 374 | at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); |
283 | if (!at91sam9g20ek_snd_device) { | 375 | if (!at91sam9g20ek_snd_device) { |
284 | printk(KERN_DEBUG | 376 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); |
285 | "platform device allocation failed\n"); | ||
286 | ret = -ENOMEM; | 377 | ret = -ENOMEM; |
287 | } | 378 | } |
288 | 379 | ||
@@ -292,14 +383,19 @@ static int __init at91sam9g20ek_init(void) | |||
292 | 383 | ||
293 | ret = platform_device_add(at91sam9g20ek_snd_device); | 384 | ret = platform_device_add(at91sam9g20ek_snd_device); |
294 | if (ret) { | 385 | if (ret) { |
295 | printk(KERN_DEBUG | 386 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); |
296 | "platform device allocation failed\n"); | ||
297 | platform_device_put(at91sam9g20ek_snd_device); | 387 | platform_device_put(at91sam9g20ek_snd_device); |
298 | } | 388 | } |
299 | 389 | ||
300 | return ret; | 390 | return ret; |
301 | 391 | ||
302 | err_ssc: | 392 | err_ssc: |
393 | ssc_free(ssc); | ||
394 | ssc_p->ssc = NULL; | ||
395 | err_mclk: | ||
396 | clk_put(mclk); | ||
397 | mclk = NULL; | ||
398 | err: | ||
303 | return ret; | 399 | return ret; |
304 | } | 400 | } |
305 | 401 | ||
@@ -317,6 +413,8 @@ static void __exit at91sam9g20ek_exit(void) | |||
317 | 413 | ||
318 | platform_device_unregister(at91sam9g20ek_snd_device); | 414 | platform_device_unregister(at91sam9g20ek_snd_device); |
319 | at91sam9g20ek_snd_device = NULL; | 415 | at91sam9g20ek_snd_device = NULL; |
416 | clk_put(mclk); | ||
417 | mclk = NULL; | ||
320 | } | 418 | } |
321 | 419 | ||
322 | module_init(at91sam9g20ek_init); | 420 | module_init(at91sam9g20ek_init); |
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index bc8d654576c0..30490a259148 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c | |||
@@ -305,7 +305,7 @@ static int au1xpsc_pcm_close(struct snd_pcm_substream *substream) | |||
305 | return 0; | 305 | return 0; |
306 | } | 306 | } |
307 | 307 | ||
308 | struct snd_pcm_ops au1xpsc_pcm_ops = { | 308 | static struct snd_pcm_ops au1xpsc_pcm_ops = { |
309 | .open = au1xpsc_pcm_open, | 309 | .open = au1xpsc_pcm_open, |
310 | .close = au1xpsc_pcm_close, | 310 | .close = au1xpsc_pcm_close, |
311 | .ioctl = snd_pcm_lib_ioctl, | 311 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index f0e30aec7f23..479d7bdf1865 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c | |||
@@ -342,6 +342,11 @@ static int au1xpsc_ac97_resume(struct snd_soc_dai *dai) | |||
342 | return 0; | 342 | return 0; |
343 | } | 343 | } |
344 | 344 | ||
345 | static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { | ||
346 | .trigger = au1xpsc_ac97_trigger, | ||
347 | .hw_params = au1xpsc_ac97_hw_params, | ||
348 | }; | ||
349 | |||
345 | struct snd_soc_dai au1xpsc_ac97_dai = { | 350 | struct snd_soc_dai au1xpsc_ac97_dai = { |
346 | .name = "au1xpsc_ac97", | 351 | .name = "au1xpsc_ac97", |
347 | .ac97_control = 1, | 352 | .ac97_control = 1, |
@@ -361,10 +366,7 @@ struct snd_soc_dai au1xpsc_ac97_dai = { | |||
361 | .channels_min = 2, | 366 | .channels_min = 2, |
362 | .channels_max = 2, | 367 | .channels_max = 2, |
363 | }, | 368 | }, |
364 | .ops = { | 369 | .ops = &au1xpsc_ac97_dai_ops, |
365 | .trigger = au1xpsc_ac97_trigger, | ||
366 | .hw_params = au1xpsc_ac97_hw_params, | ||
367 | }, | ||
368 | }; | 370 | }; |
369 | EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); | 371 | EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); |
370 | 372 | ||
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index f916de4400ed..bb589327ee32 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c | |||
@@ -367,6 +367,12 @@ static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai) | |||
367 | return 0; | 367 | return 0; |
368 | } | 368 | } |
369 | 369 | ||
370 | static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = { | ||
371 | .trigger = au1xpsc_i2s_trigger, | ||
372 | .hw_params = au1xpsc_i2s_hw_params, | ||
373 | .set_fmt = au1xpsc_i2s_set_fmt, | ||
374 | }; | ||
375 | |||
370 | struct snd_soc_dai au1xpsc_i2s_dai = { | 376 | struct snd_soc_dai au1xpsc_i2s_dai = { |
371 | .name = "au1xpsc_i2s", | 377 | .name = "au1xpsc_i2s", |
372 | .probe = au1xpsc_i2s_probe, | 378 | .probe = au1xpsc_i2s_probe, |
@@ -385,11 +391,7 @@ struct snd_soc_dai au1xpsc_i2s_dai = { | |||
385 | .channels_min = 2, | 391 | .channels_min = 2, |
386 | .channels_max = 8, /* 2 without external help */ | 392 | .channels_max = 8, /* 2 without external help */ |
387 | }, | 393 | }, |
388 | .ops = { | 394 | .ops = &au1xpsc_i2s_dai_ops, |
389 | .trigger = au1xpsc_i2s_trigger, | ||
390 | .hw_params = au1xpsc_i2s_hw_params, | ||
391 | .set_fmt = au1xpsc_i2s_set_fmt, | ||
392 | }, | ||
393 | }; | 395 | }; |
394 | EXPORT_SYMBOL(au1xpsc_i2s_dai); | 396 | EXPORT_SYMBOL(au1xpsc_i2s_dai); |
395 | 397 | ||
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 8067cfafa3a7..8cfed1a5dcbe 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c | |||
@@ -297,7 +297,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | |||
297 | } | 297 | } |
298 | #endif | 298 | #endif |
299 | 299 | ||
300 | struct snd_pcm_ops bf5xx_pcm_ac97_ops = { | 300 | static struct snd_pcm_ops bf5xx_pcm_ac97_ops = { |
301 | .open = bf5xx_pcm_open, | 301 | .open = bf5xx_pcm_open, |
302 | .ioctl = snd_pcm_lib_ioctl, | 302 | .ioctl = snd_pcm_lib_ioctl, |
303 | .hw_params = bf5xx_pcm_hw_params, | 303 | .hw_params = bf5xx_pcm_hw_params, |
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 3be2be60576d..8a935f2d1767 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c | |||
@@ -31,72 +31,46 @@ | |||
31 | #include "bf5xx-sport.h" | 31 | #include "bf5xx-sport.h" |
32 | #include "bf5xx-ac97.h" | 32 | #include "bf5xx-ac97.h" |
33 | 33 | ||
34 | #if defined(CONFIG_BF54x) | ||
35 | #define PIN_REQ_SPORT_0 {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, \ | ||
36 | P_SPORT0_RFS, P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0} | ||
37 | |||
38 | #define PIN_REQ_SPORT_1 {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, \ | ||
39 | P_SPORT1_RFS, P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0} | ||
40 | |||
41 | #define PIN_REQ_SPORT_2 {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, \ | ||
42 | P_SPORT2_RFS, P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0} | ||
43 | |||
44 | #define PIN_REQ_SPORT_3 {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, \ | ||
45 | P_SPORT3_RFS, P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0} | ||
46 | #else | ||
47 | #define PIN_REQ_SPORT_0 {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \ | ||
48 | P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0} | ||
49 | |||
50 | #define PIN_REQ_SPORT_1 {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \ | ||
51 | P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0} | ||
52 | #endif | ||
53 | |||
54 | static int *cmd_count; | 34 | static int *cmd_count; |
55 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; | 35 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; |
56 | 36 | ||
37 | #define SPORT_REQ(x) \ | ||
38 | [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \ | ||
39 | P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0} | ||
57 | static u16 sport_req[][7] = { | 40 | static u16 sport_req[][7] = { |
58 | PIN_REQ_SPORT_0, | 41 | #ifdef SPORT0_TCR1 |
59 | #ifdef PIN_REQ_SPORT_1 | 42 | SPORT_REQ(0), |
60 | PIN_REQ_SPORT_1, | 43 | #endif |
44 | #ifdef SPORT1_TCR1 | ||
45 | SPORT_REQ(1), | ||
61 | #endif | 46 | #endif |
62 | #ifdef PIN_REQ_SPORT_2 | 47 | #ifdef SPORT2_TCR1 |
63 | PIN_REQ_SPORT_2, | 48 | SPORT_REQ(2), |
64 | #endif | 49 | #endif |
65 | #ifdef PIN_REQ_SPORT_3 | 50 | #ifdef SPORT3_TCR1 |
66 | PIN_REQ_SPORT_3, | 51 | SPORT_REQ(3), |
67 | #endif | 52 | #endif |
68 | }; | 53 | }; |
69 | 54 | ||
55 | #define SPORT_PARAMS(x) \ | ||
56 | [x] = { \ | ||
57 | .dma_rx_chan = CH_SPORT##x##_RX, \ | ||
58 | .dma_tx_chan = CH_SPORT##x##_TX, \ | ||
59 | .err_irq = IRQ_SPORT##x##_ERROR, \ | ||
60 | .regs = (struct sport_register *)SPORT##x##_TCR1, \ | ||
61 | } | ||
70 | static struct sport_param sport_params[4] = { | 62 | static struct sport_param sport_params[4] = { |
71 | { | 63 | #ifdef SPORT0_TCR1 |
72 | .dma_rx_chan = CH_SPORT0_RX, | 64 | SPORT_PARAMS(0), |
73 | .dma_tx_chan = CH_SPORT0_TX, | ||
74 | .err_irq = IRQ_SPORT0_ERROR, | ||
75 | .regs = (struct sport_register *)SPORT0_TCR1, | ||
76 | }, | ||
77 | #ifdef PIN_REQ_SPORT_1 | ||
78 | { | ||
79 | .dma_rx_chan = CH_SPORT1_RX, | ||
80 | .dma_tx_chan = CH_SPORT1_TX, | ||
81 | .err_irq = IRQ_SPORT1_ERROR, | ||
82 | .regs = (struct sport_register *)SPORT1_TCR1, | ||
83 | }, | ||
84 | #endif | 65 | #endif |
85 | #ifdef PIN_REQ_SPORT_2 | 66 | #ifdef SPORT1_TCR1 |
86 | { | 67 | SPORT_PARAMS(1), |
87 | .dma_rx_chan = CH_SPORT2_RX, | ||
88 | .dma_tx_chan = CH_SPORT2_TX, | ||
89 | .err_irq = IRQ_SPORT2_ERROR, | ||
90 | .regs = (struct sport_register *)SPORT2_TCR1, | ||
91 | }, | ||
92 | #endif | 68 | #endif |
93 | #ifdef PIN_REQ_SPORT_3 | 69 | #ifdef SPORT2_TCR1 |
94 | { | 70 | SPORT_PARAMS(2), |
95 | .dma_rx_chan = CH_SPORT3_RX, | 71 | #endif |
96 | .dma_tx_chan = CH_SPORT3_TX, | 72 | #ifdef SPORT3_TCR1 |
97 | .err_irq = IRQ_SPORT3_ERROR, | 73 | SPORT_PARAMS(3), |
98 | .regs = (struct sport_register *)SPORT3_TCR1, | ||
99 | } | ||
100 | #endif | 74 | #endif |
101 | }; | 75 | }; |
102 | 76 | ||
@@ -332,11 +306,11 @@ static int bf5xx_ac97_probe(struct platform_device *pdev, | |||
332 | if (cmd_count == NULL) | 306 | if (cmd_count == NULL) |
333 | return -ENOMEM; | 307 | return -ENOMEM; |
334 | 308 | ||
335 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { | 309 | if (peripheral_request_list(sport_req[sport_num], "soc-audio")) { |
336 | pr_err("Requesting Peripherals failed\n"); | 310 | pr_err("Requesting Peripherals failed\n"); |
337 | ret = -EFAULT; | 311 | ret = -EFAULT; |
338 | goto peripheral_err; | 312 | goto peripheral_err; |
339 | } | 313 | } |
340 | 314 | ||
341 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | 315 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET |
342 | /* Request PB3 as reset pin */ | 316 | /* Request PB3 as reset pin */ |
@@ -383,9 +357,9 @@ sport_config_err: | |||
383 | sport_err: | 357 | sport_err: |
384 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | 358 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET |
385 | gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); | 359 | gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); |
386 | #endif | ||
387 | gpio_err: | 360 | gpio_err: |
388 | peripheral_free_list(&sport_req[sport_num][0]); | 361 | #endif |
362 | peripheral_free_list(sport_req[sport_num]); | ||
389 | peripheral_err: | 363 | peripheral_err: |
390 | free_page((unsigned long)cmd_count); | 364 | free_page((unsigned long)cmd_count); |
391 | cmd_count = NULL; | 365 | cmd_count = NULL; |
@@ -398,7 +372,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev, | |||
398 | { | 372 | { |
399 | free_page((unsigned long)cmd_count); | 373 | free_page((unsigned long)cmd_count); |
400 | cmd_count = NULL; | 374 | cmd_count = NULL; |
401 | peripheral_free_list(&sport_req[sport_num][0]); | 375 | peripheral_free_list(sport_req[sport_num]); |
402 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | 376 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET |
403 | gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); | 377 | gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); |
404 | #endif | 378 | #endif |
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 7f2a5e199075..edfbdc024e66 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c | |||
@@ -114,7 +114,7 @@ static int snd_ad73311_configure(void) | |||
114 | SSYNC(); | 114 | SSYNC(); |
115 | 115 | ||
116 | /* When TUVF is set, the data is already send out */ | 116 | /* When TUVF is set, the data is already send out */ |
117 | while (!(status & TUVF) && count++ < 10000) { | 117 | while (!(status & TUVF) && ++count < 10000) { |
118 | udelay(1); | 118 | udelay(1); |
119 | status = bfin_read_SPORT_STAT(); | 119 | status = bfin_read_SPORT_STAT(); |
120 | SSYNC(); | 120 | SSYNC(); |
@@ -123,7 +123,7 @@ static int snd_ad73311_configure(void) | |||
123 | SSYNC(); | 123 | SSYNC(); |
124 | local_irq_enable(); | 124 | local_irq_enable(); |
125 | 125 | ||
126 | if (count == 10000) { | 126 | if (count >= 10000) { |
127 | printk(KERN_ERR "ad73311: failed to configure codec\n"); | 127 | printk(KERN_ERR "ad73311: failed to configure codec\n"); |
128 | return -1; | 128 | return -1; |
129 | } | 129 | } |
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 53d290b3ea47..1318c4f627b7 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c | |||
@@ -184,7 +184,7 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, | |||
184 | return 0 ; | 184 | return 0 ; |
185 | } | 185 | } |
186 | 186 | ||
187 | struct snd_pcm_ops bf5xx_pcm_i2s_ops = { | 187 | static struct snd_pcm_ops bf5xx_pcm_i2s_ops = { |
188 | .open = bf5xx_pcm_open, | 188 | .open = bf5xx_pcm_open, |
189 | .ioctl = snd_pcm_lib_ioctl, | 189 | .ioctl = snd_pcm_lib_ioctl, |
190 | .hw_params = bf5xx_pcm_hw_params, | 190 | .hw_params = bf5xx_pcm_hw_params, |
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index d1d95d2393fe..964824419678 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c | |||
@@ -287,6 +287,13 @@ static int bf5xx_i2s_resume(struct platform_device *pdev, | |||
287 | #define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ | 287 | #define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ |
288 | SNDRV_PCM_FMTBIT_S32_LE) | 288 | SNDRV_PCM_FMTBIT_S32_LE) |
289 | 289 | ||
290 | static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { | ||
291 | .startup = bf5xx_i2s_startup, | ||
292 | .shutdown = bf5xx_i2s_shutdown, | ||
293 | .hw_params = bf5xx_i2s_hw_params, | ||
294 | .set_fmt = bf5xx_i2s_set_dai_fmt, | ||
295 | }; | ||
296 | |||
290 | struct snd_soc_dai bf5xx_i2s_dai = { | 297 | struct snd_soc_dai bf5xx_i2s_dai = { |
291 | .name = "bf5xx-i2s", | 298 | .name = "bf5xx-i2s", |
292 | .id = 0, | 299 | .id = 0, |
@@ -304,12 +311,7 @@ struct snd_soc_dai bf5xx_i2s_dai = { | |||
304 | .channels_max = 2, | 311 | .channels_max = 2, |
305 | .rates = BF5XX_I2S_RATES, | 312 | .rates = BF5XX_I2S_RATES, |
306 | .formats = BF5XX_I2S_FORMATS,}, | 313 | .formats = BF5XX_I2S_FORMATS,}, |
307 | .ops = { | 314 | .ops = &bf5xx_i2s_dai_ops, |
308 | .startup = bf5xx_i2s_startup, | ||
309 | .shutdown = bf5xx_i2s_shutdown, | ||
310 | .hw_params = bf5xx_i2s_hw_params, | ||
311 | .set_fmt = bf5xx_i2s_set_dai_fmt, | ||
312 | }, | ||
313 | }; | 315 | }; |
314 | EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); | 316 | EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); |
315 | 317 | ||
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c index 3b99e484d555..b7953c8cf838 100644 --- a/sound/soc/blackfin/bf5xx-sport.c +++ b/sound/soc/blackfin/bf5xx-sport.c | |||
@@ -133,7 +133,7 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount, | |||
133 | int i; | 133 | int i; |
134 | 134 | ||
135 | for (i = 0; i < fragcount; ++i) { | 135 | for (i = 0; i < fragcount; ++i) { |
136 | desc[i].next_desc_addr = (unsigned long)&(desc[i + 1]); | 136 | desc[i].next_desc_addr = &(desc[i + 1]); |
137 | desc[i].start_addr = (unsigned long)buf + i*fragsize; | 137 | desc[i].start_addr = (unsigned long)buf + i*fragsize; |
138 | desc[i].cfg = cfg; | 138 | desc[i].cfg = cfg; |
139 | desc[i].x_count = x_count; | 139 | desc[i].x_count = x_count; |
@@ -143,12 +143,12 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount, | |||
143 | } | 143 | } |
144 | 144 | ||
145 | /* make circular */ | 145 | /* make circular */ |
146 | desc[fragcount-1].next_desc_addr = (unsigned long)desc; | 146 | desc[fragcount-1].next_desc_addr = desc; |
147 | 147 | ||
148 | pr_debug("setup desc: desc0=%p, next0=%lx, desc1=%p," | 148 | pr_debug("setup desc: desc0=%p, next0=%p, desc1=%p," |
149 | "next1=%lx\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n", | 149 | "next1=%p\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n", |
150 | &(desc[0]), desc[0].next_desc_addr, | 150 | desc, desc[0].next_desc_addr, |
151 | &(desc[1]), desc[1].next_desc_addr, | 151 | desc+1, desc[1].next_desc_addr, |
152 | desc[0].x_count, desc[0].y_count, | 152 | desc[0].x_count, desc[0].y_count, |
153 | desc[0].start_addr, desc[0].cfg); | 153 | desc[0].start_addr, desc[0].cfg); |
154 | } | 154 | } |
@@ -184,22 +184,20 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport) | |||
184 | BUG_ON(sport->curr_rx_desc == sport->dummy_rx_desc); | 184 | BUG_ON(sport->curr_rx_desc == sport->dummy_rx_desc); |
185 | 185 | ||
186 | /* Maybe the dummy buffer descriptor ring is damaged */ | 186 | /* Maybe the dummy buffer descriptor ring is damaged */ |
187 | sport->dummy_rx_desc->next_desc_addr = \ | 187 | sport->dummy_rx_desc->next_desc_addr = sport->dummy_rx_desc + 1; |
188 | (unsigned long)(sport->dummy_rx_desc+1); | ||
189 | 188 | ||
190 | local_irq_save(flags); | 189 | local_irq_save(flags); |
191 | desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_rx_chan); | 190 | desc = get_dma_next_desc_ptr(sport->dma_rx_chan); |
192 | /* Copy the descriptor which will be damaged to backup */ | 191 | /* Copy the descriptor which will be damaged to backup */ |
193 | temp_desc = *desc; | 192 | temp_desc = *desc; |
194 | desc->x_count = 0xa; | 193 | desc->x_count = 0xa; |
195 | desc->y_count = 0; | 194 | desc->y_count = 0; |
196 | desc->next_desc_addr = (unsigned long)(sport->dummy_rx_desc); | 195 | desc->next_desc_addr = sport->dummy_rx_desc; |
197 | local_irq_restore(flags); | 196 | local_irq_restore(flags); |
198 | /* Waiting for dummy buffer descriptor is already hooked*/ | 197 | /* Waiting for dummy buffer descriptor is already hooked*/ |
199 | while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) - | 198 | while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) - |
200 | sizeof(struct dmasg)) != | 199 | sizeof(struct dmasg)) != sport->dummy_rx_desc) |
201 | (unsigned long)sport->dummy_rx_desc) | 200 | continue; |
202 | ; | ||
203 | sport->curr_rx_desc = sport->dummy_rx_desc; | 201 | sport->curr_rx_desc = sport->dummy_rx_desc; |
204 | /* Restore the damaged descriptor */ | 202 | /* Restore the damaged descriptor */ |
205 | *desc = temp_desc; | 203 | *desc = temp_desc; |
@@ -210,14 +208,12 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport) | |||
210 | static inline int sport_rx_dma_start(struct sport_device *sport, int dummy) | 208 | static inline int sport_rx_dma_start(struct sport_device *sport, int dummy) |
211 | { | 209 | { |
212 | if (dummy) { | 210 | if (dummy) { |
213 | sport->dummy_rx_desc->next_desc_addr = \ | 211 | sport->dummy_rx_desc->next_desc_addr = sport->dummy_rx_desc; |
214 | (unsigned long) sport->dummy_rx_desc; | ||
215 | sport->curr_rx_desc = sport->dummy_rx_desc; | 212 | sport->curr_rx_desc = sport->dummy_rx_desc; |
216 | } else | 213 | } else |
217 | sport->curr_rx_desc = sport->dma_rx_desc; | 214 | sport->curr_rx_desc = sport->dma_rx_desc; |
218 | 215 | ||
219 | set_dma_next_desc_addr(sport->dma_rx_chan, \ | 216 | set_dma_next_desc_addr(sport->dma_rx_chan, sport->curr_rx_desc); |
220 | (unsigned long)(sport->curr_rx_desc)); | ||
221 | set_dma_x_count(sport->dma_rx_chan, 0); | 217 | set_dma_x_count(sport->dma_rx_chan, 0); |
222 | set_dma_x_modify(sport->dma_rx_chan, 0); | 218 | set_dma_x_modify(sport->dma_rx_chan, 0); |
223 | set_dma_config(sport->dma_rx_chan, (DMAFLOW_LARGE | NDSIZE_9 | \ | 219 | set_dma_config(sport->dma_rx_chan, (DMAFLOW_LARGE | NDSIZE_9 | \ |
@@ -231,14 +227,12 @@ static inline int sport_rx_dma_start(struct sport_device *sport, int dummy) | |||
231 | static inline int sport_tx_dma_start(struct sport_device *sport, int dummy) | 227 | static inline int sport_tx_dma_start(struct sport_device *sport, int dummy) |
232 | { | 228 | { |
233 | if (dummy) { | 229 | if (dummy) { |
234 | sport->dummy_tx_desc->next_desc_addr = \ | 230 | sport->dummy_tx_desc->next_desc_addr = sport->dummy_tx_desc; |
235 | (unsigned long) sport->dummy_tx_desc; | ||
236 | sport->curr_tx_desc = sport->dummy_tx_desc; | 231 | sport->curr_tx_desc = sport->dummy_tx_desc; |
237 | } else | 232 | } else |
238 | sport->curr_tx_desc = sport->dma_tx_desc; | 233 | sport->curr_tx_desc = sport->dma_tx_desc; |
239 | 234 | ||
240 | set_dma_next_desc_addr(sport->dma_tx_chan, \ | 235 | set_dma_next_desc_addr(sport->dma_tx_chan, sport->curr_tx_desc); |
241 | (unsigned long)(sport->curr_tx_desc)); | ||
242 | set_dma_x_count(sport->dma_tx_chan, 0); | 236 | set_dma_x_count(sport->dma_tx_chan, 0); |
243 | set_dma_x_modify(sport->dma_tx_chan, 0); | 237 | set_dma_x_modify(sport->dma_tx_chan, 0); |
244 | set_dma_config(sport->dma_tx_chan, | 238 | set_dma_config(sport->dma_tx_chan, |
@@ -261,11 +255,9 @@ int sport_rx_start(struct sport_device *sport) | |||
261 | BUG_ON(sport->curr_rx_desc != sport->dummy_rx_desc); | 255 | BUG_ON(sport->curr_rx_desc != sport->dummy_rx_desc); |
262 | local_irq_save(flags); | 256 | local_irq_save(flags); |
263 | while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) - | 257 | while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) - |
264 | sizeof(struct dmasg)) != | 258 | sizeof(struct dmasg)) != sport->dummy_rx_desc) |
265 | (unsigned long)sport->dummy_rx_desc) | 259 | continue; |
266 | ; | 260 | sport->dummy_rx_desc->next_desc_addr = sport->dma_rx_desc; |
267 | sport->dummy_rx_desc->next_desc_addr = | ||
268 | (unsigned long)(sport->dma_rx_desc); | ||
269 | local_irq_restore(flags); | 261 | local_irq_restore(flags); |
270 | sport->curr_rx_desc = sport->dma_rx_desc; | 262 | sport->curr_rx_desc = sport->dma_rx_desc; |
271 | } else { | 263 | } else { |
@@ -310,23 +302,21 @@ static inline int sport_hook_tx_dummy(struct sport_device *sport) | |||
310 | BUG_ON(sport->dummy_tx_desc == NULL); | 302 | BUG_ON(sport->dummy_tx_desc == NULL); |
311 | BUG_ON(sport->curr_tx_desc == sport->dummy_tx_desc); | 303 | BUG_ON(sport->curr_tx_desc == sport->dummy_tx_desc); |
312 | 304 | ||
313 | sport->dummy_tx_desc->next_desc_addr = \ | 305 | sport->dummy_tx_desc->next_desc_addr = sport->dummy_tx_desc + 1; |
314 | (unsigned long)(sport->dummy_tx_desc+1); | ||
315 | 306 | ||
316 | /* Shorten the time on last normal descriptor */ | 307 | /* Shorten the time on last normal descriptor */ |
317 | local_irq_save(flags); | 308 | local_irq_save(flags); |
318 | desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_tx_chan); | 309 | desc = get_dma_next_desc_ptr(sport->dma_tx_chan); |
319 | /* Store the descriptor which will be damaged */ | 310 | /* Store the descriptor which will be damaged */ |
320 | temp_desc = *desc; | 311 | temp_desc = *desc; |
321 | desc->x_count = 0xa; | 312 | desc->x_count = 0xa; |
322 | desc->y_count = 0; | 313 | desc->y_count = 0; |
323 | desc->next_desc_addr = (unsigned long)(sport->dummy_tx_desc); | 314 | desc->next_desc_addr = sport->dummy_tx_desc; |
324 | local_irq_restore(flags); | 315 | local_irq_restore(flags); |
325 | /* Waiting for dummy buffer descriptor is already hooked*/ | 316 | /* Waiting for dummy buffer descriptor is already hooked*/ |
326 | while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - \ | 317 | while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - \ |
327 | sizeof(struct dmasg)) != \ | 318 | sizeof(struct dmasg)) != sport->dummy_tx_desc) |
328 | (unsigned long)sport->dummy_tx_desc) | 319 | continue; |
329 | ; | ||
330 | sport->curr_tx_desc = sport->dummy_tx_desc; | 320 | sport->curr_tx_desc = sport->dummy_tx_desc; |
331 | /* Restore the damaged descriptor */ | 321 | /* Restore the damaged descriptor */ |
332 | *desc = temp_desc; | 322 | *desc = temp_desc; |
@@ -347,11 +337,9 @@ int sport_tx_start(struct sport_device *sport) | |||
347 | /* Hook the normal buffer descriptor */ | 337 | /* Hook the normal buffer descriptor */ |
348 | local_irq_save(flags); | 338 | local_irq_save(flags); |
349 | while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - | 339 | while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - |
350 | sizeof(struct dmasg)) != | 340 | sizeof(struct dmasg)) != sport->dummy_tx_desc) |
351 | (unsigned long)sport->dummy_tx_desc) | 341 | continue; |
352 | ; | 342 | sport->dummy_tx_desc->next_desc_addr = sport->dma_tx_desc; |
353 | sport->dummy_tx_desc->next_desc_addr = | ||
354 | (unsigned long)(sport->dma_tx_desc); | ||
355 | local_irq_restore(flags); | 343 | local_irq_restore(flags); |
356 | sport->curr_tx_desc = sport->dma_tx_desc; | 344 | sport->curr_tx_desc = sport->dma_tx_desc; |
357 | } else { | 345 | } else { |
@@ -536,19 +524,17 @@ static int sport_config_rx_dummy(struct sport_device *sport) | |||
536 | unsigned config; | 524 | unsigned config; |
537 | 525 | ||
538 | pr_debug("%s entered\n", __func__); | 526 | pr_debug("%s entered\n", __func__); |
539 | #if L1_DATA_A_LENGTH != 0 | 527 | if (L1_DATA_A_LENGTH) |
540 | desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc)); | 528 | desc = l1_data_sram_zalloc(2 * sizeof(*desc)); |
541 | #else | 529 | else { |
542 | { | ||
543 | dma_addr_t addr; | 530 | dma_addr_t addr; |
544 | desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0); | 531 | desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0); |
532 | memset(desc, 0, 2 * sizeof(*desc)); | ||
545 | } | 533 | } |
546 | #endif | ||
547 | if (desc == NULL) { | 534 | if (desc == NULL) { |
548 | pr_err("Failed to allocate memory for dummy rx desc\n"); | 535 | pr_err("Failed to allocate memory for dummy rx desc\n"); |
549 | return -ENOMEM; | 536 | return -ENOMEM; |
550 | } | 537 | } |
551 | memset(desc, 0, 2 * sizeof(*desc)); | ||
552 | sport->dummy_rx_desc = desc; | 538 | sport->dummy_rx_desc = desc; |
553 | desc->start_addr = (unsigned long)sport->dummy_buf; | 539 | desc->start_addr = (unsigned long)sport->dummy_buf; |
554 | config = DMAFLOW_LARGE | NDSIZE_9 | compute_wdsize(sport->wdsize) | 540 | config = DMAFLOW_LARGE | NDSIZE_9 | compute_wdsize(sport->wdsize) |
@@ -559,8 +545,8 @@ static int sport_config_rx_dummy(struct sport_device *sport) | |||
559 | desc->y_count = 0; | 545 | desc->y_count = 0; |
560 | desc->y_modify = 0; | 546 | desc->y_modify = 0; |
561 | memcpy(desc+1, desc, sizeof(*desc)); | 547 | memcpy(desc+1, desc, sizeof(*desc)); |
562 | desc->next_desc_addr = (unsigned long)(desc+1); | 548 | desc->next_desc_addr = desc + 1; |
563 | desc[1].next_desc_addr = (unsigned long)desc; | 549 | desc[1].next_desc_addr = desc; |
564 | return 0; | 550 | return 0; |
565 | } | 551 | } |
566 | 552 | ||
@@ -571,19 +557,17 @@ static int sport_config_tx_dummy(struct sport_device *sport) | |||
571 | 557 | ||
572 | pr_debug("%s entered\n", __func__); | 558 | pr_debug("%s entered\n", __func__); |
573 | 559 | ||
574 | #if L1_DATA_A_LENGTH != 0 | 560 | if (L1_DATA_A_LENGTH) |
575 | desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc)); | 561 | desc = l1_data_sram_zalloc(2 * sizeof(*desc)); |
576 | #else | 562 | else { |
577 | { | ||
578 | dma_addr_t addr; | 563 | dma_addr_t addr; |
579 | desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0); | 564 | desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0); |
565 | memset(desc, 0, 2 * sizeof(*desc)); | ||
580 | } | 566 | } |
581 | #endif | ||
582 | if (!desc) { | 567 | if (!desc) { |
583 | pr_err("Failed to allocate memory for dummy tx desc\n"); | 568 | pr_err("Failed to allocate memory for dummy tx desc\n"); |
584 | return -ENOMEM; | 569 | return -ENOMEM; |
585 | } | 570 | } |
586 | memset(desc, 0, 2 * sizeof(*desc)); | ||
587 | sport->dummy_tx_desc = desc; | 571 | sport->dummy_tx_desc = desc; |
588 | desc->start_addr = (unsigned long)sport->dummy_buf + \ | 572 | desc->start_addr = (unsigned long)sport->dummy_buf + \ |
589 | sport->dummy_count; | 573 | sport->dummy_count; |
@@ -595,8 +579,8 @@ static int sport_config_tx_dummy(struct sport_device *sport) | |||
595 | desc->y_count = 0; | 579 | desc->y_count = 0; |
596 | desc->y_modify = 0; | 580 | desc->y_modify = 0; |
597 | memcpy(desc+1, desc, sizeof(*desc)); | 581 | memcpy(desc+1, desc, sizeof(*desc)); |
598 | desc->next_desc_addr = (unsigned long)(desc+1); | 582 | desc->next_desc_addr = desc + 1; |
599 | desc[1].next_desc_addr = (unsigned long)desc; | 583 | desc[1].next_desc_addr = desc; |
600 | return 0; | 584 | return 0; |
601 | } | 585 | } |
602 | 586 | ||
@@ -872,17 +856,15 @@ struct sport_device *sport_init(struct sport_param *param, unsigned wdsize, | |||
872 | sport->wdsize = wdsize; | 856 | sport->wdsize = wdsize; |
873 | sport->dummy_count = dummy_count; | 857 | sport->dummy_count = dummy_count; |
874 | 858 | ||
875 | #if L1_DATA_A_LENGTH != 0 | 859 | if (L1_DATA_A_LENGTH) |
876 | sport->dummy_buf = l1_data_sram_alloc(dummy_count * 2); | 860 | sport->dummy_buf = l1_data_sram_zalloc(dummy_count * 2); |
877 | #else | 861 | else |
878 | sport->dummy_buf = kmalloc(dummy_count * 2, GFP_KERNEL); | 862 | sport->dummy_buf = kzalloc(dummy_count * 2, GFP_KERNEL); |
879 | #endif | ||
880 | if (sport->dummy_buf == NULL) { | 863 | if (sport->dummy_buf == NULL) { |
881 | pr_err("Failed to allocate dummy buffer\n"); | 864 | pr_err("Failed to allocate dummy buffer\n"); |
882 | goto __error; | 865 | goto __error; |
883 | } | 866 | } |
884 | 867 | ||
885 | memset(sport->dummy_buf, 0, dummy_count * 2); | ||
886 | ret = sport_config_rx_dummy(sport); | 868 | ret = sport_config_rx_dummy(sport); |
887 | if (ret) { | 869 | if (ret) { |
888 | pr_err("Failed to config rx dummy ring\n"); | 870 | pr_err("Failed to config rx dummy ring\n"); |
@@ -939,6 +921,7 @@ void sport_done(struct sport_device *sport) | |||
939 | sport = NULL; | 921 | sport = NULL; |
940 | } | 922 | } |
941 | EXPORT_SYMBOL(sport_done); | 923 | EXPORT_SYMBOL(sport_done); |
924 | |||
942 | /* | 925 | /* |
943 | * It is only used to send several bytes when dma is not enabled | 926 | * It is only used to send several bytes when dma is not enabled |
944 | * sport controller is configured but not enabled. | 927 | * sport controller is configured but not enabled. |
@@ -1029,4 +1012,3 @@ EXPORT_SYMBOL(sport_send_and_recv); | |||
1029 | MODULE_AUTHOR("Roy Huang"); | 1012 | MODULE_AUTHOR("Roy Huang"); |
1030 | MODULE_DESCRIPTION("SPORT driver for ADI Blackfin"); | 1013 | MODULE_DESCRIPTION("SPORT driver for ADI Blackfin"); |
1031 | MODULE_LICENSE("GPL"); | 1014 | MODULE_LICENSE("GPL"); |
1032 | |||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d0e0d691ae51..b6c7f7a01cb0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -10,9 +10,11 @@ config SND_SOC_I2C_AND_SPI | |||
10 | 10 | ||
11 | config SND_SOC_ALL_CODECS | 11 | config SND_SOC_ALL_CODECS |
12 | tristate "Build all ASoC CODEC drivers" | 12 | tristate "Build all ASoC CODEC drivers" |
13 | select SND_SOC_L3 | ||
13 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS | 14 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS |
14 | select SND_SOC_AD1980 if SND_SOC_AC97_BUS | 15 | select SND_SOC_AD1980 if SND_SOC_AC97_BUS |
15 | select SND_SOC_AD73311 if I2C | 16 | select SND_SOC_AD73311 if I2C |
17 | select SND_SOC_AK4104 if SPI_MASTER | ||
16 | select SND_SOC_AK4535 if I2C | 18 | select SND_SOC_AK4535 if I2C |
17 | select SND_SOC_CS4270 if I2C | 19 | select SND_SOC_CS4270 if I2C |
18 | select SND_SOC_PCM3008 | 20 | select SND_SOC_PCM3008 |
@@ -24,6 +26,7 @@ config SND_SOC_ALL_CODECS | |||
24 | select SND_SOC_UDA134X | 26 | select SND_SOC_UDA134X |
25 | select SND_SOC_UDA1380 if I2C | 27 | select SND_SOC_UDA1380 if I2C |
26 | select SND_SOC_WM8350 if MFD_WM8350 | 28 | select SND_SOC_WM8350 if MFD_WM8350 |
29 | select SND_SOC_WM8400 if MFD_WM8400 | ||
27 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI | 30 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI |
28 | select SND_SOC_WM8580 if I2C | 31 | select SND_SOC_WM8580 if I2C |
29 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI | 32 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI |
@@ -34,6 +37,7 @@ config SND_SOC_ALL_CODECS | |||
34 | select SND_SOC_WM8903 if I2C | 37 | select SND_SOC_WM8903 if I2C |
35 | select SND_SOC_WM8971 if I2C | 38 | select SND_SOC_WM8971 if I2C |
36 | select SND_SOC_WM8990 if I2C | 39 | select SND_SOC_WM8990 if I2C |
40 | select SND_SOC_WM9705 if SND_SOC_AC97_BUS | ||
37 | select SND_SOC_WM9712 if SND_SOC_AC97_BUS | 41 | select SND_SOC_WM9712 if SND_SOC_AC97_BUS |
38 | select SND_SOC_WM9713 if SND_SOC_AC97_BUS | 42 | select SND_SOC_WM9713 if SND_SOC_AC97_BUS |
39 | help | 43 | help |
@@ -58,6 +62,9 @@ config SND_SOC_AD1980 | |||
58 | config SND_SOC_AD73311 | 62 | config SND_SOC_AD73311 |
59 | tristate | 63 | tristate |
60 | 64 | ||
65 | config SND_SOC_AK4104 | ||
66 | tristate | ||
67 | |||
61 | config SND_SOC_AK4535 | 68 | config SND_SOC_AK4535 |
62 | tristate | 69 | tristate |
63 | 70 | ||
@@ -65,12 +72,6 @@ config SND_SOC_AK4535 | |||
65 | config SND_SOC_CS4270 | 72 | config SND_SOC_CS4270 |
66 | tristate | 73 | tristate |
67 | 74 | ||
68 | # Cirrus Logic CS4270 Codec Hardware Mute Support | ||
69 | # Select if you have external muting circuitry attached to your CS4270. | ||
70 | config SND_SOC_CS4270_HWMUTE | ||
71 | bool | ||
72 | depends on SND_SOC_CS4270 | ||
73 | |||
74 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | 75 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata |
75 | # Select if you are affected by the errata where the part will not function | 76 | # Select if you are affected by the errata where the part will not function |
76 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will | 77 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will |
@@ -90,7 +91,6 @@ config SND_SOC_SSM2602 | |||
90 | 91 | ||
91 | config SND_SOC_TLV320AIC23 | 92 | config SND_SOC_TLV320AIC23 |
92 | tristate | 93 | tristate |
93 | depends on I2C | ||
94 | 94 | ||
95 | config SND_SOC_TLV320AIC26 | 95 | config SND_SOC_TLV320AIC26 |
96 | tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE | 96 | tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE |
@@ -98,15 +98,12 @@ config SND_SOC_TLV320AIC26 | |||
98 | 98 | ||
99 | config SND_SOC_TLV320AIC3X | 99 | config SND_SOC_TLV320AIC3X |
100 | tristate | 100 | tristate |
101 | depends on I2C | ||
102 | 101 | ||
103 | config SND_SOC_TWL4030 | 102 | config SND_SOC_TWL4030 |
104 | tristate | 103 | tristate |
105 | depends on TWL4030_CORE | ||
106 | 104 | ||
107 | config SND_SOC_UDA134X | 105 | config SND_SOC_UDA134X |
108 | tristate | 106 | tristate |
109 | select SND_SOC_L3 | ||
110 | 107 | ||
111 | config SND_SOC_UDA1380 | 108 | config SND_SOC_UDA1380 |
112 | tristate | 109 | tristate |
@@ -114,6 +111,9 @@ config SND_SOC_UDA1380 | |||
114 | config SND_SOC_WM8350 | 111 | config SND_SOC_WM8350 |
115 | tristate | 112 | tristate |
116 | 113 | ||
114 | config SND_SOC_WM8400 | ||
115 | tristate | ||
116 | |||
117 | config SND_SOC_WM8510 | 117 | config SND_SOC_WM8510 |
118 | tristate | 118 | tristate |
119 | 119 | ||
@@ -144,6 +144,9 @@ config SND_SOC_WM8971 | |||
144 | config SND_SOC_WM8990 | 144 | config SND_SOC_WM8990 |
145 | tristate | 145 | tristate |
146 | 146 | ||
147 | config SND_SOC_WM9705 | ||
148 | tristate | ||
149 | |||
147 | config SND_SOC_WM9712 | 150 | config SND_SOC_WM9712 |
148 | tristate | 151 | tristate |
149 | 152 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index c4ddc9aa2bbd..030d2454725f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | snd-soc-ac97-objs := ac97.o | 1 | snd-soc-ac97-objs := ac97.o |
2 | snd-soc-ad1980-objs := ad1980.o | 2 | snd-soc-ad1980-objs := ad1980.o |
3 | snd-soc-ad73311-objs := ad73311.o | 3 | snd-soc-ad73311-objs := ad73311.o |
4 | snd-soc-ak4104-objs := ak4104.o | ||
4 | snd-soc-ak4535-objs := ak4535.o | 5 | snd-soc-ak4535-objs := ak4535.o |
5 | snd-soc-cs4270-objs := cs4270.o | 6 | snd-soc-cs4270-objs := cs4270.o |
6 | snd-soc-l3-objs := l3.o | 7 | snd-soc-l3-objs := l3.o |
@@ -13,6 +14,7 @@ snd-soc-twl4030-objs := twl4030.o | |||
13 | snd-soc-uda134x-objs := uda134x.o | 14 | snd-soc-uda134x-objs := uda134x.o |
14 | snd-soc-uda1380-objs := uda1380.o | 15 | snd-soc-uda1380-objs := uda1380.o |
15 | snd-soc-wm8350-objs := wm8350.o | 16 | snd-soc-wm8350-objs := wm8350.o |
17 | snd-soc-wm8400-objs := wm8400.o | ||
16 | snd-soc-wm8510-objs := wm8510.o | 18 | snd-soc-wm8510-objs := wm8510.o |
17 | snd-soc-wm8580-objs := wm8580.o | 19 | snd-soc-wm8580-objs := wm8580.o |
18 | snd-soc-wm8728-objs := wm8728.o | 20 | snd-soc-wm8728-objs := wm8728.o |
@@ -23,12 +25,14 @@ snd-soc-wm8900-objs := wm8900.o | |||
23 | snd-soc-wm8903-objs := wm8903.o | 25 | snd-soc-wm8903-objs := wm8903.o |
24 | snd-soc-wm8971-objs := wm8971.o | 26 | snd-soc-wm8971-objs := wm8971.o |
25 | snd-soc-wm8990-objs := wm8990.o | 27 | snd-soc-wm8990-objs := wm8990.o |
28 | snd-soc-wm9705-objs := wm9705.o | ||
26 | snd-soc-wm9712-objs := wm9712.o | 29 | snd-soc-wm9712-objs := wm9712.o |
27 | snd-soc-wm9713-objs := wm9713.o | 30 | snd-soc-wm9713-objs := wm9713.o |
28 | 31 | ||
29 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 32 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
30 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | 33 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o |
31 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | 34 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o |
35 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | ||
32 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 36 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
33 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 37 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
34 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 38 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
@@ -41,6 +45,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o | |||
41 | obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o | 45 | obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o |
42 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o | 46 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o |
43 | obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o | 47 | obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o |
48 | obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o | ||
44 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | 49 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o |
45 | obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o | 50 | obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o |
46 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o | 51 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o |
@@ -51,5 +56,7 @@ obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o | |||
51 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o | 56 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o |
52 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o | 57 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o |
53 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | 58 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o |
59 | obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o | ||
60 | obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o | ||
54 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 61 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
55 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | 62 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index fb53e6511af2..b0d4af145b87 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -30,7 +30,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream, | |||
30 | struct snd_pcm_runtime *runtime = substream->runtime; | 30 | struct snd_pcm_runtime *runtime = substream->runtime; |
31 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 31 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
32 | struct snd_soc_device *socdev = rtd->socdev; | 32 | struct snd_soc_device *socdev = rtd->socdev; |
33 | struct snd_soc_codec *codec = socdev->codec; | 33 | struct snd_soc_codec *codec = socdev->card->codec; |
34 | 34 | ||
35 | int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | 35 | int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
36 | AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; | 36 | AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; |
@@ -41,6 +41,10 @@ static int ac97_prepare(struct snd_pcm_substream *substream, | |||
41 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 41 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ |
42 | SNDRV_PCM_RATE_48000) | 42 | SNDRV_PCM_RATE_48000) |
43 | 43 | ||
44 | static struct snd_soc_dai_ops ac97_dai_ops = { | ||
45 | .prepare = ac97_prepare, | ||
46 | }; | ||
47 | |||
44 | struct snd_soc_dai ac97_dai = { | 48 | struct snd_soc_dai ac97_dai = { |
45 | .name = "AC97 HiFi", | 49 | .name = "AC97 HiFi", |
46 | .ac97_control = 1, | 50 | .ac97_control = 1, |
@@ -56,8 +60,7 @@ struct snd_soc_dai ac97_dai = { | |||
56 | .channels_max = 2, | 60 | .channels_max = 2, |
57 | .rates = STD_AC97_RATES, | 61 | .rates = STD_AC97_RATES, |
58 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 62 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
59 | .ops = { | 63 | .ops = &ac97_dai_ops, |
60 | .prepare = ac97_prepare,}, | ||
61 | }; | 64 | }; |
62 | EXPORT_SYMBOL_GPL(ac97_dai); | 65 | EXPORT_SYMBOL_GPL(ac97_dai); |
63 | 66 | ||
@@ -84,10 +87,10 @@ static int ac97_soc_probe(struct platform_device *pdev) | |||
84 | 87 | ||
85 | printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION); | 88 | printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION); |
86 | 89 | ||
87 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 90 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
88 | if (!socdev->codec) | 91 | if (!socdev->card->codec) |
89 | return -ENOMEM; | 92 | return -ENOMEM; |
90 | codec = socdev->codec; | 93 | codec = socdev->card->codec; |
91 | mutex_init(&codec->mutex); | 94 | mutex_init(&codec->mutex); |
92 | 95 | ||
93 | codec->name = "AC97"; | 96 | codec->name = "AC97"; |
@@ -123,23 +126,21 @@ bus_err: | |||
123 | snd_soc_free_pcms(socdev); | 126 | snd_soc_free_pcms(socdev); |
124 | 127 | ||
125 | err: | 128 | err: |
126 | kfree(socdev->codec->reg_cache); | 129 | kfree(socdev->card->codec); |
127 | kfree(socdev->codec); | 130 | socdev->card->codec = NULL; |
128 | socdev->codec = NULL; | ||
129 | return ret; | 131 | return ret; |
130 | } | 132 | } |
131 | 133 | ||
132 | static int ac97_soc_remove(struct platform_device *pdev) | 134 | static int ac97_soc_remove(struct platform_device *pdev) |
133 | { | 135 | { |
134 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 136 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
135 | struct snd_soc_codec *codec = socdev->codec; | 137 | struct snd_soc_codec *codec = socdev->card->codec; |
136 | 138 | ||
137 | if (!codec) | 139 | if (!codec) |
138 | return 0; | 140 | return 0; |
139 | 141 | ||
140 | snd_soc_free_pcms(socdev); | 142 | snd_soc_free_pcms(socdev); |
141 | kfree(socdev->codec->reg_cache); | 143 | kfree(socdev->card->codec); |
142 | kfree(socdev->codec); | ||
143 | 144 | ||
144 | return 0; | 145 | return 0; |
145 | } | 146 | } |
@@ -149,7 +150,7 @@ static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg) | |||
149 | { | 150 | { |
150 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 151 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
151 | 152 | ||
152 | snd_ac97_suspend(socdev->codec->ac97); | 153 | snd_ac97_suspend(socdev->card->codec->ac97); |
153 | 154 | ||
154 | return 0; | 155 | return 0; |
155 | } | 156 | } |
@@ -158,7 +159,7 @@ static int ac97_soc_resume(struct platform_device *pdev) | |||
158 | { | 159 | { |
159 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 160 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
160 | 161 | ||
161 | snd_ac97_resume(socdev->codec->ac97); | 162 | snd_ac97_resume(socdev->card->codec->ac97); |
162 | 163 | ||
163 | return 0; | 164 | return 0; |
164 | } | 165 | } |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 73fdbb4d4a3d..ddb3b08ac23c 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -93,20 +93,6 @@ SOC_ENUM("Capture Source", ad1980_cap_src), | |||
93 | SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), | 93 | SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), |
94 | }; | 94 | }; |
95 | 95 | ||
96 | /* add non dapm controls */ | ||
97 | static int ad1980_add_controls(struct snd_soc_codec *codec) | ||
98 | { | ||
99 | int err, i; | ||
100 | |||
101 | for (i = 0; i < ARRAY_SIZE(ad1980_snd_ac97_controls); i++) { | ||
102 | err = snd_ctl_add(codec->card, snd_soc_cnew( | ||
103 | &ad1980_snd_ac97_controls[i], codec, NULL)); | ||
104 | if (err < 0) | ||
105 | return err; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 96 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
111 | unsigned int reg) | 97 | unsigned int reg) |
112 | { | 98 | { |
@@ -123,7 +109,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
123 | default: | 109 | default: |
124 | reg = reg >> 1; | 110 | reg = reg >> 1; |
125 | 111 | ||
126 | if (reg >= (ARRAY_SIZE(ad1980_reg))) | 112 | if (reg >= ARRAY_SIZE(ad1980_reg)) |
127 | return -EINVAL; | 113 | return -EINVAL; |
128 | 114 | ||
129 | return cache[reg]; | 115 | return cache[reg]; |
@@ -137,7 +123,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
137 | 123 | ||
138 | soc_ac97_ops.write(codec->ac97, reg, val); | 124 | soc_ac97_ops.write(codec->ac97, reg, val); |
139 | reg = reg >> 1; | 125 | reg = reg >> 1; |
140 | if (reg < (ARRAY_SIZE(ad1980_reg))) | 126 | if (reg < ARRAY_SIZE(ad1980_reg)) |
141 | cache[reg] = val; | 127 | cache[reg] = val; |
142 | 128 | ||
143 | return 0; | 129 | return 0; |
@@ -200,10 +186,10 @@ static int ad1980_soc_probe(struct platform_device *pdev) | |||
200 | 186 | ||
201 | printk(KERN_INFO "AD1980 SoC Audio Codec\n"); | 187 | printk(KERN_INFO "AD1980 SoC Audio Codec\n"); |
202 | 188 | ||
203 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 189 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
204 | if (socdev->codec == NULL) | 190 | if (socdev->card->codec == NULL) |
205 | return -ENOMEM; | 191 | return -ENOMEM; |
206 | codec = socdev->codec; | 192 | codec = socdev->card->codec; |
207 | mutex_init(&codec->mutex); | 193 | mutex_init(&codec->mutex); |
208 | 194 | ||
209 | codec->reg_cache = | 195 | codec->reg_cache = |
@@ -269,7 +255,8 @@ static int ad1980_soc_probe(struct platform_device *pdev) | |||
269 | ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); | 255 | ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); |
270 | ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); | 256 | ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); |
271 | 257 | ||
272 | ad1980_add_controls(codec); | 258 | snd_soc_add_controls(codec, ad1980_snd_ac97_controls, |
259 | ARRAY_SIZE(ad1980_snd_ac97_controls)); | ||
273 | ret = snd_soc_init_card(socdev); | 260 | ret = snd_soc_init_card(socdev); |
274 | if (ret < 0) { | 261 | if (ret < 0) { |
275 | printk(KERN_ERR "ad1980: failed to register card\n"); | 262 | printk(KERN_ERR "ad1980: failed to register card\n"); |
@@ -288,15 +275,15 @@ codec_err: | |||
288 | kfree(codec->reg_cache); | 275 | kfree(codec->reg_cache); |
289 | 276 | ||
290 | cache_err: | 277 | cache_err: |
291 | kfree(socdev->codec); | 278 | kfree(socdev->card->codec); |
292 | socdev->codec = NULL; | 279 | socdev->card->codec = NULL; |
293 | return ret; | 280 | return ret; |
294 | } | 281 | } |
295 | 282 | ||
296 | static int ad1980_soc_remove(struct platform_device *pdev) | 283 | static int ad1980_soc_remove(struct platform_device *pdev) |
297 | { | 284 | { |
298 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 285 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
299 | struct snd_soc_codec *codec = socdev->codec; | 286 | struct snd_soc_codec *codec = socdev->card->codec; |
300 | 287 | ||
301 | if (codec == NULL) | 288 | if (codec == NULL) |
302 | return 0; | 289 | return 0; |
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index b09289a1e55a..e61dac5e7b8f 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c | |||
@@ -53,7 +53,7 @@ static int ad73311_soc_probe(struct platform_device *pdev) | |||
53 | codec->owner = THIS_MODULE; | 53 | codec->owner = THIS_MODULE; |
54 | codec->dai = &ad73311_dai; | 54 | codec->dai = &ad73311_dai; |
55 | codec->num_dai = 1; | 55 | codec->num_dai = 1; |
56 | socdev->codec = codec; | 56 | socdev->card->codec = codec; |
57 | INIT_LIST_HEAD(&codec->dapm_widgets); | 57 | INIT_LIST_HEAD(&codec->dapm_widgets); |
58 | INIT_LIST_HEAD(&codec->dapm_paths); | 58 | INIT_LIST_HEAD(&codec->dapm_paths); |
59 | 59 | ||
@@ -75,15 +75,15 @@ static int ad73311_soc_probe(struct platform_device *pdev) | |||
75 | register_err: | 75 | register_err: |
76 | snd_soc_free_pcms(socdev); | 76 | snd_soc_free_pcms(socdev); |
77 | pcm_err: | 77 | pcm_err: |
78 | kfree(socdev->codec); | 78 | kfree(socdev->card->codec); |
79 | socdev->codec = NULL; | 79 | socdev->card->codec = NULL; |
80 | return ret; | 80 | return ret; |
81 | } | 81 | } |
82 | 82 | ||
83 | static int ad73311_soc_remove(struct platform_device *pdev) | 83 | static int ad73311_soc_remove(struct platform_device *pdev) |
84 | { | 84 | { |
85 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 85 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
86 | struct snd_soc_codec *codec = socdev->codec; | 86 | struct snd_soc_codec *codec = socdev->card->codec; |
87 | 87 | ||
88 | if (codec == NULL) | 88 | if (codec == NULL) |
89 | return 0; | 89 | return 0; |
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h index 507ce0c30edf..569573d2d4d7 100644 --- a/sound/soc/codecs/ad73311.h +++ b/sound/soc/codecs/ad73311.h | |||
@@ -70,7 +70,7 @@ | |||
70 | #define REGD_IGS(x) (x & 0x7) | 70 | #define REGD_IGS(x) (x & 0x7) |
71 | #define REGD_RMOD (1 << 3) | 71 | #define REGD_RMOD (1 << 3) |
72 | #define REGD_OGS(x) ((x & 0x7) << 4) | 72 | #define REGD_OGS(x) ((x & 0x7) << 4) |
73 | #define REGD_MUTE (x << 7) | 73 | #define REGD_MUTE (1 << 7) |
74 | 74 | ||
75 | /* Control register E */ | 75 | /* Control register E */ |
76 | #define CTRL_REG_E (4 << 8) | 76 | #define CTRL_REG_E (4 << 8) |
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c new file mode 100644 index 000000000000..4d47bc4f7428 --- /dev/null +++ b/sound/soc/codecs/ak4104.c | |||
@@ -0,0 +1,365 @@ | |||
1 | /* | ||
2 | * AK4104 ALSA SoC (ASoC) driver | ||
3 | * | ||
4 | * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> | ||
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; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <sound/core.h> | ||
14 | #include <sound/soc.h> | ||
15 | #include <sound/initval.h> | ||
16 | #include <linux/spi/spi.h> | ||
17 | #include <sound/asoundef.h> | ||
18 | |||
19 | #include "ak4104.h" | ||
20 | |||
21 | /* AK4104 registers addresses */ | ||
22 | #define AK4104_REG_CONTROL1 0x00 | ||
23 | #define AK4104_REG_RESERVED 0x01 | ||
24 | #define AK4104_REG_CONTROL2 0x02 | ||
25 | #define AK4104_REG_TX 0x03 | ||
26 | #define AK4104_REG_CHN_STATUS(x) ((x) + 0x04) | ||
27 | #define AK4104_NUM_REGS 10 | ||
28 | |||
29 | #define AK4104_REG_MASK 0x1f | ||
30 | #define AK4104_READ 0xc0 | ||
31 | #define AK4104_WRITE 0xe0 | ||
32 | #define AK4104_RESERVED_VAL 0x5b | ||
33 | |||
34 | /* Bit masks for AK4104 registers */ | ||
35 | #define AK4104_CONTROL1_RSTN (1 << 0) | ||
36 | #define AK4104_CONTROL1_PW (1 << 1) | ||
37 | #define AK4104_CONTROL1_DIF0 (1 << 2) | ||
38 | #define AK4104_CONTROL1_DIF1 (1 << 3) | ||
39 | |||
40 | #define AK4104_CONTROL2_SEL0 (1 << 0) | ||
41 | #define AK4104_CONTROL2_SEL1 (1 << 1) | ||
42 | #define AK4104_CONTROL2_MODE (1 << 2) | ||
43 | |||
44 | #define AK4104_TX_TXE (1 << 0) | ||
45 | #define AK4104_TX_V (1 << 1) | ||
46 | |||
47 | #define DRV_NAME "ak4104" | ||
48 | |||
49 | struct ak4104_private { | ||
50 | struct snd_soc_codec codec; | ||
51 | u8 reg_cache[AK4104_NUM_REGS]; | ||
52 | }; | ||
53 | |||
54 | static int ak4104_fill_cache(struct snd_soc_codec *codec) | ||
55 | { | ||
56 | int i; | ||
57 | u8 *reg_cache = codec->reg_cache; | ||
58 | struct spi_device *spi = codec->control_data; | ||
59 | |||
60 | for (i = 0; i < codec->reg_cache_size; i++) { | ||
61 | int ret = spi_w8r8(spi, i | AK4104_READ); | ||
62 | if (ret < 0) { | ||
63 | dev_err(&spi->dev, "SPI write failure\n"); | ||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | reg_cache[i] = ret; | ||
68 | } | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec, | ||
74 | unsigned int reg) | ||
75 | { | ||
76 | u8 *reg_cache = codec->reg_cache; | ||
77 | |||
78 | if (reg >= codec->reg_cache_size) | ||
79 | return -EINVAL; | ||
80 | |||
81 | return reg_cache[reg]; | ||
82 | } | ||
83 | |||
84 | static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg, | ||
85 | unsigned int value) | ||
86 | { | ||
87 | u8 *cache = codec->reg_cache; | ||
88 | struct spi_device *spi = codec->control_data; | ||
89 | |||
90 | if (reg >= codec->reg_cache_size) | ||
91 | return -EINVAL; | ||
92 | |||
93 | reg &= AK4104_REG_MASK; | ||
94 | reg |= AK4104_WRITE; | ||
95 | |||
96 | /* only write to the hardware if value has changed */ | ||
97 | if (cache[reg] != value) { | ||
98 | u8 tmp[2] = { reg, value }; | ||
99 | if (spi_write(spi, tmp, sizeof(tmp))) { | ||
100 | dev_err(&spi->dev, "SPI write failed\n"); | ||
101 | return -EIO; | ||
102 | } | ||
103 | |||
104 | cache[reg] = value; | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
111 | unsigned int format) | ||
112 | { | ||
113 | struct snd_soc_codec *codec = codec_dai->codec; | ||
114 | int val = 0; | ||
115 | |||
116 | val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1); | ||
117 | if (val < 0) | ||
118 | return val; | ||
119 | |||
120 | val &= ~(AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1); | ||
121 | |||
122 | /* set DAI format */ | ||
123 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
124 | case SND_SOC_DAIFMT_RIGHT_J: | ||
125 | break; | ||
126 | case SND_SOC_DAIFMT_LEFT_J: | ||
127 | val |= AK4104_CONTROL1_DIF0; | ||
128 | break; | ||
129 | case SND_SOC_DAIFMT_I2S: | ||
130 | val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1; | ||
131 | break; | ||
132 | default: | ||
133 | dev_err(codec->dev, "invalid dai format\n"); | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
137 | /* This device can only be slave */ | ||
138 | if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) | ||
139 | return -EINVAL; | ||
140 | |||
141 | return ak4104_spi_write(codec, AK4104_REG_CONTROL1, val); | ||
142 | } | ||
143 | |||
144 | static int ak4104_hw_params(struct snd_pcm_substream *substream, | ||
145 | struct snd_pcm_hw_params *params, | ||
146 | struct snd_soc_dai *dai) | ||
147 | { | ||
148 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
149 | struct snd_soc_device *socdev = rtd->socdev; | ||
150 | struct snd_soc_codec *codec = socdev->card->codec; | ||
151 | int val = 0; | ||
152 | |||
153 | /* set the IEC958 bits: consumer mode, no copyright bit */ | ||
154 | val |= IEC958_AES0_CON_NOT_COPYRIGHT; | ||
155 | ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(0), val); | ||
156 | |||
157 | val = 0; | ||
158 | |||
159 | switch (params_rate(params)) { | ||
160 | case 44100: | ||
161 | val |= IEC958_AES3_CON_FS_44100; | ||
162 | break; | ||
163 | case 48000: | ||
164 | val |= IEC958_AES3_CON_FS_48000; | ||
165 | break; | ||
166 | case 32000: | ||
167 | val |= IEC958_AES3_CON_FS_32000; | ||
168 | break; | ||
169 | default: | ||
170 | dev_err(codec->dev, "unsupported sampling rate\n"); | ||
171 | return -EINVAL; | ||
172 | } | ||
173 | |||
174 | return ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(3), val); | ||
175 | } | ||
176 | |||
177 | static struct snd_soc_dai_ops ak4101_dai_ops = { | ||
178 | .hw_params = ak4104_hw_params, | ||
179 | .set_fmt = ak4104_set_dai_fmt, | ||
180 | }; | ||
181 | |||
182 | struct snd_soc_dai ak4104_dai = { | ||
183 | .name = DRV_NAME, | ||
184 | .playback = { | ||
185 | .stream_name = "Playback", | ||
186 | .channels_min = 2, | ||
187 | .channels_max = 2, | ||
188 | .rates = SNDRV_PCM_RATE_44100 | | ||
189 | SNDRV_PCM_RATE_48000 | | ||
190 | SNDRV_PCM_RATE_32000, | ||
191 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
192 | SNDRV_PCM_FMTBIT_S24_3LE | | ||
193 | SNDRV_PCM_FMTBIT_S24_LE | ||
194 | }, | ||
195 | .ops = &ak4101_dai_ops, | ||
196 | }; | ||
197 | |||
198 | static struct snd_soc_codec *ak4104_codec; | ||
199 | |||
200 | static int ak4104_spi_probe(struct spi_device *spi) | ||
201 | { | ||
202 | struct snd_soc_codec *codec; | ||
203 | struct ak4104_private *ak4104; | ||
204 | int ret, val; | ||
205 | |||
206 | spi->bits_per_word = 8; | ||
207 | spi->mode = SPI_MODE_0; | ||
208 | ret = spi_setup(spi); | ||
209 | if (ret < 0) | ||
210 | return ret; | ||
211 | |||
212 | ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL); | ||
213 | if (!ak4104) { | ||
214 | dev_err(&spi->dev, "could not allocate codec\n"); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | |||
218 | codec = &ak4104->codec; | ||
219 | mutex_init(&codec->mutex); | ||
220 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
221 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
222 | |||
223 | codec->dev = &spi->dev; | ||
224 | codec->name = DRV_NAME; | ||
225 | codec->owner = THIS_MODULE; | ||
226 | codec->dai = &ak4104_dai; | ||
227 | codec->num_dai = 1; | ||
228 | codec->private_data = ak4104; | ||
229 | codec->control_data = spi; | ||
230 | codec->reg_cache = ak4104->reg_cache; | ||
231 | codec->reg_cache_size = AK4104_NUM_REGS; | ||
232 | |||
233 | /* read all regs and fill the cache */ | ||
234 | ret = ak4104_fill_cache(codec); | ||
235 | if (ret < 0) { | ||
236 | dev_err(&spi->dev, "failed to fill register cache\n"); | ||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | /* read the 'reserved' register - according to the datasheet, it | ||
241 | * should contain 0x5b. Not a good way to verify the presence of | ||
242 | * the device, but there is no hardware ID register. */ | ||
243 | if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) != | ||
244 | AK4104_RESERVED_VAL) { | ||
245 | ret = -ENODEV; | ||
246 | goto error_free_codec; | ||
247 | } | ||
248 | |||
249 | /* set power-up and non-reset bits */ | ||
250 | val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1); | ||
251 | val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN; | ||
252 | ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val); | ||
253 | if (ret < 0) | ||
254 | goto error_free_codec; | ||
255 | |||
256 | /* enable transmitter */ | ||
257 | val = ak4104_read_reg_cache(codec, AK4104_REG_TX); | ||
258 | val |= AK4104_TX_TXE; | ||
259 | ret = ak4104_spi_write(codec, AK4104_REG_TX, val); | ||
260 | if (ret < 0) | ||
261 | goto error_free_codec; | ||
262 | |||
263 | ak4104_codec = codec; | ||
264 | ret = snd_soc_register_dai(&ak4104_dai); | ||
265 | if (ret < 0) { | ||
266 | dev_err(&spi->dev, "failed to register DAI\n"); | ||
267 | goto error_free_codec; | ||
268 | } | ||
269 | |||
270 | spi_set_drvdata(spi, ak4104); | ||
271 | dev_info(&spi->dev, "SPI device initialized\n"); | ||
272 | return 0; | ||
273 | |||
274 | error_free_codec: | ||
275 | kfree(ak4104); | ||
276 | ak4104_dai.dev = NULL; | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | static int __devexit ak4104_spi_remove(struct spi_device *spi) | ||
281 | { | ||
282 | int ret, val; | ||
283 | struct ak4104_private *ak4104 = spi_get_drvdata(spi); | ||
284 | |||
285 | val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1); | ||
286 | if (val < 0) | ||
287 | return val; | ||
288 | |||
289 | /* clear power-up and non-reset bits */ | ||
290 | val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); | ||
291 | ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val); | ||
292 | if (ret < 0) | ||
293 | return ret; | ||
294 | |||
295 | ak4104_codec = NULL; | ||
296 | kfree(ak4104); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int ak4104_probe(struct platform_device *pdev) | ||
301 | { | ||
302 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
303 | struct snd_soc_codec *codec = ak4104_codec; | ||
304 | int ret; | ||
305 | |||
306 | /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ | ||
307 | socdev->card->codec = codec; | ||
308 | |||
309 | /* Register PCMs */ | ||
310 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
311 | if (ret < 0) { | ||
312 | dev_err(codec->dev, "failed to create pcms\n"); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | /* Register the socdev */ | ||
317 | ret = snd_soc_init_card(socdev); | ||
318 | if (ret < 0) { | ||
319 | dev_err(codec->dev, "failed to register card\n"); | ||
320 | snd_soc_free_pcms(socdev); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int ak4104_remove(struct platform_device *pdev) | ||
328 | { | ||
329 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
330 | snd_soc_free_pcms(socdev); | ||
331 | return 0; | ||
332 | }; | ||
333 | |||
334 | struct snd_soc_codec_device soc_codec_device_ak4104 = { | ||
335 | .probe = ak4104_probe, | ||
336 | .remove = ak4104_remove | ||
337 | }; | ||
338 | EXPORT_SYMBOL_GPL(soc_codec_device_ak4104); | ||
339 | |||
340 | static struct spi_driver ak4104_spi_driver = { | ||
341 | .driver = { | ||
342 | .name = DRV_NAME, | ||
343 | .owner = THIS_MODULE, | ||
344 | }, | ||
345 | .probe = ak4104_spi_probe, | ||
346 | .remove = __devexit_p(ak4104_spi_remove), | ||
347 | }; | ||
348 | |||
349 | static int __init ak4104_init(void) | ||
350 | { | ||
351 | pr_info("Asahi Kasei AK4104 ALSA SoC Codec Driver\n"); | ||
352 | return spi_register_driver(&ak4104_spi_driver); | ||
353 | } | ||
354 | module_init(ak4104_init); | ||
355 | |||
356 | static void __exit ak4104_exit(void) | ||
357 | { | ||
358 | spi_unregister_driver(&ak4104_spi_driver); | ||
359 | } | ||
360 | module_exit(ak4104_exit); | ||
361 | |||
362 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | ||
363 | MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver"); | ||
364 | MODULE_LICENSE("GPL"); | ||
365 | |||
diff --git a/sound/soc/codecs/ak4104.h b/sound/soc/codecs/ak4104.h new file mode 100644 index 000000000000..eb88fe7e4def --- /dev/null +++ b/sound/soc/codecs/ak4104.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef _AK4104_H | ||
2 | #define _AK4104_H | ||
3 | |||
4 | extern struct snd_soc_dai ak4104_dai; | ||
5 | extern struct snd_soc_codec_device soc_codec_device_ak4104; | ||
6 | |||
7 | #endif | ||
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 81300d8d42ca..1f63d387a2f4 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -155,21 +155,6 @@ static const struct snd_kcontrol_new ak4535_snd_controls[] = { | |||
155 | SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), | 155 | SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), |
156 | }; | 156 | }; |
157 | 157 | ||
158 | /* add non dapm controls */ | ||
159 | static int ak4535_add_controls(struct snd_soc_codec *codec) | ||
160 | { | ||
161 | int err, i; | ||
162 | |||
163 | for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) { | ||
164 | err = snd_ctl_add(codec->card, | ||
165 | snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL)); | ||
166 | if (err < 0) | ||
167 | return err; | ||
168 | } | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* Mono 1 Mixer */ | 158 | /* Mono 1 Mixer */ |
174 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { | 159 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { |
175 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), | 160 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), |
@@ -344,7 +329,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream, | |||
344 | { | 329 | { |
345 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 330 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
346 | struct snd_soc_device *socdev = rtd->socdev; | 331 | struct snd_soc_device *socdev = rtd->socdev; |
347 | struct snd_soc_codec *codec = socdev->codec; | 332 | struct snd_soc_codec *codec = socdev->card->codec; |
348 | struct ak4535_priv *ak4535 = codec->private_data; | 333 | struct ak4535_priv *ak4535 = codec->private_data; |
349 | u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); | 334 | u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); |
350 | int rate = params_rate(params), fs = 256; | 335 | int rate = params_rate(params), fs = 256; |
@@ -436,6 +421,13 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec, | |||
436 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | 421 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ |
437 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 422 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
438 | 423 | ||
424 | static struct snd_soc_dai_ops ak4535_dai_ops = { | ||
425 | .hw_params = ak4535_hw_params, | ||
426 | .set_fmt = ak4535_set_dai_fmt, | ||
427 | .digital_mute = ak4535_mute, | ||
428 | .set_sysclk = ak4535_set_dai_sysclk, | ||
429 | }; | ||
430 | |||
439 | struct snd_soc_dai ak4535_dai = { | 431 | struct snd_soc_dai ak4535_dai = { |
440 | .name = "AK4535", | 432 | .name = "AK4535", |
441 | .playback = { | 433 | .playback = { |
@@ -450,19 +442,14 @@ struct snd_soc_dai ak4535_dai = { | |||
450 | .channels_max = 2, | 442 | .channels_max = 2, |
451 | .rates = AK4535_RATES, | 443 | .rates = AK4535_RATES, |
452 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 444 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
453 | .ops = { | 445 | .ops = &ak4535_dai_ops, |
454 | .hw_params = ak4535_hw_params, | ||
455 | .set_fmt = ak4535_set_dai_fmt, | ||
456 | .digital_mute = ak4535_mute, | ||
457 | .set_sysclk = ak4535_set_dai_sysclk, | ||
458 | }, | ||
459 | }; | 446 | }; |
460 | EXPORT_SYMBOL_GPL(ak4535_dai); | 447 | EXPORT_SYMBOL_GPL(ak4535_dai); |
461 | 448 | ||
462 | static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) | 449 | static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) |
463 | { | 450 | { |
464 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 451 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
465 | struct snd_soc_codec *codec = socdev->codec; | 452 | struct snd_soc_codec *codec = socdev->card->codec; |
466 | 453 | ||
467 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | 454 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); |
468 | return 0; | 455 | return 0; |
@@ -471,7 +458,7 @@ static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) | |||
471 | static int ak4535_resume(struct platform_device *pdev) | 458 | static int ak4535_resume(struct platform_device *pdev) |
472 | { | 459 | { |
473 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 460 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
474 | struct snd_soc_codec *codec = socdev->codec; | 461 | struct snd_soc_codec *codec = socdev->card->codec; |
475 | ak4535_sync(codec); | 462 | ak4535_sync(codec); |
476 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 463 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
477 | ak4535_set_bias_level(codec, codec->suspend_bias_level); | 464 | ak4535_set_bias_level(codec, codec->suspend_bias_level); |
@@ -484,7 +471,7 @@ static int ak4535_resume(struct platform_device *pdev) | |||
484 | */ | 471 | */ |
485 | static int ak4535_init(struct snd_soc_device *socdev) | 472 | static int ak4535_init(struct snd_soc_device *socdev) |
486 | { | 473 | { |
487 | struct snd_soc_codec *codec = socdev->codec; | 474 | struct snd_soc_codec *codec = socdev->card->codec; |
488 | int ret = 0; | 475 | int ret = 0; |
489 | 476 | ||
490 | codec->name = "AK4535"; | 477 | codec->name = "AK4535"; |
@@ -510,7 +497,8 @@ static int ak4535_init(struct snd_soc_device *socdev) | |||
510 | /* power on device */ | 497 | /* power on device */ |
511 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 498 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
512 | 499 | ||
513 | ak4535_add_controls(codec); | 500 | snd_soc_add_controls(codec, ak4535_snd_controls, |
501 | ARRAY_SIZE(ak4535_snd_controls)); | ||
514 | ak4535_add_widgets(codec); | 502 | ak4535_add_widgets(codec); |
515 | ret = snd_soc_init_card(socdev); | 503 | ret = snd_soc_init_card(socdev); |
516 | if (ret < 0) { | 504 | if (ret < 0) { |
@@ -537,7 +525,7 @@ static int ak4535_i2c_probe(struct i2c_client *i2c, | |||
537 | const struct i2c_device_id *id) | 525 | const struct i2c_device_id *id) |
538 | { | 526 | { |
539 | struct snd_soc_device *socdev = ak4535_socdev; | 527 | struct snd_soc_device *socdev = ak4535_socdev; |
540 | struct snd_soc_codec *codec = socdev->codec; | 528 | struct snd_soc_codec *codec = socdev->card->codec; |
541 | int ret; | 529 | int ret; |
542 | 530 | ||
543 | i2c_set_clientdata(i2c, codec); | 531 | i2c_set_clientdata(i2c, codec); |
@@ -636,7 +624,7 @@ static int ak4535_probe(struct platform_device *pdev) | |||
636 | } | 624 | } |
637 | 625 | ||
638 | codec->private_data = ak4535; | 626 | codec->private_data = ak4535; |
639 | socdev->codec = codec; | 627 | socdev->card->codec = codec; |
640 | mutex_init(&codec->mutex); | 628 | mutex_init(&codec->mutex); |
641 | INIT_LIST_HEAD(&codec->dapm_widgets); | 629 | INIT_LIST_HEAD(&codec->dapm_widgets); |
642 | INIT_LIST_HEAD(&codec->dapm_paths); | 630 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -663,7 +651,7 @@ static int ak4535_probe(struct platform_device *pdev) | |||
663 | static int ak4535_remove(struct platform_device *pdev) | 651 | static int ak4535_remove(struct platform_device *pdev) |
664 | { | 652 | { |
665 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 653 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
666 | struct snd_soc_codec *codec = socdev->codec; | 654 | struct snd_soc_codec *codec = socdev->card->codec; |
667 | 655 | ||
668 | if (codec->control_data) | 656 | if (codec->control_data) |
669 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | 657 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); |
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index f1aa0c34421c..7fa09a387622 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -3,27 +3,22 @@ | |||
3 | * | 3 | * |
4 | * Author: Timur Tabi <timur@freescale.com> | 4 | * Author: Timur Tabi <timur@freescale.com> |
5 | * | 5 | * |
6 | * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under | 6 | * Copyright 2007-2009 Freescale Semiconductor, Inc. This file is licensed |
7 | * the terms of the GNU General Public License version 2. This program | 7 | * under the terms of the GNU General Public License version 2. This |
8 | * is licensed "as is" without any warranty of any kind, whether express | 8 | * program is licensed "as is" without any warranty of any kind, whether |
9 | * or implied. | 9 | * express or implied. |
10 | * | 10 | * |
11 | * This is an ASoC device driver for the Cirrus Logic CS4270 codec. | 11 | * This is an ASoC device driver for the Cirrus Logic CS4270 codec. |
12 | * | 12 | * |
13 | * Current features/limitations: | 13 | * Current features/limitations: |
14 | * | 14 | * |
15 | * 1) Software mode is supported. Stand-alone mode is automatically | 15 | * - Software mode is supported. Stand-alone mode is not supported. |
16 | * selected if I2C is disabled or if a CS4270 is not found on the I2C | 16 | * - Only I2C is supported, not SPI |
17 | * bus. However, stand-alone mode is only partially implemented because | 17 | * - Support for master and slave mode |
18 | * there is no mechanism yet for this driver and the machine driver to | 18 | * - The machine driver's 'startup' function must call |
19 | * communicate the values of the M0, M1, MCLK1, and MCLK2 pins. | 19 | * cs4270_set_dai_sysclk() with the value of MCLK. |
20 | * 2) Only I2C is supported, not SPI | 20 | * - Only I2S and left-justified modes are supported |
21 | * 3) Only Master mode is supported, not Slave. | 21 | * - Power management is not supported |
22 | * 4) The machine driver's 'startup' function must call | ||
23 | * cs4270_set_dai_sysclk() with the value of MCLK. | ||
24 | * 5) Only I2S and left-justified modes are supported | ||
25 | * 6) Power management is not supported | ||
26 | * 7) The only supported control is volume and hardware mute (if enabled) | ||
27 | */ | 22 | */ |
28 | 23 | ||
29 | #include <linux/module.h> | 24 | #include <linux/module.h> |
@@ -35,18 +30,6 @@ | |||
35 | 30 | ||
36 | #include "cs4270.h" | 31 | #include "cs4270.h" |
37 | 32 | ||
38 | /* If I2C is defined, then we support software mode. However, if we're | ||
39 | not compiled as module but I2C is, then we can't use I2C calls. */ | ||
40 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
41 | #define USE_I2C | ||
42 | #endif | ||
43 | |||
44 | /* Private data for the CS4270 */ | ||
45 | struct cs4270_private { | ||
46 | unsigned int mclk; /* Input frequency of the MCLK pin */ | ||
47 | unsigned int mode; /* The mode (I2S or left-justified) */ | ||
48 | }; | ||
49 | |||
50 | /* | 33 | /* |
51 | * The codec isn't really big-endian or little-endian, since the I2S | 34 | * The codec isn't really big-endian or little-endian, since the I2S |
52 | * interface requires data to be sent serially with the MSbit first. | 35 | * interface requires data to be sent serially with the MSbit first. |
@@ -60,8 +43,6 @@ struct cs4270_private { | |||
60 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ | 43 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ |
61 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) | 44 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) |
62 | 45 | ||
63 | #ifdef USE_I2C | ||
64 | |||
65 | /* CS4270 registers addresses */ | 46 | /* CS4270 registers addresses */ |
66 | #define CS4270_CHIPID 0x01 /* Chip ID */ | 47 | #define CS4270_CHIPID 0x01 /* Chip ID */ |
67 | #define CS4270_PWRCTL 0x02 /* Power Control */ | 48 | #define CS4270_PWRCTL 0x02 /* Power Control */ |
@@ -121,8 +102,22 @@ struct cs4270_private { | |||
121 | #define CS4270_MUTE_DAC_A 0x01 | 102 | #define CS4270_MUTE_DAC_A 0x01 |
122 | #define CS4270_MUTE_DAC_B 0x02 | 103 | #define CS4270_MUTE_DAC_B 0x02 |
123 | 104 | ||
124 | /* | 105 | /* Private data for the CS4270 */ |
125 | * Clock Ratio Selection for Master Mode with I2C enabled | 106 | struct cs4270_private { |
107 | struct snd_soc_codec codec; | ||
108 | u8 reg_cache[CS4270_NUMREGS]; | ||
109 | unsigned int mclk; /* Input frequency of the MCLK pin */ | ||
110 | unsigned int mode; /* The mode (I2S or left-justified) */ | ||
111 | unsigned int slave_mode; | ||
112 | }; | ||
113 | |||
114 | /** | ||
115 | * struct cs4270_mode_ratios - clock ratio tables | ||
116 | * @ratio: the ratio of MCLK to the sample rate | ||
117 | * @speed_mode: the Speed Mode bits to set in the Mode Control register for | ||
118 | * this ratio | ||
119 | * @mclk: the Ratio Select bits to set in the Mode Control register for this | ||
120 | * ratio | ||
126 | * | 121 | * |
127 | * The data for this chart is taken from Table 5 of the CS4270 reference | 122 | * The data for this chart is taken from Table 5 of the CS4270 reference |
128 | * manual. | 123 | * manual. |
@@ -131,31 +126,30 @@ struct cs4270_private { | |||
131 | * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling | 126 | * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling |
132 | * rates the CS4270 currently supports. | 127 | * rates the CS4270 currently supports. |
133 | * | 128 | * |
134 | * Each element in this array corresponds to the ratios in mclk_ratios[]. | 129 | * @speed_mode is the corresponding bit pattern to be written to the |
135 | * These two arrays need to be in sync. | ||
136 | * | ||
137 | * 'speed_mode' is the corresponding bit pattern to be written to the | ||
138 | * MODE bits of the Mode Control Register | 130 | * MODE bits of the Mode Control Register |
139 | * | 131 | * |
140 | * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of | 132 | * @mclk is the corresponding bit pattern to be wirten to the MCLK bits of |
141 | * the Mode Control Register. | 133 | * the Mode Control Register. |
142 | * | 134 | * |
143 | * In situations where a single ratio is represented by multiple speed | 135 | * In situations where a single ratio is represented by multiple speed |
144 | * modes, we favor the slowest speed. E.g, for a ratio of 128, we pick | 136 | * modes, we favor the slowest speed. E.g, for a ratio of 128, we pick |
145 | * double-speed instead of quad-speed. However, the CS4270 errata states | 137 | * double-speed instead of quad-speed. However, the CS4270 errata states |
146 | * that Divide-By-1.5 can cause failures, so we avoid that mode where | 138 | * that divide-By-1.5 can cause failures, so we avoid that mode where |
147 | * possible. | 139 | * possible. |
148 | * | 140 | * |
149 | * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not | 141 | * Errata: There is an errata for the CS4270 where divide-by-1.5 does not |
150 | * work if VD = 3.3V. If this effects you, select the | 142 | * work if Vd is 3.3V. If this effects you, select the |
151 | * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will | 143 | * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will |
152 | * never select any sample rates that require divide-by-1.5. | 144 | * never select any sample rates that require divide-by-1.5. |
153 | */ | 145 | */ |
154 | static struct { | 146 | struct cs4270_mode_ratios { |
155 | unsigned int ratio; | 147 | unsigned int ratio; |
156 | u8 speed_mode; | 148 | u8 speed_mode; |
157 | u8 mclk; | 149 | u8 mclk; |
158 | } cs4270_mode_ratios[] = { | 150 | }; |
151 | |||
152 | static struct cs4270_mode_ratios cs4270_mode_ratios[] = { | ||
159 | {64, CS4270_MODE_4X, CS4270_MODE_DIV1}, | 153 | {64, CS4270_MODE_4X, CS4270_MODE_DIV1}, |
160 | #ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA | 154 | #ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA |
161 | {96, CS4270_MODE_4X, CS4270_MODE_DIV15}, | 155 | {96, CS4270_MODE_4X, CS4270_MODE_DIV15}, |
@@ -172,34 +166,27 @@ static struct { | |||
172 | /* The number of MCLK/LRCK ratios supported by the CS4270 */ | 166 | /* The number of MCLK/LRCK ratios supported by the CS4270 */ |
173 | #define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios) | 167 | #define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios) |
174 | 168 | ||
175 | /* | 169 | /** |
176 | * Determine the CS4270 samples rates. | 170 | * cs4270_set_dai_sysclk - determine the CS4270 samples rates. |
171 | * @codec_dai: the codec DAI | ||
172 | * @clk_id: the clock ID (ignored) | ||
173 | * @freq: the MCLK input frequency | ||
174 | * @dir: the clock direction (ignored) | ||
177 | * | 175 | * |
178 | * 'freq' is the input frequency to MCLK. The other parameters are ignored. | 176 | * This function is used to tell the codec driver what the input MCLK |
177 | * frequency is. | ||
179 | * | 178 | * |
180 | * The value of MCLK is used to determine which sample rates are supported | 179 | * The value of MCLK is used to determine which sample rates are supported |
181 | * by the CS4270. The ratio of MCLK / Fs must be equal to one of nine | 180 | * by the CS4270. The ratio of MCLK / Fs must be equal to one of nine |
182 | * support values: 64, 96, 128, 192, 256, 384, 512, 768, and 1024. | 181 | * supported values - 64, 96, 128, 192, 256, 384, 512, 768, and 1024. |
183 | * | 182 | * |
184 | * This function calculates the nine ratios and determines which ones match | 183 | * This function calculates the nine ratios and determines which ones match |
185 | * a standard sample rate. If there's a match, then it is added to the list | 184 | * a standard sample rate. If there's a match, then it is added to the list |
186 | * of support sample rates. | 185 | * of supported sample rates. |
187 | * | 186 | * |
188 | * This function must be called by the machine driver's 'startup' function, | 187 | * This function must be called by the machine driver's 'startup' function, |
189 | * otherwise the list of supported sample rates will not be available in | 188 | * otherwise the list of supported sample rates will not be available in |
190 | * time for ALSA. | 189 | * time for ALSA. |
191 | * | ||
192 | * Note that in stand-alone mode, the sample rate is determined by input | ||
193 | * pins M0, M1, MDIV1, and MDIV2. Also in stand-alone mode, divide-by-3 | ||
194 | * is not a programmable option. However, divide-by-3 is not an available | ||
195 | * option in stand-alone mode. This cases two problems: a ratio of 768 is | ||
196 | * not available (it requires divide-by-3) and B) ratios 192 and 384 can | ||
197 | * only be selected with divide-by-1.5, but there is an errate that make | ||
198 | * this selection difficult. | ||
199 | * | ||
200 | * In addition, there is no mechanism for communicating with the machine | ||
201 | * driver what the input settings can be. This would need to be implemented | ||
202 | * for stand-alone mode to work. | ||
203 | */ | 190 | */ |
204 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 191 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
205 | int clk_id, unsigned int freq, int dir) | 192 | int clk_id, unsigned int freq, int dir) |
@@ -225,7 +212,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
225 | rates &= ~SNDRV_PCM_RATE_KNOT; | 212 | rates &= ~SNDRV_PCM_RATE_KNOT; |
226 | 213 | ||
227 | if (!rates) { | 214 | if (!rates) { |
228 | printk(KERN_ERR "cs4270: could not find a valid sample rate\n"); | 215 | dev_err(codec->dev, "could not find a valid sample rate\n"); |
229 | return -EINVAL; | 216 | return -EINVAL; |
230 | } | 217 | } |
231 | 218 | ||
@@ -240,8 +227,10 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
240 | return 0; | 227 | return 0; |
241 | } | 228 | } |
242 | 229 | ||
243 | /* | 230 | /** |
244 | * Configure the codec for the selected audio format | 231 | * cs4270_set_dai_fmt - configure the codec for the selected audio format |
232 | * @codec_dai: the codec DAI | ||
233 | * @format: a SND_SOC_DAIFMT_x value indicating the data format | ||
245 | * | 234 | * |
246 | * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the | 235 | * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the |
247 | * codec accordingly. | 236 | * codec accordingly. |
@@ -258,32 +247,43 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
258 | struct cs4270_private *cs4270 = codec->private_data; | 247 | struct cs4270_private *cs4270 = codec->private_data; |
259 | int ret = 0; | 248 | int ret = 0; |
260 | 249 | ||
250 | /* set DAI format */ | ||
261 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { | 251 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { |
262 | case SND_SOC_DAIFMT_I2S: | 252 | case SND_SOC_DAIFMT_I2S: |
263 | case SND_SOC_DAIFMT_LEFT_J: | 253 | case SND_SOC_DAIFMT_LEFT_J: |
264 | cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK; | 254 | cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK; |
265 | break; | 255 | break; |
266 | default: | 256 | default: |
267 | printk(KERN_ERR "cs4270: invalid DAI format\n"); | 257 | dev_err(codec->dev, "invalid dai format\n"); |
258 | ret = -EINVAL; | ||
259 | } | ||
260 | |||
261 | /* set master/slave audio interface */ | ||
262 | switch (format & SND_SOC_DAIFMT_MASTER_MASK) { | ||
263 | case SND_SOC_DAIFMT_CBS_CFS: | ||
264 | cs4270->slave_mode = 1; | ||
265 | break; | ||
266 | case SND_SOC_DAIFMT_CBM_CFM: | ||
267 | cs4270->slave_mode = 0; | ||
268 | break; | ||
269 | default: | ||
270 | /* all other modes are unsupported by the hardware */ | ||
268 | ret = -EINVAL; | 271 | ret = -EINVAL; |
269 | } | 272 | } |
270 | 273 | ||
271 | return ret; | 274 | return ret; |
272 | } | 275 | } |
273 | 276 | ||
274 | /* | 277 | /** |
275 | * A list of addresses on which this CS4270 could use. I2C addresses are | 278 | * cs4270_fill_cache - pre-fill the CS4270 register cache. |
276 | * 7 bits. For the CS4270, the upper four bits are always 1001, and the | 279 | * @codec: the codec for this CS4270 |
277 | * lower three bits are determined via the AD2, AD1, and AD0 pins | 280 | * |
278 | * (respectively). | 281 | * This function fills in the CS4270 register cache by reading the register |
279 | */ | 282 | * values from the hardware. |
280 | static const unsigned short normal_i2c[] = { | 283 | * |
281 | 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, I2C_CLIENT_END | 284 | * This CS4270 registers are cached to avoid excessive I2C I/O operations. |
282 | }; | 285 | * After the initial read to pre-fill the cache, the CS4270 never updates |
283 | I2C_CLIENT_INSMOD; | 286 | * the register values, so we won't have a cache coherency problem. |
284 | |||
285 | /* | ||
286 | * Pre-fill the CS4270 register cache. | ||
287 | * | 287 | * |
288 | * We use the auto-increment feature of the CS4270 to read all registers in | 288 | * We use the auto-increment feature of the CS4270 to read all registers in |
289 | * one shot. | 289 | * one shot. |
@@ -298,7 +298,7 @@ static int cs4270_fill_cache(struct snd_soc_codec *codec) | |||
298 | CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache); | 298 | CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache); |
299 | 299 | ||
300 | if (length != CS4270_NUMREGS) { | 300 | if (length != CS4270_NUMREGS) { |
301 | printk(KERN_ERR "cs4270: I2C read failure, addr=0x%x\n", | 301 | dev_err(codec->dev, "i2c read failure, addr=0x%x\n", |
302 | i2c_client->addr); | 302 | i2c_client->addr); |
303 | return -EIO; | 303 | return -EIO; |
304 | } | 304 | } |
@@ -306,12 +306,17 @@ static int cs4270_fill_cache(struct snd_soc_codec *codec) | |||
306 | return 0; | 306 | return 0; |
307 | } | 307 | } |
308 | 308 | ||
309 | /* | 309 | /** |
310 | * Read from the CS4270 register cache. | 310 | * cs4270_read_reg_cache - read from the CS4270 register cache. |
311 | * @codec: the codec for this CS4270 | ||
312 | * @reg: the register to read | ||
313 | * | ||
314 | * This function returns the value for a given register. It reads only from | ||
315 | * the register cache, not the hardware itself. | ||
311 | * | 316 | * |
312 | * This CS4270 registers are cached to avoid excessive I2C I/O operations. | 317 | * This CS4270 registers are cached to avoid excessive I2C I/O operations. |
313 | * After the initial read to pre-fill the cache, the CS4270 never updates | 318 | * After the initial read to pre-fill the cache, the CS4270 never updates |
314 | * the register values, so we won't have a cache coherncy problem. | 319 | * the register values, so we won't have a cache coherency problem. |
315 | */ | 320 | */ |
316 | static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec, | 321 | static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec, |
317 | unsigned int reg) | 322 | unsigned int reg) |
@@ -324,8 +329,11 @@ static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec, | |||
324 | return cache[reg - CS4270_FIRSTREG]; | 329 | return cache[reg - CS4270_FIRSTREG]; |
325 | } | 330 | } |
326 | 331 | ||
327 | /* | 332 | /** |
328 | * Write to a CS4270 register via the I2C bus. | 333 | * cs4270_i2c_write - write to a CS4270 register via the I2C bus. |
334 | * @codec: the codec for this CS4270 | ||
335 | * @reg: the register to write | ||
336 | * @value: the value to write to the register | ||
329 | * | 337 | * |
330 | * This function writes the given value to the given CS4270 register, and | 338 | * This function writes the given value to the given CS4270 register, and |
331 | * also updates the register cache. | 339 | * also updates the register cache. |
@@ -346,7 +354,7 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, | |||
346 | if (cache[reg - CS4270_FIRSTREG] != value) { | 354 | if (cache[reg - CS4270_FIRSTREG] != value) { |
347 | struct i2c_client *client = codec->control_data; | 355 | struct i2c_client *client = codec->control_data; |
348 | if (i2c_smbus_write_byte_data(client, reg, value)) { | 356 | if (i2c_smbus_write_byte_data(client, reg, value)) { |
349 | printk(KERN_ERR "cs4270: I2C write failed\n"); | 357 | dev_err(codec->dev, "i2c write failed\n"); |
350 | return -EIO; | 358 | return -EIO; |
351 | } | 359 | } |
352 | 360 | ||
@@ -357,11 +365,17 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, | |||
357 | return 0; | 365 | return 0; |
358 | } | 366 | } |
359 | 367 | ||
360 | /* | 368 | /** |
361 | * Program the CS4270 with the given hardware parameters. | 369 | * cs4270_hw_params - program the CS4270 with the given hardware parameters. |
370 | * @substream: the audio stream | ||
371 | * @params: the hardware parameters to set | ||
372 | * @dai: the SOC DAI (ignored) | ||
373 | * | ||
374 | * This function programs the hardware with the values provided. | ||
375 | * Specifically, the sample rate and the data format. | ||
362 | * | 376 | * |
363 | * The .ops functions are used to provide board-specific data, like | 377 | * The .ops functions are used to provide board-specific data, like input |
364 | * input frequencies, to this driver. This function takes that information, | 378 | * frequencies, to this driver. This function takes that information, |
365 | * combines it with the hardware parameters provided, and programs the | 379 | * combines it with the hardware parameters provided, and programs the |
366 | * hardware accordingly. | 380 | * hardware accordingly. |
367 | */ | 381 | */ |
@@ -371,7 +385,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
371 | { | 385 | { |
372 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 386 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
373 | struct snd_soc_device *socdev = rtd->socdev; | 387 | struct snd_soc_device *socdev = rtd->socdev; |
374 | struct snd_soc_codec *codec = socdev->codec; | 388 | struct snd_soc_codec *codec = socdev->card->codec; |
375 | struct cs4270_private *cs4270 = codec->private_data; | 389 | struct cs4270_private *cs4270 = codec->private_data; |
376 | int ret; | 390 | int ret; |
377 | unsigned int i; | 391 | unsigned int i; |
@@ -391,33 +405,28 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
391 | 405 | ||
392 | if (i == NUM_MCLK_RATIOS) { | 406 | if (i == NUM_MCLK_RATIOS) { |
393 | /* We did not find a matching ratio */ | 407 | /* We did not find a matching ratio */ |
394 | printk(KERN_ERR "cs4270: could not find matching ratio\n"); | 408 | dev_err(codec->dev, "could not find matching ratio\n"); |
395 | return -EINVAL; | 409 | return -EINVAL; |
396 | } | 410 | } |
397 | 411 | ||
398 | /* Freeze and power-down the codec */ | 412 | /* Set the sample rate */ |
399 | |||
400 | ret = snd_soc_write(codec, CS4270_PWRCTL, CS4270_PWRCTL_FREEZE | | ||
401 | CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | | ||
402 | CS4270_PWRCTL_PDN); | ||
403 | if (ret < 0) { | ||
404 | printk(KERN_ERR "cs4270: I2C write failed\n"); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | /* Program the mode control register */ | ||
409 | 413 | ||
410 | reg = snd_soc_read(codec, CS4270_MODE); | 414 | reg = snd_soc_read(codec, CS4270_MODE); |
411 | reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK); | 415 | reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK); |
412 | reg |= cs4270_mode_ratios[i].speed_mode | cs4270_mode_ratios[i].mclk; | 416 | reg |= cs4270_mode_ratios[i].mclk; |
417 | |||
418 | if (cs4270->slave_mode) | ||
419 | reg |= CS4270_MODE_SLAVE; | ||
420 | else | ||
421 | reg |= cs4270_mode_ratios[i].speed_mode; | ||
413 | 422 | ||
414 | ret = snd_soc_write(codec, CS4270_MODE, reg); | 423 | ret = snd_soc_write(codec, CS4270_MODE, reg); |
415 | if (ret < 0) { | 424 | if (ret < 0) { |
416 | printk(KERN_ERR "cs4270: I2C write failed\n"); | 425 | dev_err(codec->dev, "i2c write failed\n"); |
417 | return ret; | 426 | return ret; |
418 | } | 427 | } |
419 | 428 | ||
420 | /* Program the format register */ | 429 | /* Set the DAI format */ |
421 | 430 | ||
422 | reg = snd_soc_read(codec, CS4270_FORMAT); | 431 | reg = snd_soc_read(codec, CS4270_FORMAT); |
423 | reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK); | 432 | reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK); |
@@ -430,55 +439,23 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
430 | reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ; | 439 | reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ; |
431 | break; | 440 | break; |
432 | default: | 441 | default: |
433 | printk(KERN_ERR "cs4270: unknown format\n"); | 442 | dev_err(codec->dev, "unknown dai format\n"); |
434 | return -EINVAL; | 443 | return -EINVAL; |
435 | } | 444 | } |
436 | 445 | ||
437 | ret = snd_soc_write(codec, CS4270_FORMAT, reg); | 446 | ret = snd_soc_write(codec, CS4270_FORMAT, reg); |
438 | if (ret < 0) { | 447 | if (ret < 0) { |
439 | printk(KERN_ERR "cs4270: I2C write failed\n"); | 448 | dev_err(codec->dev, "i2c write failed\n"); |
440 | return ret; | ||
441 | } | ||
442 | |||
443 | /* Disable auto-mute. This feature appears to be buggy, because in | ||
444 | some situations, auto-mute will not deactivate when it should. */ | ||
445 | |||
446 | reg = snd_soc_read(codec, CS4270_MUTE); | ||
447 | reg &= ~CS4270_MUTE_AUTO; | ||
448 | ret = snd_soc_write(codec, CS4270_MUTE, reg); | ||
449 | if (ret < 0) { | ||
450 | printk(KERN_ERR "cs4270: I2C write failed\n"); | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | /* Disable automatic volume control. It's enabled by default, and | ||
455 | * it causes volume change commands to be delayed, sometimes until | ||
456 | * after playback has started. | ||
457 | */ | ||
458 | |||
459 | reg = cs4270_read_reg_cache(codec, CS4270_TRANS); | ||
460 | reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO); | ||
461 | ret = cs4270_i2c_write(codec, CS4270_TRANS, reg); | ||
462 | if (ret < 0) { | ||
463 | printk(KERN_ERR "I2C write failed\n"); | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | /* Thaw and power-up the codec */ | ||
468 | |||
469 | ret = snd_soc_write(codec, CS4270_PWRCTL, 0); | ||
470 | if (ret < 0) { | ||
471 | printk(KERN_ERR "cs4270: I2C write failed\n"); | ||
472 | return ret; | 449 | return ret; |
473 | } | 450 | } |
474 | 451 | ||
475 | return ret; | 452 | return ret; |
476 | } | 453 | } |
477 | 454 | ||
478 | #ifdef CONFIG_SND_SOC_CS4270_HWMUTE | 455 | /** |
479 | 456 | * cs4270_mute - enable/disable the CS4270 external mute | |
480 | /* | 457 | * @dai: the SOC DAI |
481 | * Set the CS4270 external mute | 458 | * @mute: 0 = disable mute, 1 = enable mute |
482 | * | 459 | * |
483 | * This function toggles the mute bits in the MUTE register. The CS4270's | 460 | * This function toggles the mute bits in the MUTE register. The CS4270's |
484 | * mute capability is intended for external muting circuitry, so if the | 461 | * mute capability is intended for external muting circuitry, so if the |
@@ -493,276 +470,306 @@ static int cs4270_mute(struct snd_soc_dai *dai, int mute) | |||
493 | reg6 = snd_soc_read(codec, CS4270_MUTE); | 470 | reg6 = snd_soc_read(codec, CS4270_MUTE); |
494 | 471 | ||
495 | if (mute) | 472 | if (mute) |
496 | reg6 |= CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | | 473 | reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B; |
497 | CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B; | ||
498 | else | 474 | else |
499 | reg6 &= ~(CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | | 475 | reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B); |
500 | CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B); | ||
501 | 476 | ||
502 | return snd_soc_write(codec, CS4270_MUTE, reg6); | 477 | return snd_soc_write(codec, CS4270_MUTE, reg6); |
503 | } | 478 | } |
504 | 479 | ||
505 | #endif | ||
506 | |||
507 | static int cs4270_i2c_probe(struct i2c_client *, const struct i2c_device_id *); | ||
508 | |||
509 | /* A list of non-DAPM controls that the CS4270 supports */ | 480 | /* A list of non-DAPM controls that the CS4270 supports */ |
510 | static const struct snd_kcontrol_new cs4270_snd_controls[] = { | 481 | static const struct snd_kcontrol_new cs4270_snd_controls[] = { |
511 | SOC_DOUBLE_R("Master Playback Volume", | 482 | SOC_DOUBLE_R("Master Playback Volume", |
512 | CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1) | 483 | CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1), |
513 | }; | 484 | SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0), |
514 | 485 | SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0), | |
515 | static const struct i2c_device_id cs4270_id[] = { | 486 | SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0), |
516 | {"cs4270", 0}, | 487 | SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1), |
517 | {} | 488 | SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0), |
518 | }; | 489 | SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 0) |
519 | MODULE_DEVICE_TABLE(i2c, cs4270_id); | ||
520 | |||
521 | static struct i2c_driver cs4270_i2c_driver = { | ||
522 | .driver = { | ||
523 | .name = "CS4270 I2C", | ||
524 | .owner = THIS_MODULE, | ||
525 | }, | ||
526 | .id_table = cs4270_id, | ||
527 | .probe = cs4270_i2c_probe, | ||
528 | }; | 490 | }; |
529 | 491 | ||
530 | /* | 492 | /* |
531 | * Global variable to store socdev for i2c probe function. | 493 | * cs4270_codec - global variable to store codec for the ASoC probe function |
532 | * | 494 | * |
533 | * If struct i2c_driver had a private_data field, we wouldn't need to use | 495 | * If struct i2c_driver had a private_data field, we wouldn't need to use |
534 | * cs4270_socdec. This is the only way to pass the socdev structure to | 496 | * cs4270_codec. This is the only way to pass the codec structure from |
535 | * cs4270_i2c_probe(). | 497 | * cs4270_i2c_probe() to cs4270_probe(). Unfortunately, there is no good |
536 | * | 498 | * way to synchronize these two functions. cs4270_i2c_probe() can be called |
537 | * The real solution to cs4270_socdev is to create a mechanism | 499 | * multiple times before cs4270_probe() is called even once. So for now, we |
538 | * that maps I2C addresses to snd_soc_device structures. Perhaps the | 500 | * also only allow cs4270_i2c_probe() to be run once. That means that we do |
539 | * creation of the snd_soc_device object should be moved out of | 501 | * not support more than one cs4270 device in the system, at least for now. |
540 | * cs4270_probe() and into cs4270_i2c_probe(), but that would make this | ||
541 | * driver dependent on I2C. The CS4270 supports "stand-alone" mode, whereby | ||
542 | * the chip is *not* connected to the I2C bus, but is instead configured via | ||
543 | * input pins. | ||
544 | */ | 502 | */ |
545 | static struct snd_soc_device *cs4270_socdev; | 503 | static struct snd_soc_codec *cs4270_codec; |
546 | 504 | ||
547 | /* | 505 | static struct snd_soc_dai_ops cs4270_dai_ops = { |
548 | * Initialize the I2C interface of the CS4270 | 506 | .hw_params = cs4270_hw_params, |
549 | * | 507 | .set_sysclk = cs4270_set_dai_sysclk, |
550 | * This function is called for whenever the I2C subsystem finds a device | 508 | .set_fmt = cs4270_set_dai_fmt, |
551 | * at a particular address. | 509 | .digital_mute = cs4270_mute, |
510 | }; | ||
511 | |||
512 | struct snd_soc_dai cs4270_dai = { | ||
513 | .name = "cs4270", | ||
514 | .playback = { | ||
515 | .stream_name = "Playback", | ||
516 | .channels_min = 1, | ||
517 | .channels_max = 2, | ||
518 | .rates = 0, | ||
519 | .formats = CS4270_FORMATS, | ||
520 | }, | ||
521 | .capture = { | ||
522 | .stream_name = "Capture", | ||
523 | .channels_min = 1, | ||
524 | .channels_max = 2, | ||
525 | .rates = 0, | ||
526 | .formats = CS4270_FORMATS, | ||
527 | }, | ||
528 | .ops = &cs4270_dai_ops, | ||
529 | }; | ||
530 | EXPORT_SYMBOL_GPL(cs4270_dai); | ||
531 | |||
532 | /** | ||
533 | * cs4270_probe - ASoC probe function | ||
534 | * @pdev: platform device | ||
552 | * | 535 | * |
553 | * Note: snd_soc_new_pcms() must be called before this function can be called, | 536 | * This function is called when ASoC has all the pieces it needs to |
554 | * because of snd_ctl_add(). | 537 | * instantiate a sound driver. |
555 | */ | 538 | */ |
556 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, | 539 | static int cs4270_probe(struct platform_device *pdev) |
557 | const struct i2c_device_id *id) | ||
558 | { | 540 | { |
559 | struct snd_soc_device *socdev = cs4270_socdev; | 541 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
560 | struct snd_soc_codec *codec = socdev->codec; | 542 | struct snd_soc_codec *codec = cs4270_codec; |
561 | int i; | 543 | int ret; |
562 | int ret = 0; | ||
563 | |||
564 | /* Probing all possible addresses has one drawback: if there are | ||
565 | multiple CS4270s on the bus, then you cannot specify which | ||
566 | socdev is matched with which CS4270. For now, we just reject | ||
567 | this I2C device if the socdev already has one attached. */ | ||
568 | if (codec->control_data) | ||
569 | return -ENODEV; | ||
570 | |||
571 | /* Note: codec_dai->codec is NULL here */ | ||
572 | |||
573 | codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL); | ||
574 | if (!codec->reg_cache) { | ||
575 | printk(KERN_ERR "cs4270: could not allocate register cache\n"); | ||
576 | ret = -ENOMEM; | ||
577 | goto error; | ||
578 | } | ||
579 | 544 | ||
580 | /* Verify that we have a CS4270 */ | 545 | /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ |
546 | socdev->card->codec = codec; | ||
581 | 547 | ||
582 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); | 548 | /* Register PCMs */ |
549 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
583 | if (ret < 0) { | 550 | if (ret < 0) { |
584 | printk(KERN_ERR "cs4270: failed to read I2C\n"); | 551 | dev_err(codec->dev, "failed to create pcms\n"); |
585 | goto error; | 552 | return ret; |
586 | } | ||
587 | /* The top four bits of the chip ID should be 1100. */ | ||
588 | if ((ret & 0xF0) != 0xC0) { | ||
589 | /* The device at this address is not a CS4270 codec */ | ||
590 | ret = -ENODEV; | ||
591 | goto error; | ||
592 | } | 553 | } |
593 | 554 | ||
594 | printk(KERN_INFO "cs4270: found device at I2C address %X\n", | 555 | /* Add the non-DAPM controls */ |
595 | i2c_client->addr); | 556 | ret = snd_soc_add_controls(codec, cs4270_snd_controls, |
596 | printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); | 557 | ARRAY_SIZE(cs4270_snd_controls)); |
597 | |||
598 | codec->control_data = i2c_client; | ||
599 | codec->read = cs4270_read_reg_cache; | ||
600 | codec->write = cs4270_i2c_write; | ||
601 | codec->reg_cache_size = CS4270_NUMREGS; | ||
602 | |||
603 | /* The I2C interface is set up, so pre-fill our register cache */ | ||
604 | |||
605 | ret = cs4270_fill_cache(codec); | ||
606 | if (ret < 0) { | 558 | if (ret < 0) { |
607 | printk(KERN_ERR "cs4270: failed to fill register cache\n"); | 559 | dev_err(codec->dev, "failed to add controls\n"); |
608 | goto error; | 560 | goto error_free_pcms; |
609 | } | 561 | } |
610 | 562 | ||
611 | /* Add the non-DAPM controls */ | 563 | /* And finally, register the socdev */ |
612 | 564 | ret = snd_soc_init_card(socdev); | |
613 | for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) { | 565 | if (ret < 0) { |
614 | struct snd_kcontrol *kctrl = | 566 | dev_err(codec->dev, "failed to register card\n"); |
615 | snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL); | 567 | goto error_free_pcms; |
616 | |||
617 | ret = snd_ctl_add(codec->card, kctrl); | ||
618 | if (ret < 0) | ||
619 | goto error; | ||
620 | } | 568 | } |
621 | 569 | ||
622 | i2c_set_clientdata(i2c_client, codec); | ||
623 | |||
624 | return 0; | 570 | return 0; |
625 | 571 | ||
626 | error: | 572 | error_free_pcms: |
627 | codec->control_data = NULL; | 573 | snd_soc_free_pcms(socdev); |
628 | |||
629 | kfree(codec->reg_cache); | ||
630 | codec->reg_cache = NULL; | ||
631 | codec->reg_cache_size = 0; | ||
632 | 574 | ||
633 | return ret; | 575 | return ret; |
634 | } | 576 | } |
635 | 577 | ||
636 | #endif /* USE_I2C*/ | 578 | /** |
579 | * cs4270_remove - ASoC remove function | ||
580 | * @pdev: platform device | ||
581 | * | ||
582 | * This function is the counterpart to cs4270_probe(). | ||
583 | */ | ||
584 | static int cs4270_remove(struct platform_device *pdev) | ||
585 | { | ||
586 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
637 | 587 | ||
638 | struct snd_soc_dai cs4270_dai = { | 588 | snd_soc_free_pcms(socdev); |
639 | .name = "CS4270", | 589 | |
640 | .playback = { | 590 | return 0; |
641 | .stream_name = "Playback", | ||
642 | .channels_min = 1, | ||
643 | .channels_max = 2, | ||
644 | .rates = 0, | ||
645 | .formats = CS4270_FORMATS, | ||
646 | }, | ||
647 | .capture = { | ||
648 | .stream_name = "Capture", | ||
649 | .channels_min = 1, | ||
650 | .channels_max = 2, | ||
651 | .rates = 0, | ||
652 | .formats = CS4270_FORMATS, | ||
653 | }, | ||
654 | }; | 591 | }; |
655 | EXPORT_SYMBOL_GPL(cs4270_dai); | ||
656 | 592 | ||
657 | /* | 593 | /** |
658 | * ASoC probe function | 594 | * cs4270_i2c_probe - initialize the I2C interface of the CS4270 |
595 | * @i2c_client: the I2C client object | ||
596 | * @id: the I2C device ID (ignored) | ||
659 | * | 597 | * |
660 | * This function is called when the machine driver calls | 598 | * This function is called whenever the I2C subsystem finds a device that |
661 | * platform_device_add(). | 599 | * matches the device ID given via a prior call to i2c_add_driver(). |
662 | */ | 600 | */ |
663 | static int cs4270_probe(struct platform_device *pdev) | 601 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, |
602 | const struct i2c_device_id *id) | ||
664 | { | 603 | { |
665 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
666 | struct snd_soc_codec *codec; | 604 | struct snd_soc_codec *codec; |
667 | int ret = 0; | 605 | struct cs4270_private *cs4270; |
606 | unsigned int reg; | ||
607 | int ret; | ||
668 | 608 | ||
669 | printk(KERN_INFO "CS4270 ALSA SoC Codec\n"); | 609 | /* For now, we only support one cs4270 device in the system. See the |
610 | * comment for cs4270_codec. | ||
611 | */ | ||
612 | if (cs4270_codec) { | ||
613 | dev_err(&i2c_client->dev, "ignoring CS4270 at addr %X\n", | ||
614 | i2c_client->addr); | ||
615 | dev_err(&i2c_client->dev, "only one per board allowed\n"); | ||
616 | /* Should we return something other than ENODEV here? */ | ||
617 | return -ENODEV; | ||
618 | } | ||
619 | |||
620 | /* Verify that we have a CS4270 */ | ||
621 | |||
622 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); | ||
623 | if (ret < 0) { | ||
624 | dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n", | ||
625 | i2c_client->addr); | ||
626 | return ret; | ||
627 | } | ||
628 | /* The top four bits of the chip ID should be 1100. */ | ||
629 | if ((ret & 0xF0) != 0xC0) { | ||
630 | dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n", | ||
631 | i2c_client->addr); | ||
632 | return -ENODEV; | ||
633 | } | ||
634 | |||
635 | dev_info(&i2c_client->dev, "found device at i2c address %X\n", | ||
636 | i2c_client->addr); | ||
637 | dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF); | ||
670 | 638 | ||
671 | /* Allocate enough space for the snd_soc_codec structure | 639 | /* Allocate enough space for the snd_soc_codec structure |
672 | and our private data together. */ | 640 | and our private data together. */ |
673 | codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) + | 641 | cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL); |
674 | sizeof(struct cs4270_private), GFP_KERNEL); | 642 | if (!cs4270) { |
675 | if (!codec) { | 643 | dev_err(&i2c_client->dev, "could not allocate codec\n"); |
676 | printk(KERN_ERR "cs4270: Could not allocate codec structure\n"); | ||
677 | return -ENOMEM; | 644 | return -ENOMEM; |
678 | } | 645 | } |
646 | codec = &cs4270->codec; | ||
679 | 647 | ||
680 | mutex_init(&codec->mutex); | 648 | mutex_init(&codec->mutex); |
681 | INIT_LIST_HEAD(&codec->dapm_widgets); | 649 | INIT_LIST_HEAD(&codec->dapm_widgets); |
682 | INIT_LIST_HEAD(&codec->dapm_paths); | 650 | INIT_LIST_HEAD(&codec->dapm_paths); |
683 | 651 | ||
652 | codec->dev = &i2c_client->dev; | ||
684 | codec->name = "CS4270"; | 653 | codec->name = "CS4270"; |
685 | codec->owner = THIS_MODULE; | 654 | codec->owner = THIS_MODULE; |
686 | codec->dai = &cs4270_dai; | 655 | codec->dai = &cs4270_dai; |
687 | codec->num_dai = 1; | 656 | codec->num_dai = 1; |
688 | codec->private_data = (void *) codec + | 657 | codec->private_data = cs4270; |
689 | ALIGN(sizeof(struct snd_soc_codec), 4); | 658 | codec->control_data = i2c_client; |
690 | 659 | codec->read = cs4270_read_reg_cache; | |
691 | socdev->codec = codec; | 660 | codec->write = cs4270_i2c_write; |
661 | codec->reg_cache = cs4270->reg_cache; | ||
662 | codec->reg_cache_size = CS4270_NUMREGS; | ||
692 | 663 | ||
693 | /* Register PCMs */ | 664 | /* The I2C interface is set up, so pre-fill our register cache */ |
694 | 665 | ||
695 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 666 | ret = cs4270_fill_cache(codec); |
696 | if (ret < 0) { | 667 | if (ret < 0) { |
697 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); | 668 | dev_err(&i2c_client->dev, "failed to fill register cache\n"); |
698 | goto error_free_codec; | 669 | goto error_free_codec; |
699 | } | 670 | } |
700 | 671 | ||
701 | #ifdef USE_I2C | 672 | /* Disable auto-mute. This feature appears to be buggy. In some |
702 | cs4270_socdev = socdev; | 673 | * situations, auto-mute will not deactivate when it should, so we want |
674 | * this feature disabled by default. An application (e.g. alsactl) can | ||
675 | * re-enabled it by using the controls. | ||
676 | */ | ||
703 | 677 | ||
704 | ret = i2c_add_driver(&cs4270_i2c_driver); | 678 | reg = cs4270_read_reg_cache(codec, CS4270_MUTE); |
705 | if (ret) { | 679 | reg &= ~CS4270_MUTE_AUTO; |
706 | printk(KERN_ERR "cs4270: failed to attach driver"); | 680 | ret = cs4270_i2c_write(codec, CS4270_MUTE, reg); |
707 | goto error_free_pcms; | 681 | if (ret < 0) { |
682 | dev_err(&i2c_client->dev, "i2c write failed\n"); | ||
683 | return ret; | ||
708 | } | 684 | } |
709 | 685 | ||
710 | /* Did we find a CS4270 on the I2C bus? */ | 686 | /* Disable automatic volume control. The hardware enables, and it |
711 | if (codec->control_data) { | 687 | * causes volume change commands to be delayed, sometimes until after |
712 | /* Initialize codec ops */ | 688 | * playback has started. An application (e.g. alsactl) can |
713 | cs4270_dai.ops.hw_params = cs4270_hw_params; | 689 | * re-enabled it by using the controls. |
714 | cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk; | 690 | */ |
715 | cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt; | ||
716 | #ifdef CONFIG_SND_SOC_CS4270_HWMUTE | ||
717 | cs4270_dai.ops.digital_mute = cs4270_mute; | ||
718 | #endif | ||
719 | } else | ||
720 | printk(KERN_INFO "cs4270: no I2C device found, " | ||
721 | "using stand-alone mode\n"); | ||
722 | #else | ||
723 | printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n"); | ||
724 | #endif | ||
725 | 691 | ||
726 | ret = snd_soc_init_card(socdev); | 692 | reg = cs4270_read_reg_cache(codec, CS4270_TRANS); |
693 | reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO); | ||
694 | ret = cs4270_i2c_write(codec, CS4270_TRANS, reg); | ||
727 | if (ret < 0) { | 695 | if (ret < 0) { |
728 | printk(KERN_ERR "cs4270: failed to register card\n"); | 696 | dev_err(&i2c_client->dev, "i2c write failed\n"); |
729 | goto error_del_driver; | 697 | return ret; |
730 | } | 698 | } |
731 | 699 | ||
732 | return 0; | 700 | /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI |
701 | * structure for each CS4270 device, but the machine driver needs to | ||
702 | * have a pointer to the DAI structure, so for now it must be a global | ||
703 | * variable. | ||
704 | */ | ||
705 | cs4270_dai.dev = &i2c_client->dev; | ||
733 | 706 | ||
734 | error_del_driver: | 707 | /* Register the DAI. If all the other ASoC driver have already |
735 | #ifdef USE_I2C | 708 | * registered, then this will call our probe function, so |
736 | i2c_del_driver(&cs4270_i2c_driver); | 709 | * cs4270_codec needs to be ready. |
710 | */ | ||
711 | cs4270_codec = codec; | ||
712 | ret = snd_soc_register_dai(&cs4270_dai); | ||
713 | if (ret < 0) { | ||
714 | dev_err(&i2c_client->dev, "failed to register DAIe\n"); | ||
715 | goto error_free_codec; | ||
716 | } | ||
737 | 717 | ||
738 | error_free_pcms: | 718 | i2c_set_clientdata(i2c_client, cs4270); |
739 | #endif | 719 | |
740 | snd_soc_free_pcms(socdev); | 720 | return 0; |
741 | 721 | ||
742 | error_free_codec: | 722 | error_free_codec: |
743 | kfree(socdev->codec); | 723 | kfree(cs4270); |
744 | socdev->codec = NULL; | 724 | cs4270_codec = NULL; |
725 | cs4270_dai.dev = NULL; | ||
745 | 726 | ||
746 | return ret; | 727 | return ret; |
747 | } | 728 | } |
748 | 729 | ||
749 | static int cs4270_remove(struct platform_device *pdev) | 730 | /** |
731 | * cs4270_i2c_remove - remove an I2C device | ||
732 | * @i2c_client: the I2C client object | ||
733 | * | ||
734 | * This function is the counterpart to cs4270_i2c_probe(). | ||
735 | */ | ||
736 | static int cs4270_i2c_remove(struct i2c_client *i2c_client) | ||
750 | { | 737 | { |
751 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 738 | struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client); |
752 | |||
753 | snd_soc_free_pcms(socdev); | ||
754 | |||
755 | #ifdef USE_I2C | ||
756 | i2c_del_driver(&cs4270_i2c_driver); | ||
757 | #endif | ||
758 | 739 | ||
759 | kfree(socdev->codec); | 740 | kfree(cs4270); |
760 | socdev->codec = NULL; | 741 | cs4270_codec = NULL; |
742 | cs4270_dai.dev = NULL; | ||
761 | 743 | ||
762 | return 0; | 744 | return 0; |
763 | } | 745 | } |
764 | 746 | ||
765 | /* | 747 | /* |
748 | * cs4270_id - I2C device IDs supported by this driver | ||
749 | */ | ||
750 | static struct i2c_device_id cs4270_id[] = { | ||
751 | {"cs4270", 0}, | ||
752 | {} | ||
753 | }; | ||
754 | MODULE_DEVICE_TABLE(i2c, cs4270_id); | ||
755 | |||
756 | /* | ||
757 | * cs4270_i2c_driver - I2C device identification | ||
758 | * | ||
759 | * This structure tells the I2C subsystem how to identify and support a | ||
760 | * given I2C device type. | ||
761 | */ | ||
762 | static struct i2c_driver cs4270_i2c_driver = { | ||
763 | .driver = { | ||
764 | .name = "cs4270", | ||
765 | .owner = THIS_MODULE, | ||
766 | }, | ||
767 | .id_table = cs4270_id, | ||
768 | .probe = cs4270_i2c_probe, | ||
769 | .remove = cs4270_i2c_remove, | ||
770 | }; | ||
771 | |||
772 | /* | ||
766 | * ASoC codec device structure | 773 | * ASoC codec device structure |
767 | * | 774 | * |
768 | * Assign this variable to the codec_dev field of the machine driver's | 775 | * Assign this variable to the codec_dev field of the machine driver's |
@@ -776,13 +783,15 @@ EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); | |||
776 | 783 | ||
777 | static int __init cs4270_init(void) | 784 | static int __init cs4270_init(void) |
778 | { | 785 | { |
779 | return snd_soc_register_dai(&cs4270_dai); | 786 | pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n"); |
787 | |||
788 | return i2c_add_driver(&cs4270_i2c_driver); | ||
780 | } | 789 | } |
781 | module_init(cs4270_init); | 790 | module_init(cs4270_init); |
782 | 791 | ||
783 | static void __exit cs4270_exit(void) | 792 | static void __exit cs4270_exit(void) |
784 | { | 793 | { |
785 | snd_soc_unregister_dai(&cs4270_dai); | 794 | i2c_del_driver(&cs4270_i2c_driver); |
786 | } | 795 | } |
787 | module_exit(cs4270_exit); | 796 | module_exit(cs4270_exit); |
788 | 797 | ||
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 9a3e67e5319c..5cda9e6b5a74 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c | |||
@@ -67,11 +67,11 @@ static int pcm3008_soc_probe(struct platform_device *pdev) | |||
67 | 67 | ||
68 | printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION); | 68 | printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION); |
69 | 69 | ||
70 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 70 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
71 | if (!socdev->codec) | 71 | if (!socdev->card->codec) |
72 | return -ENOMEM; | 72 | return -ENOMEM; |
73 | 73 | ||
74 | codec = socdev->codec; | 74 | codec = socdev->card->codec; |
75 | mutex_init(&codec->mutex); | 75 | mutex_init(&codec->mutex); |
76 | 76 | ||
77 | codec->name = "PCM3008"; | 77 | codec->name = "PCM3008"; |
@@ -139,7 +139,7 @@ gpio_err: | |||
139 | card_err: | 139 | card_err: |
140 | snd_soc_free_pcms(socdev); | 140 | snd_soc_free_pcms(socdev); |
141 | pcm_err: | 141 | pcm_err: |
142 | kfree(socdev->codec); | 142 | kfree(socdev->card->codec); |
143 | 143 | ||
144 | return ret; | 144 | return ret; |
145 | } | 145 | } |
@@ -147,7 +147,7 @@ pcm_err: | |||
147 | static int pcm3008_soc_remove(struct platform_device *pdev) | 147 | static int pcm3008_soc_remove(struct platform_device *pdev) |
148 | { | 148 | { |
149 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 149 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
150 | struct snd_soc_codec *codec = socdev->codec; | 150 | struct snd_soc_codec *codec = socdev->card->codec; |
151 | struct pcm3008_setup_data *setup = socdev->codec_data; | 151 | struct pcm3008_setup_data *setup = socdev->codec_data; |
152 | 152 | ||
153 | if (!codec) | 153 | if (!codec) |
@@ -155,7 +155,7 @@ static int pcm3008_soc_remove(struct platform_device *pdev) | |||
155 | 155 | ||
156 | pcm3008_gpio_free(setup); | 156 | pcm3008_gpio_free(setup); |
157 | snd_soc_free_pcms(socdev); | 157 | snd_soc_free_pcms(socdev); |
158 | kfree(socdev->codec); | 158 | kfree(socdev->card->codec); |
159 | 159 | ||
160 | return 0; | 160 | return 0; |
161 | } | 161 | } |
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index cac373616768..87f606c76822 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -151,21 +151,6 @@ SOC_ENUM("Capture Source", ssm2602_enum[0]), | |||
151 | SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), | 151 | SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), |
152 | }; | 152 | }; |
153 | 153 | ||
154 | /* add non dapm controls */ | ||
155 | static int ssm2602_add_controls(struct snd_soc_codec *codec) | ||
156 | { | ||
157 | int err, i; | ||
158 | |||
159 | for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) { | ||
160 | err = snd_ctl_add(codec->card, | ||
161 | snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL)); | ||
162 | if (err < 0) | ||
163 | return err; | ||
164 | } | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | /* Output Mixer */ | 154 | /* Output Mixer */ |
170 | static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { | 155 | static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { |
171 | SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), | 156 | SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), |
@@ -291,7 +276,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, | |||
291 | u16 srate; | 276 | u16 srate; |
292 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
293 | struct snd_soc_device *socdev = rtd->socdev; | 278 | struct snd_soc_device *socdev = rtd->socdev; |
294 | struct snd_soc_codec *codec = socdev->codec; | 279 | struct snd_soc_codec *codec = socdev->card->codec; |
295 | struct ssm2602_priv *ssm2602 = codec->private_data; | 280 | struct ssm2602_priv *ssm2602 = codec->private_data; |
296 | struct i2c_client *i2c = codec->control_data; | 281 | struct i2c_client *i2c = codec->control_data; |
297 | u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; | 282 | u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; |
@@ -336,7 +321,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, | |||
336 | { | 321 | { |
337 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 322 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
338 | struct snd_soc_device *socdev = rtd->socdev; | 323 | struct snd_soc_device *socdev = rtd->socdev; |
339 | struct snd_soc_codec *codec = socdev->codec; | 324 | struct snd_soc_codec *codec = socdev->card->codec; |
340 | struct ssm2602_priv *ssm2602 = codec->private_data; | 325 | struct ssm2602_priv *ssm2602 = codec->private_data; |
341 | struct i2c_client *i2c = codec->control_data; | 326 | struct i2c_client *i2c = codec->control_data; |
342 | struct snd_pcm_runtime *master_runtime; | 327 | struct snd_pcm_runtime *master_runtime; |
@@ -373,7 +358,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, | |||
373 | { | 358 | { |
374 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 359 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
375 | struct snd_soc_device *socdev = rtd->socdev; | 360 | struct snd_soc_device *socdev = rtd->socdev; |
376 | struct snd_soc_codec *codec = socdev->codec; | 361 | struct snd_soc_codec *codec = socdev->card->codec; |
377 | /* set active */ | 362 | /* set active */ |
378 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | 363 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); |
379 | 364 | ||
@@ -385,7 +370,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, | |||
385 | { | 370 | { |
386 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 371 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
387 | struct snd_soc_device *socdev = rtd->socdev; | 372 | struct snd_soc_device *socdev = rtd->socdev; |
388 | struct snd_soc_codec *codec = socdev->codec; | 373 | struct snd_soc_codec *codec = socdev->card->codec; |
389 | struct ssm2602_priv *ssm2602 = codec->private_data; | 374 | struct ssm2602_priv *ssm2602 = codec->private_data; |
390 | /* deactivate */ | 375 | /* deactivate */ |
391 | if (!codec->active) | 376 | if (!codec->active) |
@@ -521,6 +506,16 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | |||
521 | #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 506 | #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
522 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 507 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
523 | 508 | ||
509 | static struct snd_soc_dai_ops ssm2602_dai_ops = { | ||
510 | .startup = ssm2602_startup, | ||
511 | .prepare = ssm2602_pcm_prepare, | ||
512 | .hw_params = ssm2602_hw_params, | ||
513 | .shutdown = ssm2602_shutdown, | ||
514 | .digital_mute = ssm2602_mute, | ||
515 | .set_sysclk = ssm2602_set_dai_sysclk, | ||
516 | .set_fmt = ssm2602_set_dai_fmt, | ||
517 | }; | ||
518 | |||
524 | struct snd_soc_dai ssm2602_dai = { | 519 | struct snd_soc_dai ssm2602_dai = { |
525 | .name = "SSM2602", | 520 | .name = "SSM2602", |
526 | .playback = { | 521 | .playback = { |
@@ -535,22 +530,14 @@ struct snd_soc_dai ssm2602_dai = { | |||
535 | .channels_max = 2, | 530 | .channels_max = 2, |
536 | .rates = SSM2602_RATES, | 531 | .rates = SSM2602_RATES, |
537 | .formats = SSM2602_FORMATS,}, | 532 | .formats = SSM2602_FORMATS,}, |
538 | .ops = { | 533 | .ops = &ssm2602_dai_ops, |
539 | .startup = ssm2602_startup, | ||
540 | .prepare = ssm2602_pcm_prepare, | ||
541 | .hw_params = ssm2602_hw_params, | ||
542 | .shutdown = ssm2602_shutdown, | ||
543 | .digital_mute = ssm2602_mute, | ||
544 | .set_sysclk = ssm2602_set_dai_sysclk, | ||
545 | .set_fmt = ssm2602_set_dai_fmt, | ||
546 | } | ||
547 | }; | 534 | }; |
548 | EXPORT_SYMBOL_GPL(ssm2602_dai); | 535 | EXPORT_SYMBOL_GPL(ssm2602_dai); |
549 | 536 | ||
550 | static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state) | 537 | static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state) |
551 | { | 538 | { |
552 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 539 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
553 | struct snd_soc_codec *codec = socdev->codec; | 540 | struct snd_soc_codec *codec = socdev->card->codec; |
554 | 541 | ||
555 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | 542 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); |
556 | return 0; | 543 | return 0; |
@@ -559,7 +546,7 @@ static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state) | |||
559 | static int ssm2602_resume(struct platform_device *pdev) | 546 | static int ssm2602_resume(struct platform_device *pdev) |
560 | { | 547 | { |
561 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 548 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
562 | struct snd_soc_codec *codec = socdev->codec; | 549 | struct snd_soc_codec *codec = socdev->card->codec; |
563 | int i; | 550 | int i; |
564 | u8 data[2]; | 551 | u8 data[2]; |
565 | u16 *cache = codec->reg_cache; | 552 | u16 *cache = codec->reg_cache; |
@@ -581,7 +568,7 @@ static int ssm2602_resume(struct platform_device *pdev) | |||
581 | */ | 568 | */ |
582 | static int ssm2602_init(struct snd_soc_device *socdev) | 569 | static int ssm2602_init(struct snd_soc_device *socdev) |
583 | { | 570 | { |
584 | struct snd_soc_codec *codec = socdev->codec; | 571 | struct snd_soc_codec *codec = socdev->card->codec; |
585 | int reg, ret = 0; | 572 | int reg, ret = 0; |
586 | 573 | ||
587 | codec->name = "SSM2602"; | 574 | codec->name = "SSM2602"; |
@@ -622,7 +609,8 @@ static int ssm2602_init(struct snd_soc_device *socdev) | |||
622 | APANA_ENABLE_MIC_BOOST); | 609 | APANA_ENABLE_MIC_BOOST); |
623 | ssm2602_write(codec, SSM2602_PWR, 0); | 610 | ssm2602_write(codec, SSM2602_PWR, 0); |
624 | 611 | ||
625 | ssm2602_add_controls(codec); | 612 | snd_soc_add_controls(codec, ssm2602_snd_controls, |
613 | ARRAY_SIZE(ssm2602_snd_controls)); | ||
626 | ssm2602_add_widgets(codec); | 614 | ssm2602_add_widgets(codec); |
627 | ret = snd_soc_init_card(socdev); | 615 | ret = snd_soc_init_card(socdev); |
628 | if (ret < 0) { | 616 | if (ret < 0) { |
@@ -653,7 +641,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c, | |||
653 | const struct i2c_device_id *id) | 641 | const struct i2c_device_id *id) |
654 | { | 642 | { |
655 | struct snd_soc_device *socdev = ssm2602_socdev; | 643 | struct snd_soc_device *socdev = ssm2602_socdev; |
656 | struct snd_soc_codec *codec = socdev->codec; | 644 | struct snd_soc_codec *codec = socdev->card->codec; |
657 | int ret; | 645 | int ret; |
658 | 646 | ||
659 | i2c_set_clientdata(i2c, codec); | 647 | i2c_set_clientdata(i2c, codec); |
@@ -747,7 +735,7 @@ static int ssm2602_probe(struct platform_device *pdev) | |||
747 | } | 735 | } |
748 | 736 | ||
749 | codec->private_data = ssm2602; | 737 | codec->private_data = ssm2602; |
750 | socdev->codec = codec; | 738 | socdev->card->codec = codec; |
751 | mutex_init(&codec->mutex); | 739 | mutex_init(&codec->mutex); |
752 | INIT_LIST_HEAD(&codec->dapm_widgets); | 740 | INIT_LIST_HEAD(&codec->dapm_widgets); |
753 | INIT_LIST_HEAD(&codec->dapm_paths); | 741 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -768,7 +756,7 @@ static int ssm2602_probe(struct platform_device *pdev) | |||
768 | static int ssm2602_remove(struct platform_device *pdev) | 756 | static int ssm2602_remove(struct platform_device *pdev) |
769 | { | 757 | { |
770 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 758 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
771 | struct snd_soc_codec *codec = socdev->codec; | 759 | struct snd_soc_codec *codec = socdev->card->codec; |
772 | 760 | ||
773 | if (codec->control_data) | 761 | if (codec->control_data) |
774 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | 762 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); |
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index cfdea007c4cb..c3f4afb5d017 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -183,24 +183,6 @@ static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = { | |||
183 | SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph), | 183 | SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph), |
184 | }; | 184 | }; |
185 | 185 | ||
186 | /* add non dapm controls */ | ||
187 | static int tlv320aic23_add_controls(struct snd_soc_codec *codec) | ||
188 | { | ||
189 | |||
190 | int err, i; | ||
191 | |||
192 | for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) { | ||
193 | err = snd_ctl_add(codec->card, | ||
194 | snd_soc_cnew(&tlv320aic23_snd_controls[i], | ||
195 | codec, NULL)); | ||
196 | if (err < 0) | ||
197 | return err; | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | |||
202 | } | ||
203 | |||
204 | /* PGA Mixer controls for Line and Mic switch */ | 186 | /* PGA Mixer controls for Line and Mic switch */ |
205 | static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = { | 187 | static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = { |
206 | SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0), | 188 | SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0), |
@@ -423,7 +405,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, | |||
423 | { | 405 | { |
424 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 406 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
425 | struct snd_soc_device *socdev = rtd->socdev; | 407 | struct snd_soc_device *socdev = rtd->socdev; |
426 | struct snd_soc_codec *codec = socdev->codec; | 408 | struct snd_soc_codec *codec = socdev->card->codec; |
427 | u16 iface_reg; | 409 | u16 iface_reg; |
428 | int ret; | 410 | int ret; |
429 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | 411 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); |
@@ -471,7 +453,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream, | |||
471 | { | 453 | { |
472 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 454 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
473 | struct snd_soc_device *socdev = rtd->socdev; | 455 | struct snd_soc_device *socdev = rtd->socdev; |
474 | struct snd_soc_codec *codec = socdev->codec; | 456 | struct snd_soc_codec *codec = socdev->card->codec; |
475 | 457 | ||
476 | /* set active */ | 458 | /* set active */ |
477 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001); | 459 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001); |
@@ -484,7 +466,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, | |||
484 | { | 466 | { |
485 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 467 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
486 | struct snd_soc_device *socdev = rtd->socdev; | 468 | struct snd_soc_device *socdev = rtd->socdev; |
487 | struct snd_soc_codec *codec = socdev->codec; | 469 | struct snd_soc_codec *codec = socdev->card->codec; |
488 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | 470 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); |
489 | 471 | ||
490 | /* deactivate */ | 472 | /* deactivate */ |
@@ -598,6 +580,15 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, | |||
598 | #define AIC23_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | 580 | #define AIC23_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
599 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 581 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
600 | 582 | ||
583 | static struct snd_soc_dai_ops tlv320aic23_dai_ops = { | ||
584 | .prepare = tlv320aic23_pcm_prepare, | ||
585 | .hw_params = tlv320aic23_hw_params, | ||
586 | .shutdown = tlv320aic23_shutdown, | ||
587 | .digital_mute = tlv320aic23_mute, | ||
588 | .set_fmt = tlv320aic23_set_dai_fmt, | ||
589 | .set_sysclk = tlv320aic23_set_dai_sysclk, | ||
590 | }; | ||
591 | |||
601 | struct snd_soc_dai tlv320aic23_dai = { | 592 | struct snd_soc_dai tlv320aic23_dai = { |
602 | .name = "tlv320aic23", | 593 | .name = "tlv320aic23", |
603 | .playback = { | 594 | .playback = { |
@@ -612,14 +603,7 @@ struct snd_soc_dai tlv320aic23_dai = { | |||
612 | .channels_max = 2, | 603 | .channels_max = 2, |
613 | .rates = AIC23_RATES, | 604 | .rates = AIC23_RATES, |
614 | .formats = AIC23_FORMATS,}, | 605 | .formats = AIC23_FORMATS,}, |
615 | .ops = { | 606 | .ops = &tlv320aic23_dai_ops, |
616 | .prepare = tlv320aic23_pcm_prepare, | ||
617 | .hw_params = tlv320aic23_hw_params, | ||
618 | .shutdown = tlv320aic23_shutdown, | ||
619 | .digital_mute = tlv320aic23_mute, | ||
620 | .set_fmt = tlv320aic23_set_dai_fmt, | ||
621 | .set_sysclk = tlv320aic23_set_dai_sysclk, | ||
622 | } | ||
623 | }; | 607 | }; |
624 | EXPORT_SYMBOL_GPL(tlv320aic23_dai); | 608 | EXPORT_SYMBOL_GPL(tlv320aic23_dai); |
625 | 609 | ||
@@ -627,7 +611,7 @@ static int tlv320aic23_suspend(struct platform_device *pdev, | |||
627 | pm_message_t state) | 611 | pm_message_t state) |
628 | { | 612 | { |
629 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 613 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
630 | struct snd_soc_codec *codec = socdev->codec; | 614 | struct snd_soc_codec *codec = socdev->card->codec; |
631 | 615 | ||
632 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); | 616 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); |
633 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | 617 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); |
@@ -638,7 +622,7 @@ static int tlv320aic23_suspend(struct platform_device *pdev, | |||
638 | static int tlv320aic23_resume(struct platform_device *pdev) | 622 | static int tlv320aic23_resume(struct platform_device *pdev) |
639 | { | 623 | { |
640 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 624 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
641 | struct snd_soc_codec *codec = socdev->codec; | 625 | struct snd_soc_codec *codec = socdev->card->codec; |
642 | int i; | 626 | int i; |
643 | u16 reg; | 627 | u16 reg; |
644 | 628 | ||
@@ -660,7 +644,7 @@ static int tlv320aic23_resume(struct platform_device *pdev) | |||
660 | */ | 644 | */ |
661 | static int tlv320aic23_init(struct snd_soc_device *socdev) | 645 | static int tlv320aic23_init(struct snd_soc_device *socdev) |
662 | { | 646 | { |
663 | struct snd_soc_codec *codec = socdev->codec; | 647 | struct snd_soc_codec *codec = socdev->card->codec; |
664 | int ret = 0; | 648 | int ret = 0; |
665 | u16 reg; | 649 | u16 reg; |
666 | 650 | ||
@@ -718,7 +702,8 @@ static int tlv320aic23_init(struct snd_soc_device *socdev) | |||
718 | 702 | ||
719 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1); | 703 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1); |
720 | 704 | ||
721 | tlv320aic23_add_controls(codec); | 705 | snd_soc_add_controls(codec, tlv320aic23_snd_controls, |
706 | ARRAY_SIZE(tlv320aic23_snd_controls)); | ||
722 | tlv320aic23_add_widgets(codec); | 707 | tlv320aic23_add_widgets(codec); |
723 | ret = snd_soc_init_card(socdev); | 708 | ret = snd_soc_init_card(socdev); |
724 | if (ret < 0) { | 709 | if (ret < 0) { |
@@ -746,7 +731,7 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c, | |||
746 | const struct i2c_device_id *i2c_id) | 731 | const struct i2c_device_id *i2c_id) |
747 | { | 732 | { |
748 | struct snd_soc_device *socdev = tlv320aic23_socdev; | 733 | struct snd_soc_device *socdev = tlv320aic23_socdev; |
749 | struct snd_soc_codec *codec = socdev->codec; | 734 | struct snd_soc_codec *codec = socdev->card->codec; |
750 | int ret; | 735 | int ret; |
751 | 736 | ||
752 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 737 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
@@ -804,7 +789,7 @@ static int tlv320aic23_probe(struct platform_device *pdev) | |||
804 | if (aic23 == NULL) | 789 | if (aic23 == NULL) |
805 | return -ENOMEM; | 790 | return -ENOMEM; |
806 | codec = &aic23->codec; | 791 | codec = &aic23->codec; |
807 | socdev->codec = codec; | 792 | socdev->card->codec = codec; |
808 | mutex_init(&codec->mutex); | 793 | mutex_init(&codec->mutex); |
809 | INIT_LIST_HEAD(&codec->dapm_widgets); | 794 | INIT_LIST_HEAD(&codec->dapm_widgets); |
810 | INIT_LIST_HEAD(&codec->dapm_paths); | 795 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -823,7 +808,7 @@ static int tlv320aic23_probe(struct platform_device *pdev) | |||
823 | static int tlv320aic23_remove(struct platform_device *pdev) | 808 | static int tlv320aic23_remove(struct platform_device *pdev) |
824 | { | 809 | { |
825 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 810 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
826 | struct snd_soc_codec *codec = socdev->codec; | 811 | struct snd_soc_codec *codec = socdev->card->codec; |
827 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | 812 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); |
828 | 813 | ||
829 | if (codec->control_data) | 814 | if (codec->control_data) |
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 29f2f1a017fd..3387d9e736ea 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c | |||
@@ -130,7 +130,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream, | |||
130 | { | 130 | { |
131 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 131 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
132 | struct snd_soc_device *socdev = rtd->socdev; | 132 | struct snd_soc_device *socdev = rtd->socdev; |
133 | struct snd_soc_codec *codec = socdev->codec; | 133 | struct snd_soc_codec *codec = socdev->card->codec; |
134 | struct aic26 *aic26 = codec->private_data; | 134 | struct aic26 *aic26 = codec->private_data; |
135 | int fsref, divisor, wlen, pval, jval, dval, qval; | 135 | int fsref, divisor, wlen, pval, jval, dval, qval; |
136 | u16 reg; | 136 | u16 reg; |
@@ -270,6 +270,13 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
270 | #define AIC26_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\ | 270 | #define AIC26_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\ |
271 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE) | 271 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE) |
272 | 272 | ||
273 | static struct snd_soc_dai_ops aic26_dai_ops = { | ||
274 | .hw_params = aic26_hw_params, | ||
275 | .digital_mute = aic26_mute, | ||
276 | .set_sysclk = aic26_set_sysclk, | ||
277 | .set_fmt = aic26_set_fmt, | ||
278 | }; | ||
279 | |||
273 | struct snd_soc_dai aic26_dai = { | 280 | struct snd_soc_dai aic26_dai = { |
274 | .name = "tlv320aic26", | 281 | .name = "tlv320aic26", |
275 | .playback = { | 282 | .playback = { |
@@ -286,12 +293,7 @@ struct snd_soc_dai aic26_dai = { | |||
286 | .rates = AIC26_RATES, | 293 | .rates = AIC26_RATES, |
287 | .formats = AIC26_FORMATS, | 294 | .formats = AIC26_FORMATS, |
288 | }, | 295 | }, |
289 | .ops = { | 296 | .ops = &aic26_dai_ops, |
290 | .hw_params = aic26_hw_params, | ||
291 | .digital_mute = aic26_mute, | ||
292 | .set_sysclk = aic26_set_sysclk, | ||
293 | .set_fmt = aic26_set_fmt, | ||
294 | }, | ||
295 | }; | 297 | }; |
296 | EXPORT_SYMBOL_GPL(aic26_dai); | 298 | EXPORT_SYMBOL_GPL(aic26_dai); |
297 | 299 | ||
@@ -322,9 +324,8 @@ static int aic26_probe(struct platform_device *pdev) | |||
322 | { | 324 | { |
323 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 325 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
324 | struct snd_soc_codec *codec; | 326 | struct snd_soc_codec *codec; |
325 | struct snd_kcontrol *kcontrol; | ||
326 | struct aic26 *aic26; | 327 | struct aic26 *aic26; |
327 | int i, ret, err; | 328 | int ret, err; |
328 | 329 | ||
329 | dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n"); | 330 | dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n"); |
330 | dev_dbg(&pdev->dev, "socdev=%p\n", socdev); | 331 | dev_dbg(&pdev->dev, "socdev=%p\n", socdev); |
@@ -338,7 +339,7 @@ static int aic26_probe(struct platform_device *pdev) | |||
338 | return -ENODEV; | 339 | return -ENODEV; |
339 | } | 340 | } |
340 | codec = &aic26->codec; | 341 | codec = &aic26->codec; |
341 | socdev->codec = codec; | 342 | socdev->card->codec = codec; |
342 | 343 | ||
343 | dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n", | 344 | dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n", |
344 | &pdev->dev, socdev->dev); | 345 | &pdev->dev, socdev->dev); |
@@ -351,11 +352,9 @@ static int aic26_probe(struct platform_device *pdev) | |||
351 | 352 | ||
352 | /* register controls */ | 353 | /* register controls */ |
353 | dev_dbg(&pdev->dev, "Registering controls\n"); | 354 | dev_dbg(&pdev->dev, "Registering controls\n"); |
354 | for (i = 0; i < ARRAY_SIZE(aic26_snd_controls); i++) { | 355 | err = snd_soc_add_controls(codec, aic26_snd_controls, |
355 | kcontrol = snd_soc_cnew(&aic26_snd_controls[i], codec, NULL); | 356 | ARRAY_SIZE(aic26_snd_controls)); |
356 | err = snd_ctl_add(codec->card, kcontrol); | 357 | WARN_ON(err < 0); |
357 | WARN_ON(err < 0); | ||
358 | } | ||
359 | 358 | ||
360 | /* CODEC is setup, we can register the card now */ | 359 | /* CODEC is setup, we can register the card now */ |
361 | dev_dbg(&pdev->dev, "Registering card\n"); | 360 | dev_dbg(&pdev->dev, "Registering card\n"); |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index aea0cb72d80a..ab099f482487 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <sound/soc.h> | 45 | #include <sound/soc.h> |
46 | #include <sound/soc-dapm.h> | 46 | #include <sound/soc-dapm.h> |
47 | #include <sound/initval.h> | 47 | #include <sound/initval.h> |
48 | #include <sound/tlv.h> | ||
48 | 49 | ||
49 | #include "tlv320aic3x.h" | 50 | #include "tlv320aic3x.h" |
50 | 51 | ||
@@ -250,56 +251,86 @@ static const struct soc_enum aic3x_enum[] = { | |||
250 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), | 251 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), |
251 | }; | 252 | }; |
252 | 253 | ||
254 | /* | ||
255 | * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps | ||
256 | */ | ||
257 | static DECLARE_TLV_DB_SCALE(dac_tlv, -6350, 50, 0); | ||
258 | /* ADC PGA gain volumes. From 0 to 59.5 dB in 0.5 dB steps */ | ||
259 | static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 50, 0); | ||
260 | /* | ||
261 | * Output stage volumes. From -78.3 to 0 dB. Muted below -78.3 dB. | ||
262 | * Step size is approximately 0.5 dB over most of the scale but increasing | ||
263 | * near the very low levels. | ||
264 | * Define dB scale so that it is mostly correct for range about -55 to 0 dB | ||
265 | * but having increasing dB difference below that (and where it doesn't count | ||
266 | * so much). This setting shows -50 dB (actual is -50.3 dB) for register | ||
267 | * value 100 and -58.5 dB (actual is -78.3 dB) for register value 117. | ||
268 | */ | ||
269 | static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1); | ||
270 | |||
253 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { | 271 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { |
254 | /* Output */ | 272 | /* Output */ |
255 | SOC_DOUBLE_R("PCM Playback Volume", LDAC_VOL, RDAC_VOL, 0, 0x7f, 1), | 273 | SOC_DOUBLE_R_TLV("PCM Playback Volume", |
274 | LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv), | ||
256 | 275 | ||
257 | SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL, | 276 | SOC_DOUBLE_R_TLV("Line DAC Playback Volume", |
258 | DACR1_2_RLOPM_VOL, 0, 0x7f, 1), | 277 | DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, |
278 | 0, 118, 1, output_stage_tlv), | ||
259 | SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0), | 279 | SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0), |
260 | SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0), | 280 | SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0), |
261 | SOC_DOUBLE_R("LineL DAC Playback Volume", DACL1_2_LLOPM_VOL, | 281 | SOC_DOUBLE_R_TLV("LineL DAC Playback Volume", |
262 | DACR1_2_LLOPM_VOL, 0, 0x7f, 1), | 282 | DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL, |
263 | SOC_SINGLE("LineL Left PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, | 283 | 0, 118, 1, output_stage_tlv), |
264 | 0, 0x7f, 1), | 284 | SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume", |
265 | SOC_SINGLE("LineR Right PGA Bypass Playback Volume", PGAR_2_RLOPM_VOL, | 285 | PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), |
266 | 0, 0x7f, 1), | 286 | SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume", |
267 | SOC_DOUBLE_R("LineL Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, | 287 | PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), |
268 | LINE2R_2_LLOPM_VOL, 0, 0x7f, 1), | 288 | SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume", |
269 | SOC_DOUBLE_R("LineR Line2 Bypass Playback Volume", LINE2L_2_RLOPM_VOL, | 289 | LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL, |
270 | LINE2R_2_RLOPM_VOL, 0, 0x7f, 1), | 290 | 0, 118, 1, output_stage_tlv), |
271 | 291 | SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume", | |
272 | SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL, | 292 | LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL, |
273 | DACR1_2_MONOLOPM_VOL, 0, 0x7f, 1), | 293 | 0, 118, 1, output_stage_tlv), |
294 | |||
295 | SOC_DOUBLE_R_TLV("Mono DAC Playback Volume", | ||
296 | DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL, | ||
297 | 0, 118, 1, output_stage_tlv), | ||
274 | SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), | 298 | SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), |
275 | SOC_DOUBLE_R("Mono PGA Bypass Playback Volume", PGAL_2_MONOLOPM_VOL, | 299 | SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume", |
276 | PGAR_2_MONOLOPM_VOL, 0, 0x7f, 1), | 300 | PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL, |
277 | SOC_DOUBLE_R("Mono Line2 Bypass Playback Volume", LINE2L_2_MONOLOPM_VOL, | 301 | 0, 118, 1, output_stage_tlv), |
278 | LINE2R_2_MONOLOPM_VOL, 0, 0x7f, 1), | 302 | SOC_DOUBLE_R_TLV("Mono Line2 Bypass Playback Volume", |
279 | 303 | LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL, | |
280 | SOC_DOUBLE_R("HP DAC Playback Volume", DACL1_2_HPLOUT_VOL, | 304 | 0, 118, 1, output_stage_tlv), |
281 | DACR1_2_HPROUT_VOL, 0, 0x7f, 1), | 305 | |
306 | SOC_DOUBLE_R_TLV("HP DAC Playback Volume", | ||
307 | DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL, | ||
308 | 0, 118, 1, output_stage_tlv), | ||
282 | SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, | 309 | SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, |
283 | 0x01, 0), | 310 | 0x01, 0), |
284 | SOC_DOUBLE_R("HP Right PGA Bypass Playback Volume", PGAR_2_HPLOUT_VOL, | 311 | SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume", |
285 | PGAR_2_HPROUT_VOL, 0, 0x7f, 1), | 312 | PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL, |
286 | SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, | 313 | 0, 118, 1, output_stage_tlv), |
287 | 0, 0x7f, 1), | 314 | SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume", |
288 | SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL, | 315 | PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), |
289 | 0, 0x7f, 1), | 316 | SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume", |
290 | SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL, | 317 | PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), |
291 | LINE2R_2_HPROUT_VOL, 0, 0x7f, 1), | 318 | SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume", |
292 | 319 | LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, | |
293 | SOC_DOUBLE_R("HPCOM DAC Playback Volume", DACL1_2_HPLCOM_VOL, | 320 | 0, 118, 1, output_stage_tlv), |
294 | DACR1_2_HPRCOM_VOL, 0, 0x7f, 1), | 321 | |
322 | SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume", | ||
323 | DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL, | ||
324 | 0, 118, 1, output_stage_tlv), | ||
295 | SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, | 325 | SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, |
296 | 0x01, 0), | 326 | 0x01, 0), |
297 | SOC_SINGLE("HPLCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, | 327 | SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume", |
298 | 0, 0x7f, 1), | 328 | PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), |
299 | SOC_SINGLE("HPRCOM PGA Bypass Playback Volume", PGAL_2_HPRCOM_VOL, | 329 | SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume", |
300 | 0, 0x7f, 1), | 330 | PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), |
301 | SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL, | 331 | SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume", |
302 | LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1), | 332 | LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, |
333 | 0, 118, 1, output_stage_tlv), | ||
303 | 334 | ||
304 | /* | 335 | /* |
305 | * Note: enable Automatic input Gain Controller with care. It can | 336 | * Note: enable Automatic input Gain Controller with care. It can |
@@ -308,28 +339,13 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
308 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), | 339 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), |
309 | 340 | ||
310 | /* Input */ | 341 | /* Input */ |
311 | SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0), | 342 | SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL, |
343 | 0, 119, 0, adc_tlv), | ||
312 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), | 344 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), |
313 | 345 | ||
314 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | 346 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), |
315 | }; | 347 | }; |
316 | 348 | ||
317 | /* add non dapm controls */ | ||
318 | static int aic3x_add_controls(struct snd_soc_codec *codec) | ||
319 | { | ||
320 | int err, i; | ||
321 | |||
322 | for (i = 0; i < ARRAY_SIZE(aic3x_snd_controls); i++) { | ||
323 | err = snd_ctl_add(codec->card, | ||
324 | snd_soc_cnew(&aic3x_snd_controls[i], | ||
325 | codec, NULL)); | ||
326 | if (err < 0) | ||
327 | return err; | ||
328 | } | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /* Left DAC Mux */ | 349 | /* Left DAC Mux */ |
334 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = | 350 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = |
335 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); | 351 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); |
@@ -746,7 +762,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
746 | { | 762 | { |
747 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 763 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
748 | struct snd_soc_device *socdev = rtd->socdev; | 764 | struct snd_soc_device *socdev = rtd->socdev; |
749 | struct snd_soc_codec *codec = socdev->codec; | 765 | struct snd_soc_codec *codec = socdev->card->codec; |
750 | struct aic3x_priv *aic3x = codec->private_data; | 766 | struct aic3x_priv *aic3x = codec->private_data; |
751 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; | 767 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; |
752 | u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; | 768 | u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; |
@@ -1072,6 +1088,13 @@ EXPORT_SYMBOL_GPL(aic3x_button_pressed); | |||
1072 | #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | 1088 | #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
1073 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 1089 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
1074 | 1090 | ||
1091 | static struct snd_soc_dai_ops aic3x_dai_ops = { | ||
1092 | .hw_params = aic3x_hw_params, | ||
1093 | .digital_mute = aic3x_mute, | ||
1094 | .set_sysclk = aic3x_set_dai_sysclk, | ||
1095 | .set_fmt = aic3x_set_dai_fmt, | ||
1096 | }; | ||
1097 | |||
1075 | struct snd_soc_dai aic3x_dai = { | 1098 | struct snd_soc_dai aic3x_dai = { |
1076 | .name = "tlv320aic3x", | 1099 | .name = "tlv320aic3x", |
1077 | .playback = { | 1100 | .playback = { |
@@ -1086,19 +1109,14 @@ struct snd_soc_dai aic3x_dai = { | |||
1086 | .channels_max = 2, | 1109 | .channels_max = 2, |
1087 | .rates = AIC3X_RATES, | 1110 | .rates = AIC3X_RATES, |
1088 | .formats = AIC3X_FORMATS,}, | 1111 | .formats = AIC3X_FORMATS,}, |
1089 | .ops = { | 1112 | .ops = &aic3x_dai_ops, |
1090 | .hw_params = aic3x_hw_params, | ||
1091 | .digital_mute = aic3x_mute, | ||
1092 | .set_sysclk = aic3x_set_dai_sysclk, | ||
1093 | .set_fmt = aic3x_set_dai_fmt, | ||
1094 | } | ||
1095 | }; | 1113 | }; |
1096 | EXPORT_SYMBOL_GPL(aic3x_dai); | 1114 | EXPORT_SYMBOL_GPL(aic3x_dai); |
1097 | 1115 | ||
1098 | static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) | 1116 | static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) |
1099 | { | 1117 | { |
1100 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1118 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1101 | struct snd_soc_codec *codec = socdev->codec; | 1119 | struct snd_soc_codec *codec = socdev->card->codec; |
1102 | 1120 | ||
1103 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1121 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1104 | 1122 | ||
@@ -1108,7 +1126,7 @@ static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) | |||
1108 | static int aic3x_resume(struct platform_device *pdev) | 1126 | static int aic3x_resume(struct platform_device *pdev) |
1109 | { | 1127 | { |
1110 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1128 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1111 | struct snd_soc_codec *codec = socdev->codec; | 1129 | struct snd_soc_codec *codec = socdev->card->codec; |
1112 | int i; | 1130 | int i; |
1113 | u8 data[2]; | 1131 | u8 data[2]; |
1114 | u8 *cache = codec->reg_cache; | 1132 | u8 *cache = codec->reg_cache; |
@@ -1131,7 +1149,7 @@ static int aic3x_resume(struct platform_device *pdev) | |||
1131 | */ | 1149 | */ |
1132 | static int aic3x_init(struct snd_soc_device *socdev) | 1150 | static int aic3x_init(struct snd_soc_device *socdev) |
1133 | { | 1151 | { |
1134 | struct snd_soc_codec *codec = socdev->codec; | 1152 | struct snd_soc_codec *codec = socdev->card->codec; |
1135 | struct aic3x_setup_data *setup = socdev->codec_data; | 1153 | struct aic3x_setup_data *setup = socdev->codec_data; |
1136 | int reg, ret = 0; | 1154 | int reg, ret = 0; |
1137 | 1155 | ||
@@ -1227,7 +1245,8 @@ static int aic3x_init(struct snd_soc_device *socdev) | |||
1227 | aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); | 1245 | aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); |
1228 | aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); | 1246 | aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); |
1229 | 1247 | ||
1230 | aic3x_add_controls(codec); | 1248 | snd_soc_add_controls(codec, aic3x_snd_controls, |
1249 | ARRAY_SIZE(aic3x_snd_controls)); | ||
1231 | aic3x_add_widgets(codec); | 1250 | aic3x_add_widgets(codec); |
1232 | ret = snd_soc_init_card(socdev); | 1251 | ret = snd_soc_init_card(socdev); |
1233 | if (ret < 0) { | 1252 | if (ret < 0) { |
@@ -1261,7 +1280,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
1261 | const struct i2c_device_id *id) | 1280 | const struct i2c_device_id *id) |
1262 | { | 1281 | { |
1263 | struct snd_soc_device *socdev = aic3x_socdev; | 1282 | struct snd_soc_device *socdev = aic3x_socdev; |
1264 | struct snd_soc_codec *codec = socdev->codec; | 1283 | struct snd_soc_codec *codec = socdev->card->codec; |
1265 | int ret; | 1284 | int ret; |
1266 | 1285 | ||
1267 | i2c_set_clientdata(i2c, codec); | 1286 | i2c_set_clientdata(i2c, codec); |
@@ -1366,7 +1385,7 @@ static int aic3x_probe(struct platform_device *pdev) | |||
1366 | } | 1385 | } |
1367 | 1386 | ||
1368 | codec->private_data = aic3x; | 1387 | codec->private_data = aic3x; |
1369 | socdev->codec = codec; | 1388 | socdev->card->codec = codec; |
1370 | mutex_init(&codec->mutex); | 1389 | mutex_init(&codec->mutex); |
1371 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1390 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1372 | INIT_LIST_HEAD(&codec->dapm_paths); | 1391 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -1392,7 +1411,7 @@ static int aic3x_probe(struct platform_device *pdev) | |||
1392 | static int aic3x_remove(struct platform_device *pdev) | 1411 | static int aic3x_remove(struct platform_device *pdev) |
1393 | { | 1412 | { |
1394 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1413 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1395 | struct snd_soc_codec *codec = socdev->codec; | 1414 | struct snd_soc_codec *codec = socdev->card->codec; |
1396 | 1415 | ||
1397 | /* power down chip */ | 1416 | /* power down chip */ |
1398 | if (codec->control_data) | 1417 | if (codec->control_data) |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index ea370a4f86d5..97738e2ece04 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -42,7 +42,7 @@ | |||
42 | */ | 42 | */ |
43 | static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | 43 | static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { |
44 | 0x00, /* this register not used */ | 44 | 0x00, /* this register not used */ |
45 | 0x93, /* REG_CODEC_MODE (0x1) */ | 45 | 0x91, /* REG_CODEC_MODE (0x1) */ |
46 | 0xc3, /* REG_OPTION (0x2) */ | 46 | 0xc3, /* REG_OPTION (0x2) */ |
47 | 0x00, /* REG_UNKNOWN (0x3) */ | 47 | 0x00, /* REG_UNKNOWN (0x3) */ |
48 | 0x00, /* REG_MICBIAS_CTL (0x4) */ | 48 | 0x00, /* REG_MICBIAS_CTL (0x4) */ |
@@ -117,6 +117,13 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | |||
117 | 0x00, /* REG_MISC_SET_2 (0x49) */ | 117 | 0x00, /* REG_MISC_SET_2 (0x49) */ |
118 | }; | 118 | }; |
119 | 119 | ||
120 | /* codec private data */ | ||
121 | struct twl4030_priv { | ||
122 | unsigned int bypass_state; | ||
123 | unsigned int codec_powered; | ||
124 | unsigned int codec_muted; | ||
125 | }; | ||
126 | |||
120 | /* | 127 | /* |
121 | * read twl4030 register cache | 128 | * read twl4030 register cache |
122 | */ | 129 | */ |
@@ -125,6 +132,9 @@ static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec, | |||
125 | { | 132 | { |
126 | u8 *cache = codec->reg_cache; | 133 | u8 *cache = codec->reg_cache; |
127 | 134 | ||
135 | if (reg >= TWL4030_CACHEREGNUM) | ||
136 | return -EIO; | ||
137 | |||
128 | return cache[reg]; | 138 | return cache[reg]; |
129 | } | 139 | } |
130 | 140 | ||
@@ -151,26 +161,22 @@ static int twl4030_write(struct snd_soc_codec *codec, | |||
151 | return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); | 161 | return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); |
152 | } | 162 | } |
153 | 163 | ||
154 | static void twl4030_clear_codecpdz(struct snd_soc_codec *codec) | 164 | static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) |
155 | { | 165 | { |
166 | struct twl4030_priv *twl4030 = codec->private_data; | ||
156 | u8 mode; | 167 | u8 mode; |
157 | 168 | ||
158 | mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); | 169 | if (enable == twl4030->codec_powered) |
159 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, | 170 | return; |
160 | mode & ~TWL4030_CODECPDZ); | ||
161 | |||
162 | /* REVISIT: this delay is present in TI sample drivers */ | ||
163 | /* but there seems to be no TRM requirement for it */ | ||
164 | udelay(10); | ||
165 | } | ||
166 | |||
167 | static void twl4030_set_codecpdz(struct snd_soc_codec *codec) | ||
168 | { | ||
169 | u8 mode; | ||
170 | 171 | ||
171 | mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); | 172 | mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); |
172 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, | 173 | if (enable) |
173 | mode | TWL4030_CODECPDZ); | 174 | mode |= TWL4030_CODECPDZ; |
175 | else | ||
176 | mode &= ~TWL4030_CODECPDZ; | ||
177 | |||
178 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | ||
179 | twl4030->codec_powered = enable; | ||
174 | 180 | ||
175 | /* REVISIT: this delay is present in TI sample drivers */ | 181 | /* REVISIT: this delay is present in TI sample drivers */ |
176 | /* but there seems to be no TRM requirement for it */ | 182 | /* but there seems to be no TRM requirement for it */ |
@@ -182,7 +188,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) | |||
182 | int i; | 188 | int i; |
183 | 189 | ||
184 | /* clear CODECPDZ prior to setting register defaults */ | 190 | /* clear CODECPDZ prior to setting register defaults */ |
185 | twl4030_clear_codecpdz(codec); | 191 | twl4030_codec_enable(codec, 0); |
186 | 192 | ||
187 | /* set all audio section registers to reasonable defaults */ | 193 | /* set all audio section registers to reasonable defaults */ |
188 | for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) | 194 | for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) |
@@ -190,6 +196,122 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) | |||
190 | 196 | ||
191 | } | 197 | } |
192 | 198 | ||
199 | static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute) | ||
200 | { | ||
201 | struct twl4030_priv *twl4030 = codec->private_data; | ||
202 | u8 reg_val; | ||
203 | |||
204 | if (mute == twl4030->codec_muted) | ||
205 | return; | ||
206 | |||
207 | if (mute) { | ||
208 | /* Bypass the reg_cache and mute the volumes | ||
209 | * Headset mute is done in it's own event handler | ||
210 | * Things to mute: Earpiece, PreDrivL/R, CarkitL/R | ||
211 | */ | ||
212 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL); | ||
213 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
214 | reg_val & (~TWL4030_EAR_GAIN), | ||
215 | TWL4030_REG_EAR_CTL); | ||
216 | |||
217 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL); | ||
218 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
219 | reg_val & (~TWL4030_PREDL_GAIN), | ||
220 | TWL4030_REG_PREDL_CTL); | ||
221 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL); | ||
222 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
223 | reg_val & (~TWL4030_PREDR_GAIN), | ||
224 | TWL4030_REG_PREDL_CTL); | ||
225 | |||
226 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL); | ||
227 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
228 | reg_val & (~TWL4030_PRECKL_GAIN), | ||
229 | TWL4030_REG_PRECKL_CTL); | ||
230 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL); | ||
231 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
232 | reg_val & (~TWL4030_PRECKL_GAIN), | ||
233 | TWL4030_REG_PRECKR_CTL); | ||
234 | |||
235 | /* Disable PLL */ | ||
236 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); | ||
237 | reg_val &= ~TWL4030_APLL_EN; | ||
238 | twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val); | ||
239 | } else { | ||
240 | /* Restore the volumes | ||
241 | * Headset mute is done in it's own event handler | ||
242 | * Things to restore: Earpiece, PreDrivL/R, CarkitL/R | ||
243 | */ | ||
244 | twl4030_write(codec, TWL4030_REG_EAR_CTL, | ||
245 | twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL)); | ||
246 | |||
247 | twl4030_write(codec, TWL4030_REG_PREDL_CTL, | ||
248 | twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL)); | ||
249 | twl4030_write(codec, TWL4030_REG_PREDR_CTL, | ||
250 | twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL)); | ||
251 | |||
252 | twl4030_write(codec, TWL4030_REG_PRECKL_CTL, | ||
253 | twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL)); | ||
254 | twl4030_write(codec, TWL4030_REG_PRECKR_CTL, | ||
255 | twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL)); | ||
256 | |||
257 | /* Enable PLL */ | ||
258 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); | ||
259 | reg_val |= TWL4030_APLL_EN; | ||
260 | twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val); | ||
261 | } | ||
262 | |||
263 | twl4030->codec_muted = mute; | ||
264 | } | ||
265 | |||
266 | static void twl4030_power_up(struct snd_soc_codec *codec) | ||
267 | { | ||
268 | struct twl4030_priv *twl4030 = codec->private_data; | ||
269 | u8 anamicl, regmisc1, byte; | ||
270 | int i = 0; | ||
271 | |||
272 | if (twl4030->codec_powered) | ||
273 | return; | ||
274 | |||
275 | /* set CODECPDZ to turn on codec */ | ||
276 | twl4030_codec_enable(codec, 1); | ||
277 | |||
278 | /* initiate offset cancellation */ | ||
279 | anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); | ||
280 | twl4030_write(codec, TWL4030_REG_ANAMICL, | ||
281 | anamicl | TWL4030_CNCL_OFFSET_START); | ||
282 | |||
283 | /* wait for offset cancellation to complete */ | ||
284 | do { | ||
285 | /* this takes a little while, so don't slam i2c */ | ||
286 | udelay(2000); | ||
287 | twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, | ||
288 | TWL4030_REG_ANAMICL); | ||
289 | } while ((i++ < 100) && | ||
290 | ((byte & TWL4030_CNCL_OFFSET_START) == | ||
291 | TWL4030_CNCL_OFFSET_START)); | ||
292 | |||
293 | /* Make sure that the reg_cache has the same value as the HW */ | ||
294 | twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); | ||
295 | |||
296 | /* anti-pop when changing analog gain */ | ||
297 | regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); | ||
298 | twl4030_write(codec, TWL4030_REG_MISC_SET_1, | ||
299 | regmisc1 | TWL4030_SMOOTH_ANAVOL_EN); | ||
300 | |||
301 | /* toggle CODECPDZ as per TRM */ | ||
302 | twl4030_codec_enable(codec, 0); | ||
303 | twl4030_codec_enable(codec, 1); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * Unconditional power down | ||
308 | */ | ||
309 | static void twl4030_power_down(struct snd_soc_codec *codec) | ||
310 | { | ||
311 | /* power down */ | ||
312 | twl4030_codec_enable(codec, 0); | ||
313 | } | ||
314 | |||
193 | /* Earpiece */ | 315 | /* Earpiece */ |
194 | static const char *twl4030_earpiece_texts[] = | 316 | static const char *twl4030_earpiece_texts[] = |
195 | {"Off", "DACL1", "DACL2", "DACR1"}; | 317 | {"Off", "DACL1", "DACL2", "DACR1"}; |
@@ -366,6 +488,41 @@ static const struct soc_enum twl4030_micpathtx2_enum = | |||
366 | static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = | 488 | static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = |
367 | SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); | 489 | SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); |
368 | 490 | ||
491 | /* Analog bypass for AudioR1 */ | ||
492 | static const struct snd_kcontrol_new twl4030_dapm_abypassr1_control = | ||
493 | SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXR1_APGA_CTL, 2, 1, 0); | ||
494 | |||
495 | /* Analog bypass for AudioL1 */ | ||
496 | static const struct snd_kcontrol_new twl4030_dapm_abypassl1_control = | ||
497 | SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL1_APGA_CTL, 2, 1, 0); | ||
498 | |||
499 | /* Analog bypass for AudioR2 */ | ||
500 | static const struct snd_kcontrol_new twl4030_dapm_abypassr2_control = | ||
501 | SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXR2_APGA_CTL, 2, 1, 0); | ||
502 | |||
503 | /* Analog bypass for AudioL2 */ | ||
504 | static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control = | ||
505 | SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL2_APGA_CTL, 2, 1, 0); | ||
506 | |||
507 | /* Digital bypass gain, 0 mutes the bypass */ | ||
508 | static const unsigned int twl4030_dapm_dbypass_tlv[] = { | ||
509 | TLV_DB_RANGE_HEAD(2), | ||
510 | 0, 3, TLV_DB_SCALE_ITEM(-2400, 0, 1), | ||
511 | 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0), | ||
512 | }; | ||
513 | |||
514 | /* Digital bypass left (TX1L -> RX2L) */ | ||
515 | static const struct snd_kcontrol_new twl4030_dapm_dbypassl_control = | ||
516 | SOC_DAPM_SINGLE_TLV("Volume", | ||
517 | TWL4030_REG_ATX2ARXPGA, 3, 7, 0, | ||
518 | twl4030_dapm_dbypass_tlv); | ||
519 | |||
520 | /* Digital bypass right (TX1R -> RX2R) */ | ||
521 | static const struct snd_kcontrol_new twl4030_dapm_dbypassr_control = | ||
522 | SOC_DAPM_SINGLE_TLV("Volume", | ||
523 | TWL4030_REG_ATX2ARXPGA, 0, 7, 0, | ||
524 | twl4030_dapm_dbypass_tlv); | ||
525 | |||
369 | static int micpath_event(struct snd_soc_dapm_widget *w, | 526 | static int micpath_event(struct snd_soc_dapm_widget *w, |
370 | struct snd_kcontrol *kcontrol, int event) | 527 | struct snd_kcontrol *kcontrol, int event) |
371 | { | 528 | { |
@@ -420,6 +577,79 @@ static int handsfree_event(struct snd_soc_dapm_widget *w, | |||
420 | return 0; | 577 | return 0; |
421 | } | 578 | } |
422 | 579 | ||
580 | static int headsetl_event(struct snd_soc_dapm_widget *w, | ||
581 | struct snd_kcontrol *kcontrol, int event) | ||
582 | { | ||
583 | unsigned char hs_gain, hs_pop; | ||
584 | |||
585 | /* Save the current volume */ | ||
586 | hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET); | ||
587 | hs_pop = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_POPN_SET); | ||
588 | |||
589 | switch (event) { | ||
590 | case SND_SOC_DAPM_POST_PMU: | ||
591 | /* Do the anti-pop/bias ramp enable according to the TRM */ | ||
592 | hs_pop |= TWL4030_VMID_EN; | ||
593 | twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); | ||
594 | /* Is this needed? Can we just use whatever gain here? */ | ||
595 | twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, | ||
596 | (hs_gain & (~0x0f)) | 0x0a); | ||
597 | hs_pop |= TWL4030_RAMP_EN; | ||
598 | twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); | ||
599 | |||
600 | /* Restore the original volume */ | ||
601 | twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, hs_gain); | ||
602 | break; | ||
603 | case SND_SOC_DAPM_POST_PMD: | ||
604 | /* Do the anti-pop/bias ramp disable according to the TRM */ | ||
605 | hs_pop &= ~TWL4030_RAMP_EN; | ||
606 | twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); | ||
607 | /* Bypass the reg_cache to mute the headset */ | ||
608 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
609 | hs_gain & (~0x0f), | ||
610 | TWL4030_REG_HS_GAIN_SET); | ||
611 | hs_pop &= ~TWL4030_VMID_EN; | ||
612 | twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); | ||
613 | break; | ||
614 | } | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static int bypass_event(struct snd_soc_dapm_widget *w, | ||
619 | struct snd_kcontrol *kcontrol, int event) | ||
620 | { | ||
621 | struct soc_mixer_control *m = | ||
622 | (struct soc_mixer_control *)w->kcontrols->private_value; | ||
623 | struct twl4030_priv *twl4030 = w->codec->private_data; | ||
624 | unsigned char reg; | ||
625 | |||
626 | reg = twl4030_read_reg_cache(w->codec, m->reg); | ||
627 | |||
628 | if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) { | ||
629 | /* Analog bypass */ | ||
630 | if (reg & (1 << m->shift)) | ||
631 | twl4030->bypass_state |= | ||
632 | (1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL)); | ||
633 | else | ||
634 | twl4030->bypass_state &= | ||
635 | ~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL)); | ||
636 | } else { | ||
637 | /* Digital bypass */ | ||
638 | if (reg & (0x7 << m->shift)) | ||
639 | twl4030->bypass_state |= (1 << (m->shift ? 5 : 4)); | ||
640 | else | ||
641 | twl4030->bypass_state &= ~(1 << (m->shift ? 5 : 4)); | ||
642 | } | ||
643 | |||
644 | if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) { | ||
645 | if (twl4030->bypass_state) | ||
646 | twl4030_codec_mute(w->codec, 0); | ||
647 | else | ||
648 | twl4030_codec_mute(w->codec, 1); | ||
649 | } | ||
650 | return 0; | ||
651 | } | ||
652 | |||
423 | /* | 653 | /* |
424 | * Some of the gain controls in TWL (mostly those which are associated with | 654 | * Some of the gain controls in TWL (mostly those which are associated with |
425 | * the outputs) are implemented in an interesting way: | 655 | * the outputs) are implemented in an interesting way: |
@@ -614,6 +844,17 @@ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); | |||
614 | */ | 844 | */ |
615 | static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); | 845 | static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); |
616 | 846 | ||
847 | static const char *twl4030_rampdelay_texts[] = { | ||
848 | "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", | ||
849 | "437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms", | ||
850 | "3495/2581/1748 ms" | ||
851 | }; | ||
852 | |||
853 | static const struct soc_enum twl4030_rampdelay_enum = | ||
854 | SOC_ENUM_SINGLE(TWL4030_REG_HS_POPN_SET, 2, | ||
855 | ARRAY_SIZE(twl4030_rampdelay_texts), | ||
856 | twl4030_rampdelay_texts); | ||
857 | |||
617 | static const struct snd_kcontrol_new twl4030_snd_controls[] = { | 858 | static const struct snd_kcontrol_new twl4030_snd_controls[] = { |
618 | /* Common playback gain controls */ | 859 | /* Common playback gain controls */ |
619 | SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", | 860 | SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", |
@@ -668,23 +909,9 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { | |||
668 | 909 | ||
669 | SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN, | 910 | SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN, |
670 | 0, 3, 5, 0, input_gain_tlv), | 911 | 0, 3, 5, 0, input_gain_tlv), |
671 | }; | ||
672 | |||
673 | /* add non dapm controls */ | ||
674 | static int twl4030_add_controls(struct snd_soc_codec *codec) | ||
675 | { | ||
676 | int err, i; | ||
677 | |||
678 | for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) { | ||
679 | err = snd_ctl_add(codec->card, | ||
680 | snd_soc_cnew(&twl4030_snd_controls[i], | ||
681 | codec, NULL)); | ||
682 | if (err < 0) | ||
683 | return err; | ||
684 | } | ||
685 | 912 | ||
686 | return 0; | 913 | SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum), |
687 | } | 914 | }; |
688 | 915 | ||
689 | static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | 916 | static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { |
690 | /* Left channel inputs */ | 917 | /* Left channel inputs */ |
@@ -714,13 +941,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
714 | 941 | ||
715 | /* DACs */ | 942 | /* DACs */ |
716 | SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback", | 943 | SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback", |
717 | TWL4030_REG_AVDAC_CTL, 0, 0), | 944 | SND_SOC_NOPM, 0, 0), |
718 | SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback", | 945 | SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback", |
719 | TWL4030_REG_AVDAC_CTL, 1, 0), | 946 | SND_SOC_NOPM, 0, 0), |
720 | SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback", | 947 | SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback", |
721 | TWL4030_REG_AVDAC_CTL, 2, 0), | 948 | SND_SOC_NOPM, 0, 0), |
722 | SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback", | 949 | SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback", |
723 | TWL4030_REG_AVDAC_CTL, 3, 0), | 950 | SND_SOC_NOPM, 0, 0), |
724 | 951 | ||
725 | /* Analog PGAs */ | 952 | /* Analog PGAs */ |
726 | SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL, | 953 | SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL, |
@@ -732,6 +959,37 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
732 | SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, | 959 | SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, |
733 | 0, 0, NULL, 0), | 960 | 0, 0, NULL, 0), |
734 | 961 | ||
962 | /* Analog bypasses */ | ||
963 | SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0, | ||
964 | &twl4030_dapm_abypassr1_control, bypass_event, | ||
965 | SND_SOC_DAPM_POST_REG), | ||
966 | SND_SOC_DAPM_SWITCH_E("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0, | ||
967 | &twl4030_dapm_abypassl1_control, | ||
968 | bypass_event, SND_SOC_DAPM_POST_REG), | ||
969 | SND_SOC_DAPM_SWITCH_E("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0, | ||
970 | &twl4030_dapm_abypassr2_control, | ||
971 | bypass_event, SND_SOC_DAPM_POST_REG), | ||
972 | SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0, | ||
973 | &twl4030_dapm_abypassl2_control, | ||
974 | bypass_event, SND_SOC_DAPM_POST_REG), | ||
975 | |||
976 | /* Digital bypasses */ | ||
977 | SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0, | ||
978 | &twl4030_dapm_dbypassl_control, bypass_event, | ||
979 | SND_SOC_DAPM_POST_REG), | ||
980 | SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0, | ||
981 | &twl4030_dapm_dbypassr_control, bypass_event, | ||
982 | SND_SOC_DAPM_POST_REG), | ||
983 | |||
984 | SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer", TWL4030_REG_AVDAC_CTL, | ||
985 | 0, 0, NULL, 0), | ||
986 | SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", TWL4030_REG_AVDAC_CTL, | ||
987 | 1, 0, NULL, 0), | ||
988 | SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer", TWL4030_REG_AVDAC_CTL, | ||
989 | 2, 0, NULL, 0), | ||
990 | SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer", TWL4030_REG_AVDAC_CTL, | ||
991 | 3, 0, NULL, 0), | ||
992 | |||
735 | /* Output MUX controls */ | 993 | /* Output MUX controls */ |
736 | /* Earpiece */ | 994 | /* Earpiece */ |
737 | SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0, | 995 | SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0, |
@@ -742,8 +1000,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
742 | SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0, | 1000 | SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0, |
743 | &twl4030_dapm_predriver_control), | 1001 | &twl4030_dapm_predriver_control), |
744 | /* HeadsetL/R */ | 1002 | /* HeadsetL/R */ |
745 | SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0, | 1003 | SND_SOC_DAPM_MUX_E("HeadsetL Mux", SND_SOC_NOPM, 0, 0, |
746 | &twl4030_dapm_hsol_control), | 1004 | &twl4030_dapm_hsol_control, headsetl_event, |
1005 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), | ||
747 | SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, | 1006 | SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, |
748 | &twl4030_dapm_hsor_control), | 1007 | &twl4030_dapm_hsor_control), |
749 | /* CarkitL/R */ | 1008 | /* CarkitL/R */ |
@@ -782,16 +1041,16 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
782 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| | 1041 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| |
783 | SND_SOC_DAPM_POST_REG), | 1042 | SND_SOC_DAPM_POST_REG), |
784 | 1043 | ||
785 | /* Analog input muxes with power switch for the physical ADCL/R */ | 1044 | /* Analog input muxes with switch for the capture amplifiers */ |
786 | SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route", | 1045 | SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route", |
787 | TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control), | 1046 | TWL4030_REG_ANAMICL, 4, 0, &twl4030_dapm_analoglmic_control), |
788 | SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route", | 1047 | SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route", |
789 | TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control), | 1048 | TWL4030_REG_ANAMICR, 4, 0, &twl4030_dapm_analogrmic_control), |
790 | 1049 | ||
791 | SND_SOC_DAPM_PGA("Analog Left Amplifier", | 1050 | SND_SOC_DAPM_PGA("ADC Physical Left", |
792 | TWL4030_REG_ANAMICL, 4, 0, NULL, 0), | 1051 | TWL4030_REG_AVADC_CTL, 3, 0, NULL, 0), |
793 | SND_SOC_DAPM_PGA("Analog Right Amplifier", | 1052 | SND_SOC_DAPM_PGA("ADC Physical Right", |
794 | TWL4030_REG_ANAMICR, 4, 0, NULL, 0), | 1053 | TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0), |
795 | 1054 | ||
796 | SND_SOC_DAPM_PGA("Digimic0 Enable", | 1055 | SND_SOC_DAPM_PGA("Digimic0 Enable", |
797 | TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0), | 1056 | TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0), |
@@ -801,13 +1060,19 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
801 | SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0), | 1060 | SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0), |
802 | SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0), | 1061 | SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0), |
803 | SND_SOC_DAPM_MICBIAS("Headset Mic Bias", TWL4030_REG_MICBIAS_CTL, 2, 0), | 1062 | SND_SOC_DAPM_MICBIAS("Headset Mic Bias", TWL4030_REG_MICBIAS_CTL, 2, 0), |
1063 | |||
804 | }; | 1064 | }; |
805 | 1065 | ||
806 | static const struct snd_soc_dapm_route intercon[] = { | 1066 | static const struct snd_soc_dapm_route intercon[] = { |
807 | {"ARXL1_APGA", NULL, "DAC Left1"}, | 1067 | {"Analog L1 Playback Mixer", NULL, "DAC Left1"}, |
808 | {"ARXR1_APGA", NULL, "DAC Right1"}, | 1068 | {"Analog R1 Playback Mixer", NULL, "DAC Right1"}, |
809 | {"ARXL2_APGA", NULL, "DAC Left2"}, | 1069 | {"Analog L2 Playback Mixer", NULL, "DAC Left2"}, |
810 | {"ARXR2_APGA", NULL, "DAC Right2"}, | 1070 | {"Analog R2 Playback Mixer", NULL, "DAC Right2"}, |
1071 | |||
1072 | {"ARXL1_APGA", NULL, "Analog L1 Playback Mixer"}, | ||
1073 | {"ARXR1_APGA", NULL, "Analog R1 Playback Mixer"}, | ||
1074 | {"ARXL2_APGA", NULL, "Analog L2 Playback Mixer"}, | ||
1075 | {"ARXR2_APGA", NULL, "Analog R2 Playback Mixer"}, | ||
811 | 1076 | ||
812 | /* Internal playback routings */ | 1077 | /* Internal playback routings */ |
813 | /* Earpiece */ | 1078 | /* Earpiece */ |
@@ -865,23 +1130,23 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
865 | {"Analog Right Capture Route", "Sub mic", "SUBMIC"}, | 1130 | {"Analog Right Capture Route", "Sub mic", "SUBMIC"}, |
866 | {"Analog Right Capture Route", "AUXR", "AUXR"}, | 1131 | {"Analog Right Capture Route", "AUXR", "AUXR"}, |
867 | 1132 | ||
868 | {"Analog Left Amplifier", NULL, "Analog Left Capture Route"}, | 1133 | {"ADC Physical Left", NULL, "Analog Left Capture Route"}, |
869 | {"Analog Right Amplifier", NULL, "Analog Right Capture Route"}, | 1134 | {"ADC Physical Right", NULL, "Analog Right Capture Route"}, |
870 | 1135 | ||
871 | {"Digimic0 Enable", NULL, "DIGIMIC0"}, | 1136 | {"Digimic0 Enable", NULL, "DIGIMIC0"}, |
872 | {"Digimic1 Enable", NULL, "DIGIMIC1"}, | 1137 | {"Digimic1 Enable", NULL, "DIGIMIC1"}, |
873 | 1138 | ||
874 | /* TX1 Left capture path */ | 1139 | /* TX1 Left capture path */ |
875 | {"TX1 Capture Route", "Analog", "Analog Left Amplifier"}, | 1140 | {"TX1 Capture Route", "Analog", "ADC Physical Left"}, |
876 | {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, | 1141 | {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, |
877 | /* TX1 Right capture path */ | 1142 | /* TX1 Right capture path */ |
878 | {"TX1 Capture Route", "Analog", "Analog Right Amplifier"}, | 1143 | {"TX1 Capture Route", "Analog", "ADC Physical Right"}, |
879 | {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, | 1144 | {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, |
880 | /* TX2 Left capture path */ | 1145 | /* TX2 Left capture path */ |
881 | {"TX2 Capture Route", "Analog", "Analog Left Amplifier"}, | 1146 | {"TX2 Capture Route", "Analog", "ADC Physical Left"}, |
882 | {"TX2 Capture Route", "Digimic1", "Digimic1 Enable"}, | 1147 | {"TX2 Capture Route", "Digimic1", "Digimic1 Enable"}, |
883 | /* TX2 Right capture path */ | 1148 | /* TX2 Right capture path */ |
884 | {"TX2 Capture Route", "Analog", "Analog Right Amplifier"}, | 1149 | {"TX2 Capture Route", "Analog", "ADC Physical Right"}, |
885 | {"TX2 Capture Route", "Digimic1", "Digimic1 Enable"}, | 1150 | {"TX2 Capture Route", "Digimic1", "Digimic1 Enable"}, |
886 | 1151 | ||
887 | {"ADC Virtual Left1", NULL, "TX1 Capture Route"}, | 1152 | {"ADC Virtual Left1", NULL, "TX1 Capture Route"}, |
@@ -889,6 +1154,24 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
889 | {"ADC Virtual Left2", NULL, "TX2 Capture Route"}, | 1154 | {"ADC Virtual Left2", NULL, "TX2 Capture Route"}, |
890 | {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, | 1155 | {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, |
891 | 1156 | ||
1157 | /* Analog bypass routes */ | ||
1158 | {"Right1 Analog Loopback", "Switch", "Analog Right Capture Route"}, | ||
1159 | {"Left1 Analog Loopback", "Switch", "Analog Left Capture Route"}, | ||
1160 | {"Right2 Analog Loopback", "Switch", "Analog Right Capture Route"}, | ||
1161 | {"Left2 Analog Loopback", "Switch", "Analog Left Capture Route"}, | ||
1162 | |||
1163 | {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"}, | ||
1164 | {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"}, | ||
1165 | {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"}, | ||
1166 | {"Analog L2 Playback Mixer", NULL, "Left2 Analog Loopback"}, | ||
1167 | |||
1168 | /* Digital bypass routes */ | ||
1169 | {"Right Digital Loopback", "Volume", "TX1 Capture Route"}, | ||
1170 | {"Left Digital Loopback", "Volume", "TX1 Capture Route"}, | ||
1171 | |||
1172 | {"Analog R2 Playback Mixer", NULL, "Right Digital Loopback"}, | ||
1173 | {"Analog L2 Playback Mixer", NULL, "Left Digital Loopback"}, | ||
1174 | |||
892 | }; | 1175 | }; |
893 | 1176 | ||
894 | static int twl4030_add_widgets(struct snd_soc_codec *codec) | 1177 | static int twl4030_add_widgets(struct snd_soc_codec *codec) |
@@ -902,82 +1185,28 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec) | |||
902 | return 0; | 1185 | return 0; |
903 | } | 1186 | } |
904 | 1187 | ||
905 | static void twl4030_power_up(struct snd_soc_codec *codec) | ||
906 | { | ||
907 | u8 anamicl, regmisc1, byte, popn; | ||
908 | int i = 0; | ||
909 | |||
910 | /* set CODECPDZ to turn on codec */ | ||
911 | twl4030_set_codecpdz(codec); | ||
912 | |||
913 | /* initiate offset cancellation */ | ||
914 | anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); | ||
915 | twl4030_write(codec, TWL4030_REG_ANAMICL, | ||
916 | anamicl | TWL4030_CNCL_OFFSET_START); | ||
917 | |||
918 | |||
919 | /* wait for offset cancellation to complete */ | ||
920 | do { | ||
921 | /* this takes a little while, so don't slam i2c */ | ||
922 | udelay(2000); | ||
923 | twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, | ||
924 | TWL4030_REG_ANAMICL); | ||
925 | } while ((i++ < 100) && | ||
926 | ((byte & TWL4030_CNCL_OFFSET_START) == | ||
927 | TWL4030_CNCL_OFFSET_START)); | ||
928 | |||
929 | /* anti-pop when changing analog gain */ | ||
930 | regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); | ||
931 | twl4030_write(codec, TWL4030_REG_MISC_SET_1, | ||
932 | regmisc1 | TWL4030_SMOOTH_ANAVOL_EN); | ||
933 | |||
934 | /* toggle CODECPDZ as per TRM */ | ||
935 | twl4030_clear_codecpdz(codec); | ||
936 | twl4030_set_codecpdz(codec); | ||
937 | |||
938 | /* program anti-pop with bias ramp delay */ | ||
939 | popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); | ||
940 | popn &= TWL4030_RAMP_DELAY; | ||
941 | popn |= TWL4030_RAMP_DELAY_645MS; | ||
942 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); | ||
943 | popn |= TWL4030_VMID_EN; | ||
944 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); | ||
945 | |||
946 | /* enable anti-pop ramp */ | ||
947 | popn |= TWL4030_RAMP_EN; | ||
948 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); | ||
949 | } | ||
950 | |||
951 | static void twl4030_power_down(struct snd_soc_codec *codec) | ||
952 | { | ||
953 | u8 popn; | ||
954 | |||
955 | /* disable anti-pop ramp */ | ||
956 | popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); | ||
957 | popn &= ~TWL4030_RAMP_EN; | ||
958 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); | ||
959 | |||
960 | /* disable bias out */ | ||
961 | popn &= ~TWL4030_VMID_EN; | ||
962 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); | ||
963 | |||
964 | /* power down */ | ||
965 | twl4030_clear_codecpdz(codec); | ||
966 | } | ||
967 | |||
968 | static int twl4030_set_bias_level(struct snd_soc_codec *codec, | 1188 | static int twl4030_set_bias_level(struct snd_soc_codec *codec, |
969 | enum snd_soc_bias_level level) | 1189 | enum snd_soc_bias_level level) |
970 | { | 1190 | { |
1191 | struct twl4030_priv *twl4030 = codec->private_data; | ||
1192 | |||
971 | switch (level) { | 1193 | switch (level) { |
972 | case SND_SOC_BIAS_ON: | 1194 | case SND_SOC_BIAS_ON: |
973 | twl4030_power_up(codec); | 1195 | twl4030_codec_mute(codec, 0); |
974 | break; | 1196 | break; |
975 | case SND_SOC_BIAS_PREPARE: | 1197 | case SND_SOC_BIAS_PREPARE: |
976 | /* TODO: develop a twl4030_prepare function */ | 1198 | twl4030_power_up(codec); |
1199 | if (twl4030->bypass_state) | ||
1200 | twl4030_codec_mute(codec, 0); | ||
1201 | else | ||
1202 | twl4030_codec_mute(codec, 1); | ||
977 | break; | 1203 | break; |
978 | case SND_SOC_BIAS_STANDBY: | 1204 | case SND_SOC_BIAS_STANDBY: |
979 | /* TODO: develop a twl4030_standby function */ | 1205 | twl4030_power_up(codec); |
980 | twl4030_power_down(codec); | 1206 | if (twl4030->bypass_state) |
1207 | twl4030_codec_mute(codec, 0); | ||
1208 | else | ||
1209 | twl4030_codec_mute(codec, 1); | ||
981 | break; | 1210 | break; |
982 | case SND_SOC_BIAS_OFF: | 1211 | case SND_SOC_BIAS_OFF: |
983 | twl4030_power_down(codec); | 1212 | twl4030_power_down(codec); |
@@ -994,10 +1223,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
994 | { | 1223 | { |
995 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1224 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
996 | struct snd_soc_device *socdev = rtd->socdev; | 1225 | struct snd_soc_device *socdev = rtd->socdev; |
997 | struct snd_soc_codec *codec = socdev->codec; | 1226 | struct snd_soc_codec *codec = socdev->card->codec; |
998 | u8 mode, old_mode, format, old_format; | 1227 | u8 mode, old_mode, format, old_format; |
999 | 1228 | ||
1000 | |||
1001 | /* bit rate */ | 1229 | /* bit rate */ |
1002 | old_mode = twl4030_read_reg_cache(codec, | 1230 | old_mode = twl4030_read_reg_cache(codec, |
1003 | TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; | 1231 | TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; |
@@ -1039,8 +1267,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1039 | 1267 | ||
1040 | if (mode != old_mode) { | 1268 | if (mode != old_mode) { |
1041 | /* change rate and set CODECPDZ */ | 1269 | /* change rate and set CODECPDZ */ |
1270 | twl4030_codec_enable(codec, 0); | ||
1042 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | 1271 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); |
1043 | twl4030_set_codecpdz(codec); | 1272 | twl4030_codec_enable(codec, 1); |
1044 | } | 1273 | } |
1045 | 1274 | ||
1046 | /* sample size */ | 1275 | /* sample size */ |
@@ -1063,13 +1292,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1063 | if (format != old_format) { | 1292 | if (format != old_format) { |
1064 | 1293 | ||
1065 | /* clear CODECPDZ before changing format (codec requirement) */ | 1294 | /* clear CODECPDZ before changing format (codec requirement) */ |
1066 | twl4030_clear_codecpdz(codec); | 1295 | twl4030_codec_enable(codec, 0); |
1067 | 1296 | ||
1068 | /* change format */ | 1297 | /* change format */ |
1069 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | 1298 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); |
1070 | 1299 | ||
1071 | /* set CODECPDZ afterwards */ | 1300 | /* set CODECPDZ afterwards */ |
1072 | twl4030_set_codecpdz(codec); | 1301 | twl4030_codec_enable(codec, 1); |
1073 | } | 1302 | } |
1074 | return 0; | 1303 | return 0; |
1075 | } | 1304 | } |
@@ -1139,13 +1368,13 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1139 | if (format != old_format) { | 1368 | if (format != old_format) { |
1140 | 1369 | ||
1141 | /* clear CODECPDZ before changing format (codec requirement) */ | 1370 | /* clear CODECPDZ before changing format (codec requirement) */ |
1142 | twl4030_clear_codecpdz(codec); | 1371 | twl4030_codec_enable(codec, 0); |
1143 | 1372 | ||
1144 | /* change format */ | 1373 | /* change format */ |
1145 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | 1374 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); |
1146 | 1375 | ||
1147 | /* set CODECPDZ afterwards */ | 1376 | /* set CODECPDZ afterwards */ |
1148 | twl4030_set_codecpdz(codec); | 1377 | twl4030_codec_enable(codec, 1); |
1149 | } | 1378 | } |
1150 | 1379 | ||
1151 | return 0; | 1380 | return 0; |
@@ -1154,6 +1383,12 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1154 | #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) | 1383 | #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) |
1155 | #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) | 1384 | #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) |
1156 | 1385 | ||
1386 | static struct snd_soc_dai_ops twl4030_dai_ops = { | ||
1387 | .hw_params = twl4030_hw_params, | ||
1388 | .set_sysclk = twl4030_set_dai_sysclk, | ||
1389 | .set_fmt = twl4030_set_dai_fmt, | ||
1390 | }; | ||
1391 | |||
1157 | struct snd_soc_dai twl4030_dai = { | 1392 | struct snd_soc_dai twl4030_dai = { |
1158 | .name = "twl4030", | 1393 | .name = "twl4030", |
1159 | .playback = { | 1394 | .playback = { |
@@ -1168,18 +1403,14 @@ struct snd_soc_dai twl4030_dai = { | |||
1168 | .channels_max = 2, | 1403 | .channels_max = 2, |
1169 | .rates = TWL4030_RATES, | 1404 | .rates = TWL4030_RATES, |
1170 | .formats = TWL4030_FORMATS,}, | 1405 | .formats = TWL4030_FORMATS,}, |
1171 | .ops = { | 1406 | .ops = &twl4030_dai_ops, |
1172 | .hw_params = twl4030_hw_params, | ||
1173 | .set_sysclk = twl4030_set_dai_sysclk, | ||
1174 | .set_fmt = twl4030_set_dai_fmt, | ||
1175 | } | ||
1176 | }; | 1407 | }; |
1177 | EXPORT_SYMBOL_GPL(twl4030_dai); | 1408 | EXPORT_SYMBOL_GPL(twl4030_dai); |
1178 | 1409 | ||
1179 | static int twl4030_suspend(struct platform_device *pdev, pm_message_t state) | 1410 | static int twl4030_suspend(struct platform_device *pdev, pm_message_t state) |
1180 | { | 1411 | { |
1181 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1412 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1182 | struct snd_soc_codec *codec = socdev->codec; | 1413 | struct snd_soc_codec *codec = socdev->card->codec; |
1183 | 1414 | ||
1184 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1415 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1185 | 1416 | ||
@@ -1189,7 +1420,7 @@ static int twl4030_suspend(struct platform_device *pdev, pm_message_t state) | |||
1189 | static int twl4030_resume(struct platform_device *pdev) | 1420 | static int twl4030_resume(struct platform_device *pdev) |
1190 | { | 1421 | { |
1191 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1422 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1192 | struct snd_soc_codec *codec = socdev->codec; | 1423 | struct snd_soc_codec *codec = socdev->card->codec; |
1193 | 1424 | ||
1194 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1425 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1195 | twl4030_set_bias_level(codec, codec->suspend_bias_level); | 1426 | twl4030_set_bias_level(codec, codec->suspend_bias_level); |
@@ -1203,7 +1434,7 @@ static int twl4030_resume(struct platform_device *pdev) | |||
1203 | 1434 | ||
1204 | static int twl4030_init(struct snd_soc_device *socdev) | 1435 | static int twl4030_init(struct snd_soc_device *socdev) |
1205 | { | 1436 | { |
1206 | struct snd_soc_codec *codec = socdev->codec; | 1437 | struct snd_soc_codec *codec = socdev->card->codec; |
1207 | int ret = 0; | 1438 | int ret = 0; |
1208 | 1439 | ||
1209 | printk(KERN_INFO "TWL4030 Audio Codec init \n"); | 1440 | printk(KERN_INFO "TWL4030 Audio Codec init \n"); |
@@ -1233,7 +1464,8 @@ static int twl4030_init(struct snd_soc_device *socdev) | |||
1233 | /* power on device */ | 1464 | /* power on device */ |
1234 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1465 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1235 | 1466 | ||
1236 | twl4030_add_controls(codec); | 1467 | snd_soc_add_controls(codec, twl4030_snd_controls, |
1468 | ARRAY_SIZE(twl4030_snd_controls)); | ||
1237 | twl4030_add_widgets(codec); | 1469 | twl4030_add_widgets(codec); |
1238 | 1470 | ||
1239 | ret = snd_soc_init_card(socdev); | 1471 | ret = snd_soc_init_card(socdev); |
@@ -1258,12 +1490,20 @@ static int twl4030_probe(struct platform_device *pdev) | |||
1258 | { | 1490 | { |
1259 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1491 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1260 | struct snd_soc_codec *codec; | 1492 | struct snd_soc_codec *codec; |
1493 | struct twl4030_priv *twl4030; | ||
1261 | 1494 | ||
1262 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1495 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
1263 | if (codec == NULL) | 1496 | if (codec == NULL) |
1264 | return -ENOMEM; | 1497 | return -ENOMEM; |
1265 | 1498 | ||
1266 | socdev->codec = codec; | 1499 | twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL); |
1500 | if (twl4030 == NULL) { | ||
1501 | kfree(codec); | ||
1502 | return -ENOMEM; | ||
1503 | } | ||
1504 | |||
1505 | codec->private_data = twl4030; | ||
1506 | socdev->card->codec = codec; | ||
1267 | mutex_init(&codec->mutex); | 1507 | mutex_init(&codec->mutex); |
1268 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1508 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1269 | INIT_LIST_HEAD(&codec->dapm_paths); | 1509 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -1277,11 +1517,13 @@ static int twl4030_probe(struct platform_device *pdev) | |||
1277 | static int twl4030_remove(struct platform_device *pdev) | 1517 | static int twl4030_remove(struct platform_device *pdev) |
1278 | { | 1518 | { |
1279 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1519 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1280 | struct snd_soc_codec *codec = socdev->codec; | 1520 | struct snd_soc_codec *codec = socdev->card->codec; |
1281 | 1521 | ||
1282 | printk(KERN_INFO "TWL4030 Audio Codec remove\n"); | 1522 | printk(KERN_INFO "TWL4030 Audio Codec remove\n"); |
1523 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1283 | snd_soc_free_pcms(socdev); | 1524 | snd_soc_free_pcms(socdev); |
1284 | snd_soc_dapm_free(socdev); | 1525 | snd_soc_dapm_free(socdev); |
1526 | kfree(codec->private_data); | ||
1285 | kfree(codec); | 1527 | kfree(codec); |
1286 | 1528 | ||
1287 | return 0; | 1529 | return 0; |
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index 442e5a828617..33dbb144dad1 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h | |||
@@ -170,6 +170,9 @@ | |||
170 | #define TWL4030_CLK256FS_EN 0x02 | 170 | #define TWL4030_CLK256FS_EN 0x02 |
171 | #define TWL4030_AIF_EN 0x01 | 171 | #define TWL4030_AIF_EN 0x01 |
172 | 172 | ||
173 | /* EAR_CTL (0x21) */ | ||
174 | #define TWL4030_EAR_GAIN 0x30 | ||
175 | |||
173 | /* HS_GAIN_SET (0x23) Fields */ | 176 | /* HS_GAIN_SET (0x23) Fields */ |
174 | 177 | ||
175 | #define TWL4030_HSR_GAIN 0x0C | 178 | #define TWL4030_HSR_GAIN 0x0C |
@@ -198,6 +201,18 @@ | |||
198 | #define TWL4030_RAMP_DELAY_2581MS 0x1C | 201 | #define TWL4030_RAMP_DELAY_2581MS 0x1C |
199 | #define TWL4030_RAMP_EN 0x02 | 202 | #define TWL4030_RAMP_EN 0x02 |
200 | 203 | ||
204 | /* PREDL_CTL (0x25) */ | ||
205 | #define TWL4030_PREDL_GAIN 0x30 | ||
206 | |||
207 | /* PREDR_CTL (0x26) */ | ||
208 | #define TWL4030_PREDR_GAIN 0x30 | ||
209 | |||
210 | /* PRECKL_CTL (0x27) */ | ||
211 | #define TWL4030_PRECKL_GAIN 0x30 | ||
212 | |||
213 | /* PRECKR_CTL (0x28) */ | ||
214 | #define TWL4030_PRECKR_GAIN 0x30 | ||
215 | |||
201 | /* HFL_CTL (0x29, 0x2A) Fields */ | 216 | /* HFL_CTL (0x29, 0x2A) Fields */ |
202 | #define TWL4030_HF_CTL_HB_EN 0x04 | 217 | #define TWL4030_HF_CTL_HB_EN 0x04 |
203 | #define TWL4030_HF_CTL_LOOP_EN 0x08 | 218 | #define TWL4030_HF_CTL_LOOP_EN 0x08 |
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index a2c5064a774b..ddefb8f80145 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -173,7 +173,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream, | |||
173 | { | 173 | { |
174 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 174 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
175 | struct snd_soc_device *socdev = rtd->socdev; | 175 | struct snd_soc_device *socdev = rtd->socdev; |
176 | struct snd_soc_codec *codec = socdev->codec; | 176 | struct snd_soc_codec *codec = socdev->card->codec; |
177 | struct uda134x_priv *uda134x = codec->private_data; | 177 | struct uda134x_priv *uda134x = codec->private_data; |
178 | struct snd_pcm_runtime *master_runtime; | 178 | struct snd_pcm_runtime *master_runtime; |
179 | 179 | ||
@@ -206,7 +206,7 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream, | |||
206 | { | 206 | { |
207 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 207 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
208 | struct snd_soc_device *socdev = rtd->socdev; | 208 | struct snd_soc_device *socdev = rtd->socdev; |
209 | struct snd_soc_codec *codec = socdev->codec; | 209 | struct snd_soc_codec *codec = socdev->card->codec; |
210 | struct uda134x_priv *uda134x = codec->private_data; | 210 | struct uda134x_priv *uda134x = codec->private_data; |
211 | 211 | ||
212 | if (uda134x->master_substream == substream) | 212 | if (uda134x->master_substream == substream) |
@@ -221,7 +221,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream, | |||
221 | { | 221 | { |
222 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 222 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
223 | struct snd_soc_device *socdev = rtd->socdev; | 223 | struct snd_soc_device *socdev = rtd->socdev; |
224 | struct snd_soc_codec *codec = socdev->codec; | 224 | struct snd_soc_codec *codec = socdev->card->codec; |
225 | struct uda134x_priv *uda134x = codec->private_data; | 225 | struct uda134x_priv *uda134x = codec->private_data; |
226 | u8 hw_params; | 226 | u8 hw_params; |
227 | 227 | ||
@@ -431,38 +431,14 @@ SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), | |||
431 | SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), | 431 | SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), |
432 | }; | 432 | }; |
433 | 433 | ||
434 | static int uda134x_add_controls(struct snd_soc_codec *codec) | 434 | static struct snd_soc_dai_ops uda134x_dai_ops = { |
435 | { | 435 | .startup = uda134x_startup, |
436 | int err, i, n; | 436 | .shutdown = uda134x_shutdown, |
437 | const struct snd_kcontrol_new *ctrls; | 437 | .hw_params = uda134x_hw_params, |
438 | struct uda134x_platform_data *pd = codec->control_data; | 438 | .digital_mute = uda134x_mute, |
439 | 439 | .set_sysclk = uda134x_set_dai_sysclk, | |
440 | switch (pd->model) { | 440 | .set_fmt = uda134x_set_dai_fmt, |
441 | case UDA134X_UDA1340: | 441 | }; |
442 | case UDA134X_UDA1344: | ||
443 | n = ARRAY_SIZE(uda1340_snd_controls); | ||
444 | ctrls = uda1340_snd_controls; | ||
445 | break; | ||
446 | case UDA134X_UDA1341: | ||
447 | n = ARRAY_SIZE(uda1341_snd_controls); | ||
448 | ctrls = uda1341_snd_controls; | ||
449 | break; | ||
450 | default: | ||
451 | printk(KERN_ERR "%s unkown codec type: %d", | ||
452 | __func__, pd->model); | ||
453 | return -EINVAL; | ||
454 | } | ||
455 | |||
456 | for (i = 0; i < n; i++) { | ||
457 | err = snd_ctl_add(codec->card, | ||
458 | snd_soc_cnew(&ctrls[i], | ||
459 | codec, NULL)); | ||
460 | if (err < 0) | ||
461 | return err; | ||
462 | } | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | 442 | ||
467 | struct snd_soc_dai uda134x_dai = { | 443 | struct snd_soc_dai uda134x_dai = { |
468 | .name = "UDA134X", | 444 | .name = "UDA134X", |
@@ -483,14 +459,7 @@ struct snd_soc_dai uda134x_dai = { | |||
483 | .formats = UDA134X_FORMATS, | 459 | .formats = UDA134X_FORMATS, |
484 | }, | 460 | }, |
485 | /* pcm operations */ | 461 | /* pcm operations */ |
486 | .ops = { | 462 | .ops = &uda134x_dai_ops, |
487 | .startup = uda134x_startup, | ||
488 | .shutdown = uda134x_shutdown, | ||
489 | .hw_params = uda134x_hw_params, | ||
490 | .digital_mute = uda134x_mute, | ||
491 | .set_sysclk = uda134x_set_dai_sysclk, | ||
492 | .set_fmt = uda134x_set_dai_fmt, | ||
493 | } | ||
494 | }; | 463 | }; |
495 | EXPORT_SYMBOL(uda134x_dai); | 464 | EXPORT_SYMBOL(uda134x_dai); |
496 | 465 | ||
@@ -525,11 +494,11 @@ static int uda134x_soc_probe(struct platform_device *pdev) | |||
525 | return -EINVAL; | 494 | return -EINVAL; |
526 | } | 495 | } |
527 | 496 | ||
528 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 497 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
529 | if (socdev->codec == NULL) | 498 | if (socdev->card->codec == NULL) |
530 | return ret; | 499 | return ret; |
531 | 500 | ||
532 | codec = socdev->codec; | 501 | codec = socdev->card->codec; |
533 | 502 | ||
534 | uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL); | 503 | uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL); |
535 | if (uda134x == NULL) | 504 | if (uda134x == NULL) |
@@ -572,7 +541,22 @@ static int uda134x_soc_probe(struct platform_device *pdev) | |||
572 | goto pcm_err; | 541 | goto pcm_err; |
573 | } | 542 | } |
574 | 543 | ||
575 | ret = uda134x_add_controls(codec); | 544 | switch (pd->model) { |
545 | case UDA134X_UDA1340: | ||
546 | case UDA134X_UDA1344: | ||
547 | ret = snd_soc_add_controls(codec, uda1340_snd_controls, | ||
548 | ARRAY_SIZE(uda1340_snd_controls)); | ||
549 | break; | ||
550 | case UDA134X_UDA1341: | ||
551 | ret = snd_soc_add_controls(codec, uda1341_snd_controls, | ||
552 | ARRAY_SIZE(uda1341_snd_controls)); | ||
553 | break; | ||
554 | default: | ||
555 | printk(KERN_ERR "%s unkown codec type: %d", | ||
556 | __func__, pd->model); | ||
557 | return -EINVAL; | ||
558 | } | ||
559 | |||
576 | if (ret < 0) { | 560 | if (ret < 0) { |
577 | printk(KERN_ERR "UDA134X: failed to register controls\n"); | 561 | printk(KERN_ERR "UDA134X: failed to register controls\n"); |
578 | goto pcm_err; | 562 | goto pcm_err; |
@@ -602,7 +586,7 @@ priv_err: | |||
602 | static int uda134x_soc_remove(struct platform_device *pdev) | 586 | static int uda134x_soc_remove(struct platform_device *pdev) |
603 | { | 587 | { |
604 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 588 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
605 | struct snd_soc_codec *codec = socdev->codec; | 589 | struct snd_soc_codec *codec = socdev->card->codec; |
606 | 590 | ||
607 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 591 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
608 | uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); | 592 | uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
@@ -622,7 +606,7 @@ static int uda134x_soc_suspend(struct platform_device *pdev, | |||
622 | pm_message_t state) | 606 | pm_message_t state) |
623 | { | 607 | { |
624 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 608 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
625 | struct snd_soc_codec *codec = socdev->codec; | 609 | struct snd_soc_codec *codec = socdev->card->codec; |
626 | 610 | ||
627 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 611 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
628 | uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); | 612 | uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
@@ -632,7 +616,7 @@ static int uda134x_soc_suspend(struct platform_device *pdev, | |||
632 | static int uda134x_soc_resume(struct platform_device *pdev) | 616 | static int uda134x_soc_resume(struct platform_device *pdev) |
633 | { | 617 | { |
634 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
635 | struct snd_soc_codec *codec = socdev->codec; | 619 | struct snd_soc_codec *codec = socdev->card->codec; |
636 | 620 | ||
637 | uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 621 | uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
638 | uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); | 622 | uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index e6bf0844fbf3..5b21594e0e58 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/ioctl.h> | 25 | #include <linux/ioctl.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <linux/workqueue.h> | ||
28 | #include <sound/core.h> | 29 | #include <sound/core.h> |
29 | #include <sound/control.h> | 30 | #include <sound/control.h> |
30 | #include <sound/initval.h> | 31 | #include <sound/initval.h> |
@@ -35,7 +36,8 @@ | |||
35 | 36 | ||
36 | #include "uda1380.h" | 37 | #include "uda1380.h" |
37 | 38 | ||
38 | #define UDA1380_VERSION "0.6" | 39 | static struct work_struct uda1380_work; |
40 | static struct snd_soc_codec *uda1380_codec; | ||
39 | 41 | ||
40 | /* | 42 | /* |
41 | * uda1380 register cache | 43 | * uda1380 register cache |
@@ -52,6 +54,8 @@ static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = { | |||
52 | 0x0000, 0x8000, 0x0002, 0x0000, | 54 | 0x0000, 0x8000, 0x0002, 0x0000, |
53 | }; | 55 | }; |
54 | 56 | ||
57 | static unsigned long uda1380_cache_dirty; | ||
58 | |||
55 | /* | 59 | /* |
56 | * read uda1380 register cache | 60 | * read uda1380 register cache |
57 | */ | 61 | */ |
@@ -73,8 +77,11 @@ static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec, | |||
73 | u16 reg, unsigned int value) | 77 | u16 reg, unsigned int value) |
74 | { | 78 | { |
75 | u16 *cache = codec->reg_cache; | 79 | u16 *cache = codec->reg_cache; |
80 | |||
76 | if (reg >= UDA1380_CACHEREGNUM) | 81 | if (reg >= UDA1380_CACHEREGNUM) |
77 | return; | 82 | return; |
83 | if ((reg >= 0x10) && (cache[reg] != value)) | ||
84 | set_bit(reg - 0x10, &uda1380_cache_dirty); | ||
78 | cache[reg] = value; | 85 | cache[reg] = value; |
79 | } | 86 | } |
80 | 87 | ||
@@ -113,6 +120,8 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, | |||
113 | (data[0]<<8) | data[1]); | 120 | (data[0]<<8) | data[1]); |
114 | return -EIO; | 121 | return -EIO; |
115 | } | 122 | } |
123 | if (reg >= 0x10) | ||
124 | clear_bit(reg - 0x10, &uda1380_cache_dirty); | ||
116 | return 0; | 125 | return 0; |
117 | } else | 126 | } else |
118 | return -EIO; | 127 | return -EIO; |
@@ -120,6 +129,20 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, | |||
120 | 129 | ||
121 | #define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) | 130 | #define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) |
122 | 131 | ||
132 | static void uda1380_flush_work(struct work_struct *work) | ||
133 | { | ||
134 | int bit, reg; | ||
135 | |||
136 | for_each_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) { | ||
137 | reg = 0x10 + bit; | ||
138 | pr_debug("uda1380: flush reg %x val %x:\n", reg, | ||
139 | uda1380_read_reg_cache(uda1380_codec, reg)); | ||
140 | uda1380_write(uda1380_codec, reg, | ||
141 | uda1380_read_reg_cache(uda1380_codec, reg)); | ||
142 | clear_bit(bit, &uda1380_cache_dirty); | ||
143 | } | ||
144 | } | ||
145 | |||
123 | /* declarations of ALSA reg_elem_REAL controls */ | 146 | /* declarations of ALSA reg_elem_REAL controls */ |
124 | static const char *uda1380_deemp[] = { | 147 | static const char *uda1380_deemp[] = { |
125 | "None", | 148 | "None", |
@@ -254,7 +277,6 @@ static const struct snd_kcontrol_new uda1380_snd_controls[] = { | |||
254 | SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */ | 277 | SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */ |
255 | SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ | 278 | SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ |
256 | SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */ | 279 | SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */ |
257 | SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0), /* SILENCE, force DAC output to silence */ | ||
258 | SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ | 280 | SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ |
259 | SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ | 281 | SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ |
260 | SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */ | 282 | SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */ |
@@ -271,21 +293,6 @@ static const struct snd_kcontrol_new uda1380_snd_controls[] = { | |||
271 | SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), | 293 | SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), |
272 | }; | 294 | }; |
273 | 295 | ||
274 | /* add non dapm controls */ | ||
275 | static int uda1380_add_controls(struct snd_soc_codec *codec) | ||
276 | { | ||
277 | int err, i; | ||
278 | |||
279 | for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) { | ||
280 | err = snd_ctl_add(codec->card, | ||
281 | snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL)); | ||
282 | if (err < 0) | ||
283 | return err; | ||
284 | } | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | /* Input mux */ | 296 | /* Input mux */ |
290 | static const struct snd_kcontrol_new uda1380_input_mux_control = | 297 | static const struct snd_kcontrol_new uda1380_input_mux_control = |
291 | SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); | 298 | SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); |
@@ -371,7 +378,7 @@ static int uda1380_add_widgets(struct snd_soc_codec *codec) | |||
371 | return 0; | 378 | return 0; |
372 | } | 379 | } |
373 | 380 | ||
374 | static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, | 381 | static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai, |
375 | unsigned int fmt) | 382 | unsigned int fmt) |
376 | { | 383 | { |
377 | struct snd_soc_codec *codec = codec_dai->codec; | 384 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -381,61 +388,107 @@ static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
381 | iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); | 388 | iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); |
382 | iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK); | 389 | iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK); |
383 | 390 | ||
384 | /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */ | ||
385 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 391 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
386 | case SND_SOC_DAIFMT_I2S: | 392 | case SND_SOC_DAIFMT_I2S: |
387 | iface |= R01_SFORI_I2S | R01_SFORO_I2S; | 393 | iface |= R01_SFORI_I2S | R01_SFORO_I2S; |
388 | break; | 394 | break; |
389 | case SND_SOC_DAIFMT_LSB: | 395 | case SND_SOC_DAIFMT_LSB: |
390 | iface |= R01_SFORI_LSB16 | R01_SFORO_I2S; | 396 | iface |= R01_SFORI_LSB16 | R01_SFORO_LSB16; |
391 | break; | 397 | break; |
392 | case SND_SOC_DAIFMT_MSB: | 398 | case SND_SOC_DAIFMT_MSB: |
393 | iface |= R01_SFORI_MSB | R01_SFORO_I2S; | 399 | iface |= R01_SFORI_MSB | R01_SFORO_MSB; |
394 | } | 400 | } |
395 | 401 | ||
396 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) | 402 | /* DATAI is slave only, so in single-link mode, this has to be slave */ |
397 | iface |= R01_SIM; | 403 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) |
404 | return -EINVAL; | ||
398 | 405 | ||
399 | uda1380_write(codec, UDA1380_IFACE, iface); | 406 | uda1380_write(codec, UDA1380_IFACE, iface); |
400 | 407 | ||
401 | return 0; | 408 | return 0; |
402 | } | 409 | } |
403 | 410 | ||
404 | /* | 411 | static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai, |
405 | * Flush reg cache | 412 | unsigned int fmt) |
406 | * We can only write the interpolator and decimator registers | ||
407 | * when the DAI is being clocked by the CPU DAI. It's up to the | ||
408 | * machine and cpu DAI driver to do this before we are called. | ||
409 | */ | ||
410 | static int uda1380_pcm_prepare(struct snd_pcm_substream *substream, | ||
411 | struct snd_soc_dai *dai) | ||
412 | { | 413 | { |
413 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 414 | struct snd_soc_codec *codec = codec_dai->codec; |
414 | struct snd_soc_device *socdev = rtd->socdev; | 415 | int iface; |
415 | struct snd_soc_codec *codec = socdev->codec; | 416 | |
416 | int reg, reg_start, reg_end, clk; | 417 | /* set up DAI based upon fmt */ |
417 | 418 | iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); | |
418 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 419 | iface &= ~R01_SFORI_MASK; |
419 | reg_start = UDA1380_MVOL; | 420 | |
420 | reg_end = UDA1380_MIXER; | 421 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
421 | } else { | 422 | case SND_SOC_DAIFMT_I2S: |
422 | reg_start = UDA1380_DEC; | 423 | iface |= R01_SFORI_I2S; |
423 | reg_end = UDA1380_AGC; | 424 | break; |
425 | case SND_SOC_DAIFMT_LSB: | ||
426 | iface |= R01_SFORI_LSB16; | ||
427 | break; | ||
428 | case SND_SOC_DAIFMT_MSB: | ||
429 | iface |= R01_SFORI_MSB; | ||
424 | } | 430 | } |
425 | 431 | ||
426 | /* FIXME disable DAC_CLK */ | 432 | /* DATAI is slave only, so this has to be slave */ |
427 | clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | 433 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) |
428 | uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK); | 434 | return -EINVAL; |
435 | |||
436 | uda1380_write(codec, UDA1380_IFACE, iface); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai, | ||
442 | unsigned int fmt) | ||
443 | { | ||
444 | struct snd_soc_codec *codec = codec_dai->codec; | ||
445 | int iface; | ||
446 | |||
447 | /* set up DAI based upon fmt */ | ||
448 | iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); | ||
449 | iface &= ~(R01_SIM | R01_SFORO_MASK); | ||
429 | 450 | ||
430 | for (reg = reg_start; reg <= reg_end; reg++) { | 451 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
431 | pr_debug("uda1380: flush reg %x val %x:", reg, | 452 | case SND_SOC_DAIFMT_I2S: |
432 | uda1380_read_reg_cache(codec, reg)); | 453 | iface |= R01_SFORO_I2S; |
433 | uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg)); | 454 | break; |
455 | case SND_SOC_DAIFMT_LSB: | ||
456 | iface |= R01_SFORO_LSB16; | ||
457 | break; | ||
458 | case SND_SOC_DAIFMT_MSB: | ||
459 | iface |= R01_SFORO_MSB; | ||
434 | } | 460 | } |
435 | 461 | ||
436 | /* FIXME enable DAC_CLK */ | 462 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) |
437 | uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK); | 463 | iface |= R01_SIM; |
438 | 464 | ||
465 | uda1380_write(codec, UDA1380_IFACE, iface); | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd, | ||
471 | struct snd_soc_dai *dai) | ||
472 | { | ||
473 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
474 | struct snd_soc_device *socdev = rtd->socdev; | ||
475 | struct snd_soc_codec *codec = socdev->card->codec; | ||
476 | int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER); | ||
477 | |||
478 | switch (cmd) { | ||
479 | case SNDRV_PCM_TRIGGER_START: | ||
480 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
481 | uda1380_write_reg_cache(codec, UDA1380_MIXER, | ||
482 | mixer & ~R14_SILENCE); | ||
483 | schedule_work(&uda1380_work); | ||
484 | break; | ||
485 | case SNDRV_PCM_TRIGGER_STOP: | ||
486 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
487 | uda1380_write_reg_cache(codec, UDA1380_MIXER, | ||
488 | mixer | R14_SILENCE); | ||
489 | schedule_work(&uda1380_work); | ||
490 | break; | ||
491 | } | ||
439 | return 0; | 492 | return 0; |
440 | } | 493 | } |
441 | 494 | ||
@@ -445,7 +498,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, | |||
445 | { | 498 | { |
446 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 499 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
447 | struct snd_soc_device *socdev = rtd->socdev; | 500 | struct snd_soc_device *socdev = rtd->socdev; |
448 | struct snd_soc_codec *codec = socdev->codec; | 501 | struct snd_soc_codec *codec = socdev->card->codec; |
449 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | 502 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); |
450 | 503 | ||
451 | /* set WSPLL power and divider if running from this clock */ | 504 | /* set WSPLL power and divider if running from this clock */ |
@@ -484,7 +537,7 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream, | |||
484 | { | 537 | { |
485 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 538 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
486 | struct snd_soc_device *socdev = rtd->socdev; | 539 | struct snd_soc_device *socdev = rtd->socdev; |
487 | struct snd_soc_codec *codec = socdev->codec; | 540 | struct snd_soc_codec *codec = socdev->card->codec; |
488 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | 541 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); |
489 | 542 | ||
490 | /* shut down WSPLL power if running from this clock */ | 543 | /* shut down WSPLL power if running from this clock */ |
@@ -501,24 +554,6 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream, | |||
501 | uda1380_write(codec, UDA1380_CLK, clk); | 554 | uda1380_write(codec, UDA1380_CLK, clk); |
502 | } | 555 | } |
503 | 556 | ||
504 | static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute) | ||
505 | { | ||
506 | struct snd_soc_codec *codec = codec_dai->codec; | ||
507 | u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM; | ||
508 | |||
509 | /* FIXME: mute(codec,0) is called when the magician clock is already | ||
510 | * set to WSPLL, but for some unknown reason writing to interpolator | ||
511 | * registers works only when clocked by SYSCLK */ | ||
512 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
513 | uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk); | ||
514 | if (mute) | ||
515 | uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM); | ||
516 | else | ||
517 | uda1380_write(codec, UDA1380_DEEMP, mute_reg); | ||
518 | uda1380_write(codec, UDA1380_CLK, clk); | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static int uda1380_set_bias_level(struct snd_soc_codec *codec, | 557 | static int uda1380_set_bias_level(struct snd_soc_codec *codec, |
523 | enum snd_soc_bias_level level) | 558 | enum snd_soc_bias_level level) |
524 | { | 559 | { |
@@ -544,6 +579,27 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec, | |||
544 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | 579 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ |
545 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 580 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
546 | 581 | ||
582 | static struct snd_soc_dai_ops uda1380_dai_ops = { | ||
583 | .hw_params = uda1380_pcm_hw_params, | ||
584 | .shutdown = uda1380_pcm_shutdown, | ||
585 | .trigger = uda1380_trigger, | ||
586 | .set_fmt = uda1380_set_dai_fmt_both, | ||
587 | }; | ||
588 | |||
589 | static struct snd_soc_dai_ops uda1380_dai_ops_playback = { | ||
590 | .hw_params = uda1380_pcm_hw_params, | ||
591 | .shutdown = uda1380_pcm_shutdown, | ||
592 | .trigger = uda1380_trigger, | ||
593 | .set_fmt = uda1380_set_dai_fmt_playback, | ||
594 | }; | ||
595 | |||
596 | static struct snd_soc_dai_ops uda1380_dai_ops_capture = { | ||
597 | .hw_params = uda1380_pcm_hw_params, | ||
598 | .shutdown = uda1380_pcm_shutdown, | ||
599 | .trigger = uda1380_trigger, | ||
600 | .set_fmt = uda1380_set_dai_fmt_capture, | ||
601 | }; | ||
602 | |||
547 | struct snd_soc_dai uda1380_dai[] = { | 603 | struct snd_soc_dai uda1380_dai[] = { |
548 | { | 604 | { |
549 | .name = "UDA1380", | 605 | .name = "UDA1380", |
@@ -559,13 +615,7 @@ struct snd_soc_dai uda1380_dai[] = { | |||
559 | .channels_max = 2, | 615 | .channels_max = 2, |
560 | .rates = UDA1380_RATES, | 616 | .rates = UDA1380_RATES, |
561 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 617 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
562 | .ops = { | 618 | .ops = &uda1380_dai_ops, |
563 | .hw_params = uda1380_pcm_hw_params, | ||
564 | .shutdown = uda1380_pcm_shutdown, | ||
565 | .prepare = uda1380_pcm_prepare, | ||
566 | .digital_mute = uda1380_mute, | ||
567 | .set_fmt = uda1380_set_dai_fmt, | ||
568 | }, | ||
569 | }, | 619 | }, |
570 | { /* playback only - dual interface */ | 620 | { /* playback only - dual interface */ |
571 | .name = "UDA1380", | 621 | .name = "UDA1380", |
@@ -576,13 +626,7 @@ struct snd_soc_dai uda1380_dai[] = { | |||
576 | .rates = UDA1380_RATES, | 626 | .rates = UDA1380_RATES, |
577 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 627 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
578 | }, | 628 | }, |
579 | .ops = { | 629 | .ops = &uda1380_dai_ops_playback, |
580 | .hw_params = uda1380_pcm_hw_params, | ||
581 | .shutdown = uda1380_pcm_shutdown, | ||
582 | .prepare = uda1380_pcm_prepare, | ||
583 | .digital_mute = uda1380_mute, | ||
584 | .set_fmt = uda1380_set_dai_fmt, | ||
585 | }, | ||
586 | }, | 630 | }, |
587 | { /* capture only - dual interface*/ | 631 | { /* capture only - dual interface*/ |
588 | .name = "UDA1380", | 632 | .name = "UDA1380", |
@@ -593,12 +637,7 @@ struct snd_soc_dai uda1380_dai[] = { | |||
593 | .rates = UDA1380_RATES, | 637 | .rates = UDA1380_RATES, |
594 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 638 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
595 | }, | 639 | }, |
596 | .ops = { | 640 | .ops = &uda1380_dai_ops_capture, |
597 | .hw_params = uda1380_pcm_hw_params, | ||
598 | .shutdown = uda1380_pcm_shutdown, | ||
599 | .prepare = uda1380_pcm_prepare, | ||
600 | .set_fmt = uda1380_set_dai_fmt, | ||
601 | }, | ||
602 | }, | 641 | }, |
603 | }; | 642 | }; |
604 | EXPORT_SYMBOL_GPL(uda1380_dai); | 643 | EXPORT_SYMBOL_GPL(uda1380_dai); |
@@ -606,7 +645,7 @@ EXPORT_SYMBOL_GPL(uda1380_dai); | |||
606 | static int uda1380_suspend(struct platform_device *pdev, pm_message_t state) | 645 | static int uda1380_suspend(struct platform_device *pdev, pm_message_t state) |
607 | { | 646 | { |
608 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 647 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
609 | struct snd_soc_codec *codec = socdev->codec; | 648 | struct snd_soc_codec *codec = socdev->card->codec; |
610 | 649 | ||
611 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | 650 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); |
612 | return 0; | 651 | return 0; |
@@ -615,7 +654,7 @@ static int uda1380_suspend(struct platform_device *pdev, pm_message_t state) | |||
615 | static int uda1380_resume(struct platform_device *pdev) | 654 | static int uda1380_resume(struct platform_device *pdev) |
616 | { | 655 | { |
617 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 656 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
618 | struct snd_soc_codec *codec = socdev->codec; | 657 | struct snd_soc_codec *codec = socdev->card->codec; |
619 | int i; | 658 | int i; |
620 | u8 data[2]; | 659 | u8 data[2]; |
621 | u16 *cache = codec->reg_cache; | 660 | u16 *cache = codec->reg_cache; |
@@ -637,7 +676,7 @@ static int uda1380_resume(struct platform_device *pdev) | |||
637 | */ | 676 | */ |
638 | static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | 677 | static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) |
639 | { | 678 | { |
640 | struct snd_soc_codec *codec = socdev->codec; | 679 | struct snd_soc_codec *codec = socdev->card->codec; |
641 | int ret = 0; | 680 | int ret = 0; |
642 | 681 | ||
643 | codec->name = "UDA1380"; | 682 | codec->name = "UDA1380"; |
@@ -655,6 +694,9 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | |||
655 | codec->reg_cache_step = 1; | 694 | codec->reg_cache_step = 1; |
656 | uda1380_reset(codec); | 695 | uda1380_reset(codec); |
657 | 696 | ||
697 | uda1380_codec = codec; | ||
698 | INIT_WORK(&uda1380_work, uda1380_flush_work); | ||
699 | |||
658 | /* register pcms */ | 700 | /* register pcms */ |
659 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 701 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
660 | if (ret < 0) { | 702 | if (ret < 0) { |
@@ -675,7 +717,8 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | |||
675 | } | 717 | } |
676 | 718 | ||
677 | /* uda1380 init */ | 719 | /* uda1380 init */ |
678 | uda1380_add_controls(codec); | 720 | snd_soc_add_controls(codec, uda1380_snd_controls, |
721 | ARRAY_SIZE(uda1380_snd_controls)); | ||
679 | uda1380_add_widgets(codec); | 722 | uda1380_add_widgets(codec); |
680 | ret = snd_soc_init_card(socdev); | 723 | ret = snd_soc_init_card(socdev); |
681 | if (ret < 0) { | 724 | if (ret < 0) { |
@@ -702,7 +745,7 @@ static int uda1380_i2c_probe(struct i2c_client *i2c, | |||
702 | { | 745 | { |
703 | struct snd_soc_device *socdev = uda1380_socdev; | 746 | struct snd_soc_device *socdev = uda1380_socdev; |
704 | struct uda1380_setup_data *setup = socdev->codec_data; | 747 | struct uda1380_setup_data *setup = socdev->codec_data; |
705 | struct snd_soc_codec *codec = socdev->codec; | 748 | struct snd_soc_codec *codec = socdev->card->codec; |
706 | int ret; | 749 | int ret; |
707 | 750 | ||
708 | i2c_set_clientdata(i2c, codec); | 751 | i2c_set_clientdata(i2c, codec); |
@@ -786,14 +829,12 @@ static int uda1380_probe(struct platform_device *pdev) | |||
786 | struct snd_soc_codec *codec; | 829 | struct snd_soc_codec *codec; |
787 | int ret; | 830 | int ret; |
788 | 831 | ||
789 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); | ||
790 | |||
791 | setup = socdev->codec_data; | 832 | setup = socdev->codec_data; |
792 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 833 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
793 | if (codec == NULL) | 834 | if (codec == NULL) |
794 | return -ENOMEM; | 835 | return -ENOMEM; |
795 | 836 | ||
796 | socdev->codec = codec; | 837 | socdev->card->codec = codec; |
797 | mutex_init(&codec->mutex); | 838 | mutex_init(&codec->mutex); |
798 | INIT_LIST_HEAD(&codec->dapm_widgets); | 839 | INIT_LIST_HEAD(&codec->dapm_widgets); |
799 | INIT_LIST_HEAD(&codec->dapm_paths); | 840 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -817,7 +858,7 @@ static int uda1380_probe(struct platform_device *pdev) | |||
817 | static int uda1380_remove(struct platform_device *pdev) | 858 | static int uda1380_remove(struct platform_device *pdev) |
818 | { | 859 | { |
819 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 860 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
820 | struct snd_soc_codec *codec = socdev->codec; | 861 | struct snd_soc_codec *codec = socdev->card->codec; |
821 | 862 | ||
822 | if (codec->control_data) | 863 | if (codec->control_data) |
823 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | 864 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); |
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 35d99750c383..3b1d0993bed9 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -51,10 +51,17 @@ struct wm8350_output { | |||
51 | u16 mute; | 51 | u16 mute; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | struct wm8350_jack_data { | ||
55 | struct snd_soc_jack *jack; | ||
56 | int report; | ||
57 | }; | ||
58 | |||
54 | struct wm8350_data { | 59 | struct wm8350_data { |
55 | struct snd_soc_codec codec; | 60 | struct snd_soc_codec codec; |
56 | struct wm8350_output out1; | 61 | struct wm8350_output out1; |
57 | struct wm8350_output out2; | 62 | struct wm8350_output out2; |
63 | struct wm8350_jack_data hpl; | ||
64 | struct wm8350_jack_data hpr; | ||
58 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | 65 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; |
59 | }; | 66 | }; |
60 | 67 | ||
@@ -775,21 +782,6 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
775 | {"Beep", NULL, "IN3R PGA"}, | 782 | {"Beep", NULL, "IN3R PGA"}, |
776 | }; | 783 | }; |
777 | 784 | ||
778 | static int wm8350_add_controls(struct snd_soc_codec *codec) | ||
779 | { | ||
780 | int err, i; | ||
781 | |||
782 | for (i = 0; i < ARRAY_SIZE(wm8350_snd_controls); i++) { | ||
783 | err = snd_ctl_add(codec->card, | ||
784 | snd_soc_cnew(&wm8350_snd_controls[i], | ||
785 | codec, NULL)); | ||
786 | if (err < 0) | ||
787 | return err; | ||
788 | } | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static int wm8350_add_widgets(struct snd_soc_codec *codec) | 785 | static int wm8350_add_widgets(struct snd_soc_codec *codec) |
794 | { | 786 | { |
795 | int ret; | 787 | int ret; |
@@ -1309,7 +1301,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec, | |||
1309 | static int wm8350_suspend(struct platform_device *pdev, pm_message_t state) | 1301 | static int wm8350_suspend(struct platform_device *pdev, pm_message_t state) |
1310 | { | 1302 | { |
1311 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1303 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1312 | struct snd_soc_codec *codec = socdev->codec; | 1304 | struct snd_soc_codec *codec = socdev->card->codec; |
1313 | 1305 | ||
1314 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1306 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1315 | return 0; | 1307 | return 0; |
@@ -1318,7 +1310,7 @@ static int wm8350_suspend(struct platform_device *pdev, pm_message_t state) | |||
1318 | static int wm8350_resume(struct platform_device *pdev) | 1310 | static int wm8350_resume(struct platform_device *pdev) |
1319 | { | 1311 | { |
1320 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1312 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1321 | struct snd_soc_codec *codec = socdev->codec; | 1313 | struct snd_soc_codec *codec = socdev->card->codec; |
1322 | 1314 | ||
1323 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1315 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1324 | 1316 | ||
@@ -1328,6 +1320,95 @@ static int wm8350_resume(struct platform_device *pdev) | |||
1328 | return 0; | 1320 | return 0; |
1329 | } | 1321 | } |
1330 | 1322 | ||
1323 | static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data) | ||
1324 | { | ||
1325 | struct wm8350_data *priv = data; | ||
1326 | u16 reg; | ||
1327 | int report; | ||
1328 | int mask; | ||
1329 | struct wm8350_jack_data *jack = NULL; | ||
1330 | |||
1331 | switch (irq) { | ||
1332 | case WM8350_IRQ_CODEC_JCK_DET_L: | ||
1333 | jack = &priv->hpl; | ||
1334 | mask = WM8350_JACK_L_LVL; | ||
1335 | break; | ||
1336 | |||
1337 | case WM8350_IRQ_CODEC_JCK_DET_R: | ||
1338 | jack = &priv->hpr; | ||
1339 | mask = WM8350_JACK_R_LVL; | ||
1340 | break; | ||
1341 | |||
1342 | default: | ||
1343 | BUG(); | ||
1344 | } | ||
1345 | |||
1346 | if (!jack->jack) { | ||
1347 | dev_warn(wm8350->dev, "Jack interrupt called with no jack\n"); | ||
1348 | return; | ||
1349 | } | ||
1350 | |||
1351 | /* Debounce */ | ||
1352 | msleep(200); | ||
1353 | |||
1354 | reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS); | ||
1355 | if (reg & mask) | ||
1356 | report = jack->report; | ||
1357 | else | ||
1358 | report = 0; | ||
1359 | |||
1360 | snd_soc_jack_report(jack->jack, report, jack->report); | ||
1361 | } | ||
1362 | |||
1363 | /** | ||
1364 | * wm8350_hp_jack_detect - Enable headphone jack detection. | ||
1365 | * | ||
1366 | * @codec: WM8350 codec | ||
1367 | * @which: left or right jack detect signal | ||
1368 | * @jack: jack to report detection events on | ||
1369 | * @report: value to report | ||
1370 | * | ||
1371 | * Enables the headphone jack detection of the WM8350. | ||
1372 | */ | ||
1373 | int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, | ||
1374 | struct snd_soc_jack *jack, int report) | ||
1375 | { | ||
1376 | struct wm8350_data *priv = codec->private_data; | ||
1377 | struct wm8350 *wm8350 = codec->control_data; | ||
1378 | int irq; | ||
1379 | int ena; | ||
1380 | |||
1381 | switch (which) { | ||
1382 | case WM8350_JDL: | ||
1383 | priv->hpl.jack = jack; | ||
1384 | priv->hpl.report = report; | ||
1385 | irq = WM8350_IRQ_CODEC_JCK_DET_L; | ||
1386 | ena = WM8350_JDL_ENA; | ||
1387 | break; | ||
1388 | |||
1389 | case WM8350_JDR: | ||
1390 | priv->hpr.jack = jack; | ||
1391 | priv->hpr.report = report; | ||
1392 | irq = WM8350_IRQ_CODEC_JCK_DET_R; | ||
1393 | ena = WM8350_JDR_ENA; | ||
1394 | break; | ||
1395 | |||
1396 | default: | ||
1397 | return -EINVAL; | ||
1398 | } | ||
1399 | |||
1400 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); | ||
1401 | wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); | ||
1402 | |||
1403 | /* Sync status */ | ||
1404 | wm8350_hp_jack_handler(wm8350, irq, priv); | ||
1405 | |||
1406 | wm8350_unmask_irq(wm8350, irq); | ||
1407 | |||
1408 | return 0; | ||
1409 | } | ||
1410 | EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect); | ||
1411 | |||
1331 | static struct snd_soc_codec *wm8350_codec; | 1412 | static struct snd_soc_codec *wm8350_codec; |
1332 | 1413 | ||
1333 | static int wm8350_probe(struct platform_device *pdev) | 1414 | static int wm8350_probe(struct platform_device *pdev) |
@@ -1342,8 +1423,8 @@ static int wm8350_probe(struct platform_device *pdev) | |||
1342 | 1423 | ||
1343 | BUG_ON(!wm8350_codec); | 1424 | BUG_ON(!wm8350_codec); |
1344 | 1425 | ||
1345 | socdev->codec = wm8350_codec; | 1426 | socdev->card->codec = wm8350_codec; |
1346 | codec = socdev->codec; | 1427 | codec = socdev->card->codec; |
1347 | wm8350 = codec->control_data; | 1428 | wm8350 = codec->control_data; |
1348 | priv = codec->private_data; | 1429 | priv = codec->private_data; |
1349 | 1430 | ||
@@ -1381,13 +1462,21 @@ static int wm8350_probe(struct platform_device *pdev) | |||
1381 | wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, | 1462 | wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, |
1382 | WM8350_OUT2_VU | WM8350_OUT2R_MUTE); | 1463 | WM8350_OUT2_VU | WM8350_OUT2R_MUTE); |
1383 | 1464 | ||
1465 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | ||
1466 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | ||
1467 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, | ||
1468 | wm8350_hp_jack_handler, priv); | ||
1469 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, | ||
1470 | wm8350_hp_jack_handler, priv); | ||
1471 | |||
1384 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 1472 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
1385 | if (ret < 0) { | 1473 | if (ret < 0) { |
1386 | dev_err(&pdev->dev, "failed to create pcms\n"); | 1474 | dev_err(&pdev->dev, "failed to create pcms\n"); |
1387 | return ret; | 1475 | return ret; |
1388 | } | 1476 | } |
1389 | 1477 | ||
1390 | wm8350_add_controls(codec); | 1478 | snd_soc_add_controls(codec, wm8350_snd_controls, |
1479 | ARRAY_SIZE(wm8350_snd_controls)); | ||
1391 | wm8350_add_widgets(codec); | 1480 | wm8350_add_widgets(codec); |
1392 | 1481 | ||
1393 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1482 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
@@ -1409,10 +1498,23 @@ card_err: | |||
1409 | static int wm8350_remove(struct platform_device *pdev) | 1498 | static int wm8350_remove(struct platform_device *pdev) |
1410 | { | 1499 | { |
1411 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1500 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1412 | struct snd_soc_codec *codec = socdev->codec; | 1501 | struct snd_soc_codec *codec = socdev->card->codec; |
1413 | struct wm8350 *wm8350 = codec->control_data; | 1502 | struct wm8350 *wm8350 = codec->control_data; |
1503 | struct wm8350_data *priv = codec->private_data; | ||
1414 | int ret; | 1504 | int ret; |
1415 | 1505 | ||
1506 | wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, | ||
1507 | WM8350_JDL_ENA | WM8350_JDR_ENA); | ||
1508 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); | ||
1509 | |||
1510 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | ||
1511 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | ||
1512 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | ||
1513 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | ||
1514 | |||
1515 | priv->hpl.jack = NULL; | ||
1516 | priv->hpr.jack = NULL; | ||
1517 | |||
1416 | /* cancel any work waiting to be queued. */ | 1518 | /* cancel any work waiting to be queued. */ |
1417 | ret = cancel_delayed_work(&codec->delayed_work); | 1519 | ret = cancel_delayed_work(&codec->delayed_work); |
1418 | 1520 | ||
@@ -1436,6 +1538,16 @@ static int wm8350_remove(struct platform_device *pdev) | |||
1436 | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1538 | SNDRV_PCM_FMTBIT_S20_3LE |\ |
1437 | SNDRV_PCM_FMTBIT_S24_LE) | 1539 | SNDRV_PCM_FMTBIT_S24_LE) |
1438 | 1540 | ||
1541 | static struct snd_soc_dai_ops wm8350_dai_ops = { | ||
1542 | .hw_params = wm8350_pcm_hw_params, | ||
1543 | .digital_mute = wm8350_mute, | ||
1544 | .trigger = wm8350_pcm_trigger, | ||
1545 | .set_fmt = wm8350_set_dai_fmt, | ||
1546 | .set_sysclk = wm8350_set_dai_sysclk, | ||
1547 | .set_pll = wm8350_set_fll, | ||
1548 | .set_clkdiv = wm8350_set_clkdiv, | ||
1549 | }; | ||
1550 | |||
1439 | struct snd_soc_dai wm8350_dai = { | 1551 | struct snd_soc_dai wm8350_dai = { |
1440 | .name = "WM8350", | 1552 | .name = "WM8350", |
1441 | .playback = { | 1553 | .playback = { |
@@ -1452,15 +1564,7 @@ struct snd_soc_dai wm8350_dai = { | |||
1452 | .rates = WM8350_RATES, | 1564 | .rates = WM8350_RATES, |
1453 | .formats = WM8350_FORMATS, | 1565 | .formats = WM8350_FORMATS, |
1454 | }, | 1566 | }, |
1455 | .ops = { | 1567 | .ops = &wm8350_dai_ops, |
1456 | .hw_params = wm8350_pcm_hw_params, | ||
1457 | .digital_mute = wm8350_mute, | ||
1458 | .trigger = wm8350_pcm_trigger, | ||
1459 | .set_fmt = wm8350_set_dai_fmt, | ||
1460 | .set_sysclk = wm8350_set_dai_sysclk, | ||
1461 | .set_pll = wm8350_set_fll, | ||
1462 | .set_clkdiv = wm8350_set_clkdiv, | ||
1463 | }, | ||
1464 | }; | 1568 | }; |
1465 | EXPORT_SYMBOL_GPL(wm8350_dai); | 1569 | EXPORT_SYMBOL_GPL(wm8350_dai); |
1466 | 1570 | ||
@@ -1472,7 +1576,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8350 = { | |||
1472 | }; | 1576 | }; |
1473 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350); | 1577 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350); |
1474 | 1578 | ||
1475 | static int wm8350_codec_probe(struct platform_device *pdev) | 1579 | static __devinit int wm8350_codec_probe(struct platform_device *pdev) |
1476 | { | 1580 | { |
1477 | struct wm8350 *wm8350 = platform_get_drvdata(pdev); | 1581 | struct wm8350 *wm8350 = platform_get_drvdata(pdev); |
1478 | struct wm8350_data *priv; | 1582 | struct wm8350_data *priv; |
diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h index cc2887aa6c38..d11bd9288cf9 100644 --- a/sound/soc/codecs/wm8350.h +++ b/sound/soc/codecs/wm8350.h | |||
@@ -17,4 +17,12 @@ | |||
17 | extern struct snd_soc_dai wm8350_dai; | 17 | extern struct snd_soc_dai wm8350_dai; |
18 | extern struct snd_soc_codec_device soc_codec_dev_wm8350; | 18 | extern struct snd_soc_codec_device soc_codec_dev_wm8350; |
19 | 19 | ||
20 | enum wm8350_jack { | ||
21 | WM8350_JDL = 1, | ||
22 | WM8350_JDR = 2, | ||
23 | }; | ||
24 | |||
25 | int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, | ||
26 | struct snd_soc_jack *jack, int report); | ||
27 | |||
20 | #endif | 28 | #endif |
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c new file mode 100644 index 000000000000..510efa604008 --- /dev/null +++ b/sound/soc/codecs/wm8400.c | |||
@@ -0,0 +1,1582 @@ | |||
1 | /* | ||
2 | * wm8400.c -- WM8400 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2008, 2009 Wolfson Microelectronics PLC. | ||
5 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <linux/mfd/wm8400-audio.h> | ||
23 | #include <linux/mfd/wm8400-private.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | #include <sound/soc-dapm.h> | ||
29 | #include <sound/initval.h> | ||
30 | #include <sound/tlv.h> | ||
31 | |||
32 | #include "wm8400.h" | ||
33 | |||
34 | /* Fake register for internal state */ | ||
35 | #define WM8400_INTDRIVBITS (WM8400_REGISTER_COUNT + 1) | ||
36 | #define WM8400_INMIXL_PWR 0 | ||
37 | #define WM8400_AINLMUX_PWR 1 | ||
38 | #define WM8400_INMIXR_PWR 2 | ||
39 | #define WM8400_AINRMUX_PWR 3 | ||
40 | |||
41 | static struct regulator_bulk_data power[] = { | ||
42 | { | ||
43 | .supply = "I2S1VDD", | ||
44 | }, | ||
45 | { | ||
46 | .supply = "I2S2VDD", | ||
47 | }, | ||
48 | { | ||
49 | .supply = "DCVDD", | ||
50 | }, | ||
51 | { | ||
52 | .supply = "AVDD", | ||
53 | }, | ||
54 | { | ||
55 | .supply = "FLLVDD", | ||
56 | }, | ||
57 | { | ||
58 | .supply = "HPVDD", | ||
59 | }, | ||
60 | { | ||
61 | .supply = "SPKVDD", | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | /* codec private data */ | ||
66 | struct wm8400_priv { | ||
67 | struct snd_soc_codec codec; | ||
68 | struct wm8400 *wm8400; | ||
69 | u16 fake_register; | ||
70 | unsigned int sysclk; | ||
71 | unsigned int pcmclk; | ||
72 | struct work_struct work; | ||
73 | int fll_in, fll_out; | ||
74 | }; | ||
75 | |||
76 | static inline unsigned int wm8400_read(struct snd_soc_codec *codec, | ||
77 | unsigned int reg) | ||
78 | { | ||
79 | struct wm8400_priv *wm8400 = codec->private_data; | ||
80 | |||
81 | if (reg == WM8400_INTDRIVBITS) | ||
82 | return wm8400->fake_register; | ||
83 | else | ||
84 | return wm8400_reg_read(wm8400->wm8400, reg); | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * write to the wm8400 register space | ||
89 | */ | ||
90 | static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg, | ||
91 | unsigned int value) | ||
92 | { | ||
93 | struct wm8400_priv *wm8400 = codec->private_data; | ||
94 | |||
95 | if (reg == WM8400_INTDRIVBITS) { | ||
96 | wm8400->fake_register = value; | ||
97 | return 0; | ||
98 | } else | ||
99 | return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value); | ||
100 | } | ||
101 | |||
102 | static void wm8400_codec_reset(struct snd_soc_codec *codec) | ||
103 | { | ||
104 | struct wm8400_priv *wm8400 = codec->private_data; | ||
105 | |||
106 | wm8400_reset_codec_reg_cache(wm8400->wm8400); | ||
107 | } | ||
108 | |||
109 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); | ||
110 | |||
111 | static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); | ||
112 | |||
113 | static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, -2100, 0); | ||
114 | |||
115 | static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); | ||
116 | |||
117 | static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); | ||
118 | |||
119 | static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); | ||
120 | |||
121 | static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); | ||
122 | |||
123 | static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); | ||
124 | |||
125 | static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | ||
126 | struct snd_ctl_elem_value *ucontrol) | ||
127 | { | ||
128 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
129 | struct soc_mixer_control *mc = | ||
130 | (struct soc_mixer_control *)kcontrol->private_value; | ||
131 | int reg = mc->reg; | ||
132 | int ret; | ||
133 | u16 val; | ||
134 | |||
135 | ret = snd_soc_put_volsw(kcontrol, ucontrol); | ||
136 | if (ret < 0) | ||
137 | return ret; | ||
138 | |||
139 | /* now hit the volume update bits (always bit 8) */ | ||
140 | val = wm8400_read(codec, reg); | ||
141 | return wm8400_write(codec, reg, val | 0x0100); | ||
142 | } | ||
143 | |||
144 | #define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \ | ||
145 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
146 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
147 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
148 | .tlv.p = (tlv_array), \ | ||
149 | .info = snd_soc_info_volsw, \ | ||
150 | .get = snd_soc_get_volsw, .put = wm8400_outpga_put_volsw_vu, \ | ||
151 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
152 | |||
153 | |||
154 | static const char *wm8400_digital_sidetone[] = | ||
155 | {"None", "Left ADC", "Right ADC", "Reserved"}; | ||
156 | |||
157 | static const struct soc_enum wm8400_left_digital_sidetone_enum = | ||
158 | SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, | ||
159 | WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone); | ||
160 | |||
161 | static const struct soc_enum wm8400_right_digital_sidetone_enum = | ||
162 | SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, | ||
163 | WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone); | ||
164 | |||
165 | static const char *wm8400_adcmode[] = | ||
166 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; | ||
167 | |||
168 | static const struct soc_enum wm8400_right_adcmode_enum = | ||
169 | SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode); | ||
170 | |||
171 | static const struct snd_kcontrol_new wm8400_snd_controls[] = { | ||
172 | /* INMIXL */ | ||
173 | SOC_SINGLE("LIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L12MNBST_SHIFT, | ||
174 | 1, 0), | ||
175 | SOC_SINGLE("LIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L34MNBST_SHIFT, | ||
176 | 1, 0), | ||
177 | /* INMIXR */ | ||
178 | SOC_SINGLE("RIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R12MNBST_SHIFT, | ||
179 | 1, 0), | ||
180 | SOC_SINGLE("RIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R34MNBST_SHIFT, | ||
181 | 1, 0), | ||
182 | |||
183 | /* LOMIX */ | ||
184 | SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER3, | ||
185 | WM8400_LLI3LOVOL_SHIFT, 7, 0, out_mix_tlv), | ||
186 | SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3, | ||
187 | WM8400_LR12LOVOL_SHIFT, 7, 0, out_mix_tlv), | ||
188 | SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3, | ||
189 | WM8400_LL12LOVOL_SHIFT, 7, 0, out_mix_tlv), | ||
190 | SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER5, | ||
191 | WM8400_LRI3LOVOL_SHIFT, 7, 0, out_mix_tlv), | ||
192 | SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER5, | ||
193 | WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv), | ||
194 | SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER5, | ||
195 | WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv), | ||
196 | |||
197 | /* ROMIX */ | ||
198 | SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER4, | ||
199 | WM8400_RRI3ROVOL_SHIFT, 7, 0, out_mix_tlv), | ||
200 | SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4, | ||
201 | WM8400_RL12ROVOL_SHIFT, 7, 0, out_mix_tlv), | ||
202 | SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4, | ||
203 | WM8400_RR12ROVOL_SHIFT, 7, 0, out_mix_tlv), | ||
204 | SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER6, | ||
205 | WM8400_RLI3ROVOL_SHIFT, 7, 0, out_mix_tlv), | ||
206 | SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER6, | ||
207 | WM8400_RLBROVOL_SHIFT, 7, 0, out_mix_tlv), | ||
208 | SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER6, | ||
209 | WM8400_RRBROVOL_SHIFT, 7, 0, out_mix_tlv), | ||
210 | |||
211 | /* LOUT */ | ||
212 | WM8400_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8400_LEFT_OUTPUT_VOLUME, | ||
213 | WM8400_LOUTVOL_SHIFT, WM8400_LOUTVOL_MASK, 0, out_pga_tlv), | ||
214 | SOC_SINGLE("LOUT ZC", WM8400_LEFT_OUTPUT_VOLUME, WM8400_LOZC_SHIFT, 1, 0), | ||
215 | |||
216 | /* ROUT */ | ||
217 | WM8400_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8400_RIGHT_OUTPUT_VOLUME, | ||
218 | WM8400_ROUTVOL_SHIFT, WM8400_ROUTVOL_MASK, 0, out_pga_tlv), | ||
219 | SOC_SINGLE("ROUT ZC", WM8400_RIGHT_OUTPUT_VOLUME, WM8400_ROZC_SHIFT, 1, 0), | ||
220 | |||
221 | /* LOPGA */ | ||
222 | WM8400_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8400_LEFT_OPGA_VOLUME, | ||
223 | WM8400_LOPGAVOL_SHIFT, WM8400_LOPGAVOL_MASK, 0, out_pga_tlv), | ||
224 | SOC_SINGLE("LOPGA ZC Switch", WM8400_LEFT_OPGA_VOLUME, | ||
225 | WM8400_LOPGAZC_SHIFT, 1, 0), | ||
226 | |||
227 | /* ROPGA */ | ||
228 | WM8400_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8400_RIGHT_OPGA_VOLUME, | ||
229 | WM8400_ROPGAVOL_SHIFT, WM8400_ROPGAVOL_MASK, 0, out_pga_tlv), | ||
230 | SOC_SINGLE("ROPGA ZC Switch", WM8400_RIGHT_OPGA_VOLUME, | ||
231 | WM8400_ROPGAZC_SHIFT, 1, 0), | ||
232 | |||
233 | SOC_SINGLE("LON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME, | ||
234 | WM8400_LONMUTE_SHIFT, 1, 0), | ||
235 | SOC_SINGLE("LOP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME, | ||
236 | WM8400_LOPMUTE_SHIFT, 1, 0), | ||
237 | SOC_SINGLE("LOP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME, | ||
238 | WM8400_LOATTN_SHIFT, 1, 0), | ||
239 | SOC_SINGLE("RON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME, | ||
240 | WM8400_RONMUTE_SHIFT, 1, 0), | ||
241 | SOC_SINGLE("ROP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME, | ||
242 | WM8400_ROPMUTE_SHIFT, 1, 0), | ||
243 | SOC_SINGLE("ROP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME, | ||
244 | WM8400_ROATTN_SHIFT, 1, 0), | ||
245 | |||
246 | SOC_SINGLE("OUT3 Mute Switch", WM8400_OUT3_4_VOLUME, | ||
247 | WM8400_OUT3MUTE_SHIFT, 1, 0), | ||
248 | SOC_SINGLE("OUT3 Attenuation Switch", WM8400_OUT3_4_VOLUME, | ||
249 | WM8400_OUT3ATTN_SHIFT, 1, 0), | ||
250 | |||
251 | SOC_SINGLE("OUT4 Mute Switch", WM8400_OUT3_4_VOLUME, | ||
252 | WM8400_OUT4MUTE_SHIFT, 1, 0), | ||
253 | SOC_SINGLE("OUT4 Attenuation Switch", WM8400_OUT3_4_VOLUME, | ||
254 | WM8400_OUT4ATTN_SHIFT, 1, 0), | ||
255 | |||
256 | SOC_SINGLE("Speaker Mode Switch", WM8400_CLASSD1, | ||
257 | WM8400_CDMODE_SHIFT, 1, 0), | ||
258 | |||
259 | SOC_SINGLE("Speaker Output Attenuation Volume", WM8400_SPEAKER_VOLUME, | ||
260 | WM8400_SPKATTN_SHIFT, WM8400_SPKATTN_MASK, 0), | ||
261 | SOC_SINGLE("Speaker DC Boost Volume", WM8400_CLASSD3, | ||
262 | WM8400_DCGAIN_SHIFT, 6, 0), | ||
263 | SOC_SINGLE("Speaker AC Boost Volume", WM8400_CLASSD3, | ||
264 | WM8400_ACGAIN_SHIFT, 6, 0), | ||
265 | |||
266 | WM8400_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume", | ||
267 | WM8400_LEFT_DAC_DIGITAL_VOLUME, WM8400_DACL_VOL_SHIFT, | ||
268 | 127, 0, out_dac_tlv), | ||
269 | |||
270 | WM8400_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume", | ||
271 | WM8400_RIGHT_DAC_DIGITAL_VOLUME, WM8400_DACR_VOL_SHIFT, | ||
272 | 127, 0, out_dac_tlv), | ||
273 | |||
274 | SOC_ENUM("Left Digital Sidetone", wm8400_left_digital_sidetone_enum), | ||
275 | SOC_ENUM("Right Digital Sidetone", wm8400_right_digital_sidetone_enum), | ||
276 | |||
277 | SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE, | ||
278 | WM8400_ADCL_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv), | ||
279 | SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE, | ||
280 | WM8400_ADCR_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv), | ||
281 | |||
282 | SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8400_ADC_CTRL, | ||
283 | WM8400_ADC_HPF_ENA_SHIFT, 1, 0), | ||
284 | |||
285 | SOC_ENUM("ADC HPF Mode", wm8400_right_adcmode_enum), | ||
286 | |||
287 | WM8400_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume", | ||
288 | WM8400_LEFT_ADC_DIGITAL_VOLUME, | ||
289 | WM8400_ADCL_VOL_SHIFT, | ||
290 | WM8400_ADCL_VOL_MASK, | ||
291 | 0, | ||
292 | in_adc_tlv), | ||
293 | |||
294 | WM8400_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume", | ||
295 | WM8400_RIGHT_ADC_DIGITAL_VOLUME, | ||
296 | WM8400_ADCR_VOL_SHIFT, | ||
297 | WM8400_ADCR_VOL_MASK, | ||
298 | 0, | ||
299 | in_adc_tlv), | ||
300 | |||
301 | WM8400_OUTPGA_SINGLE_R_TLV("LIN12 Volume", | ||
302 | WM8400_LEFT_LINE_INPUT_1_2_VOLUME, | ||
303 | WM8400_LIN12VOL_SHIFT, | ||
304 | WM8400_LIN12VOL_MASK, | ||
305 | 0, | ||
306 | in_pga_tlv), | ||
307 | |||
308 | SOC_SINGLE("LIN12 ZC Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME, | ||
309 | WM8400_LI12ZC_SHIFT, 1, 0), | ||
310 | |||
311 | SOC_SINGLE("LIN12 Mute Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME, | ||
312 | WM8400_LI12MUTE_SHIFT, 1, 0), | ||
313 | |||
314 | WM8400_OUTPGA_SINGLE_R_TLV("LIN34 Volume", | ||
315 | WM8400_LEFT_LINE_INPUT_3_4_VOLUME, | ||
316 | WM8400_LIN34VOL_SHIFT, | ||
317 | WM8400_LIN34VOL_MASK, | ||
318 | 0, | ||
319 | in_pga_tlv), | ||
320 | |||
321 | SOC_SINGLE("LIN34 ZC Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME, | ||
322 | WM8400_LI34ZC_SHIFT, 1, 0), | ||
323 | |||
324 | SOC_SINGLE("LIN34 Mute Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME, | ||
325 | WM8400_LI34MUTE_SHIFT, 1, 0), | ||
326 | |||
327 | WM8400_OUTPGA_SINGLE_R_TLV("RIN12 Volume", | ||
328 | WM8400_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
329 | WM8400_RIN12VOL_SHIFT, | ||
330 | WM8400_RIN12VOL_MASK, | ||
331 | 0, | ||
332 | in_pga_tlv), | ||
333 | |||
334 | SOC_SINGLE("RIN12 ZC Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
335 | WM8400_RI12ZC_SHIFT, 1, 0), | ||
336 | |||
337 | SOC_SINGLE("RIN12 Mute Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
338 | WM8400_RI12MUTE_SHIFT, 1, 0), | ||
339 | |||
340 | WM8400_OUTPGA_SINGLE_R_TLV("RIN34 Volume", | ||
341 | WM8400_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
342 | WM8400_RIN34VOL_SHIFT, | ||
343 | WM8400_RIN34VOL_MASK, | ||
344 | 0, | ||
345 | in_pga_tlv), | ||
346 | |||
347 | SOC_SINGLE("RIN34 ZC Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
348 | WM8400_RI34ZC_SHIFT, 1, 0), | ||
349 | |||
350 | SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
351 | WM8400_RI34MUTE_SHIFT, 1, 0), | ||
352 | |||
353 | }; | ||
354 | |||
355 | /* add non dapm controls */ | ||
356 | static int wm8400_add_controls(struct snd_soc_codec *codec) | ||
357 | { | ||
358 | return snd_soc_add_controls(codec, wm8400_snd_controls, | ||
359 | ARRAY_SIZE(wm8400_snd_controls)); | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * _DAPM_ Controls | ||
364 | */ | ||
365 | |||
366 | static int inmixer_event (struct snd_soc_dapm_widget *w, | ||
367 | struct snd_kcontrol *kcontrol, int event) | ||
368 | { | ||
369 | u16 reg, fakepower; | ||
370 | |||
371 | reg = wm8400_read(w->codec, WM8400_POWER_MANAGEMENT_2); | ||
372 | fakepower = wm8400_read(w->codec, WM8400_INTDRIVBITS); | ||
373 | |||
374 | if (fakepower & ((1 << WM8400_INMIXL_PWR) | | ||
375 | (1 << WM8400_AINLMUX_PWR))) { | ||
376 | reg |= WM8400_AINL_ENA; | ||
377 | } else { | ||
378 | reg &= ~WM8400_AINL_ENA; | ||
379 | } | ||
380 | |||
381 | if (fakepower & ((1 << WM8400_INMIXR_PWR) | | ||
382 | (1 << WM8400_AINRMUX_PWR))) { | ||
383 | reg |= WM8400_AINR_ENA; | ||
384 | } else { | ||
385 | reg &= ~WM8400_AINL_ENA; | ||
386 | } | ||
387 | wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int outmixer_event (struct snd_soc_dapm_widget *w, | ||
393 | struct snd_kcontrol * kcontrol, int event) | ||
394 | { | ||
395 | struct soc_mixer_control *mc = | ||
396 | (struct soc_mixer_control *)kcontrol->private_value; | ||
397 | u32 reg_shift = mc->shift; | ||
398 | int ret = 0; | ||
399 | u16 reg; | ||
400 | |||
401 | switch (reg_shift) { | ||
402 | case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) : | ||
403 | reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER1); | ||
404 | if (reg & WM8400_LDLO) { | ||
405 | printk(KERN_WARNING | ||
406 | "Cannot set as Output Mixer 1 LDLO Set\n"); | ||
407 | ret = -1; | ||
408 | } | ||
409 | break; | ||
410 | case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8): | ||
411 | reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER2); | ||
412 | if (reg & WM8400_RDRO) { | ||
413 | printk(KERN_WARNING | ||
414 | "Cannot set as Output Mixer 2 RDRO Set\n"); | ||
415 | ret = -1; | ||
416 | } | ||
417 | break; | ||
418 | case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8): | ||
419 | reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER); | ||
420 | if (reg & WM8400_LDSPK) { | ||
421 | printk(KERN_WARNING | ||
422 | "Cannot set as Speaker Mixer LDSPK Set\n"); | ||
423 | ret = -1; | ||
424 | } | ||
425 | break; | ||
426 | case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8): | ||
427 | reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER); | ||
428 | if (reg & WM8400_RDSPK) { | ||
429 | printk(KERN_WARNING | ||
430 | "Cannot set as Speaker Mixer RDSPK Set\n"); | ||
431 | ret = -1; | ||
432 | } | ||
433 | break; | ||
434 | } | ||
435 | |||
436 | return ret; | ||
437 | } | ||
438 | |||
439 | /* INMIX dB values */ | ||
440 | static const unsigned int in_mix_tlv[] = { | ||
441 | TLV_DB_RANGE_HEAD(1), | ||
442 | 0,7, TLV_DB_LINEAR_ITEM(-1200, 600), | ||
443 | }; | ||
444 | |||
445 | /* Left In PGA Connections */ | ||
446 | static const struct snd_kcontrol_new wm8400_dapm_lin12_pga_controls[] = { | ||
447 | SOC_DAPM_SINGLE("LIN1 Switch", WM8400_INPUT_MIXER2, WM8400_LMN1_SHIFT, 1, 0), | ||
448 | SOC_DAPM_SINGLE("LIN2 Switch", WM8400_INPUT_MIXER2, WM8400_LMP2_SHIFT, 1, 0), | ||
449 | }; | ||
450 | |||
451 | static const struct snd_kcontrol_new wm8400_dapm_lin34_pga_controls[] = { | ||
452 | SOC_DAPM_SINGLE("LIN3 Switch", WM8400_INPUT_MIXER2, WM8400_LMN3_SHIFT, 1, 0), | ||
453 | SOC_DAPM_SINGLE("LIN4 Switch", WM8400_INPUT_MIXER2, WM8400_LMP4_SHIFT, 1, 0), | ||
454 | }; | ||
455 | |||
456 | /* Right In PGA Connections */ | ||
457 | static const struct snd_kcontrol_new wm8400_dapm_rin12_pga_controls[] = { | ||
458 | SOC_DAPM_SINGLE("RIN1 Switch", WM8400_INPUT_MIXER2, WM8400_RMN1_SHIFT, 1, 0), | ||
459 | SOC_DAPM_SINGLE("RIN2 Switch", WM8400_INPUT_MIXER2, WM8400_RMP2_SHIFT, 1, 0), | ||
460 | }; | ||
461 | |||
462 | static const struct snd_kcontrol_new wm8400_dapm_rin34_pga_controls[] = { | ||
463 | SOC_DAPM_SINGLE("RIN3 Switch", WM8400_INPUT_MIXER2, WM8400_RMN3_SHIFT, 1, 0), | ||
464 | SOC_DAPM_SINGLE("RIN4 Switch", WM8400_INPUT_MIXER2, WM8400_RMP4_SHIFT, 1, 0), | ||
465 | }; | ||
466 | |||
467 | /* INMIXL */ | ||
468 | static const struct snd_kcontrol_new wm8400_dapm_inmixl_controls[] = { | ||
469 | SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8400_INPUT_MIXER3, | ||
470 | WM8400_LDBVOL_SHIFT, WM8400_LDBVOL_MASK, 0, in_mix_tlv), | ||
471 | SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8400_INPUT_MIXER5, WM8400_LI2BVOL_SHIFT, | ||
472 | 7, 0, in_mix_tlv), | ||
473 | SOC_DAPM_SINGLE("LINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT, | ||
474 | 1, 0), | ||
475 | SOC_DAPM_SINGLE("LINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT, | ||
476 | 1, 0), | ||
477 | }; | ||
478 | |||
479 | /* INMIXR */ | ||
480 | static const struct snd_kcontrol_new wm8400_dapm_inmixr_controls[] = { | ||
481 | SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8400_INPUT_MIXER4, | ||
482 | WM8400_RDBVOL_SHIFT, WM8400_RDBVOL_MASK, 0, in_mix_tlv), | ||
483 | SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8400_INPUT_MIXER6, WM8400_RI2BVOL_SHIFT, | ||
484 | 7, 0, in_mix_tlv), | ||
485 | SOC_DAPM_SINGLE("RINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT, | ||
486 | 1, 0), | ||
487 | SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT, | ||
488 | 1, 0), | ||
489 | }; | ||
490 | |||
491 | /* AINLMUX */ | ||
492 | static const char *wm8400_ainlmux[] = | ||
493 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; | ||
494 | |||
495 | static const struct soc_enum wm8400_ainlmux_enum = | ||
496 | SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT, | ||
497 | ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux); | ||
498 | |||
499 | static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls = | ||
500 | SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); | ||
501 | |||
502 | /* DIFFINL */ | ||
503 | |||
504 | /* AINRMUX */ | ||
505 | static const char *wm8400_ainrmux[] = | ||
506 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; | ||
507 | |||
508 | static const struct soc_enum wm8400_ainrmux_enum = | ||
509 | SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT, | ||
510 | ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux); | ||
511 | |||
512 | static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls = | ||
513 | SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum); | ||
514 | |||
515 | /* RXVOICE */ | ||
516 | static const struct snd_kcontrol_new wm8400_dapm_rxvoice_controls[] = { | ||
517 | SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8400_INPUT_MIXER5, WM8400_LR4BVOL_SHIFT, | ||
518 | WM8400_LR4BVOL_MASK, 0, in_mix_tlv), | ||
519 | SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8400_INPUT_MIXER6, WM8400_RL4BVOL_SHIFT, | ||
520 | WM8400_RL4BVOL_MASK, 0, in_mix_tlv), | ||
521 | }; | ||
522 | |||
523 | /* LOMIX */ | ||
524 | static const struct snd_kcontrol_new wm8400_dapm_lomix_controls[] = { | ||
525 | SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER1, | ||
526 | WM8400_LRBLO_SHIFT, 1, 0), | ||
527 | SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER1, | ||
528 | WM8400_LLBLO_SHIFT, 1, 0), | ||
529 | SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER1, | ||
530 | WM8400_LRI3LO_SHIFT, 1, 0), | ||
531 | SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER1, | ||
532 | WM8400_LLI3LO_SHIFT, 1, 0), | ||
533 | SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1, | ||
534 | WM8400_LR12LO_SHIFT, 1, 0), | ||
535 | SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1, | ||
536 | WM8400_LL12LO_SHIFT, 1, 0), | ||
537 | SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8400_OUTPUT_MIXER1, | ||
538 | WM8400_LDLO_SHIFT, 1, 0), | ||
539 | }; | ||
540 | |||
541 | /* ROMIX */ | ||
542 | static const struct snd_kcontrol_new wm8400_dapm_romix_controls[] = { | ||
543 | SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER2, | ||
544 | WM8400_RLBRO_SHIFT, 1, 0), | ||
545 | SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER2, | ||
546 | WM8400_RRBRO_SHIFT, 1, 0), | ||
547 | SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER2, | ||
548 | WM8400_RLI3RO_SHIFT, 1, 0), | ||
549 | SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER2, | ||
550 | WM8400_RRI3RO_SHIFT, 1, 0), | ||
551 | SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2, | ||
552 | WM8400_RL12RO_SHIFT, 1, 0), | ||
553 | SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2, | ||
554 | WM8400_RR12RO_SHIFT, 1, 0), | ||
555 | SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8400_OUTPUT_MIXER2, | ||
556 | WM8400_RDRO_SHIFT, 1, 0), | ||
557 | }; | ||
558 | |||
559 | /* LONMIX */ | ||
560 | static const struct snd_kcontrol_new wm8400_dapm_lonmix_controls[] = { | ||
561 | SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1, | ||
562 | WM8400_LLOPGALON_SHIFT, 1, 0), | ||
563 | SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER1, | ||
564 | WM8400_LROPGALON_SHIFT, 1, 0), | ||
565 | SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8400_LINE_MIXER1, | ||
566 | WM8400_LOPLON_SHIFT, 1, 0), | ||
567 | }; | ||
568 | |||
569 | /* LOPMIX */ | ||
570 | static const struct snd_kcontrol_new wm8400_dapm_lopmix_controls[] = { | ||
571 | SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER1, | ||
572 | WM8400_LR12LOP_SHIFT, 1, 0), | ||
573 | SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER1, | ||
574 | WM8400_LL12LOP_SHIFT, 1, 0), | ||
575 | SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1, | ||
576 | WM8400_LLOPGALOP_SHIFT, 1, 0), | ||
577 | }; | ||
578 | |||
579 | /* RONMIX */ | ||
580 | static const struct snd_kcontrol_new wm8400_dapm_ronmix_controls[] = { | ||
581 | SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2, | ||
582 | WM8400_RROPGARON_SHIFT, 1, 0), | ||
583 | SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER2, | ||
584 | WM8400_RLOPGARON_SHIFT, 1, 0), | ||
585 | SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8400_LINE_MIXER2, | ||
586 | WM8400_ROPRON_SHIFT, 1, 0), | ||
587 | }; | ||
588 | |||
589 | /* ROPMIX */ | ||
590 | static const struct snd_kcontrol_new wm8400_dapm_ropmix_controls[] = { | ||
591 | SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER2, | ||
592 | WM8400_RL12ROP_SHIFT, 1, 0), | ||
593 | SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER2, | ||
594 | WM8400_RR12ROP_SHIFT, 1, 0), | ||
595 | SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2, | ||
596 | WM8400_RROPGAROP_SHIFT, 1, 0), | ||
597 | }; | ||
598 | |||
599 | /* OUT3MIX */ | ||
600 | static const struct snd_kcontrol_new wm8400_dapm_out3mix_controls[] = { | ||
601 | SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER, | ||
602 | WM8400_LI4O3_SHIFT, 1, 0), | ||
603 | SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8400_OUT3_4_MIXER, | ||
604 | WM8400_LPGAO3_SHIFT, 1, 0), | ||
605 | }; | ||
606 | |||
607 | /* OUT4MIX */ | ||
608 | static const struct snd_kcontrol_new wm8400_dapm_out4mix_controls[] = { | ||
609 | SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8400_OUT3_4_MIXER, | ||
610 | WM8400_RPGAO4_SHIFT, 1, 0), | ||
611 | SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER, | ||
612 | WM8400_RI4O4_SHIFT, 1, 0), | ||
613 | }; | ||
614 | |||
615 | /* SPKMIX */ | ||
616 | static const struct snd_kcontrol_new wm8400_dapm_spkmix_controls[] = { | ||
617 | SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8400_SPEAKER_MIXER, | ||
618 | WM8400_LI2SPK_SHIFT, 1, 0), | ||
619 | SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8400_SPEAKER_MIXER, | ||
620 | WM8400_LB2SPK_SHIFT, 1, 0), | ||
621 | SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8400_SPEAKER_MIXER, | ||
622 | WM8400_LOPGASPK_SHIFT, 1, 0), | ||
623 | SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8400_SPEAKER_MIXER, | ||
624 | WM8400_LDSPK_SHIFT, 1, 0), | ||
625 | SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8400_SPEAKER_MIXER, | ||
626 | WM8400_RDSPK_SHIFT, 1, 0), | ||
627 | SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8400_SPEAKER_MIXER, | ||
628 | WM8400_ROPGASPK_SHIFT, 1, 0), | ||
629 | SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8400_SPEAKER_MIXER, | ||
630 | WM8400_RL12ROP_SHIFT, 1, 0), | ||
631 | SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8400_SPEAKER_MIXER, | ||
632 | WM8400_RI2SPK_SHIFT, 1, 0), | ||
633 | }; | ||
634 | |||
635 | static const struct snd_soc_dapm_widget wm8400_dapm_widgets[] = { | ||
636 | /* Input Side */ | ||
637 | /* Input Lines */ | ||
638 | SND_SOC_DAPM_INPUT("LIN1"), | ||
639 | SND_SOC_DAPM_INPUT("LIN2"), | ||
640 | SND_SOC_DAPM_INPUT("LIN3"), | ||
641 | SND_SOC_DAPM_INPUT("LIN4/RXN"), | ||
642 | SND_SOC_DAPM_INPUT("RIN3"), | ||
643 | SND_SOC_DAPM_INPUT("RIN4/RXP"), | ||
644 | SND_SOC_DAPM_INPUT("RIN1"), | ||
645 | SND_SOC_DAPM_INPUT("RIN2"), | ||
646 | SND_SOC_DAPM_INPUT("Internal ADC Source"), | ||
647 | |||
648 | /* DACs */ | ||
649 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8400_POWER_MANAGEMENT_2, | ||
650 | WM8400_ADCL_ENA_SHIFT, 0), | ||
651 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8400_POWER_MANAGEMENT_2, | ||
652 | WM8400_ADCR_ENA_SHIFT, 0), | ||
653 | |||
654 | /* Input PGAs */ | ||
655 | SND_SOC_DAPM_MIXER("LIN12 PGA", WM8400_POWER_MANAGEMENT_2, | ||
656 | WM8400_LIN12_ENA_SHIFT, | ||
657 | 0, &wm8400_dapm_lin12_pga_controls[0], | ||
658 | ARRAY_SIZE(wm8400_dapm_lin12_pga_controls)), | ||
659 | SND_SOC_DAPM_MIXER("LIN34 PGA", WM8400_POWER_MANAGEMENT_2, | ||
660 | WM8400_LIN34_ENA_SHIFT, | ||
661 | 0, &wm8400_dapm_lin34_pga_controls[0], | ||
662 | ARRAY_SIZE(wm8400_dapm_lin34_pga_controls)), | ||
663 | SND_SOC_DAPM_MIXER("RIN12 PGA", WM8400_POWER_MANAGEMENT_2, | ||
664 | WM8400_RIN12_ENA_SHIFT, | ||
665 | 0, &wm8400_dapm_rin12_pga_controls[0], | ||
666 | ARRAY_SIZE(wm8400_dapm_rin12_pga_controls)), | ||
667 | SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2, | ||
668 | WM8400_RIN34_ENA_SHIFT, | ||
669 | 0, &wm8400_dapm_rin34_pga_controls[0], | ||
670 | ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)), | ||
671 | |||
672 | /* INMIXL */ | ||
673 | SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0, | ||
674 | &wm8400_dapm_inmixl_controls[0], | ||
675 | ARRAY_SIZE(wm8400_dapm_inmixl_controls), | ||
676 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
677 | |||
678 | /* AINLMUX */ | ||
679 | SND_SOC_DAPM_MUX_E("AILNMUX", WM8400_INTDRIVBITS, WM8400_AINLMUX_PWR, 0, | ||
680 | &wm8400_dapm_ainlmux_controls, inmixer_event, | ||
681 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
682 | |||
683 | /* INMIXR */ | ||
684 | SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0, | ||
685 | &wm8400_dapm_inmixr_controls[0], | ||
686 | ARRAY_SIZE(wm8400_dapm_inmixr_controls), | ||
687 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
688 | |||
689 | /* AINRMUX */ | ||
690 | SND_SOC_DAPM_MUX_E("AIRNMUX", WM8400_INTDRIVBITS, WM8400_AINRMUX_PWR, 0, | ||
691 | &wm8400_dapm_ainrmux_controls, inmixer_event, | ||
692 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
693 | |||
694 | /* Output Side */ | ||
695 | /* DACs */ | ||
696 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8400_POWER_MANAGEMENT_3, | ||
697 | WM8400_DACL_ENA_SHIFT, 0), | ||
698 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8400_POWER_MANAGEMENT_3, | ||
699 | WM8400_DACR_ENA_SHIFT, 0), | ||
700 | |||
701 | /* LOMIX */ | ||
702 | SND_SOC_DAPM_MIXER_E("LOMIX", WM8400_POWER_MANAGEMENT_3, | ||
703 | WM8400_LOMIX_ENA_SHIFT, | ||
704 | 0, &wm8400_dapm_lomix_controls[0], | ||
705 | ARRAY_SIZE(wm8400_dapm_lomix_controls), | ||
706 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
707 | |||
708 | /* LONMIX */ | ||
709 | SND_SOC_DAPM_MIXER("LONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LON_ENA_SHIFT, | ||
710 | 0, &wm8400_dapm_lonmix_controls[0], | ||
711 | ARRAY_SIZE(wm8400_dapm_lonmix_controls)), | ||
712 | |||
713 | /* LOPMIX */ | ||
714 | SND_SOC_DAPM_MIXER("LOPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LOP_ENA_SHIFT, | ||
715 | 0, &wm8400_dapm_lopmix_controls[0], | ||
716 | ARRAY_SIZE(wm8400_dapm_lopmix_controls)), | ||
717 | |||
718 | /* OUT3MIX */ | ||
719 | SND_SOC_DAPM_MIXER("OUT3MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT3_ENA_SHIFT, | ||
720 | 0, &wm8400_dapm_out3mix_controls[0], | ||
721 | ARRAY_SIZE(wm8400_dapm_out3mix_controls)), | ||
722 | |||
723 | /* SPKMIX */ | ||
724 | SND_SOC_DAPM_MIXER_E("SPKMIX", WM8400_POWER_MANAGEMENT_1, WM8400_SPK_ENA_SHIFT, | ||
725 | 0, &wm8400_dapm_spkmix_controls[0], | ||
726 | ARRAY_SIZE(wm8400_dapm_spkmix_controls), outmixer_event, | ||
727 | SND_SOC_DAPM_PRE_REG), | ||
728 | |||
729 | /* OUT4MIX */ | ||
730 | SND_SOC_DAPM_MIXER("OUT4MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT4_ENA_SHIFT, | ||
731 | 0, &wm8400_dapm_out4mix_controls[0], | ||
732 | ARRAY_SIZE(wm8400_dapm_out4mix_controls)), | ||
733 | |||
734 | /* ROPMIX */ | ||
735 | SND_SOC_DAPM_MIXER("ROPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_ROP_ENA_SHIFT, | ||
736 | 0, &wm8400_dapm_ropmix_controls[0], | ||
737 | ARRAY_SIZE(wm8400_dapm_ropmix_controls)), | ||
738 | |||
739 | /* RONMIX */ | ||
740 | SND_SOC_DAPM_MIXER("RONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_RON_ENA_SHIFT, | ||
741 | 0, &wm8400_dapm_ronmix_controls[0], | ||
742 | ARRAY_SIZE(wm8400_dapm_ronmix_controls)), | ||
743 | |||
744 | /* ROMIX */ | ||
745 | SND_SOC_DAPM_MIXER_E("ROMIX", WM8400_POWER_MANAGEMENT_3, | ||
746 | WM8400_ROMIX_ENA_SHIFT, | ||
747 | 0, &wm8400_dapm_romix_controls[0], | ||
748 | ARRAY_SIZE(wm8400_dapm_romix_controls), | ||
749 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
750 | |||
751 | /* LOUT PGA */ | ||
752 | SND_SOC_DAPM_PGA("LOUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_LOUT_ENA_SHIFT, | ||
753 | 0, NULL, 0), | ||
754 | |||
755 | /* ROUT PGA */ | ||
756 | SND_SOC_DAPM_PGA("ROUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_ROUT_ENA_SHIFT, | ||
757 | 0, NULL, 0), | ||
758 | |||
759 | /* LOPGA */ | ||
760 | SND_SOC_DAPM_PGA("LOPGA", WM8400_POWER_MANAGEMENT_3, WM8400_LOPGA_ENA_SHIFT, 0, | ||
761 | NULL, 0), | ||
762 | |||
763 | /* ROPGA */ | ||
764 | SND_SOC_DAPM_PGA("ROPGA", WM8400_POWER_MANAGEMENT_3, WM8400_ROPGA_ENA_SHIFT, 0, | ||
765 | NULL, 0), | ||
766 | |||
767 | /* MICBIAS */ | ||
768 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8400_POWER_MANAGEMENT_1, | ||
769 | WM8400_MIC1BIAS_ENA_SHIFT, 0), | ||
770 | |||
771 | SND_SOC_DAPM_OUTPUT("LON"), | ||
772 | SND_SOC_DAPM_OUTPUT("LOP"), | ||
773 | SND_SOC_DAPM_OUTPUT("OUT3"), | ||
774 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
775 | SND_SOC_DAPM_OUTPUT("SPKN"), | ||
776 | SND_SOC_DAPM_OUTPUT("SPKP"), | ||
777 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
778 | SND_SOC_DAPM_OUTPUT("OUT4"), | ||
779 | SND_SOC_DAPM_OUTPUT("ROP"), | ||
780 | SND_SOC_DAPM_OUTPUT("RON"), | ||
781 | |||
782 | SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), | ||
783 | }; | ||
784 | |||
785 | static const struct snd_soc_dapm_route audio_map[] = { | ||
786 | /* Make DACs turn on when playing even if not mixed into any outputs */ | ||
787 | {"Internal DAC Sink", NULL, "Left DAC"}, | ||
788 | {"Internal DAC Sink", NULL, "Right DAC"}, | ||
789 | |||
790 | /* Make ADCs turn on when recording | ||
791 | * even if not mixed from any inputs */ | ||
792 | {"Left ADC", NULL, "Internal ADC Source"}, | ||
793 | {"Right ADC", NULL, "Internal ADC Source"}, | ||
794 | |||
795 | /* Input Side */ | ||
796 | /* LIN12 PGA */ | ||
797 | {"LIN12 PGA", "LIN1 Switch", "LIN1"}, | ||
798 | {"LIN12 PGA", "LIN2 Switch", "LIN2"}, | ||
799 | /* LIN34 PGA */ | ||
800 | {"LIN34 PGA", "LIN3 Switch", "LIN3"}, | ||
801 | {"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"}, | ||
802 | /* INMIXL */ | ||
803 | {"INMIXL", "Record Left Volume", "LOMIX"}, | ||
804 | {"INMIXL", "LIN2 Volume", "LIN2"}, | ||
805 | {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, | ||
806 | {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, | ||
807 | /* AILNMUX */ | ||
808 | {"AILNMUX", "INMIXL Mix", "INMIXL"}, | ||
809 | {"AILNMUX", "DIFFINL Mix", "LIN12 PGA"}, | ||
810 | {"AILNMUX", "DIFFINL Mix", "LIN34 PGA"}, | ||
811 | {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"}, | ||
812 | {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"}, | ||
813 | /* ADC */ | ||
814 | {"Left ADC", NULL, "AILNMUX"}, | ||
815 | |||
816 | /* RIN12 PGA */ | ||
817 | {"RIN12 PGA", "RIN1 Switch", "RIN1"}, | ||
818 | {"RIN12 PGA", "RIN2 Switch", "RIN2"}, | ||
819 | /* RIN34 PGA */ | ||
820 | {"RIN34 PGA", "RIN3 Switch", "RIN3"}, | ||
821 | {"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"}, | ||
822 | /* INMIXL */ | ||
823 | {"INMIXR", "Record Right Volume", "ROMIX"}, | ||
824 | {"INMIXR", "RIN2 Volume", "RIN2"}, | ||
825 | {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, | ||
826 | {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, | ||
827 | /* AIRNMUX */ | ||
828 | {"AIRNMUX", "INMIXR Mix", "INMIXR"}, | ||
829 | {"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"}, | ||
830 | {"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"}, | ||
831 | {"AIRNMUX", "RXVOICE Mix", "LIN4/RXN"}, | ||
832 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"}, | ||
833 | /* ADC */ | ||
834 | {"Right ADC", NULL, "AIRNMUX"}, | ||
835 | |||
836 | /* LOMIX */ | ||
837 | {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"}, | ||
838 | {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"}, | ||
839 | {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
840 | {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
841 | {"LOMIX", "LOMIX Right ADC Bypass Switch", "AIRNMUX"}, | ||
842 | {"LOMIX", "LOMIX Left ADC Bypass Switch", "AILNMUX"}, | ||
843 | {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"}, | ||
844 | |||
845 | /* ROMIX */ | ||
846 | {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"}, | ||
847 | {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"}, | ||
848 | {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
849 | {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
850 | {"ROMIX", "ROMIX Right ADC Bypass Switch", "AIRNMUX"}, | ||
851 | {"ROMIX", "ROMIX Left ADC Bypass Switch", "AILNMUX"}, | ||
852 | {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"}, | ||
853 | |||
854 | /* SPKMIX */ | ||
855 | {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"}, | ||
856 | {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"}, | ||
857 | {"SPKMIX", "SPKMIX LADC Bypass Switch", "AILNMUX"}, | ||
858 | {"SPKMIX", "SPKMIX RADC Bypass Switch", "AIRNMUX"}, | ||
859 | {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"}, | ||
860 | {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"}, | ||
861 | {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"}, | ||
862 | {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"}, | ||
863 | |||
864 | /* LONMIX */ | ||
865 | {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
866 | {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
867 | {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"}, | ||
868 | |||
869 | /* LOPMIX */ | ||
870 | {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
871 | {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
872 | {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"}, | ||
873 | |||
874 | /* OUT3MIX */ | ||
875 | {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXN"}, | ||
876 | {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"}, | ||
877 | |||
878 | /* OUT4MIX */ | ||
879 | {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"}, | ||
880 | {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"}, | ||
881 | |||
882 | /* RONMIX */ | ||
883 | {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
884 | {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
885 | {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"}, | ||
886 | |||
887 | /* ROPMIX */ | ||
888 | {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
889 | {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
890 | {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"}, | ||
891 | |||
892 | /* Out Mixer PGAs */ | ||
893 | {"LOPGA", NULL, "LOMIX"}, | ||
894 | {"ROPGA", NULL, "ROMIX"}, | ||
895 | |||
896 | {"LOUT PGA", NULL, "LOMIX"}, | ||
897 | {"ROUT PGA", NULL, "ROMIX"}, | ||
898 | |||
899 | /* Output Pins */ | ||
900 | {"LON", NULL, "LONMIX"}, | ||
901 | {"LOP", NULL, "LOPMIX"}, | ||
902 | {"OUT3", NULL, "OUT3MIX"}, | ||
903 | {"LOUT", NULL, "LOUT PGA"}, | ||
904 | {"SPKN", NULL, "SPKMIX"}, | ||
905 | {"ROUT", NULL, "ROUT PGA"}, | ||
906 | {"OUT4", NULL, "OUT4MIX"}, | ||
907 | {"ROP", NULL, "ROPMIX"}, | ||
908 | {"RON", NULL, "RONMIX"}, | ||
909 | }; | ||
910 | |||
911 | static int wm8400_add_widgets(struct snd_soc_codec *codec) | ||
912 | { | ||
913 | snd_soc_dapm_new_controls(codec, wm8400_dapm_widgets, | ||
914 | ARRAY_SIZE(wm8400_dapm_widgets)); | ||
915 | |||
916 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
917 | |||
918 | snd_soc_dapm_new_widgets(codec); | ||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | /* | ||
923 | * Clock after FLL and dividers | ||
924 | */ | ||
925 | static int wm8400_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
926 | int clk_id, unsigned int freq, int dir) | ||
927 | { | ||
928 | struct snd_soc_codec *codec = codec_dai->codec; | ||
929 | struct wm8400_priv *wm8400 = codec->private_data; | ||
930 | |||
931 | wm8400->sysclk = freq; | ||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | struct fll_factors { | ||
936 | u16 n; | ||
937 | u16 k; | ||
938 | u16 outdiv; | ||
939 | u16 fratio; | ||
940 | u16 freq_ref; | ||
941 | }; | ||
942 | |||
943 | #define FIXED_FLL_SIZE ((1 << 16) * 10) | ||
944 | |||
945 | static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors, | ||
946 | unsigned int Fref, unsigned int Fout) | ||
947 | { | ||
948 | u64 Kpart; | ||
949 | unsigned int K, Nmod, target; | ||
950 | |||
951 | factors->outdiv = 2; | ||
952 | while (Fout * factors->outdiv < 90000000 || | ||
953 | Fout * factors->outdiv > 100000000) { | ||
954 | factors->outdiv *= 2; | ||
955 | if (factors->outdiv > 32) { | ||
956 | dev_err(wm8400->wm8400->dev, | ||
957 | "Unsupported FLL output frequency %dHz\n", | ||
958 | Fout); | ||
959 | return -EINVAL; | ||
960 | } | ||
961 | } | ||
962 | target = Fout * factors->outdiv; | ||
963 | factors->outdiv = factors->outdiv >> 2; | ||
964 | |||
965 | if (Fref < 48000) | ||
966 | factors->freq_ref = 1; | ||
967 | else | ||
968 | factors->freq_ref = 0; | ||
969 | |||
970 | if (Fref < 1000000) | ||
971 | factors->fratio = 9; | ||
972 | else | ||
973 | factors->fratio = 0; | ||
974 | |||
975 | /* Ensure we have a fractional part */ | ||
976 | do { | ||
977 | if (Fref < 1000000) | ||
978 | factors->fratio--; | ||
979 | else | ||
980 | factors->fratio++; | ||
981 | |||
982 | if (factors->fratio < 1 || factors->fratio > 8) { | ||
983 | dev_err(wm8400->wm8400->dev, | ||
984 | "Unable to calculate FRATIO\n"); | ||
985 | return -EINVAL; | ||
986 | } | ||
987 | |||
988 | factors->n = target / (Fref * factors->fratio); | ||
989 | Nmod = target % (Fref * factors->fratio); | ||
990 | } while (Nmod == 0); | ||
991 | |||
992 | /* Calculate fractional part - scale up so we can round. */ | ||
993 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | ||
994 | |||
995 | do_div(Kpart, (Fref * factors->fratio)); | ||
996 | |||
997 | K = Kpart & 0xFFFFFFFF; | ||
998 | |||
999 | if ((K % 10) >= 5) | ||
1000 | K += 5; | ||
1001 | |||
1002 | /* Move down to proper range now rounding is done */ | ||
1003 | factors->k = K / 10; | ||
1004 | |||
1005 | dev_dbg(wm8400->wm8400->dev, | ||
1006 | "FLL: Fref=%d Fout=%d N=%x K=%x, FRATIO=%x OUTDIV=%x\n", | ||
1007 | Fref, Fout, | ||
1008 | factors->n, factors->k, factors->fratio, factors->outdiv); | ||
1009 | |||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, | ||
1014 | unsigned int freq_in, unsigned int freq_out) | ||
1015 | { | ||
1016 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1017 | struct wm8400_priv *wm8400 = codec->private_data; | ||
1018 | struct fll_factors factors; | ||
1019 | int ret; | ||
1020 | u16 reg; | ||
1021 | |||
1022 | if (freq_in == wm8400->fll_in && freq_out == wm8400->fll_out) | ||
1023 | return 0; | ||
1024 | |||
1025 | if (freq_out != 0) { | ||
1026 | ret = fll_factors(wm8400, &factors, freq_in, freq_out); | ||
1027 | if (ret != 0) | ||
1028 | return ret; | ||
1029 | } | ||
1030 | |||
1031 | wm8400->fll_out = freq_out; | ||
1032 | wm8400->fll_in = freq_in; | ||
1033 | |||
1034 | /* We *must* disable the FLL before any changes */ | ||
1035 | reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_2); | ||
1036 | reg &= ~WM8400_FLL_ENA; | ||
1037 | wm8400_write(codec, WM8400_POWER_MANAGEMENT_2, reg); | ||
1038 | |||
1039 | reg = wm8400_read(codec, WM8400_FLL_CONTROL_1); | ||
1040 | reg &= ~WM8400_FLL_OSC_ENA; | ||
1041 | wm8400_write(codec, WM8400_FLL_CONTROL_1, reg); | ||
1042 | |||
1043 | if (freq_out == 0) | ||
1044 | return 0; | ||
1045 | |||
1046 | reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK); | ||
1047 | reg |= WM8400_FLL_FRAC | factors.fratio; | ||
1048 | reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT; | ||
1049 | wm8400_write(codec, WM8400_FLL_CONTROL_1, reg); | ||
1050 | |||
1051 | wm8400_write(codec, WM8400_FLL_CONTROL_2, factors.k); | ||
1052 | wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n); | ||
1053 | |||
1054 | reg = wm8400_read(codec, WM8400_FLL_CONTROL_4); | ||
1055 | reg &= WM8400_FLL_OUTDIV_MASK; | ||
1056 | reg |= factors.outdiv; | ||
1057 | wm8400_write(codec, WM8400_FLL_CONTROL_4, reg); | ||
1058 | |||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1062 | /* | ||
1063 | * Sets ADC and Voice DAC format. | ||
1064 | */ | ||
1065 | static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
1066 | unsigned int fmt) | ||
1067 | { | ||
1068 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1069 | u16 audio1, audio3; | ||
1070 | |||
1071 | audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1); | ||
1072 | audio3 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_3); | ||
1073 | |||
1074 | /* set master/slave audio interface */ | ||
1075 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1076 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1077 | audio3 &= ~WM8400_AIF_MSTR1; | ||
1078 | break; | ||
1079 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1080 | audio3 |= WM8400_AIF_MSTR1; | ||
1081 | break; | ||
1082 | default: | ||
1083 | return -EINVAL; | ||
1084 | } | ||
1085 | |||
1086 | audio1 &= ~WM8400_AIF_FMT_MASK; | ||
1087 | |||
1088 | /* interface format */ | ||
1089 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1090 | case SND_SOC_DAIFMT_I2S: | ||
1091 | audio1 |= WM8400_AIF_FMT_I2S; | ||
1092 | audio1 &= ~WM8400_AIF_LRCLK_INV; | ||
1093 | break; | ||
1094 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1095 | audio1 |= WM8400_AIF_FMT_RIGHTJ; | ||
1096 | audio1 &= ~WM8400_AIF_LRCLK_INV; | ||
1097 | break; | ||
1098 | case SND_SOC_DAIFMT_LEFT_J: | ||
1099 | audio1 |= WM8400_AIF_FMT_LEFTJ; | ||
1100 | audio1 &= ~WM8400_AIF_LRCLK_INV; | ||
1101 | break; | ||
1102 | case SND_SOC_DAIFMT_DSP_A: | ||
1103 | audio1 |= WM8400_AIF_FMT_DSP; | ||
1104 | audio1 &= ~WM8400_AIF_LRCLK_INV; | ||
1105 | break; | ||
1106 | case SND_SOC_DAIFMT_DSP_B: | ||
1107 | audio1 |= WM8400_AIF_FMT_DSP | WM8400_AIF_LRCLK_INV; | ||
1108 | break; | ||
1109 | default: | ||
1110 | return -EINVAL; | ||
1111 | } | ||
1112 | |||
1113 | wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1); | ||
1114 | wm8400_write(codec, WM8400_AUDIO_INTERFACE_3, audio3); | ||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | static int wm8400_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
1119 | int div_id, int div) | ||
1120 | { | ||
1121 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1122 | u16 reg; | ||
1123 | |||
1124 | switch (div_id) { | ||
1125 | case WM8400_MCLK_DIV: | ||
1126 | reg = wm8400_read(codec, WM8400_CLOCKING_2) & | ||
1127 | ~WM8400_MCLK_DIV_MASK; | ||
1128 | wm8400_write(codec, WM8400_CLOCKING_2, reg | div); | ||
1129 | break; | ||
1130 | case WM8400_DACCLK_DIV: | ||
1131 | reg = wm8400_read(codec, WM8400_CLOCKING_2) & | ||
1132 | ~WM8400_DAC_CLKDIV_MASK; | ||
1133 | wm8400_write(codec, WM8400_CLOCKING_2, reg | div); | ||
1134 | break; | ||
1135 | case WM8400_ADCCLK_DIV: | ||
1136 | reg = wm8400_read(codec, WM8400_CLOCKING_2) & | ||
1137 | ~WM8400_ADC_CLKDIV_MASK; | ||
1138 | wm8400_write(codec, WM8400_CLOCKING_2, reg | div); | ||
1139 | break; | ||
1140 | case WM8400_BCLK_DIV: | ||
1141 | reg = wm8400_read(codec, WM8400_CLOCKING_1) & | ||
1142 | ~WM8400_BCLK_DIV_MASK; | ||
1143 | wm8400_write(codec, WM8400_CLOCKING_1, reg | div); | ||
1144 | break; | ||
1145 | default: | ||
1146 | return -EINVAL; | ||
1147 | } | ||
1148 | |||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1152 | /* | ||
1153 | * Set PCM DAI bit size and sample rate. | ||
1154 | */ | ||
1155 | static int wm8400_hw_params(struct snd_pcm_substream *substream, | ||
1156 | struct snd_pcm_hw_params *params, | ||
1157 | struct snd_soc_dai *dai) | ||
1158 | { | ||
1159 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1160 | struct snd_soc_device *socdev = rtd->socdev; | ||
1161 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1162 | u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1); | ||
1163 | |||
1164 | audio1 &= ~WM8400_AIF_WL_MASK; | ||
1165 | /* bit size */ | ||
1166 | switch (params_format(params)) { | ||
1167 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1168 | break; | ||
1169 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
1170 | audio1 |= WM8400_AIF_WL_20BITS; | ||
1171 | break; | ||
1172 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1173 | audio1 |= WM8400_AIF_WL_24BITS; | ||
1174 | break; | ||
1175 | case SNDRV_PCM_FORMAT_S32_LE: | ||
1176 | audio1 |= WM8400_AIF_WL_32BITS; | ||
1177 | break; | ||
1178 | } | ||
1179 | |||
1180 | wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1); | ||
1181 | return 0; | ||
1182 | } | ||
1183 | |||
1184 | static int wm8400_mute(struct snd_soc_dai *dai, int mute) | ||
1185 | { | ||
1186 | struct snd_soc_codec *codec = dai->codec; | ||
1187 | u16 val = wm8400_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE; | ||
1188 | |||
1189 | if (mute) | ||
1190 | wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE); | ||
1191 | else | ||
1192 | wm8400_write(codec, WM8400_DAC_CTRL, val); | ||
1193 | |||
1194 | return 0; | ||
1195 | } | ||
1196 | |||
1197 | /* TODO: set bias for best performance at standby */ | ||
1198 | static int wm8400_set_bias_level(struct snd_soc_codec *codec, | ||
1199 | enum snd_soc_bias_level level) | ||
1200 | { | ||
1201 | struct wm8400_priv *wm8400 = codec->private_data; | ||
1202 | u16 val; | ||
1203 | int ret; | ||
1204 | |||
1205 | switch (level) { | ||
1206 | case SND_SOC_BIAS_ON: | ||
1207 | break; | ||
1208 | |||
1209 | case SND_SOC_BIAS_PREPARE: | ||
1210 | /* VMID=2*50k */ | ||
1211 | val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) & | ||
1212 | ~WM8400_VMID_MODE_MASK; | ||
1213 | wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2); | ||
1214 | break; | ||
1215 | |||
1216 | case SND_SOC_BIAS_STANDBY: | ||
1217 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
1218 | ret = regulator_bulk_enable(ARRAY_SIZE(power), | ||
1219 | &power[0]); | ||
1220 | if (ret != 0) { | ||
1221 | dev_err(wm8400->wm8400->dev, | ||
1222 | "Failed to enable regulators: %d\n", | ||
1223 | ret); | ||
1224 | return ret; | ||
1225 | } | ||
1226 | |||
1227 | wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, | ||
1228 | WM8400_CODEC_ENA | WM8400_SYSCLK_ENA); | ||
1229 | |||
1230 | /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ | ||
1231 | wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST | | ||
1232 | WM8400_BUFDCOPEN | WM8400_POBCTRL); | ||
1233 | |||
1234 | msleep(50); | ||
1235 | |||
1236 | /* Enable VREF & VMID at 2x50k */ | ||
1237 | val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1); | ||
1238 | val |= 0x2 | WM8400_VREF_ENA; | ||
1239 | wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); | ||
1240 | |||
1241 | /* Enable BUFIOEN */ | ||
1242 | wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST | | ||
1243 | WM8400_BUFDCOPEN | WM8400_POBCTRL | | ||
1244 | WM8400_BUFIOEN); | ||
1245 | |||
1246 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1247 | wm8400_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN); | ||
1248 | } | ||
1249 | |||
1250 | /* VMID=2*300k */ | ||
1251 | val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) & | ||
1252 | ~WM8400_VMID_MODE_MASK; | ||
1253 | wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4); | ||
1254 | break; | ||
1255 | |||
1256 | case SND_SOC_BIAS_OFF: | ||
1257 | /* Enable POBCTRL and SOFT_ST */ | ||
1258 | wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST | | ||
1259 | WM8400_POBCTRL | WM8400_BUFIOEN); | ||
1260 | |||
1261 | /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1262 | wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST | | ||
1263 | WM8400_BUFDCOPEN | WM8400_POBCTRL | | ||
1264 | WM8400_BUFIOEN); | ||
1265 | |||
1266 | /* mute DAC */ | ||
1267 | val = wm8400_read(codec, WM8400_DAC_CTRL); | ||
1268 | wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE); | ||
1269 | |||
1270 | /* Enable any disabled outputs */ | ||
1271 | val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1); | ||
1272 | val |= WM8400_SPK_ENA | WM8400_OUT3_ENA | | ||
1273 | WM8400_OUT4_ENA | WM8400_LOUT_ENA | | ||
1274 | WM8400_ROUT_ENA; | ||
1275 | wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); | ||
1276 | |||
1277 | /* Disable VMID */ | ||
1278 | val &= ~WM8400_VMID_MODE_MASK; | ||
1279 | wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); | ||
1280 | |||
1281 | msleep(300); | ||
1282 | |||
1283 | /* Enable all output discharge bits */ | ||
1284 | wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE | | ||
1285 | WM8400_DIS_RLINE | WM8400_DIS_OUT3 | | ||
1286 | WM8400_DIS_OUT4 | WM8400_DIS_LOUT | | ||
1287 | WM8400_DIS_ROUT); | ||
1288 | |||
1289 | /* Disable VREF */ | ||
1290 | val &= ~WM8400_VREF_ENA; | ||
1291 | wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); | ||
1292 | |||
1293 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1294 | wm8400_write(codec, WM8400_ANTIPOP2, 0x0); | ||
1295 | |||
1296 | ret = regulator_bulk_disable(ARRAY_SIZE(power), | ||
1297 | &power[0]); | ||
1298 | if (ret != 0) | ||
1299 | return ret; | ||
1300 | |||
1301 | break; | ||
1302 | } | ||
1303 | |||
1304 | codec->bias_level = level; | ||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | #define WM8400_RATES SNDRV_PCM_RATE_8000_96000 | ||
1309 | |||
1310 | #define WM8400_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
1311 | SNDRV_PCM_FMTBIT_S24_LE) | ||
1312 | |||
1313 | static struct snd_soc_dai_ops wm8400_dai_ops = { | ||
1314 | .hw_params = wm8400_hw_params, | ||
1315 | .digital_mute = wm8400_mute, | ||
1316 | .set_fmt = wm8400_set_dai_fmt, | ||
1317 | .set_clkdiv = wm8400_set_dai_clkdiv, | ||
1318 | .set_sysclk = wm8400_set_dai_sysclk, | ||
1319 | .set_pll = wm8400_set_dai_pll, | ||
1320 | }; | ||
1321 | |||
1322 | /* | ||
1323 | * The WM8400 supports 2 different and mutually exclusive DAI | ||
1324 | * configurations. | ||
1325 | * | ||
1326 | * 1. ADC/DAC on Primary Interface | ||
1327 | * 2. ADC on Primary Interface/DAC on secondary | ||
1328 | */ | ||
1329 | struct snd_soc_dai wm8400_dai = { | ||
1330 | /* ADC/DAC on primary */ | ||
1331 | .name = "WM8400 ADC/DAC Primary", | ||
1332 | .id = 1, | ||
1333 | .playback = { | ||
1334 | .stream_name = "Playback", | ||
1335 | .channels_min = 1, | ||
1336 | .channels_max = 2, | ||
1337 | .rates = WM8400_RATES, | ||
1338 | .formats = WM8400_FORMATS, | ||
1339 | }, | ||
1340 | .capture = { | ||
1341 | .stream_name = "Capture", | ||
1342 | .channels_min = 1, | ||
1343 | .channels_max = 2, | ||
1344 | .rates = WM8400_RATES, | ||
1345 | .formats = WM8400_FORMATS, | ||
1346 | }, | ||
1347 | .ops = &wm8400_dai_ops, | ||
1348 | }; | ||
1349 | EXPORT_SYMBOL_GPL(wm8400_dai); | ||
1350 | |||
1351 | static int wm8400_suspend(struct platform_device *pdev, pm_message_t state) | ||
1352 | { | ||
1353 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1354 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1355 | |||
1356 | wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1357 | |||
1358 | return 0; | ||
1359 | } | ||
1360 | |||
1361 | static int wm8400_resume(struct platform_device *pdev) | ||
1362 | { | ||
1363 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1364 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1365 | |||
1366 | wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1367 | |||
1368 | return 0; | ||
1369 | } | ||
1370 | |||
1371 | static struct snd_soc_codec *wm8400_codec; | ||
1372 | |||
1373 | static int wm8400_probe(struct platform_device *pdev) | ||
1374 | { | ||
1375 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1376 | struct snd_soc_codec *codec; | ||
1377 | int ret; | ||
1378 | |||
1379 | if (!wm8400_codec) { | ||
1380 | dev_err(&pdev->dev, "wm8400 not yet discovered\n"); | ||
1381 | return -ENODEV; | ||
1382 | } | ||
1383 | codec = wm8400_codec; | ||
1384 | |||
1385 | socdev->card->codec = codec; | ||
1386 | |||
1387 | /* register pcms */ | ||
1388 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1389 | if (ret < 0) { | ||
1390 | dev_err(&pdev->dev, "failed to create pcms\n"); | ||
1391 | goto pcm_err; | ||
1392 | } | ||
1393 | |||
1394 | wm8400_add_controls(codec); | ||
1395 | wm8400_add_widgets(codec); | ||
1396 | |||
1397 | ret = snd_soc_init_card(socdev); | ||
1398 | if (ret < 0) { | ||
1399 | dev_err(&pdev->dev, "failed to register card\n"); | ||
1400 | goto card_err; | ||
1401 | } | ||
1402 | |||
1403 | return ret; | ||
1404 | |||
1405 | card_err: | ||
1406 | snd_soc_free_pcms(socdev); | ||
1407 | snd_soc_dapm_free(socdev); | ||
1408 | pcm_err: | ||
1409 | return ret; | ||
1410 | } | ||
1411 | |||
1412 | /* power down chip */ | ||
1413 | static int wm8400_remove(struct platform_device *pdev) | ||
1414 | { | ||
1415 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1416 | |||
1417 | snd_soc_free_pcms(socdev); | ||
1418 | snd_soc_dapm_free(socdev); | ||
1419 | |||
1420 | return 0; | ||
1421 | } | ||
1422 | |||
1423 | struct snd_soc_codec_device soc_codec_dev_wm8400 = { | ||
1424 | .probe = wm8400_probe, | ||
1425 | .remove = wm8400_remove, | ||
1426 | .suspend = wm8400_suspend, | ||
1427 | .resume = wm8400_resume, | ||
1428 | }; | ||
1429 | |||
1430 | static void wm8400_probe_deferred(struct work_struct *work) | ||
1431 | { | ||
1432 | struct wm8400_priv *priv = container_of(work, struct wm8400_priv, | ||
1433 | work); | ||
1434 | struct snd_soc_codec *codec = &priv->codec; | ||
1435 | int ret; | ||
1436 | |||
1437 | /* charge output caps */ | ||
1438 | wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1439 | |||
1440 | /* We're done, tell the subsystem. */ | ||
1441 | ret = snd_soc_register_codec(codec); | ||
1442 | if (ret != 0) { | ||
1443 | dev_err(priv->wm8400->dev, | ||
1444 | "Failed to register codec: %d\n", ret); | ||
1445 | goto err; | ||
1446 | } | ||
1447 | |||
1448 | ret = snd_soc_register_dai(&wm8400_dai); | ||
1449 | if (ret != 0) { | ||
1450 | dev_err(priv->wm8400->dev, | ||
1451 | "Failed to register DAI: %d\n", ret); | ||
1452 | goto err_codec; | ||
1453 | } | ||
1454 | |||
1455 | return; | ||
1456 | |||
1457 | err_codec: | ||
1458 | snd_soc_unregister_codec(codec); | ||
1459 | err: | ||
1460 | wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1461 | } | ||
1462 | |||
1463 | static int wm8400_codec_probe(struct platform_device *dev) | ||
1464 | { | ||
1465 | struct wm8400_priv *priv; | ||
1466 | int ret; | ||
1467 | u16 reg; | ||
1468 | struct snd_soc_codec *codec; | ||
1469 | |||
1470 | priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL); | ||
1471 | if (priv == NULL) | ||
1472 | return -ENOMEM; | ||
1473 | |||
1474 | codec = &priv->codec; | ||
1475 | codec->private_data = priv; | ||
1476 | codec->control_data = dev->dev.driver_data; | ||
1477 | priv->wm8400 = dev->dev.driver_data; | ||
1478 | |||
1479 | ret = regulator_bulk_get(priv->wm8400->dev, | ||
1480 | ARRAY_SIZE(power), &power[0]); | ||
1481 | if (ret != 0) { | ||
1482 | dev_err(&dev->dev, "Failed to get regulators: %d\n", ret); | ||
1483 | goto err; | ||
1484 | } | ||
1485 | |||
1486 | codec->dev = &dev->dev; | ||
1487 | wm8400_dai.dev = &dev->dev; | ||
1488 | |||
1489 | codec->name = "WM8400"; | ||
1490 | codec->owner = THIS_MODULE; | ||
1491 | codec->read = wm8400_read; | ||
1492 | codec->write = wm8400_write; | ||
1493 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1494 | codec->set_bias_level = wm8400_set_bias_level; | ||
1495 | codec->dai = &wm8400_dai; | ||
1496 | codec->num_dai = 1; | ||
1497 | codec->reg_cache_size = WM8400_REGISTER_COUNT; | ||
1498 | mutex_init(&codec->mutex); | ||
1499 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1500 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1501 | INIT_WORK(&priv->work, wm8400_probe_deferred); | ||
1502 | |||
1503 | wm8400_codec_reset(codec); | ||
1504 | |||
1505 | reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1); | ||
1506 | wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA); | ||
1507 | |||
1508 | /* Latch volume update bits */ | ||
1509 | reg = wm8400_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME); | ||
1510 | wm8400_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME, | ||
1511 | reg & WM8400_IPVU); | ||
1512 | reg = wm8400_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME); | ||
1513 | wm8400_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
1514 | reg & WM8400_IPVU); | ||
1515 | |||
1516 | wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
1517 | wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
1518 | |||
1519 | wm8400_codec = codec; | ||
1520 | |||
1521 | if (!schedule_work(&priv->work)) { | ||
1522 | ret = -EINVAL; | ||
1523 | goto err_regulator; | ||
1524 | } | ||
1525 | |||
1526 | return 0; | ||
1527 | |||
1528 | err_regulator: | ||
1529 | wm8400_codec = NULL; | ||
1530 | regulator_bulk_free(ARRAY_SIZE(power), power); | ||
1531 | err: | ||
1532 | kfree(priv); | ||
1533 | return ret; | ||
1534 | } | ||
1535 | |||
1536 | static int __exit wm8400_codec_remove(struct platform_device *dev) | ||
1537 | { | ||
1538 | struct wm8400_priv *priv = wm8400_codec->private_data; | ||
1539 | u16 reg; | ||
1540 | |||
1541 | snd_soc_unregister_dai(&wm8400_dai); | ||
1542 | snd_soc_unregister_codec(wm8400_codec); | ||
1543 | |||
1544 | reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1); | ||
1545 | wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1, | ||
1546 | reg & (~WM8400_CODEC_ENA)); | ||
1547 | |||
1548 | regulator_bulk_free(ARRAY_SIZE(power), power); | ||
1549 | kfree(priv); | ||
1550 | |||
1551 | wm8400_codec = NULL; | ||
1552 | |||
1553 | return 0; | ||
1554 | } | ||
1555 | |||
1556 | static struct platform_driver wm8400_codec_driver = { | ||
1557 | .driver = { | ||
1558 | .name = "wm8400-codec", | ||
1559 | .owner = THIS_MODULE, | ||
1560 | }, | ||
1561 | .probe = wm8400_codec_probe, | ||
1562 | .remove = __exit_p(wm8400_codec_remove), | ||
1563 | }; | ||
1564 | |||
1565 | static int __init wm8400_codec_init(void) | ||
1566 | { | ||
1567 | return platform_driver_register(&wm8400_codec_driver); | ||
1568 | } | ||
1569 | module_init(wm8400_codec_init); | ||
1570 | |||
1571 | static void __exit wm8400_codec_exit(void) | ||
1572 | { | ||
1573 | platform_driver_unregister(&wm8400_codec_driver); | ||
1574 | } | ||
1575 | module_exit(wm8400_codec_exit); | ||
1576 | |||
1577 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400); | ||
1578 | |||
1579 | MODULE_DESCRIPTION("ASoC WM8400 driver"); | ||
1580 | MODULE_AUTHOR("Mark Brown"); | ||
1581 | MODULE_LICENSE("GPL"); | ||
1582 | MODULE_ALIAS("platform:wm8400-codec"); | ||
diff --git a/sound/soc/codecs/wm8400.h b/sound/soc/codecs/wm8400.h new file mode 100644 index 000000000000..79c5934d4776 --- /dev/null +++ b/sound/soc/codecs/wm8400.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * wm8400.h -- audio driver for WM8400 | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
5 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef _WM8400_CODEC_H | ||
15 | #define _WM8400_CODEC_H | ||
16 | |||
17 | #define WM8400_MCLK_DIV 0 | ||
18 | #define WM8400_DACCLK_DIV 1 | ||
19 | #define WM8400_ADCCLK_DIV 2 | ||
20 | #define WM8400_BCLK_DIV 3 | ||
21 | |||
22 | #define WM8400_MCLK_DIV_1 0x400 | ||
23 | #define WM8400_MCLK_DIV_2 0x800 | ||
24 | |||
25 | #define WM8400_DAC_CLKDIV_1 0x00 | ||
26 | #define WM8400_DAC_CLKDIV_1_5 0x04 | ||
27 | #define WM8400_DAC_CLKDIV_2 0x08 | ||
28 | #define WM8400_DAC_CLKDIV_3 0x0c | ||
29 | #define WM8400_DAC_CLKDIV_4 0x10 | ||
30 | #define WM8400_DAC_CLKDIV_5_5 0x14 | ||
31 | #define WM8400_DAC_CLKDIV_6 0x18 | ||
32 | |||
33 | #define WM8400_ADC_CLKDIV_1 0x00 | ||
34 | #define WM8400_ADC_CLKDIV_1_5 0x20 | ||
35 | #define WM8400_ADC_CLKDIV_2 0x40 | ||
36 | #define WM8400_ADC_CLKDIV_3 0x60 | ||
37 | #define WM8400_ADC_CLKDIV_4 0x80 | ||
38 | #define WM8400_ADC_CLKDIV_5_5 0xa0 | ||
39 | #define WM8400_ADC_CLKDIV_6 0xc0 | ||
40 | |||
41 | |||
42 | #define WM8400_BCLK_DIV_1 (0x0 << 1) | ||
43 | #define WM8400_BCLK_DIV_1_5 (0x1 << 1) | ||
44 | #define WM8400_BCLK_DIV_2 (0x2 << 1) | ||
45 | #define WM8400_BCLK_DIV_3 (0x3 << 1) | ||
46 | #define WM8400_BCLK_DIV_4 (0x4 << 1) | ||
47 | #define WM8400_BCLK_DIV_5_5 (0x5 << 1) | ||
48 | #define WM8400_BCLK_DIV_6 (0x6 << 1) | ||
49 | #define WM8400_BCLK_DIV_8 (0x7 << 1) | ||
50 | #define WM8400_BCLK_DIV_11 (0x8 << 1) | ||
51 | #define WM8400_BCLK_DIV_12 (0x9 << 1) | ||
52 | #define WM8400_BCLK_DIV_16 (0xA << 1) | ||
53 | #define WM8400_BCLK_DIV_22 (0xB << 1) | ||
54 | #define WM8400_BCLK_DIV_24 (0xC << 1) | ||
55 | #define WM8400_BCLK_DIV_32 (0xD << 1) | ||
56 | #define WM8400_BCLK_DIV_44 (0xE << 1) | ||
57 | #define WM8400_BCLK_DIV_48 (0xF << 1) | ||
58 | |||
59 | extern struct snd_soc_dai wm8400_dai; | ||
60 | extern struct snd_soc_codec_device soc_codec_dev_wm8400; | ||
61 | |||
62 | #endif | ||
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 40f8238df717..6a4cea09c45d 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -171,22 +171,6 @@ SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST, 8, 1, 0), | |||
171 | SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), | 171 | SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), |
172 | }; | 172 | }; |
173 | 173 | ||
174 | /* add non dapm controls */ | ||
175 | static int wm8510_add_controls(struct snd_soc_codec *codec) | ||
176 | { | ||
177 | int err, i; | ||
178 | |||
179 | for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) { | ||
180 | err = snd_ctl_add(codec->card, | ||
181 | snd_soc_cnew(&wm8510_snd_controls[i], codec, | ||
182 | NULL)); | ||
183 | if (err < 0) | ||
184 | return err; | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* Speaker Output Mixer */ | 174 | /* Speaker Output Mixer */ |
191 | static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { | 175 | static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { |
192 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0), | 176 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0), |
@@ -352,7 +336,7 @@ static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, | |||
352 | return 0; | 336 | return 0; |
353 | } | 337 | } |
354 | 338 | ||
355 | pll_factors(freq_out*8, freq_in); | 339 | pll_factors(freq_out*4, freq_in); |
356 | 340 | ||
357 | wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); | 341 | wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); |
358 | wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); | 342 | wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); |
@@ -383,7 +367,7 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | |||
383 | wm8510_write(codec, WM8510_GPIO, reg | div); | 367 | wm8510_write(codec, WM8510_GPIO, reg | div); |
384 | break; | 368 | break; |
385 | case WM8510_MCLKDIV: | 369 | case WM8510_MCLKDIV: |
386 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f; | 370 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f; |
387 | wm8510_write(codec, WM8510_CLOCK, reg | div); | 371 | wm8510_write(codec, WM8510_CLOCK, reg | div); |
388 | break; | 372 | break; |
389 | case WM8510_ADCCLK: | 373 | case WM8510_ADCCLK: |
@@ -468,7 +452,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, | |||
468 | { | 452 | { |
469 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 453 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
470 | struct snd_soc_device *socdev = rtd->socdev; | 454 | struct snd_soc_device *socdev = rtd->socdev; |
471 | struct snd_soc_codec *codec = socdev->codec; | 455 | struct snd_soc_codec *codec = socdev->card->codec; |
472 | u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; | 456 | u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; |
473 | u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; | 457 | u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; |
474 | 458 | ||
@@ -570,6 +554,14 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec, | |||
570 | #define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 554 | #define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
571 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 555 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
572 | 556 | ||
557 | static struct snd_soc_dai_ops wm8510_dai_ops = { | ||
558 | .hw_params = wm8510_pcm_hw_params, | ||
559 | .digital_mute = wm8510_mute, | ||
560 | .set_fmt = wm8510_set_dai_fmt, | ||
561 | .set_clkdiv = wm8510_set_dai_clkdiv, | ||
562 | .set_pll = wm8510_set_dai_pll, | ||
563 | }; | ||
564 | |||
573 | struct snd_soc_dai wm8510_dai = { | 565 | struct snd_soc_dai wm8510_dai = { |
574 | .name = "WM8510 HiFi", | 566 | .name = "WM8510 HiFi", |
575 | .playback = { | 567 | .playback = { |
@@ -584,20 +576,14 @@ struct snd_soc_dai wm8510_dai = { | |||
584 | .channels_max = 2, | 576 | .channels_max = 2, |
585 | .rates = WM8510_RATES, | 577 | .rates = WM8510_RATES, |
586 | .formats = WM8510_FORMATS,}, | 578 | .formats = WM8510_FORMATS,}, |
587 | .ops = { | 579 | .ops = &wm8510_dai_ops, |
588 | .hw_params = wm8510_pcm_hw_params, | ||
589 | .digital_mute = wm8510_mute, | ||
590 | .set_fmt = wm8510_set_dai_fmt, | ||
591 | .set_clkdiv = wm8510_set_dai_clkdiv, | ||
592 | .set_pll = wm8510_set_dai_pll, | ||
593 | }, | ||
594 | }; | 580 | }; |
595 | EXPORT_SYMBOL_GPL(wm8510_dai); | 581 | EXPORT_SYMBOL_GPL(wm8510_dai); |
596 | 582 | ||
597 | static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) | 583 | static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) |
598 | { | 584 | { |
599 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 585 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
600 | struct snd_soc_codec *codec = socdev->codec; | 586 | struct snd_soc_codec *codec = socdev->card->codec; |
601 | 587 | ||
602 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | 588 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); |
603 | return 0; | 589 | return 0; |
@@ -606,7 +592,7 @@ static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) | |||
606 | static int wm8510_resume(struct platform_device *pdev) | 592 | static int wm8510_resume(struct platform_device *pdev) |
607 | { | 593 | { |
608 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 594 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
609 | struct snd_soc_codec *codec = socdev->codec; | 595 | struct snd_soc_codec *codec = socdev->card->codec; |
610 | int i; | 596 | int i; |
611 | u8 data[2]; | 597 | u8 data[2]; |
612 | u16 *cache = codec->reg_cache; | 598 | u16 *cache = codec->reg_cache; |
@@ -628,7 +614,7 @@ static int wm8510_resume(struct platform_device *pdev) | |||
628 | */ | 614 | */ |
629 | static int wm8510_init(struct snd_soc_device *socdev) | 615 | static int wm8510_init(struct snd_soc_device *socdev) |
630 | { | 616 | { |
631 | struct snd_soc_codec *codec = socdev->codec; | 617 | struct snd_soc_codec *codec = socdev->card->codec; |
632 | int ret = 0; | 618 | int ret = 0; |
633 | 619 | ||
634 | codec->name = "WM8510"; | 620 | codec->name = "WM8510"; |
@@ -656,7 +642,8 @@ static int wm8510_init(struct snd_soc_device *socdev) | |||
656 | /* power on device */ | 642 | /* power on device */ |
657 | codec->bias_level = SND_SOC_BIAS_OFF; | 643 | codec->bias_level = SND_SOC_BIAS_OFF; |
658 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 644 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
659 | wm8510_add_controls(codec); | 645 | snd_soc_add_controls(codec, wm8510_snd_controls, |
646 | ARRAY_SIZE(wm8510_snd_controls)); | ||
660 | wm8510_add_widgets(codec); | 647 | wm8510_add_widgets(codec); |
661 | ret = snd_soc_init_card(socdev); | 648 | ret = snd_soc_init_card(socdev); |
662 | if (ret < 0) { | 649 | if (ret < 0) { |
@@ -685,7 +672,7 @@ static int wm8510_i2c_probe(struct i2c_client *i2c, | |||
685 | const struct i2c_device_id *id) | 672 | const struct i2c_device_id *id) |
686 | { | 673 | { |
687 | struct snd_soc_device *socdev = wm8510_socdev; | 674 | struct snd_soc_device *socdev = wm8510_socdev; |
688 | struct snd_soc_codec *codec = socdev->codec; | 675 | struct snd_soc_codec *codec = socdev->card->codec; |
689 | int ret; | 676 | int ret; |
690 | 677 | ||
691 | i2c_set_clientdata(i2c, codec); | 678 | i2c_set_clientdata(i2c, codec); |
@@ -766,7 +753,7 @@ err_driver: | |||
766 | static int __devinit wm8510_spi_probe(struct spi_device *spi) | 753 | static int __devinit wm8510_spi_probe(struct spi_device *spi) |
767 | { | 754 | { |
768 | struct snd_soc_device *socdev = wm8510_socdev; | 755 | struct snd_soc_device *socdev = wm8510_socdev; |
769 | struct snd_soc_codec *codec = socdev->codec; | 756 | struct snd_soc_codec *codec = socdev->card->codec; |
770 | int ret; | 757 | int ret; |
771 | 758 | ||
772 | codec->control_data = spi; | 759 | codec->control_data = spi; |
@@ -832,7 +819,7 @@ static int wm8510_probe(struct platform_device *pdev) | |||
832 | if (codec == NULL) | 819 | if (codec == NULL) |
833 | return -ENOMEM; | 820 | return -ENOMEM; |
834 | 821 | ||
835 | socdev->codec = codec; | 822 | socdev->card->codec = codec; |
836 | mutex_init(&codec->mutex); | 823 | mutex_init(&codec->mutex); |
837 | INIT_LIST_HEAD(&codec->dapm_widgets); | 824 | INIT_LIST_HEAD(&codec->dapm_widgets); |
838 | INIT_LIST_HEAD(&codec->dapm_paths); | 825 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -862,7 +849,7 @@ static int wm8510_probe(struct platform_device *pdev) | |||
862 | static int wm8510_remove(struct platform_device *pdev) | 849 | static int wm8510_remove(struct platform_device *pdev) |
863 | { | 850 | { |
864 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 851 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
865 | struct snd_soc_codec *codec = socdev->codec; | 852 | struct snd_soc_codec *codec = socdev->card->codec; |
866 | 853 | ||
867 | if (codec->control_data) | 854 | if (codec->control_data) |
868 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | 855 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index d004e5845298..442ea6f160fc 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8580.c -- WM8580 ALSA Soc Audio driver | 2 | * wm8580.c -- WM8580 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008 Wolfson Microelectronics PLC. | 4 | * Copyright 2008, 2009 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * 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 |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
@@ -35,19 +35,6 @@ | |||
35 | 35 | ||
36 | #include "wm8580.h" | 36 | #include "wm8580.h" |
37 | 37 | ||
38 | #define WM8580_VERSION "0.1" | ||
39 | |||
40 | struct pll_state { | ||
41 | unsigned int in; | ||
42 | unsigned int out; | ||
43 | }; | ||
44 | |||
45 | /* codec private data */ | ||
46 | struct wm8580_priv { | ||
47 | struct pll_state a; | ||
48 | struct pll_state b; | ||
49 | }; | ||
50 | |||
51 | /* WM8580 register space */ | 38 | /* WM8580 register space */ |
52 | #define WM8580_PLLA1 0x00 | 39 | #define WM8580_PLLA1 0x00 |
53 | #define WM8580_PLLA2 0x01 | 40 | #define WM8580_PLLA2 0x01 |
@@ -102,6 +89,8 @@ struct wm8580_priv { | |||
102 | #define WM8580_READBACK 0x34 | 89 | #define WM8580_READBACK 0x34 |
103 | #define WM8580_RESET 0x35 | 90 | #define WM8580_RESET 0x35 |
104 | 91 | ||
92 | #define WM8580_MAX_REGISTER 0x35 | ||
93 | |||
105 | /* PLLB4 (register 7h) */ | 94 | /* PLLB4 (register 7h) */ |
106 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 | 95 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 |
107 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 | 96 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 |
@@ -193,6 +182,20 @@ static const u16 wm8580_reg[] = { | |||
193 | 0x0000, 0x0000 /*R53*/ | 182 | 0x0000, 0x0000 /*R53*/ |
194 | }; | 183 | }; |
195 | 184 | ||
185 | struct pll_state { | ||
186 | unsigned int in; | ||
187 | unsigned int out; | ||
188 | }; | ||
189 | |||
190 | /* codec private data */ | ||
191 | struct wm8580_priv { | ||
192 | struct snd_soc_codec codec; | ||
193 | u16 reg_cache[WM8580_MAX_REGISTER + 1]; | ||
194 | struct pll_state a; | ||
195 | struct pll_state b; | ||
196 | }; | ||
197 | |||
198 | |||
196 | /* | 199 | /* |
197 | * read wm8580 register cache | 200 | * read wm8580 register cache |
198 | */ | 201 | */ |
@@ -200,7 +203,7 @@ static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec, | |||
200 | unsigned int reg) | 203 | unsigned int reg) |
201 | { | 204 | { |
202 | u16 *cache = codec->reg_cache; | 205 | u16 *cache = codec->reg_cache; |
203 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | 206 | BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); |
204 | return cache[reg]; | 207 | return cache[reg]; |
205 | } | 208 | } |
206 | 209 | ||
@@ -223,7 +226,7 @@ static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg, | |||
223 | { | 226 | { |
224 | u8 data[2]; | 227 | u8 data[2]; |
225 | 228 | ||
226 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | 229 | BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); |
227 | 230 | ||
228 | /* Registers are 9 bits wide */ | 231 | /* Registers are 9 bits wide */ |
229 | value &= 0x1ff; | 232 | value &= 0x1ff; |
@@ -330,20 +333,6 @@ SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), | |||
330 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), | 333 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), |
331 | }; | 334 | }; |
332 | 335 | ||
333 | /* Add non-DAPM controls */ | ||
334 | static int wm8580_add_controls(struct snd_soc_codec *codec) | ||
335 | { | ||
336 | int err, i; | ||
337 | |||
338 | for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) { | ||
339 | err = snd_ctl_add(codec->card, | ||
340 | snd_soc_cnew(&wm8580_snd_controls[i], | ||
341 | codec, NULL)); | ||
342 | if (err < 0) | ||
343 | return err; | ||
344 | } | ||
345 | return 0; | ||
346 | } | ||
347 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { | 336 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { |
348 | SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), | 337 | SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), |
349 | SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), | 338 | SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), |
@@ -553,7 +542,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, | |||
553 | { | 542 | { |
554 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 543 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
555 | struct snd_soc_device *socdev = rtd->socdev; | 544 | struct snd_soc_device *socdev = rtd->socdev; |
556 | struct snd_soc_codec *codec = socdev->codec; | 545 | struct snd_soc_codec *codec = socdev->card->codec; |
557 | u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); | 546 | u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); |
558 | 547 | ||
559 | paifb &= ~WM8580_AIF_LENGTH_MASK; | 548 | paifb &= ~WM8580_AIF_LENGTH_MASK; |
@@ -771,8 +760,22 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
771 | switch (level) { | 760 | switch (level) { |
772 | case SND_SOC_BIAS_ON: | 761 | case SND_SOC_BIAS_ON: |
773 | case SND_SOC_BIAS_PREPARE: | 762 | case SND_SOC_BIAS_PREPARE: |
763 | break; | ||
764 | |||
774 | case SND_SOC_BIAS_STANDBY: | 765 | case SND_SOC_BIAS_STANDBY: |
766 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
767 | /* Power up and get individual control of the DACs */ | ||
768 | reg = wm8580_read(codec, WM8580_PWRDN1); | ||
769 | reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); | ||
770 | wm8580_write(codec, WM8580_PWRDN1, reg); | ||
771 | |||
772 | /* Make VMID high impedence */ | ||
773 | reg = wm8580_read(codec, WM8580_ADC_CONTROL1); | ||
774 | reg &= ~0x100; | ||
775 | wm8580_write(codec, WM8580_ADC_CONTROL1, reg); | ||
776 | } | ||
775 | break; | 777 | break; |
778 | |||
776 | case SND_SOC_BIAS_OFF: | 779 | case SND_SOC_BIAS_OFF: |
777 | reg = wm8580_read(codec, WM8580_PWRDN1); | 780 | reg = wm8580_read(codec, WM8580_PWRDN1); |
778 | wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); | 781 | wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); |
@@ -785,6 +788,21 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
785 | #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 788 | #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
786 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 789 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
787 | 790 | ||
791 | static struct snd_soc_dai_ops wm8580_dai_ops_playback = { | ||
792 | .hw_params = wm8580_paif_hw_params, | ||
793 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
794 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
795 | .set_pll = wm8580_set_dai_pll, | ||
796 | .digital_mute = wm8580_digital_mute, | ||
797 | }; | ||
798 | |||
799 | static struct snd_soc_dai_ops wm8580_dai_ops_capture = { | ||
800 | .hw_params = wm8580_paif_hw_params, | ||
801 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
802 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
803 | .set_pll = wm8580_set_dai_pll, | ||
804 | }; | ||
805 | |||
788 | struct snd_soc_dai wm8580_dai[] = { | 806 | struct snd_soc_dai wm8580_dai[] = { |
789 | { | 807 | { |
790 | .name = "WM8580 PAIFRX", | 808 | .name = "WM8580 PAIFRX", |
@@ -796,13 +814,7 @@ struct snd_soc_dai wm8580_dai[] = { | |||
796 | .rates = SNDRV_PCM_RATE_8000_192000, | 814 | .rates = SNDRV_PCM_RATE_8000_192000, |
797 | .formats = WM8580_FORMATS, | 815 | .formats = WM8580_FORMATS, |
798 | }, | 816 | }, |
799 | .ops = { | 817 | .ops = &wm8580_dai_ops_playback, |
800 | .hw_params = wm8580_paif_hw_params, | ||
801 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
802 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
803 | .set_pll = wm8580_set_dai_pll, | ||
804 | .digital_mute = wm8580_digital_mute, | ||
805 | }, | ||
806 | }, | 818 | }, |
807 | { | 819 | { |
808 | .name = "WM8580 PAIFTX", | 820 | .name = "WM8580 PAIFTX", |
@@ -814,109 +826,168 @@ struct snd_soc_dai wm8580_dai[] = { | |||
814 | .rates = SNDRV_PCM_RATE_8000_192000, | 826 | .rates = SNDRV_PCM_RATE_8000_192000, |
815 | .formats = WM8580_FORMATS, | 827 | .formats = WM8580_FORMATS, |
816 | }, | 828 | }, |
817 | .ops = { | 829 | .ops = &wm8580_dai_ops_capture, |
818 | .hw_params = wm8580_paif_hw_params, | ||
819 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
820 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
821 | .set_pll = wm8580_set_dai_pll, | ||
822 | }, | ||
823 | }, | 830 | }, |
824 | }; | 831 | }; |
825 | EXPORT_SYMBOL_GPL(wm8580_dai); | 832 | EXPORT_SYMBOL_GPL(wm8580_dai); |
826 | 833 | ||
827 | /* | 834 | static struct snd_soc_codec *wm8580_codec; |
828 | * initialise the WM8580 driver | 835 | |
829 | * register the mixer and dsp interfaces with the kernel | 836 | static int wm8580_probe(struct platform_device *pdev) |
830 | */ | ||
831 | static int wm8580_init(struct snd_soc_device *socdev) | ||
832 | { | 837 | { |
833 | struct snd_soc_codec *codec = socdev->codec; | 838 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
839 | struct snd_soc_codec *codec; | ||
834 | int ret = 0; | 840 | int ret = 0; |
835 | 841 | ||
836 | codec->name = "WM8580"; | 842 | if (wm8580_codec == NULL) { |
837 | codec->owner = THIS_MODULE; | 843 | dev_err(&pdev->dev, "Codec device not registered\n"); |
838 | codec->read = wm8580_read_reg_cache; | 844 | return -ENODEV; |
839 | codec->write = wm8580_write; | 845 | } |
840 | codec->set_bias_level = wm8580_set_bias_level; | ||
841 | codec->dai = wm8580_dai; | ||
842 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
843 | codec->reg_cache_size = ARRAY_SIZE(wm8580_reg); | ||
844 | codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg), | ||
845 | GFP_KERNEL); | ||
846 | |||
847 | if (codec->reg_cache == NULL) | ||
848 | return -ENOMEM; | ||
849 | |||
850 | /* Get the codec into a known state */ | ||
851 | wm8580_write(codec, WM8580_RESET, 0); | ||
852 | |||
853 | /* Power up and get individual control of the DACs */ | ||
854 | wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) & | ||
855 | ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD)); | ||
856 | 846 | ||
857 | /* Make VMID high impedence */ | 847 | socdev->card->codec = wm8580_codec; |
858 | wm8580_write(codec, WM8580_ADC_CONTROL1, | 848 | codec = wm8580_codec; |
859 | wm8580_read(codec, WM8580_ADC_CONTROL1) & ~0x100); | ||
860 | 849 | ||
861 | /* register pcms */ | 850 | /* register pcms */ |
862 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, | 851 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
863 | SNDRV_DEFAULT_STR1); | ||
864 | if (ret < 0) { | 852 | if (ret < 0) { |
865 | printk(KERN_ERR "wm8580: failed to create pcms\n"); | 853 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); |
866 | goto pcm_err; | 854 | goto pcm_err; |
867 | } | 855 | } |
868 | 856 | ||
869 | wm8580_add_controls(codec); | 857 | snd_soc_add_controls(codec, wm8580_snd_controls, |
858 | ARRAY_SIZE(wm8580_snd_controls)); | ||
870 | wm8580_add_widgets(codec); | 859 | wm8580_add_widgets(codec); |
871 | |||
872 | ret = snd_soc_init_card(socdev); | 860 | ret = snd_soc_init_card(socdev); |
873 | if (ret < 0) { | 861 | if (ret < 0) { |
874 | printk(KERN_ERR "wm8580: failed to register card\n"); | 862 | dev_err(codec->dev, "failed to register card: %d\n", ret); |
875 | goto card_err; | 863 | goto card_err; |
876 | } | 864 | } |
865 | |||
877 | return ret; | 866 | return ret; |
878 | 867 | ||
879 | card_err: | 868 | card_err: |
880 | snd_soc_free_pcms(socdev); | 869 | snd_soc_free_pcms(socdev); |
881 | snd_soc_dapm_free(socdev); | 870 | snd_soc_dapm_free(socdev); |
882 | pcm_err: | 871 | pcm_err: |
883 | kfree(codec->reg_cache); | ||
884 | return ret; | 872 | return ret; |
885 | } | 873 | } |
886 | 874 | ||
887 | /* If the i2c layer weren't so broken, we could pass this kind of data | 875 | /* power down chip */ |
888 | around */ | 876 | static int wm8580_remove(struct platform_device *pdev) |
889 | static struct snd_soc_device *wm8580_socdev; | 877 | { |
878 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
879 | |||
880 | snd_soc_free_pcms(socdev); | ||
881 | snd_soc_dapm_free(socdev); | ||
890 | 882 | ||
891 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 883 | return 0; |
884 | } | ||
892 | 885 | ||
893 | /* | 886 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { |
894 | * WM8580 2 wire address is determined by GPIO5 | 887 | .probe = wm8580_probe, |
895 | * state during powerup. | 888 | .remove = wm8580_remove, |
896 | * low = 0x1a | 889 | }; |
897 | * high = 0x1b | 890 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); |
898 | */ | 891 | |
892 | static int wm8580_register(struct wm8580_priv *wm8580) | ||
893 | { | ||
894 | int ret, i; | ||
895 | struct snd_soc_codec *codec = &wm8580->codec; | ||
896 | |||
897 | if (wm8580_codec) { | ||
898 | dev_err(codec->dev, "Another WM8580 is registered\n"); | ||
899 | ret = -EINVAL; | ||
900 | goto err; | ||
901 | } | ||
902 | |||
903 | mutex_init(&codec->mutex); | ||
904 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
905 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
899 | 906 | ||
907 | codec->private_data = wm8580; | ||
908 | codec->name = "WM8580"; | ||
909 | codec->owner = THIS_MODULE; | ||
910 | codec->read = wm8580_read_reg_cache; | ||
911 | codec->write = wm8580_write; | ||
912 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
913 | codec->set_bias_level = wm8580_set_bias_level; | ||
914 | codec->dai = wm8580_dai; | ||
915 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
916 | codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache); | ||
917 | codec->reg_cache = &wm8580->reg_cache; | ||
918 | |||
919 | memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); | ||
920 | |||
921 | /* Get the codec into a known state */ | ||
922 | ret = wm8580_write(codec, WM8580_RESET, 0); | ||
923 | if (ret != 0) { | ||
924 | dev_err(codec->dev, "Failed to reset codec: %d\n", ret); | ||
925 | goto err; | ||
926 | } | ||
927 | |||
928 | for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++) | ||
929 | wm8580_dai[i].dev = codec->dev; | ||
930 | |||
931 | wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
932 | |||
933 | wm8580_codec = codec; | ||
934 | |||
935 | ret = snd_soc_register_codec(codec); | ||
936 | if (ret != 0) { | ||
937 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
938 | goto err; | ||
939 | } | ||
940 | |||
941 | ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
942 | if (ret != 0) { | ||
943 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
944 | goto err_codec; | ||
945 | } | ||
946 | |||
947 | return 0; | ||
948 | |||
949 | err_codec: | ||
950 | snd_soc_unregister_codec(codec); | ||
951 | err: | ||
952 | kfree(wm8580); | ||
953 | return ret; | ||
954 | } | ||
955 | |||
956 | static void wm8580_unregister(struct wm8580_priv *wm8580) | ||
957 | { | ||
958 | wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF); | ||
959 | snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
960 | snd_soc_unregister_codec(&wm8580->codec); | ||
961 | kfree(wm8580); | ||
962 | wm8580_codec = NULL; | ||
963 | } | ||
964 | |||
965 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
900 | static int wm8580_i2c_probe(struct i2c_client *i2c, | 966 | static int wm8580_i2c_probe(struct i2c_client *i2c, |
901 | const struct i2c_device_id *id) | 967 | const struct i2c_device_id *id) |
902 | { | 968 | { |
903 | struct snd_soc_device *socdev = wm8580_socdev; | 969 | struct wm8580_priv *wm8580; |
904 | struct snd_soc_codec *codec = socdev->codec; | 970 | struct snd_soc_codec *codec; |
905 | int ret; | ||
906 | 971 | ||
907 | i2c_set_clientdata(i2c, codec); | 972 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); |
973 | if (wm8580 == NULL) | ||
974 | return -ENOMEM; | ||
975 | |||
976 | codec = &wm8580->codec; | ||
977 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
978 | |||
979 | i2c_set_clientdata(i2c, wm8580); | ||
908 | codec->control_data = i2c; | 980 | codec->control_data = i2c; |
909 | 981 | ||
910 | ret = wm8580_init(socdev); | 982 | codec->dev = &i2c->dev; |
911 | if (ret < 0) | 983 | |
912 | dev_err(&i2c->dev, "failed to initialise WM8580\n"); | 984 | return wm8580_register(wm8580); |
913 | return ret; | ||
914 | } | 985 | } |
915 | 986 | ||
916 | static int wm8580_i2c_remove(struct i2c_client *client) | 987 | static int wm8580_i2c_remove(struct i2c_client *client) |
917 | { | 988 | { |
918 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 989 | struct wm8580_priv *wm8580 = i2c_get_clientdata(client); |
919 | kfree(codec->reg_cache); | 990 | wm8580_unregister(wm8580); |
920 | return 0; | 991 | return 0; |
921 | } | 992 | } |
922 | 993 | ||
@@ -928,129 +999,35 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); | |||
928 | 999 | ||
929 | static struct i2c_driver wm8580_i2c_driver = { | 1000 | static struct i2c_driver wm8580_i2c_driver = { |
930 | .driver = { | 1001 | .driver = { |
931 | .name = "WM8580 I2C Codec", | 1002 | .name = "wm8580", |
932 | .owner = THIS_MODULE, | 1003 | .owner = THIS_MODULE, |
933 | }, | 1004 | }, |
934 | .probe = wm8580_i2c_probe, | 1005 | .probe = wm8580_i2c_probe, |
935 | .remove = wm8580_i2c_remove, | 1006 | .remove = wm8580_i2c_remove, |
936 | .id_table = wm8580_i2c_id, | 1007 | .id_table = wm8580_i2c_id, |
937 | }; | 1008 | }; |
1009 | #endif | ||
938 | 1010 | ||
939 | static int wm8580_add_i2c_device(struct platform_device *pdev, | 1011 | static int __init wm8580_modinit(void) |
940 | const struct wm8580_setup_data *setup) | ||
941 | { | 1012 | { |
942 | struct i2c_board_info info; | ||
943 | struct i2c_adapter *adapter; | ||
944 | struct i2c_client *client; | ||
945 | int ret; | 1013 | int ret; |
946 | 1014 | ||
1015 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
947 | ret = i2c_add_driver(&wm8580_i2c_driver); | 1016 | ret = i2c_add_driver(&wm8580_i2c_driver); |
948 | if (ret != 0) { | 1017 | if (ret != 0) { |
949 | dev_err(&pdev->dev, "can't add i2c driver\n"); | 1018 | pr_err("Failed to register WM8580 I2C driver: %d\n", ret); |
950 | return ret; | ||
951 | } | ||
952 | |||
953 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
954 | info.addr = setup->i2c_address; | ||
955 | strlcpy(info.type, "wm8580", I2C_NAME_SIZE); | ||
956 | |||
957 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
958 | if (!adapter) { | ||
959 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
960 | setup->i2c_bus); | ||
961 | goto err_driver; | ||
962 | } | ||
963 | |||
964 | client = i2c_new_device(adapter, &info); | ||
965 | i2c_put_adapter(adapter); | ||
966 | if (!client) { | ||
967 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
968 | (unsigned int)info.addr); | ||
969 | goto err_driver; | ||
970 | } | 1019 | } |
971 | |||
972 | return 0; | ||
973 | |||
974 | err_driver: | ||
975 | i2c_del_driver(&wm8580_i2c_driver); | ||
976 | return -ENODEV; | ||
977 | } | ||
978 | #endif | 1020 | #endif |
979 | 1021 | ||
980 | static int wm8580_probe(struct platform_device *pdev) | ||
981 | { | ||
982 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
983 | struct wm8580_setup_data *setup; | ||
984 | struct snd_soc_codec *codec; | ||
985 | struct wm8580_priv *wm8580; | ||
986 | int ret = 0; | ||
987 | |||
988 | pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION); | ||
989 | |||
990 | setup = socdev->codec_data; | ||
991 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
992 | if (codec == NULL) | ||
993 | return -ENOMEM; | ||
994 | |||
995 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); | ||
996 | if (wm8580 == NULL) { | ||
997 | kfree(codec); | ||
998 | return -ENOMEM; | ||
999 | } | ||
1000 | |||
1001 | codec->private_data = wm8580; | ||
1002 | socdev->codec = codec; | ||
1003 | mutex_init(&codec->mutex); | ||
1004 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1005 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1006 | wm8580_socdev = socdev; | ||
1007 | |||
1008 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1009 | if (setup->i2c_address) { | ||
1010 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1011 | ret = wm8580_add_i2c_device(pdev, setup); | ||
1012 | } | ||
1013 | #else | ||
1014 | /* Add other interfaces here */ | ||
1015 | #endif | ||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | /* power down chip */ | ||
1020 | static int wm8580_remove(struct platform_device *pdev) | ||
1021 | { | ||
1022 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1023 | struct snd_soc_codec *codec = socdev->codec; | ||
1024 | |||
1025 | if (codec->control_data) | ||
1026 | wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1027 | snd_soc_free_pcms(socdev); | ||
1028 | snd_soc_dapm_free(socdev); | ||
1029 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1030 | i2c_unregister_device(codec->control_data); | ||
1031 | i2c_del_driver(&wm8580_i2c_driver); | ||
1032 | #endif | ||
1033 | kfree(codec->private_data); | ||
1034 | kfree(codec); | ||
1035 | |||
1036 | return 0; | 1022 | return 0; |
1037 | } | 1023 | } |
1038 | |||
1039 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { | ||
1040 | .probe = wm8580_probe, | ||
1041 | .remove = wm8580_remove, | ||
1042 | }; | ||
1043 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); | ||
1044 | |||
1045 | static int __init wm8580_modinit(void) | ||
1046 | { | ||
1047 | return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
1048 | } | ||
1049 | module_init(wm8580_modinit); | 1024 | module_init(wm8580_modinit); |
1050 | 1025 | ||
1051 | static void __exit wm8580_exit(void) | 1026 | static void __exit wm8580_exit(void) |
1052 | { | 1027 | { |
1053 | snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | 1028 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1029 | i2c_del_driver(&wm8580_i2c_driver); | ||
1030 | #endif | ||
1054 | } | 1031 | } |
1055 | module_exit(wm8580_exit); | 1032 | module_exit(wm8580_exit); |
1056 | 1033 | ||
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h index 09e4422f6f2f..0dfb5ddde6a2 100644 --- a/sound/soc/codecs/wm8580.h +++ b/sound/soc/codecs/wm8580.h | |||
@@ -28,11 +28,6 @@ | |||
28 | #define WM8580_CLKSRC_OSC 4 | 28 | #define WM8580_CLKSRC_OSC 4 |
29 | #define WM8580_CLKSRC_NONE 5 | 29 | #define WM8580_CLKSRC_NONE 5 |
30 | 30 | ||
31 | struct wm8580_setup_data { | ||
32 | int i2c_bus; | ||
33 | unsigned short i2c_address; | ||
34 | }; | ||
35 | |||
36 | #define WM8580_DAI_PAIFRX 0 | 31 | #define WM8580_DAI_PAIFRX 0 |
37 | #define WM8580_DAI_PAIFTX 1 | 32 | #define WM8580_DAI_PAIFTX 1 |
38 | 33 | ||
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 80b11983e137..e7ff2121ede9 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c | |||
@@ -47,7 +47,7 @@ static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec, | |||
47 | unsigned int reg) | 47 | unsigned int reg) |
48 | { | 48 | { |
49 | u16 *cache = codec->reg_cache; | 49 | u16 *cache = codec->reg_cache; |
50 | BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); | 50 | BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); |
51 | return cache[reg]; | 51 | return cache[reg]; |
52 | } | 52 | } |
53 | 53 | ||
@@ -55,7 +55,7 @@ static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec, | |||
55 | u16 reg, unsigned int value) | 55 | u16 reg, unsigned int value) |
56 | { | 56 | { |
57 | u16 *cache = codec->reg_cache; | 57 | u16 *cache = codec->reg_cache; |
58 | BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); | 58 | BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); |
59 | cache[reg] = value; | 59 | cache[reg] = value; |
60 | } | 60 | } |
61 | 61 | ||
@@ -92,21 +92,6 @@ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL, | |||
92 | SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), | 92 | SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), |
93 | }; | 93 | }; |
94 | 94 | ||
95 | static int wm8728_add_controls(struct snd_soc_codec *codec) | ||
96 | { | ||
97 | int err, i; | ||
98 | |||
99 | for (i = 0; i < ARRAY_SIZE(wm8728_snd_controls); i++) { | ||
100 | err = snd_ctl_add(codec->card, | ||
101 | snd_soc_cnew(&wm8728_snd_controls[i], | ||
102 | codec, NULL)); | ||
103 | if (err < 0) | ||
104 | return err; | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* | 95 | /* |
111 | * DAPM controls. | 96 | * DAPM controls. |
112 | */ | 97 | */ |
@@ -152,7 +137,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream, | |||
152 | { | 137 | { |
153 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 138 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
154 | struct snd_soc_device *socdev = rtd->socdev; | 139 | struct snd_soc_device *socdev = rtd->socdev; |
155 | struct snd_soc_codec *codec = socdev->codec; | 140 | struct snd_soc_codec *codec = socdev->card->codec; |
156 | u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); | 141 | u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); |
157 | 142 | ||
158 | dac &= ~0x18; | 143 | dac &= ~0x18; |
@@ -259,6 +244,12 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec, | |||
259 | #define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 244 | #define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
260 | SNDRV_PCM_FMTBIT_S24_LE) | 245 | SNDRV_PCM_FMTBIT_S24_LE) |
261 | 246 | ||
247 | static struct snd_soc_dai_ops wm8728_dai_ops = { | ||
248 | .hw_params = wm8728_hw_params, | ||
249 | .digital_mute = wm8728_mute, | ||
250 | .set_fmt = wm8728_set_dai_fmt, | ||
251 | }; | ||
252 | |||
262 | struct snd_soc_dai wm8728_dai = { | 253 | struct snd_soc_dai wm8728_dai = { |
263 | .name = "WM8728", | 254 | .name = "WM8728", |
264 | .playback = { | 255 | .playback = { |
@@ -268,18 +259,14 @@ struct snd_soc_dai wm8728_dai = { | |||
268 | .rates = WM8728_RATES, | 259 | .rates = WM8728_RATES, |
269 | .formats = WM8728_FORMATS, | 260 | .formats = WM8728_FORMATS, |
270 | }, | 261 | }, |
271 | .ops = { | 262 | .ops = &wm8728_dai_ops, |
272 | .hw_params = wm8728_hw_params, | ||
273 | .digital_mute = wm8728_mute, | ||
274 | .set_fmt = wm8728_set_dai_fmt, | ||
275 | } | ||
276 | }; | 263 | }; |
277 | EXPORT_SYMBOL_GPL(wm8728_dai); | 264 | EXPORT_SYMBOL_GPL(wm8728_dai); |
278 | 265 | ||
279 | static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) | 266 | static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) |
280 | { | 267 | { |
281 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 268 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
282 | struct snd_soc_codec *codec = socdev->codec; | 269 | struct snd_soc_codec *codec = socdev->card->codec; |
283 | 270 | ||
284 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); | 271 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); |
285 | 272 | ||
@@ -289,7 +276,7 @@ static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) | |||
289 | static int wm8728_resume(struct platform_device *pdev) | 276 | static int wm8728_resume(struct platform_device *pdev) |
290 | { | 277 | { |
291 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 278 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
292 | struct snd_soc_codec *codec = socdev->codec; | 279 | struct snd_soc_codec *codec = socdev->card->codec; |
293 | 280 | ||
294 | wm8728_set_bias_level(codec, codec->suspend_bias_level); | 281 | wm8728_set_bias_level(codec, codec->suspend_bias_level); |
295 | 282 | ||
@@ -302,7 +289,7 @@ static int wm8728_resume(struct platform_device *pdev) | |||
302 | */ | 289 | */ |
303 | static int wm8728_init(struct snd_soc_device *socdev) | 290 | static int wm8728_init(struct snd_soc_device *socdev) |
304 | { | 291 | { |
305 | struct snd_soc_codec *codec = socdev->codec; | 292 | struct snd_soc_codec *codec = socdev->card->codec; |
306 | int ret = 0; | 293 | int ret = 0; |
307 | 294 | ||
308 | codec->name = "WM8728"; | 295 | codec->name = "WM8728"; |
@@ -330,7 +317,8 @@ static int wm8728_init(struct snd_soc_device *socdev) | |||
330 | /* power on device */ | 317 | /* power on device */ |
331 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 318 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
332 | 319 | ||
333 | wm8728_add_controls(codec); | 320 | snd_soc_add_controls(codec, wm8728_snd_controls, |
321 | ARRAY_SIZE(wm8728_snd_controls)); | ||
334 | wm8728_add_widgets(codec); | 322 | wm8728_add_widgets(codec); |
335 | ret = snd_soc_init_card(socdev); | 323 | ret = snd_soc_init_card(socdev); |
336 | if (ret < 0) { | 324 | if (ret < 0) { |
@@ -363,7 +351,7 @@ static int wm8728_i2c_probe(struct i2c_client *i2c, | |||
363 | const struct i2c_device_id *id) | 351 | const struct i2c_device_id *id) |
364 | { | 352 | { |
365 | struct snd_soc_device *socdev = wm8728_socdev; | 353 | struct snd_soc_device *socdev = wm8728_socdev; |
366 | struct snd_soc_codec *codec = socdev->codec; | 354 | struct snd_soc_codec *codec = socdev->card->codec; |
367 | int ret; | 355 | int ret; |
368 | 356 | ||
369 | i2c_set_clientdata(i2c, codec); | 357 | i2c_set_clientdata(i2c, codec); |
@@ -444,7 +432,7 @@ err_driver: | |||
444 | static int __devinit wm8728_spi_probe(struct spi_device *spi) | 432 | static int __devinit wm8728_spi_probe(struct spi_device *spi) |
445 | { | 433 | { |
446 | struct snd_soc_device *socdev = wm8728_socdev; | 434 | struct snd_soc_device *socdev = wm8728_socdev; |
447 | struct snd_soc_codec *codec = socdev->codec; | 435 | struct snd_soc_codec *codec = socdev->card->codec; |
448 | int ret; | 436 | int ret; |
449 | 437 | ||
450 | codec->control_data = spi; | 438 | codec->control_data = spi; |
@@ -508,7 +496,7 @@ static int wm8728_probe(struct platform_device *pdev) | |||
508 | if (codec == NULL) | 496 | if (codec == NULL) |
509 | return -ENOMEM; | 497 | return -ENOMEM; |
510 | 498 | ||
511 | socdev->codec = codec; | 499 | socdev->card->codec = codec; |
512 | mutex_init(&codec->mutex); | 500 | mutex_init(&codec->mutex); |
513 | INIT_LIST_HEAD(&codec->dapm_widgets); | 501 | INIT_LIST_HEAD(&codec->dapm_widgets); |
514 | INIT_LIST_HEAD(&codec->dapm_paths); | 502 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -541,7 +529,7 @@ static int wm8728_probe(struct platform_device *pdev) | |||
541 | static int wm8728_remove(struct platform_device *pdev) | 529 | static int wm8728_remove(struct platform_device *pdev) |
542 | { | 530 | { |
543 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 531 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
544 | struct snd_soc_codec *codec = socdev->codec; | 532 | struct snd_soc_codec *codec = socdev->card->codec; |
545 | 533 | ||
546 | if (codec->control_data) | 534 | if (codec->control_data) |
547 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); | 535 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index c444b9f2701e..e043e3f60008 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -29,15 +29,20 @@ | |||
29 | 29 | ||
30 | #include "wm8731.h" | 30 | #include "wm8731.h" |
31 | 31 | ||
32 | #define WM8731_VERSION "0.13" | 32 | static struct snd_soc_codec *wm8731_codec; |
33 | |||
34 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 33 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
35 | 34 | ||
36 | /* codec private data */ | 35 | /* codec private data */ |
37 | struct wm8731_priv { | 36 | struct wm8731_priv { |
37 | struct snd_soc_codec codec; | ||
38 | u16 reg_cache[WM8731_CACHEREGNUM]; | ||
38 | unsigned int sysclk; | 39 | unsigned int sysclk; |
39 | }; | 40 | }; |
40 | 41 | ||
42 | #ifdef CONFIG_SPI_MASTER | ||
43 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len); | ||
44 | #endif | ||
45 | |||
41 | /* | 46 | /* |
42 | * wm8731 register cache | 47 | * wm8731 register cache |
43 | * We can't read the WM8731 register space when we are | 48 | * We can't read the WM8731 register space when we are |
@@ -129,22 +134,6 @@ SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), | |||
129 | SOC_ENUM("Playback De-emphasis", wm8731_enum[1]), | 134 | SOC_ENUM("Playback De-emphasis", wm8731_enum[1]), |
130 | }; | 135 | }; |
131 | 136 | ||
132 | /* add non dapm controls */ | ||
133 | static int wm8731_add_controls(struct snd_soc_codec *codec) | ||
134 | { | ||
135 | int err, i; | ||
136 | |||
137 | for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) { | ||
138 | err = snd_ctl_add(codec->card, | ||
139 | snd_soc_cnew(&wm8731_snd_controls[i], | ||
140 | codec, NULL)); | ||
141 | if (err < 0) | ||
142 | return err; | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* Output Mixer */ | 137 | /* Output Mixer */ |
149 | static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { | 138 | static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { |
150 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), | 139 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), |
@@ -269,7 +258,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, | |||
269 | { | 258 | { |
270 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 259 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
271 | struct snd_soc_device *socdev = rtd->socdev; | 260 | struct snd_soc_device *socdev = rtd->socdev; |
272 | struct snd_soc_codec *codec = socdev->codec; | 261 | struct snd_soc_codec *codec = socdev->card->codec; |
273 | struct wm8731_priv *wm8731 = codec->private_data; | 262 | struct wm8731_priv *wm8731 = codec->private_data; |
274 | u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3; | 263 | u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3; |
275 | int i = get_coeff(wm8731->sysclk, params_rate(params)); | 264 | int i = get_coeff(wm8731->sysclk, params_rate(params)); |
@@ -299,7 +288,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, | |||
299 | { | 288 | { |
300 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 289 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
301 | struct snd_soc_device *socdev = rtd->socdev; | 290 | struct snd_soc_device *socdev = rtd->socdev; |
302 | struct snd_soc_codec *codec = socdev->codec; | 291 | struct snd_soc_codec *codec = socdev->card->codec; |
303 | 292 | ||
304 | /* set active */ | 293 | /* set active */ |
305 | wm8731_write(codec, WM8731_ACTIVE, 0x0001); | 294 | wm8731_write(codec, WM8731_ACTIVE, 0x0001); |
@@ -312,7 +301,7 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream, | |||
312 | { | 301 | { |
313 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 302 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
314 | struct snd_soc_device *socdev = rtd->socdev; | 303 | struct snd_soc_device *socdev = rtd->socdev; |
315 | struct snd_soc_codec *codec = socdev->codec; | 304 | struct snd_soc_codec *codec = socdev->card->codec; |
316 | 305 | ||
317 | /* deactivate */ | 306 | /* deactivate */ |
318 | if (!codec->active) { | 307 | if (!codec->active) { |
@@ -414,21 +403,19 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
414 | static int wm8731_set_bias_level(struct snd_soc_codec *codec, | 403 | static int wm8731_set_bias_level(struct snd_soc_codec *codec, |
415 | enum snd_soc_bias_level level) | 404 | enum snd_soc_bias_level level) |
416 | { | 405 | { |
417 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; | 406 | u16 reg; |
418 | 407 | ||
419 | switch (level) { | 408 | switch (level) { |
420 | case SND_SOC_BIAS_ON: | 409 | case SND_SOC_BIAS_ON: |
421 | /* vref/mid, osc on, dac unmute */ | ||
422 | wm8731_write(codec, WM8731_PWR, reg); | ||
423 | break; | 410 | break; |
424 | case SND_SOC_BIAS_PREPARE: | 411 | case SND_SOC_BIAS_PREPARE: |
425 | break; | 412 | break; |
426 | case SND_SOC_BIAS_STANDBY: | 413 | case SND_SOC_BIAS_STANDBY: |
427 | /* everything off except vref/vmid, */ | 414 | /* Clear PWROFF, gate CLKOUT, everything else as-is */ |
415 | reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; | ||
428 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); | 416 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); |
429 | break; | 417 | break; |
430 | case SND_SOC_BIAS_OFF: | 418 | case SND_SOC_BIAS_OFF: |
431 | /* everything off, dac mute, inactive */ | ||
432 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 419 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
433 | wm8731_write(codec, WM8731_PWR, 0xffff); | 420 | wm8731_write(codec, WM8731_PWR, 0xffff); |
434 | break; | 421 | break; |
@@ -446,6 +433,15 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, | |||
446 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 433 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
447 | SNDRV_PCM_FMTBIT_S24_LE) | 434 | SNDRV_PCM_FMTBIT_S24_LE) |
448 | 435 | ||
436 | static struct snd_soc_dai_ops wm8731_dai_ops = { | ||
437 | .prepare = wm8731_pcm_prepare, | ||
438 | .hw_params = wm8731_hw_params, | ||
439 | .shutdown = wm8731_shutdown, | ||
440 | .digital_mute = wm8731_mute, | ||
441 | .set_sysclk = wm8731_set_dai_sysclk, | ||
442 | .set_fmt = wm8731_set_dai_fmt, | ||
443 | }; | ||
444 | |||
449 | struct snd_soc_dai wm8731_dai = { | 445 | struct snd_soc_dai wm8731_dai = { |
450 | .name = "WM8731", | 446 | .name = "WM8731", |
451 | .playback = { | 447 | .playback = { |
@@ -460,21 +456,14 @@ struct snd_soc_dai wm8731_dai = { | |||
460 | .channels_max = 2, | 456 | .channels_max = 2, |
461 | .rates = WM8731_RATES, | 457 | .rates = WM8731_RATES, |
462 | .formats = WM8731_FORMATS,}, | 458 | .formats = WM8731_FORMATS,}, |
463 | .ops = { | 459 | .ops = &wm8731_dai_ops, |
464 | .prepare = wm8731_pcm_prepare, | ||
465 | .hw_params = wm8731_hw_params, | ||
466 | .shutdown = wm8731_shutdown, | ||
467 | .digital_mute = wm8731_mute, | ||
468 | .set_sysclk = wm8731_set_dai_sysclk, | ||
469 | .set_fmt = wm8731_set_dai_fmt, | ||
470 | } | ||
471 | }; | 460 | }; |
472 | EXPORT_SYMBOL_GPL(wm8731_dai); | 461 | EXPORT_SYMBOL_GPL(wm8731_dai); |
473 | 462 | ||
474 | static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | 463 | static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) |
475 | { | 464 | { |
476 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 465 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
477 | struct snd_soc_codec *codec = socdev->codec; | 466 | struct snd_soc_codec *codec = socdev->card->codec; |
478 | 467 | ||
479 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 468 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
480 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | 469 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
@@ -484,7 +473,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | |||
484 | static int wm8731_resume(struct platform_device *pdev) | 473 | static int wm8731_resume(struct platform_device *pdev) |
485 | { | 474 | { |
486 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 475 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
487 | struct snd_soc_codec *codec = socdev->codec; | 476 | struct snd_soc_codec *codec = socdev->card->codec; |
488 | int i; | 477 | int i; |
489 | u8 data[2]; | 478 | u8 data[2]; |
490 | u16 *cache = codec->reg_cache; | 479 | u16 *cache = codec->reg_cache; |
@@ -500,54 +489,33 @@ static int wm8731_resume(struct platform_device *pdev) | |||
500 | return 0; | 489 | return 0; |
501 | } | 490 | } |
502 | 491 | ||
503 | /* | 492 | static int wm8731_probe(struct platform_device *pdev) |
504 | * initialise the WM8731 driver | ||
505 | * register the mixer and dsp interfaces with the kernel | ||
506 | */ | ||
507 | static int wm8731_init(struct snd_soc_device *socdev) | ||
508 | { | 493 | { |
509 | struct snd_soc_codec *codec = socdev->codec; | 494 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
510 | int reg, ret = 0; | 495 | struct snd_soc_codec *codec; |
496 | int ret = 0; | ||
511 | 497 | ||
512 | codec->name = "WM8731"; | 498 | if (wm8731_codec == NULL) { |
513 | codec->owner = THIS_MODULE; | 499 | dev_err(&pdev->dev, "Codec device not registered\n"); |
514 | codec->read = wm8731_read_reg_cache; | 500 | return -ENODEV; |
515 | codec->write = wm8731_write; | 501 | } |
516 | codec->set_bias_level = wm8731_set_bias_level; | ||
517 | codec->dai = &wm8731_dai; | ||
518 | codec->num_dai = 1; | ||
519 | codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); | ||
520 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); | ||
521 | if (codec->reg_cache == NULL) | ||
522 | return -ENOMEM; | ||
523 | 502 | ||
524 | wm8731_reset(codec); | 503 | socdev->card->codec = wm8731_codec; |
504 | codec = wm8731_codec; | ||
525 | 505 | ||
526 | /* register pcms */ | 506 | /* register pcms */ |
527 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 507 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
528 | if (ret < 0) { | 508 | if (ret < 0) { |
529 | printk(KERN_ERR "wm8731: failed to create pcms\n"); | 509 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); |
530 | goto pcm_err; | 510 | goto pcm_err; |
531 | } | 511 | } |
532 | 512 | ||
533 | /* power on device */ | 513 | snd_soc_add_controls(codec, wm8731_snd_controls, |
534 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 514 | ARRAY_SIZE(wm8731_snd_controls)); |
535 | |||
536 | /* set the update bits */ | ||
537 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | ||
538 | wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); | ||
539 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); | ||
540 | wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); | ||
541 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); | ||
542 | wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); | ||
543 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); | ||
544 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); | ||
545 | |||
546 | wm8731_add_controls(codec); | ||
547 | wm8731_add_widgets(codec); | 515 | wm8731_add_widgets(codec); |
548 | ret = snd_soc_init_card(socdev); | 516 | ret = snd_soc_init_card(socdev); |
549 | if (ret < 0) { | 517 | if (ret < 0) { |
550 | printk(KERN_ERR "wm8731: failed to register card\n"); | 518 | dev_err(codec->dev, "failed to register card: %d\n", ret); |
551 | goto card_err; | 519 | goto card_err; |
552 | } | 520 | } |
553 | 521 | ||
@@ -557,133 +525,109 @@ card_err: | |||
557 | snd_soc_free_pcms(socdev); | 525 | snd_soc_free_pcms(socdev); |
558 | snd_soc_dapm_free(socdev); | 526 | snd_soc_dapm_free(socdev); |
559 | pcm_err: | 527 | pcm_err: |
560 | kfree(codec->reg_cache); | ||
561 | return ret; | 528 | return ret; |
562 | } | 529 | } |
563 | 530 | ||
564 | static struct snd_soc_device *wm8731_socdev; | 531 | /* power down chip */ |
565 | 532 | static int wm8731_remove(struct platform_device *pdev) | |
566 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
567 | |||
568 | /* | ||
569 | * WM8731 2 wire address is determined by GPIO5 | ||
570 | * state during powerup. | ||
571 | * low = 0x1a | ||
572 | * high = 0x1b | ||
573 | */ | ||
574 | |||
575 | static int wm8731_i2c_probe(struct i2c_client *i2c, | ||
576 | const struct i2c_device_id *id) | ||
577 | { | 533 | { |
578 | struct snd_soc_device *socdev = wm8731_socdev; | 534 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
579 | struct snd_soc_codec *codec = socdev->codec; | ||
580 | int ret; | ||
581 | |||
582 | i2c_set_clientdata(i2c, codec); | ||
583 | codec->control_data = i2c; | ||
584 | |||
585 | ret = wm8731_init(socdev); | ||
586 | if (ret < 0) | ||
587 | pr_err("failed to initialise WM8731\n"); | ||
588 | 535 | ||
589 | return ret; | 536 | snd_soc_free_pcms(socdev); |
590 | } | 537 | snd_soc_dapm_free(socdev); |
591 | 538 | ||
592 | static int wm8731_i2c_remove(struct i2c_client *client) | ||
593 | { | ||
594 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
595 | kfree(codec->reg_cache); | ||
596 | return 0; | 539 | return 0; |
597 | } | 540 | } |
598 | 541 | ||
599 | static const struct i2c_device_id wm8731_i2c_id[] = { | 542 | struct snd_soc_codec_device soc_codec_dev_wm8731 = { |
600 | { "wm8731", 0 }, | 543 | .probe = wm8731_probe, |
601 | { } | 544 | .remove = wm8731_remove, |
602 | }; | 545 | .suspend = wm8731_suspend, |
603 | MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); | 546 | .resume = wm8731_resume, |
604 | |||
605 | static struct i2c_driver wm8731_i2c_driver = { | ||
606 | .driver = { | ||
607 | .name = "WM8731 I2C Codec", | ||
608 | .owner = THIS_MODULE, | ||
609 | }, | ||
610 | .probe = wm8731_i2c_probe, | ||
611 | .remove = wm8731_i2c_remove, | ||
612 | .id_table = wm8731_i2c_id, | ||
613 | }; | 547 | }; |
548 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); | ||
614 | 549 | ||
615 | static int wm8731_add_i2c_device(struct platform_device *pdev, | 550 | static int wm8731_register(struct wm8731_priv *wm8731) |
616 | const struct wm8731_setup_data *setup) | ||
617 | { | 551 | { |
618 | struct i2c_board_info info; | ||
619 | struct i2c_adapter *adapter; | ||
620 | struct i2c_client *client; | ||
621 | int ret; | 552 | int ret; |
553 | struct snd_soc_codec *codec = &wm8731->codec; | ||
554 | u16 reg; | ||
622 | 555 | ||
623 | ret = i2c_add_driver(&wm8731_i2c_driver); | 556 | if (wm8731_codec) { |
624 | if (ret != 0) { | 557 | dev_err(codec->dev, "Another WM8731 is registered\n"); |
625 | dev_err(&pdev->dev, "can't add i2c driver\n"); | 558 | return -EINVAL; |
626 | return ret; | ||
627 | } | 559 | } |
628 | 560 | ||
629 | memset(&info, 0, sizeof(struct i2c_board_info)); | 561 | mutex_init(&codec->mutex); |
630 | info.addr = setup->i2c_address; | 562 | INIT_LIST_HEAD(&codec->dapm_widgets); |
631 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | 563 | INIT_LIST_HEAD(&codec->dapm_paths); |
632 | 564 | ||
633 | adapter = i2c_get_adapter(setup->i2c_bus); | 565 | codec->private_data = wm8731; |
634 | if (!adapter) { | 566 | codec->name = "WM8731"; |
635 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | 567 | codec->owner = THIS_MODULE; |
636 | setup->i2c_bus); | 568 | codec->read = wm8731_read_reg_cache; |
637 | goto err_driver; | 569 | codec->write = wm8731_write; |
638 | } | 570 | codec->bias_level = SND_SOC_BIAS_OFF; |
571 | codec->set_bias_level = wm8731_set_bias_level; | ||
572 | codec->dai = &wm8731_dai; | ||
573 | codec->num_dai = 1; | ||
574 | codec->reg_cache_size = WM8731_CACHEREGNUM; | ||
575 | codec->reg_cache = &wm8731->reg_cache; | ||
639 | 576 | ||
640 | client = i2c_new_device(adapter, &info); | 577 | memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg)); |
641 | i2c_put_adapter(adapter); | 578 | |
642 | if (!client) { | 579 | ret = wm8731_reset(codec); |
643 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | 580 | if (ret < 0) { |
644 | (unsigned int)info.addr); | 581 | dev_err(codec->dev, "Failed to issue reset\n"); |
645 | goto err_driver; | 582 | return ret; |
646 | } | 583 | } |
647 | 584 | ||
648 | return 0; | 585 | wm8731_dai.dev = codec->dev; |
649 | 586 | ||
650 | err_driver: | 587 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
651 | i2c_del_driver(&wm8731_i2c_driver); | ||
652 | return -ENODEV; | ||
653 | } | ||
654 | #endif | ||
655 | 588 | ||
656 | #if defined(CONFIG_SPI_MASTER) | 589 | /* Latch the update bits */ |
657 | static int __devinit wm8731_spi_probe(struct spi_device *spi) | 590 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); |
658 | { | 591 | wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); |
659 | struct snd_soc_device *socdev = wm8731_socdev; | 592 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); |
660 | struct snd_soc_codec *codec = socdev->codec; | 593 | wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); |
661 | int ret; | 594 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); |
595 | wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); | ||
596 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); | ||
597 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); | ||
662 | 598 | ||
663 | codec->control_data = spi; | 599 | /* Disable bypass path by default */ |
600 | reg = wm8731_read_reg_cache(codec, WM8731_APANA); | ||
601 | wm8731_write(codec, WM8731_APANA, reg & ~0x4); | ||
664 | 602 | ||
665 | ret = wm8731_init(socdev); | 603 | wm8731_codec = codec; |
666 | if (ret < 0) | ||
667 | dev_err(&spi->dev, "failed to initialise WM8731\n"); | ||
668 | 604 | ||
669 | return ret; | 605 | ret = snd_soc_register_codec(codec); |
670 | } | 606 | if (ret != 0) { |
607 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
608 | return ret; | ||
609 | } | ||
610 | |||
611 | ret = snd_soc_register_dai(&wm8731_dai); | ||
612 | if (ret != 0) { | ||
613 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
614 | snd_soc_unregister_codec(codec); | ||
615 | return ret; | ||
616 | } | ||
671 | 617 | ||
672 | static int __devexit wm8731_spi_remove(struct spi_device *spi) | ||
673 | { | ||
674 | return 0; | 618 | return 0; |
675 | } | 619 | } |
676 | 620 | ||
677 | static struct spi_driver wm8731_spi_driver = { | 621 | static void wm8731_unregister(struct wm8731_priv *wm8731) |
678 | .driver = { | 622 | { |
679 | .name = "wm8731", | 623 | wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF); |
680 | .bus = &spi_bus_type, | 624 | snd_soc_unregister_dai(&wm8731_dai); |
681 | .owner = THIS_MODULE, | 625 | snd_soc_unregister_codec(&wm8731->codec); |
682 | }, | 626 | kfree(wm8731); |
683 | .probe = wm8731_spi_probe, | 627 | wm8731_codec = NULL; |
684 | .remove = __devexit_p(wm8731_spi_remove), | 628 | } |
685 | }; | ||
686 | 629 | ||
630 | #if defined(CONFIG_SPI_MASTER) | ||
687 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) | 631 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) |
688 | { | 632 | { |
689 | struct spi_transfer t; | 633 | struct spi_transfer t; |
@@ -707,101 +651,121 @@ static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) | |||
707 | 651 | ||
708 | return len; | 652 | return len; |
709 | } | 653 | } |
710 | #endif /* CONFIG_SPI_MASTER */ | ||
711 | 654 | ||
712 | static int wm8731_probe(struct platform_device *pdev) | 655 | static int __devinit wm8731_spi_probe(struct spi_device *spi) |
713 | { | 656 | { |
714 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
715 | struct wm8731_setup_data *setup; | ||
716 | struct snd_soc_codec *codec; | 657 | struct snd_soc_codec *codec; |
717 | struct wm8731_priv *wm8731; | 658 | struct wm8731_priv *wm8731; |
718 | int ret = 0; | ||
719 | |||
720 | pr_info("WM8731 Audio Codec %s", WM8731_VERSION); | ||
721 | |||
722 | setup = socdev->codec_data; | ||
723 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
724 | if (codec == NULL) | ||
725 | return -ENOMEM; | ||
726 | 659 | ||
727 | wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); | 660 | wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); |
728 | if (wm8731 == NULL) { | 661 | if (wm8731 == NULL) |
729 | kfree(codec); | ||
730 | return -ENOMEM; | 662 | return -ENOMEM; |
731 | } | ||
732 | 663 | ||
733 | codec->private_data = wm8731; | 664 | codec = &wm8731->codec; |
734 | socdev->codec = codec; | 665 | codec->control_data = spi; |
735 | mutex_init(&codec->mutex); | 666 | codec->hw_write = (hw_write_t)wm8731_spi_write; |
736 | INIT_LIST_HEAD(&codec->dapm_widgets); | 667 | codec->dev = &spi->dev; |
737 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
738 | 668 | ||
739 | wm8731_socdev = socdev; | 669 | spi->dev.driver_data = wm8731; |
740 | ret = -ENODEV; | ||
741 | 670 | ||
742 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 671 | return wm8731_register(wm8731); |
743 | if (setup->i2c_address) { | ||
744 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
745 | ret = wm8731_add_i2c_device(pdev, setup); | ||
746 | } | ||
747 | #endif | ||
748 | #if defined(CONFIG_SPI_MASTER) | ||
749 | if (setup->spi) { | ||
750 | codec->hw_write = (hw_write_t)wm8731_spi_write; | ||
751 | ret = spi_register_driver(&wm8731_spi_driver); | ||
752 | if (ret != 0) | ||
753 | printk(KERN_ERR "can't add spi driver"); | ||
754 | } | ||
755 | #endif | ||
756 | |||
757 | if (ret != 0) { | ||
758 | kfree(codec->private_data); | ||
759 | kfree(codec); | ||
760 | } | ||
761 | return ret; | ||
762 | } | 672 | } |
763 | 673 | ||
764 | /* power down chip */ | 674 | static int __devexit wm8731_spi_remove(struct spi_device *spi) |
765 | static int wm8731_remove(struct platform_device *pdev) | ||
766 | { | 675 | { |
767 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 676 | struct wm8731_priv *wm8731 = spi->dev.driver_data; |
768 | struct snd_soc_codec *codec = socdev->codec; | ||
769 | 677 | ||
770 | if (codec->control_data) | 678 | wm8731_unregister(wm8731); |
771 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | 679 | |
680 | return 0; | ||
681 | } | ||
682 | |||
683 | static struct spi_driver wm8731_spi_driver = { | ||
684 | .driver = { | ||
685 | .name = "wm8731", | ||
686 | .bus = &spi_bus_type, | ||
687 | .owner = THIS_MODULE, | ||
688 | }, | ||
689 | .probe = wm8731_spi_probe, | ||
690 | .remove = __devexit_p(wm8731_spi_remove), | ||
691 | }; | ||
692 | #endif /* CONFIG_SPI_MASTER */ | ||
772 | 693 | ||
773 | snd_soc_free_pcms(socdev); | ||
774 | snd_soc_dapm_free(socdev); | ||
775 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 694 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
776 | i2c_unregister_device(codec->control_data); | 695 | static __devinit int wm8731_i2c_probe(struct i2c_client *i2c, |
777 | i2c_del_driver(&wm8731_i2c_driver); | 696 | const struct i2c_device_id *id) |
778 | #endif | 697 | { |
779 | #if defined(CONFIG_SPI_MASTER) | 698 | struct wm8731_priv *wm8731; |
780 | spi_unregister_driver(&wm8731_spi_driver); | 699 | struct snd_soc_codec *codec; |
781 | #endif | 700 | |
782 | kfree(codec->private_data); | 701 | wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); |
783 | kfree(codec); | 702 | if (wm8731 == NULL) |
703 | return -ENOMEM; | ||
704 | |||
705 | codec = &wm8731->codec; | ||
706 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
784 | 707 | ||
708 | i2c_set_clientdata(i2c, wm8731); | ||
709 | codec->control_data = i2c; | ||
710 | |||
711 | codec->dev = &i2c->dev; | ||
712 | |||
713 | return wm8731_register(wm8731); | ||
714 | } | ||
715 | |||
716 | static __devexit int wm8731_i2c_remove(struct i2c_client *client) | ||
717 | { | ||
718 | struct wm8731_priv *wm8731 = i2c_get_clientdata(client); | ||
719 | wm8731_unregister(wm8731); | ||
785 | return 0; | 720 | return 0; |
786 | } | 721 | } |
787 | 722 | ||
788 | struct snd_soc_codec_device soc_codec_dev_wm8731 = { | 723 | static const struct i2c_device_id wm8731_i2c_id[] = { |
789 | .probe = wm8731_probe, | 724 | { "wm8731", 0 }, |
790 | .remove = wm8731_remove, | 725 | { } |
791 | .suspend = wm8731_suspend, | ||
792 | .resume = wm8731_resume, | ||
793 | }; | 726 | }; |
794 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); | 727 | MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); |
728 | |||
729 | static struct i2c_driver wm8731_i2c_driver = { | ||
730 | .driver = { | ||
731 | .name = "WM8731 I2C Codec", | ||
732 | .owner = THIS_MODULE, | ||
733 | }, | ||
734 | .probe = wm8731_i2c_probe, | ||
735 | .remove = __devexit_p(wm8731_i2c_remove), | ||
736 | .id_table = wm8731_i2c_id, | ||
737 | }; | ||
738 | #endif | ||
795 | 739 | ||
796 | static int __init wm8731_modinit(void) | 740 | static int __init wm8731_modinit(void) |
797 | { | 741 | { |
798 | return snd_soc_register_dai(&wm8731_dai); | 742 | int ret; |
743 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
744 | ret = i2c_add_driver(&wm8731_i2c_driver); | ||
745 | if (ret != 0) { | ||
746 | printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n", | ||
747 | ret); | ||
748 | } | ||
749 | #endif | ||
750 | #if defined(CONFIG_SPI_MASTER) | ||
751 | ret = spi_register_driver(&wm8731_spi_driver); | ||
752 | if (ret != 0) { | ||
753 | printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n", | ||
754 | ret); | ||
755 | } | ||
756 | #endif | ||
757 | return 0; | ||
799 | } | 758 | } |
800 | module_init(wm8731_modinit); | 759 | module_init(wm8731_modinit); |
801 | 760 | ||
802 | static void __exit wm8731_exit(void) | 761 | static void __exit wm8731_exit(void) |
803 | { | 762 | { |
804 | snd_soc_unregister_dai(&wm8731_dai); | 763 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
764 | i2c_del_driver(&wm8731_i2c_driver); | ||
765 | #endif | ||
766 | #if defined(CONFIG_SPI_MASTER) | ||
767 | spi_unregister_driver(&wm8731_spi_driver); | ||
768 | #endif | ||
805 | } | 769 | } |
806 | module_exit(wm8731_exit); | 770 | module_exit(wm8731_exit); |
807 | 771 | ||
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 95190e9c0c14..cd7b806e8ad0 100644 --- a/sound/soc/codecs/wm8731.h +++ b/sound/soc/codecs/wm8731.h | |||
@@ -34,12 +34,6 @@ | |||
34 | #define WM8731_SYSCLK 0 | 34 | #define WM8731_SYSCLK 0 |
35 | #define WM8731_DAI 0 | 35 | #define WM8731_DAI 0 |
36 | 36 | ||
37 | struct wm8731_setup_data { | ||
38 | int spi; | ||
39 | int i2c_bus; | ||
40 | unsigned short i2c_address; | ||
41 | }; | ||
42 | |||
43 | extern struct snd_soc_dai wm8731_dai; | 37 | extern struct snd_soc_dai wm8731_dai; |
44 | extern struct snd_soc_codec_device soc_codec_dev_wm8731; | 38 | extern struct snd_soc_codec_device soc_codec_dev_wm8731; |
45 | 39 | ||
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 5997fa68e0d5..b64509b01a49 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -231,21 +231,6 @@ SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0), | |||
231 | 231 | ||
232 | }; | 232 | }; |
233 | 233 | ||
234 | /* add non dapm controls */ | ||
235 | static int wm8750_add_controls(struct snd_soc_codec *codec) | ||
236 | { | ||
237 | int err, i; | ||
238 | |||
239 | for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) { | ||
240 | err = snd_ctl_add(codec->card, | ||
241 | snd_soc_cnew(&wm8750_snd_controls[i], | ||
242 | codec, NULL)); | ||
243 | if (err < 0) | ||
244 | return err; | ||
245 | } | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | 234 | /* |
250 | * DAPM Controls | 235 | * DAPM Controls |
251 | */ | 236 | */ |
@@ -619,7 +604,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | |||
619 | { | 604 | { |
620 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 605 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
621 | struct snd_soc_device *socdev = rtd->socdev; | 606 | struct snd_soc_device *socdev = rtd->socdev; |
622 | struct snd_soc_codec *codec = socdev->codec; | 607 | struct snd_soc_codec *codec = socdev->card->codec; |
623 | struct wm8750_priv *wm8750 = codec->private_data; | 608 | struct wm8750_priv *wm8750 = codec->private_data; |
624 | u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; | 609 | u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; |
625 | u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; | 610 | u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; |
@@ -694,6 +679,13 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec, | |||
694 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 679 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
695 | SNDRV_PCM_FMTBIT_S24_LE) | 680 | SNDRV_PCM_FMTBIT_S24_LE) |
696 | 681 | ||
682 | static struct snd_soc_dai_ops wm8750_dai_ops = { | ||
683 | .hw_params = wm8750_pcm_hw_params, | ||
684 | .digital_mute = wm8750_mute, | ||
685 | .set_fmt = wm8750_set_dai_fmt, | ||
686 | .set_sysclk = wm8750_set_dai_sysclk, | ||
687 | }; | ||
688 | |||
697 | struct snd_soc_dai wm8750_dai = { | 689 | struct snd_soc_dai wm8750_dai = { |
698 | .name = "WM8750", | 690 | .name = "WM8750", |
699 | .playback = { | 691 | .playback = { |
@@ -708,12 +700,7 @@ struct snd_soc_dai wm8750_dai = { | |||
708 | .channels_max = 2, | 700 | .channels_max = 2, |
709 | .rates = WM8750_RATES, | 701 | .rates = WM8750_RATES, |
710 | .formats = WM8750_FORMATS,}, | 702 | .formats = WM8750_FORMATS,}, |
711 | .ops = { | 703 | .ops = &wm8750_dai_ops, |
712 | .hw_params = wm8750_pcm_hw_params, | ||
713 | .digital_mute = wm8750_mute, | ||
714 | .set_fmt = wm8750_set_dai_fmt, | ||
715 | .set_sysclk = wm8750_set_dai_sysclk, | ||
716 | }, | ||
717 | }; | 704 | }; |
718 | EXPORT_SYMBOL_GPL(wm8750_dai); | 705 | EXPORT_SYMBOL_GPL(wm8750_dai); |
719 | 706 | ||
@@ -727,7 +714,7 @@ static void wm8750_work(struct work_struct *work) | |||
727 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | 714 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) |
728 | { | 715 | { |
729 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 716 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
730 | struct snd_soc_codec *codec = socdev->codec; | 717 | struct snd_soc_codec *codec = socdev->card->codec; |
731 | 718 | ||
732 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | 719 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
733 | return 0; | 720 | return 0; |
@@ -736,7 +723,7 @@ static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | |||
736 | static int wm8750_resume(struct platform_device *pdev) | 723 | static int wm8750_resume(struct platform_device *pdev) |
737 | { | 724 | { |
738 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 725 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
739 | struct snd_soc_codec *codec = socdev->codec; | 726 | struct snd_soc_codec *codec = socdev->card->codec; |
740 | int i; | 727 | int i; |
741 | u8 data[2]; | 728 | u8 data[2]; |
742 | u16 *cache = codec->reg_cache; | 729 | u16 *cache = codec->reg_cache; |
@@ -769,7 +756,7 @@ static int wm8750_resume(struct platform_device *pdev) | |||
769 | */ | 756 | */ |
770 | static int wm8750_init(struct snd_soc_device *socdev) | 757 | static int wm8750_init(struct snd_soc_device *socdev) |
771 | { | 758 | { |
772 | struct snd_soc_codec *codec = socdev->codec; | 759 | struct snd_soc_codec *codec = socdev->card->codec; |
773 | int reg, ret = 0; | 760 | int reg, ret = 0; |
774 | 761 | ||
775 | codec->name = "WM8750"; | 762 | codec->name = "WM8750"; |
@@ -816,7 +803,8 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
816 | reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); | 803 | reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); |
817 | wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); | 804 | wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); |
818 | 805 | ||
819 | wm8750_add_controls(codec); | 806 | snd_soc_add_controls(codec, wm8750_snd_controls, |
807 | ARRAY_SIZE(wm8750_snd_controls)); | ||
820 | wm8750_add_widgets(codec); | 808 | wm8750_add_widgets(codec); |
821 | ret = snd_soc_init_card(socdev); | 809 | ret = snd_soc_init_card(socdev); |
822 | if (ret < 0) { | 810 | if (ret < 0) { |
@@ -850,7 +838,7 @@ static int wm8750_i2c_probe(struct i2c_client *i2c, | |||
850 | const struct i2c_device_id *id) | 838 | const struct i2c_device_id *id) |
851 | { | 839 | { |
852 | struct snd_soc_device *socdev = wm8750_socdev; | 840 | struct snd_soc_device *socdev = wm8750_socdev; |
853 | struct snd_soc_codec *codec = socdev->codec; | 841 | struct snd_soc_codec *codec = socdev->card->codec; |
854 | int ret; | 842 | int ret; |
855 | 843 | ||
856 | i2c_set_clientdata(i2c, codec); | 844 | i2c_set_clientdata(i2c, codec); |
@@ -931,7 +919,7 @@ err_driver: | |||
931 | static int __devinit wm8750_spi_probe(struct spi_device *spi) | 919 | static int __devinit wm8750_spi_probe(struct spi_device *spi) |
932 | { | 920 | { |
933 | struct snd_soc_device *socdev = wm8750_socdev; | 921 | struct snd_soc_device *socdev = wm8750_socdev; |
934 | struct snd_soc_codec *codec = socdev->codec; | 922 | struct snd_soc_codec *codec = socdev->card->codec; |
935 | int ret; | 923 | int ret; |
936 | 924 | ||
937 | codec->control_data = spi; | 925 | codec->control_data = spi; |
@@ -1003,7 +991,7 @@ static int wm8750_probe(struct platform_device *pdev) | |||
1003 | } | 991 | } |
1004 | 992 | ||
1005 | codec->private_data = wm8750; | 993 | codec->private_data = wm8750; |
1006 | socdev->codec = codec; | 994 | socdev->card->codec = codec; |
1007 | mutex_init(&codec->mutex); | 995 | mutex_init(&codec->mutex); |
1008 | INIT_LIST_HEAD(&codec->dapm_widgets); | 996 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1009 | INIT_LIST_HEAD(&codec->dapm_paths); | 997 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -1057,7 +1045,7 @@ static int run_delayed_work(struct delayed_work *dwork) | |||
1057 | static int wm8750_remove(struct platform_device *pdev) | 1045 | static int wm8750_remove(struct platform_device *pdev) |
1058 | { | 1046 | { |
1059 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1047 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1060 | struct snd_soc_codec *codec = socdev->codec; | 1048 | struct snd_soc_codec *codec = socdev->card->codec; |
1061 | 1049 | ||
1062 | if (codec->control_data) | 1050 | if (codec->control_data) |
1063 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1051 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 77620ab98756..a6e8f3f7f052 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -51,8 +51,6 @@ | |||
51 | 51 | ||
52 | #include "wm8753.h" | 52 | #include "wm8753.h" |
53 | 53 | ||
54 | #define WM8753_VERSION "0.16" | ||
55 | |||
56 | static int caps_charge = 2000; | 54 | static int caps_charge = 2000; |
57 | module_param(caps_charge, int, 0); | 55 | module_param(caps_charge, int, 0); |
58 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | 56 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); |
@@ -60,12 +58,6 @@ MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | |||
60 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, | 58 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, |
61 | unsigned int mode); | 59 | unsigned int mode); |
62 | 60 | ||
63 | /* codec private data */ | ||
64 | struct wm8753_priv { | ||
65 | unsigned int sysclk; | ||
66 | unsigned int pcmclk; | ||
67 | }; | ||
68 | |||
69 | /* | 61 | /* |
70 | * wm8753 register cache | 62 | * wm8753 register cache |
71 | * We can't read the WM8753 register space when we | 63 | * We can't read the WM8753 register space when we |
@@ -90,6 +82,14 @@ static const u16 wm8753_reg[] = { | |||
90 | 0x0000, 0x0000 | 82 | 0x0000, 0x0000 |
91 | }; | 83 | }; |
92 | 84 | ||
85 | /* codec private data */ | ||
86 | struct wm8753_priv { | ||
87 | unsigned int sysclk; | ||
88 | unsigned int pcmclk; | ||
89 | struct snd_soc_codec codec; | ||
90 | u16 reg_cache[ARRAY_SIZE(wm8753_reg)]; | ||
91 | }; | ||
92 | |||
93 | /* | 93 | /* |
94 | * read wm8753 register cache | 94 | * read wm8753 register cache |
95 | */ | 95 | */ |
@@ -97,7 +97,7 @@ static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec, | |||
97 | unsigned int reg) | 97 | unsigned int reg) |
98 | { | 98 | { |
99 | u16 *cache = codec->reg_cache; | 99 | u16 *cache = codec->reg_cache; |
100 | if (reg < 1 || reg > (ARRAY_SIZE(wm8753_reg) + 1)) | 100 | if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1)) |
101 | return -1; | 101 | return -1; |
102 | return cache[reg - 1]; | 102 | return cache[reg - 1]; |
103 | } | 103 | } |
@@ -109,7 +109,7 @@ static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec, | |||
109 | unsigned int reg, unsigned int value) | 109 | unsigned int reg, unsigned int value) |
110 | { | 110 | { |
111 | u16 *cache = codec->reg_cache; | 111 | u16 *cache = codec->reg_cache; |
112 | if (reg < 1 || reg > 0x3f) | 112 | if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1)) |
113 | return; | 113 | return; |
114 | cache[reg - 1] = value; | 114 | cache[reg - 1] = value; |
115 | } | 115 | } |
@@ -339,21 +339,6 @@ SOC_ENUM("ADC Data Select", wm8753_enum[27]), | |||
339 | SOC_ENUM("ROUT2 Phase", wm8753_enum[28]), | 339 | SOC_ENUM("ROUT2 Phase", wm8753_enum[28]), |
340 | }; | 340 | }; |
341 | 341 | ||
342 | /* add non dapm controls */ | ||
343 | static int wm8753_add_controls(struct snd_soc_codec *codec) | ||
344 | { | ||
345 | int err, i; | ||
346 | |||
347 | for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) { | ||
348 | err = snd_ctl_add(codec->card, | ||
349 | snd_soc_cnew(&wm8753_snd_controls[i], | ||
350 | codec, NULL)); | ||
351 | if (err < 0) | ||
352 | return err; | ||
353 | } | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* | 342 | /* |
358 | * _DAPM_ Controls | 343 | * _DAPM_ Controls |
359 | */ | 344 | */ |
@@ -927,7 +912,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, | |||
927 | { | 912 | { |
928 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 913 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
929 | struct snd_soc_device *socdev = rtd->socdev; | 914 | struct snd_soc_device *socdev = rtd->socdev; |
930 | struct snd_soc_codec *codec = socdev->codec; | 915 | struct snd_soc_codec *codec = socdev->card->codec; |
931 | struct wm8753_priv *wm8753 = codec->private_data; | 916 | struct wm8753_priv *wm8753 = codec->private_data; |
932 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; | 917 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; |
933 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; | 918 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; |
@@ -1161,7 +1146,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, | |||
1161 | { | 1146 | { |
1162 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1147 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1163 | struct snd_soc_device *socdev = rtd->socdev; | 1148 | struct snd_soc_device *socdev = rtd->socdev; |
1164 | struct snd_soc_codec *codec = socdev->codec; | 1149 | struct snd_soc_codec *codec = socdev->card->codec; |
1165 | struct wm8753_priv *wm8753 = codec->private_data; | 1150 | struct wm8753_priv *wm8753 = codec->private_data; |
1166 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; | 1151 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; |
1167 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; | 1152 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; |
@@ -1316,6 +1301,51 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, | |||
1316 | * 3. Voice disabled - HIFI over HIFI | 1301 | * 3. Voice disabled - HIFI over HIFI |
1317 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture | 1302 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture |
1318 | */ | 1303 | */ |
1304 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { | ||
1305 | .hw_params = wm8753_i2s_hw_params, | ||
1306 | .digital_mute = wm8753_mute, | ||
1307 | .set_fmt = wm8753_mode1h_set_dai_fmt, | ||
1308 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1309 | .set_pll = wm8753_set_dai_pll, | ||
1310 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1311 | }; | ||
1312 | |||
1313 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { | ||
1314 | .hw_params = wm8753_pcm_hw_params, | ||
1315 | .digital_mute = wm8753_mute, | ||
1316 | .set_fmt = wm8753_mode1v_set_dai_fmt, | ||
1317 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1318 | .set_pll = wm8753_set_dai_pll, | ||
1319 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1320 | }; | ||
1321 | |||
1322 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { | ||
1323 | .hw_params = wm8753_pcm_hw_params, | ||
1324 | .digital_mute = wm8753_mute, | ||
1325 | .set_fmt = wm8753_mode2_set_dai_fmt, | ||
1326 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1327 | .set_pll = wm8753_set_dai_pll, | ||
1328 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1329 | }; | ||
1330 | |||
1331 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = { | ||
1332 | .hw_params = wm8753_i2s_hw_params, | ||
1333 | .digital_mute = wm8753_mute, | ||
1334 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1335 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1336 | .set_pll = wm8753_set_dai_pll, | ||
1337 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1338 | }; | ||
1339 | |||
1340 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = { | ||
1341 | .hw_params = wm8753_i2s_hw_params, | ||
1342 | .digital_mute = wm8753_mute, | ||
1343 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1344 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1345 | .set_pll = wm8753_set_dai_pll, | ||
1346 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1347 | }; | ||
1348 | |||
1319 | static const struct snd_soc_dai wm8753_all_dai[] = { | 1349 | static const struct snd_soc_dai wm8753_all_dai[] = { |
1320 | /* DAI HiFi mode 1 */ | 1350 | /* DAI HiFi mode 1 */ |
1321 | { .name = "WM8753 HiFi", | 1351 | { .name = "WM8753 HiFi", |
@@ -1332,14 +1362,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1332 | .channels_max = 2, | 1362 | .channels_max = 2, |
1333 | .rates = WM8753_RATES, | 1363 | .rates = WM8753_RATES, |
1334 | .formats = WM8753_FORMATS}, | 1364 | .formats = WM8753_FORMATS}, |
1335 | .ops = { | 1365 | .ops = &wm8753_dai_ops_hifi_mode1, |
1336 | .hw_params = wm8753_i2s_hw_params, | ||
1337 | .digital_mute = wm8753_mute, | ||
1338 | .set_fmt = wm8753_mode1h_set_dai_fmt, | ||
1339 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1340 | .set_pll = wm8753_set_dai_pll, | ||
1341 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1342 | }, | ||
1343 | }, | 1366 | }, |
1344 | /* DAI Voice mode 1 */ | 1367 | /* DAI Voice mode 1 */ |
1345 | { .name = "WM8753 Voice", | 1368 | { .name = "WM8753 Voice", |
@@ -1356,14 +1379,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1356 | .channels_max = 2, | 1379 | .channels_max = 2, |
1357 | .rates = WM8753_RATES, | 1380 | .rates = WM8753_RATES, |
1358 | .formats = WM8753_FORMATS,}, | 1381 | .formats = WM8753_FORMATS,}, |
1359 | .ops = { | 1382 | .ops = &wm8753_dai_ops_voice_mode1, |
1360 | .hw_params = wm8753_pcm_hw_params, | ||
1361 | .digital_mute = wm8753_mute, | ||
1362 | .set_fmt = wm8753_mode1v_set_dai_fmt, | ||
1363 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1364 | .set_pll = wm8753_set_dai_pll, | ||
1365 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1366 | }, | ||
1367 | }, | 1383 | }, |
1368 | /* DAI HiFi mode 2 - dummy */ | 1384 | /* DAI HiFi mode 2 - dummy */ |
1369 | { .name = "WM8753 HiFi", | 1385 | { .name = "WM8753 HiFi", |
@@ -1384,14 +1400,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1384 | .channels_max = 2, | 1400 | .channels_max = 2, |
1385 | .rates = WM8753_RATES, | 1401 | .rates = WM8753_RATES, |
1386 | .formats = WM8753_FORMATS,}, | 1402 | .formats = WM8753_FORMATS,}, |
1387 | .ops = { | 1403 | .ops = &wm8753_dai_ops_voice_mode2, |
1388 | .hw_params = wm8753_pcm_hw_params, | ||
1389 | .digital_mute = wm8753_mute, | ||
1390 | .set_fmt = wm8753_mode2_set_dai_fmt, | ||
1391 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1392 | .set_pll = wm8753_set_dai_pll, | ||
1393 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1394 | }, | ||
1395 | }, | 1404 | }, |
1396 | /* DAI HiFi mode 3 */ | 1405 | /* DAI HiFi mode 3 */ |
1397 | { .name = "WM8753 HiFi", | 1406 | { .name = "WM8753 HiFi", |
@@ -1408,14 +1417,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1408 | .channels_max = 2, | 1417 | .channels_max = 2, |
1409 | .rates = WM8753_RATES, | 1418 | .rates = WM8753_RATES, |
1410 | .formats = WM8753_FORMATS,}, | 1419 | .formats = WM8753_FORMATS,}, |
1411 | .ops = { | 1420 | .ops = &wm8753_dai_ops_hifi_mode3, |
1412 | .hw_params = wm8753_i2s_hw_params, | ||
1413 | .digital_mute = wm8753_mute, | ||
1414 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1415 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1416 | .set_pll = wm8753_set_dai_pll, | ||
1417 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1418 | }, | ||
1419 | }, | 1421 | }, |
1420 | /* DAI Voice mode 3 - dummy */ | 1422 | /* DAI Voice mode 3 - dummy */ |
1421 | { .name = "WM8753 Voice", | 1423 | { .name = "WM8753 Voice", |
@@ -1436,14 +1438,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1436 | .channels_max = 2, | 1438 | .channels_max = 2, |
1437 | .rates = WM8753_RATES, | 1439 | .rates = WM8753_RATES, |
1438 | .formats = WM8753_FORMATS,}, | 1440 | .formats = WM8753_FORMATS,}, |
1439 | .ops = { | 1441 | .ops = &wm8753_dai_ops_hifi_mode4, |
1440 | .hw_params = wm8753_i2s_hw_params, | ||
1441 | .digital_mute = wm8753_mute, | ||
1442 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1443 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1444 | .set_pll = wm8753_set_dai_pll, | ||
1445 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1446 | }, | ||
1447 | }, | 1442 | }, |
1448 | /* DAI Voice mode 4 - dummy */ | 1443 | /* DAI Voice mode 4 - dummy */ |
1449 | { .name = "WM8753 Voice", | 1444 | { .name = "WM8753 Voice", |
@@ -1466,30 +1461,35 @@ static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) | |||
1466 | if (mode < 4) { | 1461 | if (mode < 4) { |
1467 | int playback_active, capture_active, codec_active, pop_wait; | 1462 | int playback_active, capture_active, codec_active, pop_wait; |
1468 | void *private_data; | 1463 | void *private_data; |
1464 | struct list_head list; | ||
1469 | 1465 | ||
1470 | playback_active = wm8753_dai[0].playback.active; | 1466 | playback_active = wm8753_dai[0].playback.active; |
1471 | capture_active = wm8753_dai[0].capture.active; | 1467 | capture_active = wm8753_dai[0].capture.active; |
1472 | codec_active = wm8753_dai[0].active; | 1468 | codec_active = wm8753_dai[0].active; |
1473 | private_data = wm8753_dai[0].private_data; | 1469 | private_data = wm8753_dai[0].private_data; |
1474 | pop_wait = wm8753_dai[0].pop_wait; | 1470 | pop_wait = wm8753_dai[0].pop_wait; |
1471 | list = wm8753_dai[0].list; | ||
1475 | wm8753_dai[0] = wm8753_all_dai[mode << 1]; | 1472 | wm8753_dai[0] = wm8753_all_dai[mode << 1]; |
1476 | wm8753_dai[0].playback.active = playback_active; | 1473 | wm8753_dai[0].playback.active = playback_active; |
1477 | wm8753_dai[0].capture.active = capture_active; | 1474 | wm8753_dai[0].capture.active = capture_active; |
1478 | wm8753_dai[0].active = codec_active; | 1475 | wm8753_dai[0].active = codec_active; |
1479 | wm8753_dai[0].private_data = private_data; | 1476 | wm8753_dai[0].private_data = private_data; |
1480 | wm8753_dai[0].pop_wait = pop_wait; | 1477 | wm8753_dai[0].pop_wait = pop_wait; |
1478 | wm8753_dai[0].list = list; | ||
1481 | 1479 | ||
1482 | playback_active = wm8753_dai[1].playback.active; | 1480 | playback_active = wm8753_dai[1].playback.active; |
1483 | capture_active = wm8753_dai[1].capture.active; | 1481 | capture_active = wm8753_dai[1].capture.active; |
1484 | codec_active = wm8753_dai[1].active; | 1482 | codec_active = wm8753_dai[1].active; |
1485 | private_data = wm8753_dai[1].private_data; | 1483 | private_data = wm8753_dai[1].private_data; |
1486 | pop_wait = wm8753_dai[1].pop_wait; | 1484 | pop_wait = wm8753_dai[1].pop_wait; |
1485 | list = wm8753_dai[1].list; | ||
1487 | wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1]; | 1486 | wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1]; |
1488 | wm8753_dai[1].playback.active = playback_active; | 1487 | wm8753_dai[1].playback.active = playback_active; |
1489 | wm8753_dai[1].capture.active = capture_active; | 1488 | wm8753_dai[1].capture.active = capture_active; |
1490 | wm8753_dai[1].active = codec_active; | 1489 | wm8753_dai[1].active = codec_active; |
1491 | wm8753_dai[1].private_data = private_data; | 1490 | wm8753_dai[1].private_data = private_data; |
1492 | wm8753_dai[1].pop_wait = pop_wait; | 1491 | wm8753_dai[1].pop_wait = pop_wait; |
1492 | wm8753_dai[1].list = list; | ||
1493 | } | 1493 | } |
1494 | wm8753_dai[0].codec = codec; | 1494 | wm8753_dai[0].codec = codec; |
1495 | wm8753_dai[1].codec = codec; | 1495 | wm8753_dai[1].codec = codec; |
@@ -1505,7 +1505,7 @@ static void wm8753_work(struct work_struct *work) | |||
1505 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | 1505 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) |
1506 | { | 1506 | { |
1507 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1507 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1508 | struct snd_soc_codec *codec = socdev->codec; | 1508 | struct snd_soc_codec *codec = socdev->card->codec; |
1509 | 1509 | ||
1510 | /* we only need to suspend if we are a valid card */ | 1510 | /* we only need to suspend if we are a valid card */ |
1511 | if (!codec->card) | 1511 | if (!codec->card) |
@@ -1518,7 +1518,7 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | |||
1518 | static int wm8753_resume(struct platform_device *pdev) | 1518 | static int wm8753_resume(struct platform_device *pdev) |
1519 | { | 1519 | { |
1520 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1520 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1521 | struct snd_soc_codec *codec = socdev->codec; | 1521 | struct snd_soc_codec *codec = socdev->card->codec; |
1522 | int i; | 1522 | int i; |
1523 | u8 data[2]; | 1523 | u8 data[2]; |
1524 | u16 *cache = codec->reg_cache; | 1524 | u16 *cache = codec->reg_cache; |
@@ -1531,6 +1531,11 @@ static int wm8753_resume(struct platform_device *pdev) | |||
1531 | for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { | 1531 | for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { |
1532 | if (i + 1 == WM8753_RESET) | 1532 | if (i + 1 == WM8753_RESET) |
1533 | continue; | 1533 | continue; |
1534 | |||
1535 | /* No point in writing hardware default values back */ | ||
1536 | if (cache[i] == wm8753_reg[i]) | ||
1537 | continue; | ||
1538 | |||
1534 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); | 1539 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); |
1535 | data[1] = cache[i] & 0x00ff; | 1540 | data[1] = cache[i] & 0x00ff; |
1536 | codec->hw_write(codec->control_data, data, 2); | 1541 | codec->hw_write(codec->control_data, data, 2); |
@@ -1549,44 +1554,129 @@ static int wm8753_resume(struct platform_device *pdev) | |||
1549 | return 0; | 1554 | return 0; |
1550 | } | 1555 | } |
1551 | 1556 | ||
1557 | static struct snd_soc_codec *wm8753_codec; | ||
1558 | |||
1559 | static int wm8753_probe(struct platform_device *pdev) | ||
1560 | { | ||
1561 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1562 | struct snd_soc_codec *codec; | ||
1563 | int ret = 0; | ||
1564 | |||
1565 | if (!wm8753_codec) { | ||
1566 | dev_err(&pdev->dev, "WM8753 codec not yet registered\n"); | ||
1567 | return -EINVAL; | ||
1568 | } | ||
1569 | |||
1570 | socdev->card->codec = wm8753_codec; | ||
1571 | codec = wm8753_codec; | ||
1572 | |||
1573 | wm8753_set_dai_mode(codec, 0); | ||
1574 | |||
1575 | /* register pcms */ | ||
1576 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1577 | if (ret < 0) { | ||
1578 | printk(KERN_ERR "wm8753: failed to create pcms\n"); | ||
1579 | goto pcm_err; | ||
1580 | } | ||
1581 | |||
1582 | snd_soc_add_controls(codec, wm8753_snd_controls, | ||
1583 | ARRAY_SIZE(wm8753_snd_controls)); | ||
1584 | wm8753_add_widgets(codec); | ||
1585 | ret = snd_soc_init_card(socdev); | ||
1586 | if (ret < 0) { | ||
1587 | printk(KERN_ERR "wm8753: failed to register card\n"); | ||
1588 | goto card_err; | ||
1589 | } | ||
1590 | |||
1591 | return 0; | ||
1592 | |||
1593 | card_err: | ||
1594 | snd_soc_free_pcms(socdev); | ||
1595 | snd_soc_dapm_free(socdev); | ||
1596 | |||
1597 | pcm_err: | ||
1598 | return ret; | ||
1599 | } | ||
1600 | |||
1552 | /* | 1601 | /* |
1553 | * initialise the WM8753 driver | 1602 | * This function forces any delayed work to be queued and run. |
1554 | * register the mixer and dsp interfaces with the kernel | ||
1555 | */ | 1603 | */ |
1556 | static int wm8753_init(struct snd_soc_device *socdev) | 1604 | static int run_delayed_work(struct delayed_work *dwork) |
1605 | { | ||
1606 | int ret; | ||
1607 | |||
1608 | /* cancel any work waiting to be queued. */ | ||
1609 | ret = cancel_delayed_work(dwork); | ||
1610 | |||
1611 | /* if there was any work waiting then we run it now and | ||
1612 | * wait for it's completion */ | ||
1613 | if (ret) { | ||
1614 | schedule_delayed_work(dwork, 0); | ||
1615 | flush_scheduled_work(); | ||
1616 | } | ||
1617 | return ret; | ||
1618 | } | ||
1619 | |||
1620 | /* power down chip */ | ||
1621 | static int wm8753_remove(struct platform_device *pdev) | ||
1557 | { | 1622 | { |
1558 | struct snd_soc_codec *codec = socdev->codec; | 1623 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1559 | int reg, ret = 0; | 1624 | |
1625 | snd_soc_free_pcms(socdev); | ||
1626 | snd_soc_dapm_free(socdev); | ||
1627 | |||
1628 | return 0; | ||
1629 | } | ||
1630 | |||
1631 | struct snd_soc_codec_device soc_codec_dev_wm8753 = { | ||
1632 | .probe = wm8753_probe, | ||
1633 | .remove = wm8753_remove, | ||
1634 | .suspend = wm8753_suspend, | ||
1635 | .resume = wm8753_resume, | ||
1636 | }; | ||
1637 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); | ||
1638 | |||
1639 | static int wm8753_register(struct wm8753_priv *wm8753) | ||
1640 | { | ||
1641 | int ret, i; | ||
1642 | struct snd_soc_codec *codec = &wm8753->codec; | ||
1643 | u16 reg; | ||
1644 | |||
1645 | if (wm8753_codec) { | ||
1646 | dev_err(codec->dev, "Multiple WM8753 devices not supported\n"); | ||
1647 | ret = -EINVAL; | ||
1648 | goto err; | ||
1649 | } | ||
1650 | |||
1651 | mutex_init(&codec->mutex); | ||
1652 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1653 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1560 | 1654 | ||
1561 | codec->name = "WM8753"; | 1655 | codec->name = "WM8753"; |
1562 | codec->owner = THIS_MODULE; | 1656 | codec->owner = THIS_MODULE; |
1563 | codec->read = wm8753_read_reg_cache; | 1657 | codec->read = wm8753_read_reg_cache; |
1564 | codec->write = wm8753_write; | 1658 | codec->write = wm8753_write; |
1659 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
1565 | codec->set_bias_level = wm8753_set_bias_level; | 1660 | codec->set_bias_level = wm8753_set_bias_level; |
1566 | codec->dai = wm8753_dai; | 1661 | codec->dai = wm8753_dai; |
1567 | codec->num_dai = 2; | 1662 | codec->num_dai = 2; |
1568 | codec->reg_cache_size = ARRAY_SIZE(wm8753_reg); | 1663 | codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache); |
1569 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); | 1664 | codec->reg_cache = &wm8753->reg_cache; |
1570 | 1665 | codec->private_data = wm8753; | |
1571 | if (codec->reg_cache == NULL) | ||
1572 | return -ENOMEM; | ||
1573 | |||
1574 | wm8753_set_dai_mode(codec, 0); | ||
1575 | 1666 | ||
1576 | wm8753_reset(codec); | 1667 | memcpy(codec->reg_cache, wm8753_reg, sizeof(codec->reg_cache)); |
1668 | INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); | ||
1577 | 1669 | ||
1578 | /* register pcms */ | 1670 | ret = wm8753_reset(codec); |
1579 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1580 | if (ret < 0) { | 1671 | if (ret < 0) { |
1581 | printk(KERN_ERR "wm8753: failed to create pcms\n"); | 1672 | dev_err(codec->dev, "Failed to issue reset\n"); |
1582 | goto pcm_err; | 1673 | goto err; |
1583 | } | 1674 | } |
1584 | 1675 | ||
1585 | /* charge output caps */ | 1676 | /* charge output caps */ |
1586 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 1677 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1587 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
1588 | schedule_delayed_work(&codec->delayed_work, | 1678 | schedule_delayed_work(&codec->delayed_work, |
1589 | msecs_to_jiffies(caps_charge)); | 1679 | msecs_to_jiffies(caps_charge)); |
1590 | 1680 | ||
1591 | /* set the update bits */ | 1681 | /* set the update bits */ |
1592 | reg = wm8753_read_reg_cache(codec, WM8753_LDAC); | 1682 | reg = wm8753_read_reg_cache(codec, WM8753_LDAC); |
@@ -1610,59 +1700,70 @@ static int wm8753_init(struct snd_soc_device *socdev) | |||
1610 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); | 1700 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); |
1611 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); | 1701 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); |
1612 | 1702 | ||
1613 | wm8753_add_controls(codec); | 1703 | wm8753_codec = codec; |
1614 | wm8753_add_widgets(codec); | 1704 | |
1615 | ret = snd_soc_init_card(socdev); | 1705 | for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++) |
1616 | if (ret < 0) { | 1706 | wm8753_dai[i].dev = codec->dev; |
1617 | printk(KERN_ERR "wm8753: failed to register card\n"); | 1707 | |
1618 | goto card_err; | 1708 | ret = snd_soc_register_codec(codec); |
1709 | if (ret != 0) { | ||
1710 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
1711 | goto err; | ||
1619 | } | 1712 | } |
1620 | 1713 | ||
1621 | return ret; | 1714 | ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai)); |
1715 | if (ret != 0) { | ||
1716 | dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); | ||
1717 | goto err_codec; | ||
1718 | } | ||
1622 | 1719 | ||
1623 | card_err: | 1720 | return 0; |
1624 | snd_soc_free_pcms(socdev); | 1721 | |
1625 | snd_soc_dapm_free(socdev); | 1722 | err_codec: |
1626 | pcm_err: | 1723 | run_delayed_work(&codec->delayed_work); |
1627 | kfree(codec->reg_cache); | 1724 | snd_soc_unregister_codec(codec); |
1725 | err: | ||
1726 | kfree(wm8753); | ||
1628 | return ret; | 1727 | return ret; |
1629 | } | 1728 | } |
1630 | 1729 | ||
1631 | /* If the i2c layer weren't so broken, we could pass this kind of data | 1730 | static void wm8753_unregister(struct wm8753_priv *wm8753) |
1632 | around */ | 1731 | { |
1633 | static struct snd_soc_device *wm8753_socdev; | 1732 | wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF); |
1733 | run_delayed_work(&wm8753->codec.delayed_work); | ||
1734 | snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai)); | ||
1735 | snd_soc_unregister_codec(&wm8753->codec); | ||
1736 | kfree(wm8753); | ||
1737 | wm8753_codec = NULL; | ||
1738 | } | ||
1634 | 1739 | ||
1635 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1740 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1636 | 1741 | ||
1637 | /* | ||
1638 | * WM8753 2 wire address is determined by GPIO5 | ||
1639 | * state during powerup. | ||
1640 | * low = 0x1a | ||
1641 | * high = 0x1b | ||
1642 | */ | ||
1643 | |||
1644 | static int wm8753_i2c_probe(struct i2c_client *i2c, | 1742 | static int wm8753_i2c_probe(struct i2c_client *i2c, |
1645 | const struct i2c_device_id *id) | 1743 | const struct i2c_device_id *id) |
1646 | { | 1744 | { |
1647 | struct snd_soc_device *socdev = wm8753_socdev; | 1745 | struct snd_soc_codec *codec; |
1648 | struct snd_soc_codec *codec = socdev->codec; | 1746 | struct wm8753_priv *wm8753; |
1649 | int ret; | ||
1650 | 1747 | ||
1651 | i2c_set_clientdata(i2c, codec); | 1748 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); |
1652 | codec->control_data = i2c; | 1749 | if (wm8753 == NULL) |
1750 | return -ENOMEM; | ||
1653 | 1751 | ||
1654 | ret = wm8753_init(socdev); | 1752 | codec = &wm8753->codec; |
1655 | if (ret < 0) | 1753 | codec->hw_write = (hw_write_t)i2c_master_send; |
1656 | pr_err("failed to initialise WM8753\n"); | 1754 | codec->control_data = i2c; |
1755 | i2c_set_clientdata(i2c, wm8753); | ||
1657 | 1756 | ||
1658 | return ret; | 1757 | codec->dev = &i2c->dev; |
1758 | |||
1759 | return wm8753_register(wm8753); | ||
1659 | } | 1760 | } |
1660 | 1761 | ||
1661 | static int wm8753_i2c_remove(struct i2c_client *client) | 1762 | static int wm8753_i2c_remove(struct i2c_client *client) |
1662 | { | 1763 | { |
1663 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1764 | struct wm8753_priv *wm8753 = i2c_get_clientdata(client); |
1664 | kfree(codec->reg_cache); | 1765 | wm8753_unregister(wm8753); |
1665 | return 0; | 1766 | return 0; |
1666 | } | 1767 | } |
1667 | 1768 | ||
1668 | static const struct i2c_device_id wm8753_i2c_id[] = { | 1769 | static const struct i2c_device_id wm8753_i2c_id[] = { |
@@ -1673,86 +1774,16 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); | |||
1673 | 1774 | ||
1674 | static struct i2c_driver wm8753_i2c_driver = { | 1775 | static struct i2c_driver wm8753_i2c_driver = { |
1675 | .driver = { | 1776 | .driver = { |
1676 | .name = "WM8753 I2C Codec", | 1777 | .name = "wm8753", |
1677 | .owner = THIS_MODULE, | 1778 | .owner = THIS_MODULE, |
1678 | }, | 1779 | }, |
1679 | .probe = wm8753_i2c_probe, | 1780 | .probe = wm8753_i2c_probe, |
1680 | .remove = wm8753_i2c_remove, | 1781 | .remove = wm8753_i2c_remove, |
1681 | .id_table = wm8753_i2c_id, | 1782 | .id_table = wm8753_i2c_id, |
1682 | }; | 1783 | }; |
1683 | |||
1684 | static int wm8753_add_i2c_device(struct platform_device *pdev, | ||
1685 | const struct wm8753_setup_data *setup) | ||
1686 | { | ||
1687 | struct i2c_board_info info; | ||
1688 | struct i2c_adapter *adapter; | ||
1689 | struct i2c_client *client; | ||
1690 | int ret; | ||
1691 | |||
1692 | ret = i2c_add_driver(&wm8753_i2c_driver); | ||
1693 | if (ret != 0) { | ||
1694 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1695 | return ret; | ||
1696 | } | ||
1697 | |||
1698 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1699 | info.addr = setup->i2c_address; | ||
1700 | strlcpy(info.type, "wm8753", I2C_NAME_SIZE); | ||
1701 | |||
1702 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1703 | if (!adapter) { | ||
1704 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1705 | setup->i2c_bus); | ||
1706 | goto err_driver; | ||
1707 | } | ||
1708 | |||
1709 | client = i2c_new_device(adapter, &info); | ||
1710 | i2c_put_adapter(adapter); | ||
1711 | if (!client) { | ||
1712 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1713 | (unsigned int)info.addr); | ||
1714 | goto err_driver; | ||
1715 | } | ||
1716 | |||
1717 | return 0; | ||
1718 | |||
1719 | err_driver: | ||
1720 | i2c_del_driver(&wm8753_i2c_driver); | ||
1721 | return -ENODEV; | ||
1722 | } | ||
1723 | #endif | 1784 | #endif |
1724 | 1785 | ||
1725 | #if defined(CONFIG_SPI_MASTER) | 1786 | #if defined(CONFIG_SPI_MASTER) |
1726 | static int __devinit wm8753_spi_probe(struct spi_device *spi) | ||
1727 | { | ||
1728 | struct snd_soc_device *socdev = wm8753_socdev; | ||
1729 | struct snd_soc_codec *codec = socdev->codec; | ||
1730 | int ret; | ||
1731 | |||
1732 | codec->control_data = spi; | ||
1733 | |||
1734 | ret = wm8753_init(socdev); | ||
1735 | if (ret < 0) | ||
1736 | dev_err(&spi->dev, "failed to initialise WM8753\n"); | ||
1737 | |||
1738 | return ret; | ||
1739 | } | ||
1740 | |||
1741 | static int __devexit wm8753_spi_remove(struct spi_device *spi) | ||
1742 | { | ||
1743 | return 0; | ||
1744 | } | ||
1745 | |||
1746 | static struct spi_driver wm8753_spi_driver = { | ||
1747 | .driver = { | ||
1748 | .name = "wm8753", | ||
1749 | .bus = &spi_bus_type, | ||
1750 | .owner = THIS_MODULE, | ||
1751 | }, | ||
1752 | .probe = wm8753_spi_probe, | ||
1753 | .remove = __devexit_p(wm8753_spi_remove), | ||
1754 | }; | ||
1755 | |||
1756 | static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) | 1787 | static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) |
1757 | { | 1788 | { |
1758 | struct spi_transfer t; | 1789 | struct spi_transfer t; |
@@ -1776,120 +1807,69 @@ static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) | |||
1776 | 1807 | ||
1777 | return len; | 1808 | return len; |
1778 | } | 1809 | } |
1779 | #endif | ||
1780 | 1810 | ||
1781 | 1811 | static int __devinit wm8753_spi_probe(struct spi_device *spi) | |
1782 | static int wm8753_probe(struct platform_device *pdev) | ||
1783 | { | 1812 | { |
1784 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1785 | struct wm8753_setup_data *setup; | ||
1786 | struct snd_soc_codec *codec; | 1813 | struct snd_soc_codec *codec; |
1787 | struct wm8753_priv *wm8753; | 1814 | struct wm8753_priv *wm8753; |
1788 | int ret = 0; | ||
1789 | |||
1790 | pr_info("WM8753 Audio Codec %s", WM8753_VERSION); | ||
1791 | |||
1792 | setup = socdev->codec_data; | ||
1793 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1794 | if (codec == NULL) | ||
1795 | return -ENOMEM; | ||
1796 | 1815 | ||
1797 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); | 1816 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); |
1798 | if (wm8753 == NULL) { | 1817 | if (wm8753 == NULL) |
1799 | kfree(codec); | ||
1800 | return -ENOMEM; | 1818 | return -ENOMEM; |
1801 | } | ||
1802 | 1819 | ||
1803 | codec->private_data = wm8753; | 1820 | codec = &wm8753->codec; |
1804 | socdev->codec = codec; | 1821 | codec->control_data = spi; |
1805 | mutex_init(&codec->mutex); | 1822 | codec->hw_write = (hw_write_t)wm8753_spi_write; |
1806 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1823 | codec->dev = &spi->dev; |
1807 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1808 | wm8753_socdev = socdev; | ||
1809 | INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); | ||
1810 | 1824 | ||
1811 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1825 | spi->dev.driver_data = wm8753; |
1812 | if (setup->i2c_address) { | ||
1813 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1814 | ret = wm8753_add_i2c_device(pdev, setup); | ||
1815 | } | ||
1816 | #endif | ||
1817 | #if defined(CONFIG_SPI_MASTER) | ||
1818 | if (setup->spi) { | ||
1819 | codec->hw_write = (hw_write_t)wm8753_spi_write; | ||
1820 | ret = spi_register_driver(&wm8753_spi_driver); | ||
1821 | if (ret != 0) | ||
1822 | printk(KERN_ERR "can't add spi driver"); | ||
1823 | } | ||
1824 | #endif | ||
1825 | 1826 | ||
1826 | if (ret != 0) { | 1827 | return wm8753_register(wm8753); |
1827 | kfree(codec->private_data); | ||
1828 | kfree(codec); | ||
1829 | } | ||
1830 | return ret; | ||
1831 | } | 1828 | } |
1832 | 1829 | ||
1833 | /* | 1830 | static int __devexit wm8753_spi_remove(struct spi_device *spi) |
1834 | * This function forces any delayed work to be queued and run. | ||
1835 | */ | ||
1836 | static int run_delayed_work(struct delayed_work *dwork) | ||
1837 | { | 1831 | { |
1838 | int ret; | 1832 | struct wm8753_priv *wm8753 = spi->dev.driver_data; |
1839 | 1833 | wm8753_unregister(wm8753); | |
1840 | /* cancel any work waiting to be queued. */ | 1834 | return 0; |
1841 | ret = cancel_delayed_work(dwork); | ||
1842 | |||
1843 | /* if there was any work waiting then we run it now and | ||
1844 | * wait for it's completion */ | ||
1845 | if (ret) { | ||
1846 | schedule_delayed_work(dwork, 0); | ||
1847 | flush_scheduled_work(); | ||
1848 | } | ||
1849 | return ret; | ||
1850 | } | 1835 | } |
1851 | 1836 | ||
1852 | /* power down chip */ | 1837 | static struct spi_driver wm8753_spi_driver = { |
1853 | static int wm8753_remove(struct platform_device *pdev) | 1838 | .driver = { |
1854 | { | 1839 | .name = "wm8753", |
1855 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1840 | .bus = &spi_bus_type, |
1856 | struct snd_soc_codec *codec = socdev->codec; | 1841 | .owner = THIS_MODULE, |
1842 | }, | ||
1843 | .probe = wm8753_spi_probe, | ||
1844 | .remove = __devexit_p(wm8753_spi_remove), | ||
1845 | }; | ||
1846 | #endif | ||
1857 | 1847 | ||
1858 | if (codec->control_data) | 1848 | static int __init wm8753_modinit(void) |
1859 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1849 | { |
1860 | run_delayed_work(&codec->delayed_work); | 1850 | int ret; |
1861 | snd_soc_free_pcms(socdev); | ||
1862 | snd_soc_dapm_free(socdev); | ||
1863 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1851 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1864 | i2c_unregister_device(codec->control_data); | 1852 | ret = i2c_add_driver(&wm8753_i2c_driver); |
1865 | i2c_del_driver(&wm8753_i2c_driver); | 1853 | if (ret != 0) |
1854 | pr_err("Failed to register WM8753 I2C driver: %d\n", ret); | ||
1866 | #endif | 1855 | #endif |
1867 | #if defined(CONFIG_SPI_MASTER) | 1856 | #if defined(CONFIG_SPI_MASTER) |
1868 | spi_unregister_driver(&wm8753_spi_driver); | 1857 | ret = spi_register_driver(&wm8753_spi_driver); |
1858 | if (ret != 0) | ||
1859 | pr_err("Failed to register WM8753 SPI driver: %d\n", ret); | ||
1869 | #endif | 1860 | #endif |
1870 | kfree(codec->private_data); | ||
1871 | kfree(codec); | ||
1872 | |||
1873 | return 0; | 1861 | return 0; |
1874 | } | 1862 | } |
1875 | |||
1876 | struct snd_soc_codec_device soc_codec_dev_wm8753 = { | ||
1877 | .probe = wm8753_probe, | ||
1878 | .remove = wm8753_remove, | ||
1879 | .suspend = wm8753_suspend, | ||
1880 | .resume = wm8753_resume, | ||
1881 | }; | ||
1882 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); | ||
1883 | |||
1884 | static int __init wm8753_modinit(void) | ||
1885 | { | ||
1886 | return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); | ||
1887 | } | ||
1888 | module_init(wm8753_modinit); | 1863 | module_init(wm8753_modinit); |
1889 | 1864 | ||
1890 | static void __exit wm8753_exit(void) | 1865 | static void __exit wm8753_exit(void) |
1891 | { | 1866 | { |
1892 | snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); | 1867 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1868 | i2c_del_driver(&wm8753_i2c_driver); | ||
1869 | #endif | ||
1870 | #if defined(CONFIG_SPI_MASTER) | ||
1871 | spi_unregister_driver(&wm8753_spi_driver); | ||
1872 | #endif | ||
1893 | } | 1873 | } |
1894 | module_exit(wm8753_exit); | 1874 | module_exit(wm8753_exit); |
1895 | 1875 | ||
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index f55704ce931b..57b2ba244040 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h | |||
@@ -77,12 +77,6 @@ | |||
77 | #define WM8753_BIASCTL 0x3d | 77 | #define WM8753_BIASCTL 0x3d |
78 | #define WM8753_ADCTL2 0x3f | 78 | #define WM8753_ADCTL2 0x3f |
79 | 79 | ||
80 | struct wm8753_setup_data { | ||
81 | int spi; | ||
82 | int i2c_bus; | ||
83 | unsigned short i2c_address; | ||
84 | }; | ||
85 | |||
86 | #define WM8753_PLL1 0 | 80 | #define WM8753_PLL1 0 |
87 | #define WM8753_PLL2 1 | 81 | #define WM8753_PLL2 1 |
88 | 82 | ||
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 6767de10ded0..46c5ea1ff921 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -517,22 +517,6 @@ SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1, | |||
517 | 517 | ||
518 | }; | 518 | }; |
519 | 519 | ||
520 | /* add non dapm controls */ | ||
521 | static int wm8900_add_controls(struct snd_soc_codec *codec) | ||
522 | { | ||
523 | int err, i; | ||
524 | |||
525 | for (i = 0; i < ARRAY_SIZE(wm8900_snd_controls); i++) { | ||
526 | err = snd_ctl_add(codec->card, | ||
527 | snd_soc_cnew(&wm8900_snd_controls[i], | ||
528 | codec, NULL)); | ||
529 | if (err < 0) | ||
530 | return err; | ||
531 | } | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static const struct snd_kcontrol_new wm8900_dapm_loutput2_control = | 520 | static const struct snd_kcontrol_new wm8900_dapm_loutput2_control = |
537 | SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0); | 521 | SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0); |
538 | 522 | ||
@@ -736,7 +720,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream, | |||
736 | { | 720 | { |
737 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 721 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
738 | struct snd_soc_device *socdev = rtd->socdev; | 722 | struct snd_soc_device *socdev = rtd->socdev; |
739 | struct snd_soc_codec *codec = socdev->codec; | 723 | struct snd_soc_codec *codec = socdev->card->codec; |
740 | u16 reg; | 724 | u16 reg; |
741 | 725 | ||
742 | reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60; | 726 | reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60; |
@@ -1104,6 +1088,14 @@ static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute) | |||
1104 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | 1088 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ |
1105 | SNDRV_PCM_FORMAT_S24_LE) | 1089 | SNDRV_PCM_FORMAT_S24_LE) |
1106 | 1090 | ||
1091 | static struct snd_soc_dai_ops wm8900_dai_ops = { | ||
1092 | .hw_params = wm8900_hw_params, | ||
1093 | .set_clkdiv = wm8900_set_dai_clkdiv, | ||
1094 | .set_pll = wm8900_set_dai_pll, | ||
1095 | .set_fmt = wm8900_set_dai_fmt, | ||
1096 | .digital_mute = wm8900_digital_mute, | ||
1097 | }; | ||
1098 | |||
1107 | struct snd_soc_dai wm8900_dai = { | 1099 | struct snd_soc_dai wm8900_dai = { |
1108 | .name = "WM8900 HiFi", | 1100 | .name = "WM8900 HiFi", |
1109 | .playback = { | 1101 | .playback = { |
@@ -1120,13 +1112,7 @@ struct snd_soc_dai wm8900_dai = { | |||
1120 | .rates = WM8900_RATES, | 1112 | .rates = WM8900_RATES, |
1121 | .formats = WM8900_PCM_FORMATS, | 1113 | .formats = WM8900_PCM_FORMATS, |
1122 | }, | 1114 | }, |
1123 | .ops = { | 1115 | .ops = &wm8900_dai_ops, |
1124 | .hw_params = wm8900_hw_params, | ||
1125 | .set_clkdiv = wm8900_set_dai_clkdiv, | ||
1126 | .set_pll = wm8900_set_dai_pll, | ||
1127 | .set_fmt = wm8900_set_dai_fmt, | ||
1128 | .digital_mute = wm8900_digital_mute, | ||
1129 | }, | ||
1130 | }; | 1116 | }; |
1131 | EXPORT_SYMBOL_GPL(wm8900_dai); | 1117 | EXPORT_SYMBOL_GPL(wm8900_dai); |
1132 | 1118 | ||
@@ -1226,7 +1212,7 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, | |||
1226 | static int wm8900_suspend(struct platform_device *pdev, pm_message_t state) | 1212 | static int wm8900_suspend(struct platform_device *pdev, pm_message_t state) |
1227 | { | 1213 | { |
1228 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1214 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1229 | struct snd_soc_codec *codec = socdev->codec; | 1215 | struct snd_soc_codec *codec = socdev->card->codec; |
1230 | struct wm8900_priv *wm8900 = codec->private_data; | 1216 | struct wm8900_priv *wm8900 = codec->private_data; |
1231 | int fll_out = wm8900->fll_out; | 1217 | int fll_out = wm8900->fll_out; |
1232 | int fll_in = wm8900->fll_in; | 1218 | int fll_in = wm8900->fll_in; |
@@ -1250,7 +1236,7 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state) | |||
1250 | static int wm8900_resume(struct platform_device *pdev) | 1236 | static int wm8900_resume(struct platform_device *pdev) |
1251 | { | 1237 | { |
1252 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1238 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1253 | struct snd_soc_codec *codec = socdev->codec; | 1239 | struct snd_soc_codec *codec = socdev->card->codec; |
1254 | struct wm8900_priv *wm8900 = codec->private_data; | 1240 | struct wm8900_priv *wm8900 = codec->private_data; |
1255 | u16 *cache; | 1241 | u16 *cache; |
1256 | int i, ret; | 1242 | int i, ret; |
@@ -1288,8 +1274,8 @@ static int wm8900_resume(struct platform_device *pdev) | |||
1288 | 1274 | ||
1289 | static struct snd_soc_codec *wm8900_codec; | 1275 | static struct snd_soc_codec *wm8900_codec; |
1290 | 1276 | ||
1291 | static int wm8900_i2c_probe(struct i2c_client *i2c, | 1277 | static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, |
1292 | const struct i2c_device_id *id) | 1278 | const struct i2c_device_id *id) |
1293 | { | 1279 | { |
1294 | struct wm8900_priv *wm8900; | 1280 | struct wm8900_priv *wm8900; |
1295 | struct snd_soc_codec *codec; | 1281 | struct snd_soc_codec *codec; |
@@ -1388,7 +1374,7 @@ err: | |||
1388 | return ret; | 1374 | return ret; |
1389 | } | 1375 | } |
1390 | 1376 | ||
1391 | static int wm8900_i2c_remove(struct i2c_client *client) | 1377 | static __devexit int wm8900_i2c_remove(struct i2c_client *client) |
1392 | { | 1378 | { |
1393 | snd_soc_unregister_dai(&wm8900_dai); | 1379 | snd_soc_unregister_dai(&wm8900_dai); |
1394 | snd_soc_unregister_codec(wm8900_codec); | 1380 | snd_soc_unregister_codec(wm8900_codec); |
@@ -1414,7 +1400,7 @@ static struct i2c_driver wm8900_i2c_driver = { | |||
1414 | .owner = THIS_MODULE, | 1400 | .owner = THIS_MODULE, |
1415 | }, | 1401 | }, |
1416 | .probe = wm8900_i2c_probe, | 1402 | .probe = wm8900_i2c_probe, |
1417 | .remove = wm8900_i2c_remove, | 1403 | .remove = __devexit_p(wm8900_i2c_remove), |
1418 | .id_table = wm8900_i2c_id, | 1404 | .id_table = wm8900_i2c_id, |
1419 | }; | 1405 | }; |
1420 | 1406 | ||
@@ -1430,7 +1416,7 @@ static int wm8900_probe(struct platform_device *pdev) | |||
1430 | } | 1416 | } |
1431 | 1417 | ||
1432 | codec = wm8900_codec; | 1418 | codec = wm8900_codec; |
1433 | socdev->codec = codec; | 1419 | socdev->card->codec = codec; |
1434 | 1420 | ||
1435 | /* Register pcms */ | 1421 | /* Register pcms */ |
1436 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 1422 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
@@ -1439,7 +1425,8 @@ static int wm8900_probe(struct platform_device *pdev) | |||
1439 | goto pcm_err; | 1425 | goto pcm_err; |
1440 | } | 1426 | } |
1441 | 1427 | ||
1442 | wm8900_add_controls(codec); | 1428 | snd_soc_add_controls(codec, wm8900_snd_controls, |
1429 | ARRAY_SIZE(wm8900_snd_controls)); | ||
1443 | wm8900_add_widgets(codec); | 1430 | wm8900_add_widgets(codec); |
1444 | 1431 | ||
1445 | ret = snd_soc_init_card(socdev); | 1432 | ret = snd_soc_init_card(socdev); |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index bde74546db4a..8cf571f1a803 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -744,21 +744,6 @@ SOC_DOUBLE_R_TLV("Speaker Volume", | |||
744 | 0, 63, 0, out_tlv), | 744 | 0, 63, 0, out_tlv), |
745 | }; | 745 | }; |
746 | 746 | ||
747 | static int wm8903_add_controls(struct snd_soc_codec *codec) | ||
748 | { | ||
749 | int err, i; | ||
750 | |||
751 | for (i = 0; i < ARRAY_SIZE(wm8903_snd_controls); i++) { | ||
752 | err = snd_ctl_add(codec->card, | ||
753 | snd_soc_cnew(&wm8903_snd_controls[i], | ||
754 | codec, NULL)); | ||
755 | if (err < 0) | ||
756 | return err; | ||
757 | } | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static const struct snd_kcontrol_new linput_mode_mux = | 747 | static const struct snd_kcontrol_new linput_mode_mux = |
763 | SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum); | 748 | SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum); |
764 | 749 | ||
@@ -1276,7 +1261,7 @@ static int wm8903_startup(struct snd_pcm_substream *substream, | |||
1276 | { | 1261 | { |
1277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1262 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1278 | struct snd_soc_device *socdev = rtd->socdev; | 1263 | struct snd_soc_device *socdev = rtd->socdev; |
1279 | struct snd_soc_codec *codec = socdev->codec; | 1264 | struct snd_soc_codec *codec = socdev->card->codec; |
1280 | struct wm8903_priv *wm8903 = codec->private_data; | 1265 | struct wm8903_priv *wm8903 = codec->private_data; |
1281 | struct i2c_client *i2c = codec->control_data; | 1266 | struct i2c_client *i2c = codec->control_data; |
1282 | struct snd_pcm_runtime *master_runtime; | 1267 | struct snd_pcm_runtime *master_runtime; |
@@ -1318,7 +1303,7 @@ static void wm8903_shutdown(struct snd_pcm_substream *substream, | |||
1318 | { | 1303 | { |
1319 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1304 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1320 | struct snd_soc_device *socdev = rtd->socdev; | 1305 | struct snd_soc_device *socdev = rtd->socdev; |
1321 | struct snd_soc_codec *codec = socdev->codec; | 1306 | struct snd_soc_codec *codec = socdev->card->codec; |
1322 | struct wm8903_priv *wm8903 = codec->private_data; | 1307 | struct wm8903_priv *wm8903 = codec->private_data; |
1323 | 1308 | ||
1324 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 1309 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
@@ -1338,7 +1323,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, | |||
1338 | { | 1323 | { |
1339 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1324 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1340 | struct snd_soc_device *socdev = rtd->socdev; | 1325 | struct snd_soc_device *socdev = rtd->socdev; |
1341 | struct snd_soc_codec *codec = socdev->codec; | 1326 | struct snd_soc_codec *codec = socdev->card->codec; |
1342 | struct wm8903_priv *wm8903 = codec->private_data; | 1327 | struct wm8903_priv *wm8903 = codec->private_data; |
1343 | struct i2c_client *i2c = codec->control_data; | 1328 | struct i2c_client *i2c = codec->control_data; |
1344 | int fs = params_rate(params); | 1329 | int fs = params_rate(params); |
@@ -1512,6 +1497,15 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, | |||
1512 | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1497 | SNDRV_PCM_FMTBIT_S20_3LE |\ |
1513 | SNDRV_PCM_FMTBIT_S24_LE) | 1498 | SNDRV_PCM_FMTBIT_S24_LE) |
1514 | 1499 | ||
1500 | static struct snd_soc_dai_ops wm8903_dai_ops = { | ||
1501 | .startup = wm8903_startup, | ||
1502 | .shutdown = wm8903_shutdown, | ||
1503 | .hw_params = wm8903_hw_params, | ||
1504 | .digital_mute = wm8903_digital_mute, | ||
1505 | .set_fmt = wm8903_set_dai_fmt, | ||
1506 | .set_sysclk = wm8903_set_dai_sysclk, | ||
1507 | }; | ||
1508 | |||
1515 | struct snd_soc_dai wm8903_dai = { | 1509 | struct snd_soc_dai wm8903_dai = { |
1516 | .name = "WM8903", | 1510 | .name = "WM8903", |
1517 | .playback = { | 1511 | .playback = { |
@@ -1528,21 +1522,14 @@ struct snd_soc_dai wm8903_dai = { | |||
1528 | .rates = WM8903_CAPTURE_RATES, | 1522 | .rates = WM8903_CAPTURE_RATES, |
1529 | .formats = WM8903_FORMATS, | 1523 | .formats = WM8903_FORMATS, |
1530 | }, | 1524 | }, |
1531 | .ops = { | 1525 | .ops = &wm8903_dai_ops, |
1532 | .startup = wm8903_startup, | ||
1533 | .shutdown = wm8903_shutdown, | ||
1534 | .hw_params = wm8903_hw_params, | ||
1535 | .digital_mute = wm8903_digital_mute, | ||
1536 | .set_fmt = wm8903_set_dai_fmt, | ||
1537 | .set_sysclk = wm8903_set_dai_sysclk | ||
1538 | } | ||
1539 | }; | 1526 | }; |
1540 | EXPORT_SYMBOL_GPL(wm8903_dai); | 1527 | EXPORT_SYMBOL_GPL(wm8903_dai); |
1541 | 1528 | ||
1542 | static int wm8903_suspend(struct platform_device *pdev, pm_message_t state) | 1529 | static int wm8903_suspend(struct platform_device *pdev, pm_message_t state) |
1543 | { | 1530 | { |
1544 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1531 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1545 | struct snd_soc_codec *codec = socdev->codec; | 1532 | struct snd_soc_codec *codec = socdev->card->codec; |
1546 | 1533 | ||
1547 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1534 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1548 | 1535 | ||
@@ -1552,7 +1539,7 @@ static int wm8903_suspend(struct platform_device *pdev, pm_message_t state) | |||
1552 | static int wm8903_resume(struct platform_device *pdev) | 1539 | static int wm8903_resume(struct platform_device *pdev) |
1553 | { | 1540 | { |
1554 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1541 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1555 | struct snd_soc_codec *codec = socdev->codec; | 1542 | struct snd_soc_codec *codec = socdev->card->codec; |
1556 | struct i2c_client *i2c = codec->control_data; | 1543 | struct i2c_client *i2c = codec->control_data; |
1557 | int i; | 1544 | int i; |
1558 | u16 *reg_cache = codec->reg_cache; | 1545 | u16 *reg_cache = codec->reg_cache; |
@@ -1577,8 +1564,8 @@ static int wm8903_resume(struct platform_device *pdev) | |||
1577 | 1564 | ||
1578 | static struct snd_soc_codec *wm8903_codec; | 1565 | static struct snd_soc_codec *wm8903_codec; |
1579 | 1566 | ||
1580 | static int wm8903_i2c_probe(struct i2c_client *i2c, | 1567 | static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, |
1581 | const struct i2c_device_id *id) | 1568 | const struct i2c_device_id *id) |
1582 | { | 1569 | { |
1583 | struct wm8903_priv *wm8903; | 1570 | struct wm8903_priv *wm8903; |
1584 | struct snd_soc_codec *codec; | 1571 | struct snd_soc_codec *codec; |
@@ -1684,7 +1671,7 @@ err: | |||
1684 | return ret; | 1671 | return ret; |
1685 | } | 1672 | } |
1686 | 1673 | ||
1687 | static int wm8903_i2c_remove(struct i2c_client *client) | 1674 | static __devexit int wm8903_i2c_remove(struct i2c_client *client) |
1688 | { | 1675 | { |
1689 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1676 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1690 | 1677 | ||
@@ -1714,7 +1701,7 @@ static struct i2c_driver wm8903_i2c_driver = { | |||
1714 | .owner = THIS_MODULE, | 1701 | .owner = THIS_MODULE, |
1715 | }, | 1702 | }, |
1716 | .probe = wm8903_i2c_probe, | 1703 | .probe = wm8903_i2c_probe, |
1717 | .remove = wm8903_i2c_remove, | 1704 | .remove = __devexit_p(wm8903_i2c_remove), |
1718 | .id_table = wm8903_i2c_id, | 1705 | .id_table = wm8903_i2c_id, |
1719 | }; | 1706 | }; |
1720 | 1707 | ||
@@ -1728,7 +1715,7 @@ static int wm8903_probe(struct platform_device *pdev) | |||
1728 | goto err; | 1715 | goto err; |
1729 | } | 1716 | } |
1730 | 1717 | ||
1731 | socdev->codec = wm8903_codec; | 1718 | socdev->card->codec = wm8903_codec; |
1732 | 1719 | ||
1733 | /* register pcms */ | 1720 | /* register pcms */ |
1734 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 1721 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
@@ -1737,8 +1724,9 @@ static int wm8903_probe(struct platform_device *pdev) | |||
1737 | goto err; | 1724 | goto err; |
1738 | } | 1725 | } |
1739 | 1726 | ||
1740 | wm8903_add_controls(socdev->codec); | 1727 | snd_soc_add_controls(socdev->card->codec, wm8903_snd_controls, |
1741 | wm8903_add_widgets(socdev->codec); | 1728 | ARRAY_SIZE(wm8903_snd_controls)); |
1729 | wm8903_add_widgets(socdev->card->codec); | ||
1742 | 1730 | ||
1743 | ret = snd_soc_init_card(socdev); | 1731 | ret = snd_soc_init_card(socdev); |
1744 | if (ret < 0) { | 1732 | if (ret < 0) { |
@@ -1759,7 +1747,7 @@ err: | |||
1759 | static int wm8903_remove(struct platform_device *pdev) | 1747 | static int wm8903_remove(struct platform_device *pdev) |
1760 | { | 1748 | { |
1761 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1749 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1762 | struct snd_soc_codec *codec = socdev->codec; | 1750 | struct snd_soc_codec *codec = socdev->card->codec; |
1763 | 1751 | ||
1764 | if (codec->control_data) | 1752 | if (codec->control_data) |
1765 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1753 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); |
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 88ead7f8dd98..032dca22dbd3 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c | |||
@@ -195,21 +195,6 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = { | |||
195 | SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0), | 195 | SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0), |
196 | }; | 196 | }; |
197 | 197 | ||
198 | /* add non-DAPM controls */ | ||
199 | static int wm8971_add_controls(struct snd_soc_codec *codec) | ||
200 | { | ||
201 | int err, i; | ||
202 | |||
203 | for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) { | ||
204 | err = snd_ctl_add(codec->card, | ||
205 | snd_soc_cnew(&wm8971_snd_controls[i], | ||
206 | codec, NULL)); | ||
207 | if (err < 0) | ||
208 | return err; | ||
209 | } | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | /* | 198 | /* |
214 | * DAPM Controls | 199 | * DAPM Controls |
215 | */ | 200 | */ |
@@ -546,7 +531,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, | |||
546 | { | 531 | { |
547 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 532 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
548 | struct snd_soc_device *socdev = rtd->socdev; | 533 | struct snd_soc_device *socdev = rtd->socdev; |
549 | struct snd_soc_codec *codec = socdev->codec; | 534 | struct snd_soc_codec *codec = socdev->card->codec; |
550 | struct wm8971_priv *wm8971 = codec->private_data; | 535 | struct wm8971_priv *wm8971 = codec->private_data; |
551 | u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3; | 536 | u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3; |
552 | u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0; | 537 | u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0; |
@@ -619,6 +604,13 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec, | |||
619 | #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 604 | #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
620 | SNDRV_PCM_FMTBIT_S24_LE) | 605 | SNDRV_PCM_FMTBIT_S24_LE) |
621 | 606 | ||
607 | static struct snd_soc_dai_ops wm8971_dai_ops = { | ||
608 | .hw_params = wm8971_pcm_hw_params, | ||
609 | .digital_mute = wm8971_mute, | ||
610 | .set_fmt = wm8971_set_dai_fmt, | ||
611 | .set_sysclk = wm8971_set_dai_sysclk, | ||
612 | }; | ||
613 | |||
622 | struct snd_soc_dai wm8971_dai = { | 614 | struct snd_soc_dai wm8971_dai = { |
623 | .name = "WM8971", | 615 | .name = "WM8971", |
624 | .playback = { | 616 | .playback = { |
@@ -633,12 +625,7 @@ struct snd_soc_dai wm8971_dai = { | |||
633 | .channels_max = 2, | 625 | .channels_max = 2, |
634 | .rates = WM8971_RATES, | 626 | .rates = WM8971_RATES, |
635 | .formats = WM8971_FORMATS,}, | 627 | .formats = WM8971_FORMATS,}, |
636 | .ops = { | 628 | .ops = &wm8971_dai_ops, |
637 | .hw_params = wm8971_pcm_hw_params, | ||
638 | .digital_mute = wm8971_mute, | ||
639 | .set_fmt = wm8971_set_dai_fmt, | ||
640 | .set_sysclk = wm8971_set_dai_sysclk, | ||
641 | }, | ||
642 | }; | 629 | }; |
643 | EXPORT_SYMBOL_GPL(wm8971_dai); | 630 | EXPORT_SYMBOL_GPL(wm8971_dai); |
644 | 631 | ||
@@ -652,7 +639,7 @@ static void wm8971_work(struct work_struct *work) | |||
652 | static int wm8971_suspend(struct platform_device *pdev, pm_message_t state) | 639 | static int wm8971_suspend(struct platform_device *pdev, pm_message_t state) |
653 | { | 640 | { |
654 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 641 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
655 | struct snd_soc_codec *codec = socdev->codec; | 642 | struct snd_soc_codec *codec = socdev->card->codec; |
656 | 643 | ||
657 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); | 644 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); |
658 | return 0; | 645 | return 0; |
@@ -661,7 +648,7 @@ static int wm8971_suspend(struct platform_device *pdev, pm_message_t state) | |||
661 | static int wm8971_resume(struct platform_device *pdev) | 648 | static int wm8971_resume(struct platform_device *pdev) |
662 | { | 649 | { |
663 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 650 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
664 | struct snd_soc_codec *codec = socdev->codec; | 651 | struct snd_soc_codec *codec = socdev->card->codec; |
665 | int i; | 652 | int i; |
666 | u8 data[2]; | 653 | u8 data[2]; |
667 | u16 *cache = codec->reg_cache; | 654 | u16 *cache = codec->reg_cache; |
@@ -692,7 +679,7 @@ static int wm8971_resume(struct platform_device *pdev) | |||
692 | 679 | ||
693 | static int wm8971_init(struct snd_soc_device *socdev) | 680 | static int wm8971_init(struct snd_soc_device *socdev) |
694 | { | 681 | { |
695 | struct snd_soc_codec *codec = socdev->codec; | 682 | struct snd_soc_codec *codec = socdev->card->codec; |
696 | int reg, ret = 0; | 683 | int reg, ret = 0; |
697 | 684 | ||
698 | codec->name = "WM8971"; | 685 | codec->name = "WM8971"; |
@@ -745,7 +732,8 @@ static int wm8971_init(struct snd_soc_device *socdev) | |||
745 | reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); | 732 | reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); |
746 | wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); | 733 | wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); |
747 | 734 | ||
748 | wm8971_add_controls(codec); | 735 | snd_soc_add_controls(codec, wm8971_snd_controls, |
736 | ARRAY_SIZE(wm8971_snd_controls)); | ||
749 | wm8971_add_widgets(codec); | 737 | wm8971_add_widgets(codec); |
750 | ret = snd_soc_init_card(socdev); | 738 | ret = snd_soc_init_card(socdev); |
751 | if (ret < 0) { | 739 | if (ret < 0) { |
@@ -772,7 +760,7 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, | |||
772 | const struct i2c_device_id *id) | 760 | const struct i2c_device_id *id) |
773 | { | 761 | { |
774 | struct snd_soc_device *socdev = wm8971_socdev; | 762 | struct snd_soc_device *socdev = wm8971_socdev; |
775 | struct snd_soc_codec *codec = socdev->codec; | 763 | struct snd_soc_codec *codec = socdev->card->codec; |
776 | int ret; | 764 | int ret; |
777 | 765 | ||
778 | i2c_set_clientdata(i2c, codec); | 766 | i2c_set_clientdata(i2c, codec); |
@@ -873,7 +861,7 @@ static int wm8971_probe(struct platform_device *pdev) | |||
873 | } | 861 | } |
874 | 862 | ||
875 | codec->private_data = wm8971; | 863 | codec->private_data = wm8971; |
876 | socdev->codec = codec; | 864 | socdev->card->codec = codec; |
877 | mutex_init(&codec->mutex); | 865 | mutex_init(&codec->mutex); |
878 | INIT_LIST_HEAD(&codec->dapm_widgets); | 866 | INIT_LIST_HEAD(&codec->dapm_widgets); |
879 | INIT_LIST_HEAD(&codec->dapm_paths); | 867 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -908,7 +896,7 @@ static int wm8971_probe(struct platform_device *pdev) | |||
908 | static int wm8971_remove(struct platform_device *pdev) | 896 | static int wm8971_remove(struct platform_device *pdev) |
909 | { | 897 | { |
910 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 898 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
911 | struct snd_soc_codec *codec = socdev->codec; | 899 | struct snd_soc_codec *codec = socdev->card->codec; |
912 | 900 | ||
913 | if (codec->control_data) | 901 | if (codec->control_data) |
914 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); | 902 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index a5731faa150c..c518c3e5aa3f 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -115,7 +115,7 @@ static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, | |||
115 | unsigned int reg) | 115 | unsigned int reg) |
116 | { | 116 | { |
117 | u16 *cache = codec->reg_cache; | 117 | u16 *cache = codec->reg_cache; |
118 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | 118 | BUG_ON(reg >= ARRAY_SIZE(wm8990_reg)); |
119 | return cache[reg]; | 119 | return cache[reg]; |
120 | } | 120 | } |
121 | 121 | ||
@@ -128,7 +128,7 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, | |||
128 | u16 *cache = codec->reg_cache; | 128 | u16 *cache = codec->reg_cache; |
129 | 129 | ||
130 | /* Reset register and reserved registers are uncached */ | 130 | /* Reset register and reserved registers are uncached */ |
131 | if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1) | 131 | if (reg == 0 || reg >= ARRAY_SIZE(wm8990_reg)) |
132 | return; | 132 | return; |
133 | 133 | ||
134 | cache[reg] = value; | 134 | cache[reg] = value; |
@@ -418,21 +418,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | |||
418 | 418 | ||
419 | }; | 419 | }; |
420 | 420 | ||
421 | /* add non dapm controls */ | ||
422 | static int wm8990_add_controls(struct snd_soc_codec *codec) | ||
423 | { | ||
424 | int err, i; | ||
425 | |||
426 | for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) { | ||
427 | err = snd_ctl_add(codec->card, | ||
428 | snd_soc_cnew(&wm8990_snd_controls[i], codec, | ||
429 | NULL)); | ||
430 | if (err < 0) | ||
431 | return err; | ||
432 | } | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | /* | 421 | /* |
437 | * _DAPM_ Controls | 422 | * _DAPM_ Controls |
438 | */ | 423 | */ |
@@ -1178,7 +1163,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream, | |||
1178 | { | 1163 | { |
1179 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1164 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1180 | struct snd_soc_device *socdev = rtd->socdev; | 1165 | struct snd_soc_device *socdev = rtd->socdev; |
1181 | struct snd_soc_codec *codec = socdev->codec; | 1166 | struct snd_soc_codec *codec = socdev->card->codec; |
1182 | u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); | 1167 | u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); |
1183 | 1168 | ||
1184 | audio1 &= ~WM8990_AIF_WL_MASK; | 1169 | audio1 &= ~WM8990_AIF_WL_MASK; |
@@ -1347,6 +1332,15 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, | |||
1347 | * 1. ADC/DAC on Primary Interface | 1332 | * 1. ADC/DAC on Primary Interface |
1348 | * 2. ADC on Primary Interface/DAC on secondary | 1333 | * 2. ADC on Primary Interface/DAC on secondary |
1349 | */ | 1334 | */ |
1335 | static struct snd_soc_dai_ops wm8990_dai_ops = { | ||
1336 | .hw_params = wm8990_hw_params, | ||
1337 | .digital_mute = wm8990_mute, | ||
1338 | .set_fmt = wm8990_set_dai_fmt, | ||
1339 | .set_clkdiv = wm8990_set_dai_clkdiv, | ||
1340 | .set_pll = wm8990_set_dai_pll, | ||
1341 | .set_sysclk = wm8990_set_dai_sysclk, | ||
1342 | }; | ||
1343 | |||
1350 | struct snd_soc_dai wm8990_dai = { | 1344 | struct snd_soc_dai wm8990_dai = { |
1351 | /* ADC/DAC on primary */ | 1345 | /* ADC/DAC on primary */ |
1352 | .name = "WM8990 ADC/DAC Primary", | 1346 | .name = "WM8990 ADC/DAC Primary", |
@@ -1363,21 +1357,14 @@ struct snd_soc_dai wm8990_dai = { | |||
1363 | .channels_max = 2, | 1357 | .channels_max = 2, |
1364 | .rates = WM8990_RATES, | 1358 | .rates = WM8990_RATES, |
1365 | .formats = WM8990_FORMATS,}, | 1359 | .formats = WM8990_FORMATS,}, |
1366 | .ops = { | 1360 | .ops = &wm8990_dai_ops, |
1367 | .hw_params = wm8990_hw_params, | ||
1368 | .digital_mute = wm8990_mute, | ||
1369 | .set_fmt = wm8990_set_dai_fmt, | ||
1370 | .set_clkdiv = wm8990_set_dai_clkdiv, | ||
1371 | .set_pll = wm8990_set_dai_pll, | ||
1372 | .set_sysclk = wm8990_set_dai_sysclk, | ||
1373 | }, | ||
1374 | }; | 1361 | }; |
1375 | EXPORT_SYMBOL_GPL(wm8990_dai); | 1362 | EXPORT_SYMBOL_GPL(wm8990_dai); |
1376 | 1363 | ||
1377 | static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) | 1364 | static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) |
1378 | { | 1365 | { |
1379 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1366 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1380 | struct snd_soc_codec *codec = socdev->codec; | 1367 | struct snd_soc_codec *codec = socdev->card->codec; |
1381 | 1368 | ||
1382 | /* we only need to suspend if we are a valid card */ | 1369 | /* we only need to suspend if we are a valid card */ |
1383 | if (!codec->card) | 1370 | if (!codec->card) |
@@ -1390,7 +1377,7 @@ static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) | |||
1390 | static int wm8990_resume(struct platform_device *pdev) | 1377 | static int wm8990_resume(struct platform_device *pdev) |
1391 | { | 1378 | { |
1392 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1379 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1393 | struct snd_soc_codec *codec = socdev->codec; | 1380 | struct snd_soc_codec *codec = socdev->card->codec; |
1394 | int i; | 1381 | int i; |
1395 | u8 data[2]; | 1382 | u8 data[2]; |
1396 | u16 *cache = codec->reg_cache; | 1383 | u16 *cache = codec->reg_cache; |
@@ -1418,7 +1405,7 @@ static int wm8990_resume(struct platform_device *pdev) | |||
1418 | */ | 1405 | */ |
1419 | static int wm8990_init(struct snd_soc_device *socdev) | 1406 | static int wm8990_init(struct snd_soc_device *socdev) |
1420 | { | 1407 | { |
1421 | struct snd_soc_codec *codec = socdev->codec; | 1408 | struct snd_soc_codec *codec = socdev->card->codec; |
1422 | u16 reg; | 1409 | u16 reg; |
1423 | int ret = 0; | 1410 | int ret = 0; |
1424 | 1411 | ||
@@ -1461,7 +1448,8 @@ static int wm8990_init(struct snd_soc_device *socdev) | |||
1461 | wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1448 | wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1462 | wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1449 | wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1463 | 1450 | ||
1464 | wm8990_add_controls(codec); | 1451 | snd_soc_add_controls(codec, wm8990_snd_controls, |
1452 | ARRAY_SIZE(wm8990_snd_controls)); | ||
1465 | wm8990_add_widgets(codec); | 1453 | wm8990_add_widgets(codec); |
1466 | ret = snd_soc_init_card(socdev); | 1454 | ret = snd_soc_init_card(socdev); |
1467 | if (ret < 0) { | 1455 | if (ret < 0) { |
@@ -1495,7 +1483,7 @@ static int wm8990_i2c_probe(struct i2c_client *i2c, | |||
1495 | const struct i2c_device_id *id) | 1483 | const struct i2c_device_id *id) |
1496 | { | 1484 | { |
1497 | struct snd_soc_device *socdev = wm8990_socdev; | 1485 | struct snd_soc_device *socdev = wm8990_socdev; |
1498 | struct snd_soc_codec *codec = socdev->codec; | 1486 | struct snd_soc_codec *codec = socdev->card->codec; |
1499 | int ret; | 1487 | int ret; |
1500 | 1488 | ||
1501 | i2c_set_clientdata(i2c, codec); | 1489 | i2c_set_clientdata(i2c, codec); |
@@ -1594,7 +1582,7 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1594 | } | 1582 | } |
1595 | 1583 | ||
1596 | codec->private_data = wm8990; | 1584 | codec->private_data = wm8990; |
1597 | socdev->codec = codec; | 1585 | socdev->card->codec = codec; |
1598 | mutex_init(&codec->mutex); | 1586 | mutex_init(&codec->mutex); |
1599 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1587 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1600 | INIT_LIST_HEAD(&codec->dapm_paths); | 1588 | INIT_LIST_HEAD(&codec->dapm_paths); |
@@ -1620,7 +1608,7 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1620 | static int wm8990_remove(struct platform_device *pdev) | 1608 | static int wm8990_remove(struct platform_device *pdev) |
1621 | { | 1609 | { |
1622 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1610 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1623 | struct snd_soc_codec *codec = socdev->codec; | 1611 | struct snd_soc_codec *codec = socdev->card->codec; |
1624 | 1612 | ||
1625 | if (codec->control_data) | 1613 | if (codec->control_data) |
1626 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1614 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); |
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c new file mode 100644 index 000000000000..3265817c5c26 --- /dev/null +++ b/sound/soc/codecs/wm9705.c | |||
@@ -0,0 +1,415 @@ | |||
1 | /* | ||
2 | * wm9705.c -- ALSA Soc WM9705 codec support | ||
3 | * | ||
4 | * Copyright 2008 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 of the License only. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <sound/core.h> | ||
17 | #include <sound/pcm.h> | ||
18 | #include <sound/ac97_codec.h> | ||
19 | #include <sound/initval.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include <sound/soc-dapm.h> | ||
22 | |||
23 | #include "wm9705.h" | ||
24 | |||
25 | /* | ||
26 | * WM9705 register cache | ||
27 | */ | ||
28 | static const u16 wm9705_reg[] = { | ||
29 | 0x6150, 0x8000, 0x8000, 0x8000, /* 0x0 */ | ||
30 | 0x0000, 0x8000, 0x8008, 0x8008, /* 0x8 */ | ||
31 | 0x8808, 0x8808, 0x8808, 0x8808, /* 0x10 */ | ||
32 | 0x8808, 0x0000, 0x8000, 0x0000, /* 0x18 */ | ||
33 | 0x0000, 0x0000, 0x0000, 0x000f, /* 0x20 */ | ||
34 | 0x0605, 0x0000, 0xbb80, 0x0000, /* 0x28 */ | ||
35 | 0x0000, 0xbb80, 0x0000, 0x0000, /* 0x30 */ | ||
36 | 0x0000, 0x2000, 0x0000, 0x0000, /* 0x38 */ | ||
37 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x40 */ | ||
38 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x48 */ | ||
39 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x50 */ | ||
40 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x58 */ | ||
41 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x60 */ | ||
42 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x68 */ | ||
43 | 0x0000, 0x0808, 0x0000, 0x0006, /* 0x70 */ | ||
44 | 0x0000, 0x0000, 0x574d, 0x4c05, /* 0x78 */ | ||
45 | }; | ||
46 | |||
47 | static const struct snd_kcontrol_new wm9705_snd_ac97_controls[] = { | ||
48 | SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), | ||
49 | SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1), | ||
50 | SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), | ||
51 | SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1), | ||
52 | SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1), | ||
53 | SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1), | ||
54 | SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1), | ||
55 | SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), | ||
56 | SOC_SINGLE("PCBeep Playback Volume", AC97_PC_BEEP, 1, 15, 1), | ||
57 | SOC_SINGLE("Phone Playback Volume", AC97_PHONE, 0, 31, 1), | ||
58 | SOC_DOUBLE("Line Playback Volume", AC97_LINE, 8, 0, 31, 1), | ||
59 | SOC_DOUBLE("CD Playback Volume", AC97_CD, 8, 0, 31, 1), | ||
60 | SOC_SINGLE("Mic Playback Volume", AC97_MIC, 0, 31, 1), | ||
61 | SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 6, 1, 0), | ||
62 | SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 0), | ||
63 | SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1), | ||
64 | }; | ||
65 | |||
66 | static const char *wm9705_mic[] = {"Mic 1", "Mic 2"}; | ||
67 | static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC", | ||
68 | "Line", "Stereo Mix", "Mono Mix", "Phone"}; | ||
69 | |||
70 | static const struct soc_enum wm9705_enum_mic = | ||
71 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, wm9705_mic); | ||
72 | static const struct soc_enum wm9705_enum_rec_l = | ||
73 | SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9705_rec_sel); | ||
74 | static const struct soc_enum wm9705_enum_rec_r = | ||
75 | SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9705_rec_sel); | ||
76 | |||
77 | /* Headphone Mixer */ | ||
78 | static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = { | ||
79 | SOC_DAPM_SINGLE("PCBeep Playback Switch", AC97_PC_BEEP, 15, 1, 1), | ||
80 | SOC_DAPM_SINGLE("CD Playback Switch", AC97_CD, 15, 1, 1), | ||
81 | SOC_DAPM_SINGLE("Mic Playback Switch", AC97_MIC, 15, 1, 1), | ||
82 | SOC_DAPM_SINGLE("Phone Playback Switch", AC97_PHONE, 15, 1, 1), | ||
83 | SOC_DAPM_SINGLE("Line Playback Switch", AC97_LINE, 15, 1, 1), | ||
84 | }; | ||
85 | |||
86 | /* Mic source */ | ||
87 | static const struct snd_kcontrol_new wm9705_mic_src_controls = | ||
88 | SOC_DAPM_ENUM("Route", wm9705_enum_mic); | ||
89 | |||
90 | /* Capture source */ | ||
91 | static const struct snd_kcontrol_new wm9705_capture_selectl_controls = | ||
92 | SOC_DAPM_ENUM("Route", wm9705_enum_rec_l); | ||
93 | static const struct snd_kcontrol_new wm9705_capture_selectr_controls = | ||
94 | SOC_DAPM_ENUM("Route", wm9705_enum_rec_r); | ||
95 | |||
96 | /* DAPM widgets */ | ||
97 | static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = { | ||
98 | SND_SOC_DAPM_MUX("Mic Source", SND_SOC_NOPM, 0, 0, | ||
99 | &wm9705_mic_src_controls), | ||
100 | SND_SOC_DAPM_MUX("Left Capture Source", SND_SOC_NOPM, 0, 0, | ||
101 | &wm9705_capture_selectl_controls), | ||
102 | SND_SOC_DAPM_MUX("Right Capture Source", SND_SOC_NOPM, 0, 0, | ||
103 | &wm9705_capture_selectr_controls), | ||
104 | SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", | ||
105 | SND_SOC_NOPM, 0, 0), | ||
106 | SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", | ||
107 | SND_SOC_NOPM, 0, 0), | ||
108 | SND_SOC_DAPM_MIXER_NAMED_CTL("HP Mixer", SND_SOC_NOPM, 0, 0, | ||
109 | &wm9705_hp_mixer_controls[0], | ||
110 | ARRAY_SIZE(wm9705_hp_mixer_controls)), | ||
111 | SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
112 | SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
113 | SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
114 | SND_SOC_DAPM_PGA("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
115 | SND_SOC_DAPM_PGA("Speaker PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
116 | SND_SOC_DAPM_PGA("Line PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
117 | SND_SOC_DAPM_PGA("Line out PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
118 | SND_SOC_DAPM_PGA("Mono PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
119 | SND_SOC_DAPM_PGA("Phone PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
120 | SND_SOC_DAPM_PGA("Mic PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
121 | SND_SOC_DAPM_PGA("PCBEEP PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
122 | SND_SOC_DAPM_PGA("CD PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
123 | SND_SOC_DAPM_PGA("ADC PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
124 | SND_SOC_DAPM_OUTPUT("HPOUTL"), | ||
125 | SND_SOC_DAPM_OUTPUT("HPOUTR"), | ||
126 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
127 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
128 | SND_SOC_DAPM_OUTPUT("MONOOUT"), | ||
129 | SND_SOC_DAPM_INPUT("PHONE"), | ||
130 | SND_SOC_DAPM_INPUT("LINEINL"), | ||
131 | SND_SOC_DAPM_INPUT("LINEINR"), | ||
132 | SND_SOC_DAPM_INPUT("CDINL"), | ||
133 | SND_SOC_DAPM_INPUT("CDINR"), | ||
134 | SND_SOC_DAPM_INPUT("PCBEEP"), | ||
135 | SND_SOC_DAPM_INPUT("MIC1"), | ||
136 | SND_SOC_DAPM_INPUT("MIC2"), | ||
137 | }; | ||
138 | |||
139 | /* Audio map | ||
140 | * WM9705 has no switches to disable the route from the inputs to the HP mixer | ||
141 | * so in order to prevent active inputs from forcing the audio outputs to be | ||
142 | * constantly enabled, we use the mutes on those inputs to simulate such | ||
143 | * controls. | ||
144 | */ | ||
145 | static const struct snd_soc_dapm_route audio_map[] = { | ||
146 | /* HP mixer */ | ||
147 | {"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"}, | ||
148 | {"HP Mixer", "CD Playback Switch", "CD PGA"}, | ||
149 | {"HP Mixer", "Mic Playback Switch", "Mic PGA"}, | ||
150 | {"HP Mixer", "Phone Playback Switch", "Phone PGA"}, | ||
151 | {"HP Mixer", "Line Playback Switch", "Line PGA"}, | ||
152 | {"HP Mixer", NULL, "Left DAC"}, | ||
153 | {"HP Mixer", NULL, "Right DAC"}, | ||
154 | |||
155 | /* mono mixer */ | ||
156 | {"Mono Mixer", NULL, "HP Mixer"}, | ||
157 | |||
158 | /* outputs */ | ||
159 | {"Headphone PGA", NULL, "HP Mixer"}, | ||
160 | {"HPOUTL", NULL, "Headphone PGA"}, | ||
161 | {"HPOUTR", NULL, "Headphone PGA"}, | ||
162 | {"Line out PGA", NULL, "HP Mixer"}, | ||
163 | {"LOUT", NULL, "Line out PGA"}, | ||
164 | {"ROUT", NULL, "Line out PGA"}, | ||
165 | {"Mono PGA", NULL, "Mono Mixer"}, | ||
166 | {"MONOOUT", NULL, "Mono PGA"}, | ||
167 | |||
168 | /* inputs */ | ||
169 | {"CD PGA", NULL, "CDINL"}, | ||
170 | {"CD PGA", NULL, "CDINR"}, | ||
171 | {"Line PGA", NULL, "LINEINL"}, | ||
172 | {"Line PGA", NULL, "LINEINR"}, | ||
173 | {"Phone PGA", NULL, "PHONE"}, | ||
174 | {"Mic Source", "Mic 1", "MIC1"}, | ||
175 | {"Mic Source", "Mic 2", "MIC2"}, | ||
176 | {"Mic PGA", NULL, "Mic Source"}, | ||
177 | {"PCBEEP PGA", NULL, "PCBEEP"}, | ||
178 | |||
179 | /* Left capture selector */ | ||
180 | {"Left Capture Source", "Mic", "Mic Source"}, | ||
181 | {"Left Capture Source", "CD", "CDINL"}, | ||
182 | {"Left Capture Source", "Line", "LINEINL"}, | ||
183 | {"Left Capture Source", "Stereo Mix", "HP Mixer"}, | ||
184 | {"Left Capture Source", "Mono Mix", "HP Mixer"}, | ||
185 | {"Left Capture Source", "Phone", "PHONE"}, | ||
186 | |||
187 | /* Right capture source */ | ||
188 | {"Right Capture Source", "Mic", "Mic Source"}, | ||
189 | {"Right Capture Source", "CD", "CDINR"}, | ||
190 | {"Right Capture Source", "Line", "LINEINR"}, | ||
191 | {"Right Capture Source", "Stereo Mix", "HP Mixer"}, | ||
192 | {"Right Capture Source", "Mono Mix", "HP Mixer"}, | ||
193 | {"Right Capture Source", "Phone", "PHONE"}, | ||
194 | |||
195 | {"ADC PGA", NULL, "Left Capture Source"}, | ||
196 | {"ADC PGA", NULL, "Right Capture Source"}, | ||
197 | |||
198 | /* ADC's */ | ||
199 | {"Left ADC", NULL, "ADC PGA"}, | ||
200 | {"Right ADC", NULL, "ADC PGA"}, | ||
201 | }; | ||
202 | |||
203 | static int wm9705_add_widgets(struct snd_soc_codec *codec) | ||
204 | { | ||
205 | snd_soc_dapm_new_controls(codec, wm9705_dapm_widgets, | ||
206 | ARRAY_SIZE(wm9705_dapm_widgets)); | ||
207 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
208 | snd_soc_dapm_new_widgets(codec); | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | /* We use a register cache to enhance read performance. */ | ||
214 | static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) | ||
215 | { | ||
216 | u16 *cache = codec->reg_cache; | ||
217 | |||
218 | switch (reg) { | ||
219 | case AC97_RESET: | ||
220 | case AC97_VENDOR_ID1: | ||
221 | case AC97_VENDOR_ID2: | ||
222 | return soc_ac97_ops.read(codec->ac97, reg); | ||
223 | default: | ||
224 | reg = reg >> 1; | ||
225 | |||
226 | if (reg >= (ARRAY_SIZE(wm9705_reg))) | ||
227 | return -EIO; | ||
228 | |||
229 | return cache[reg]; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
234 | unsigned int val) | ||
235 | { | ||
236 | u16 *cache = codec->reg_cache; | ||
237 | |||
238 | soc_ac97_ops.write(codec->ac97, reg, val); | ||
239 | reg = reg >> 1; | ||
240 | if (reg < (ARRAY_SIZE(wm9705_reg))) | ||
241 | cache[reg] = val; | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int ac97_prepare(struct snd_pcm_substream *substream, | ||
247 | struct snd_soc_dai *dai) | ||
248 | { | ||
249 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
250 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
251 | struct snd_soc_device *socdev = rtd->socdev; | ||
252 | struct snd_soc_codec *codec = socdev->card->codec; | ||
253 | int reg; | ||
254 | u16 vra; | ||
255 | |||
256 | vra = ac97_read(codec, AC97_EXTENDED_STATUS); | ||
257 | ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); | ||
258 | |||
259 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
260 | reg = AC97_PCM_FRONT_DAC_RATE; | ||
261 | else | ||
262 | reg = AC97_PCM_LR_ADC_RATE; | ||
263 | |||
264 | return ac97_write(codec, reg, runtime->rate); | ||
265 | } | ||
266 | |||
267 | #define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \ | ||
268 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | ||
269 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
270 | SNDRV_PCM_RATE_48000) | ||
271 | |||
272 | static struct snd_soc_dai_ops wm9705_dai_ops = { | ||
273 | .prepare = ac97_prepare, | ||
274 | }; | ||
275 | |||
276 | struct snd_soc_dai wm9705_dai[] = { | ||
277 | { | ||
278 | .name = "AC97 HiFi", | ||
279 | .ac97_control = 1, | ||
280 | .playback = { | ||
281 | .stream_name = "HiFi Playback", | ||
282 | .channels_min = 1, | ||
283 | .channels_max = 2, | ||
284 | .rates = WM9705_AC97_RATES, | ||
285 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
286 | }, | ||
287 | .capture = { | ||
288 | .stream_name = "HiFi Capture", | ||
289 | .channels_min = 1, | ||
290 | .channels_max = 2, | ||
291 | .rates = WM9705_AC97_RATES, | ||
292 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
293 | }, | ||
294 | .ops = &wm9705_dai_ops, | ||
295 | }, | ||
296 | { | ||
297 | .name = "AC97 Aux", | ||
298 | .playback = { | ||
299 | .stream_name = "Aux Playback", | ||
300 | .channels_min = 1, | ||
301 | .channels_max = 1, | ||
302 | .rates = WM9705_AC97_RATES, | ||
303 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
304 | }, | ||
305 | } | ||
306 | }; | ||
307 | EXPORT_SYMBOL_GPL(wm9705_dai); | ||
308 | |||
309 | static int wm9705_reset(struct snd_soc_codec *codec) | ||
310 | { | ||
311 | if (soc_ac97_ops.reset) { | ||
312 | soc_ac97_ops.reset(codec->ac97); | ||
313 | if (ac97_read(codec, 0) == wm9705_reg[0]) | ||
314 | return 0; /* Success */ | ||
315 | } | ||
316 | |||
317 | return -EIO; | ||
318 | } | ||
319 | |||
320 | static int wm9705_soc_probe(struct platform_device *pdev) | ||
321 | { | ||
322 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
323 | struct snd_soc_codec *codec; | ||
324 | int ret = 0; | ||
325 | |||
326 | printk(KERN_INFO "WM9705 SoC Audio Codec\n"); | ||
327 | |||
328 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), | ||
329 | GFP_KERNEL); | ||
330 | if (socdev->card->codec == NULL) | ||
331 | return -ENOMEM; | ||
332 | codec = socdev->card->codec; | ||
333 | mutex_init(&codec->mutex); | ||
334 | |||
335 | codec->reg_cache = kmemdup(wm9705_reg, sizeof(wm9705_reg), GFP_KERNEL); | ||
336 | if (codec->reg_cache == NULL) { | ||
337 | ret = -ENOMEM; | ||
338 | goto cache_err; | ||
339 | } | ||
340 | codec->reg_cache_size = sizeof(wm9705_reg); | ||
341 | codec->reg_cache_step = 2; | ||
342 | |||
343 | codec->name = "WM9705"; | ||
344 | codec->owner = THIS_MODULE; | ||
345 | codec->dai = wm9705_dai; | ||
346 | codec->num_dai = ARRAY_SIZE(wm9705_dai); | ||
347 | codec->write = ac97_write; | ||
348 | codec->read = ac97_read; | ||
349 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
350 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
351 | |||
352 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | ||
353 | if (ret < 0) { | ||
354 | printk(KERN_ERR "wm9705: failed to register AC97 codec\n"); | ||
355 | goto codec_err; | ||
356 | } | ||
357 | |||
358 | /* register pcms */ | ||
359 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
360 | if (ret < 0) | ||
361 | goto pcm_err; | ||
362 | |||
363 | ret = wm9705_reset(codec); | ||
364 | if (ret) | ||
365 | goto reset_err; | ||
366 | |||
367 | snd_soc_add_controls(codec, wm9705_snd_ac97_controls, | ||
368 | ARRAY_SIZE(wm9705_snd_ac97_controls)); | ||
369 | wm9705_add_widgets(codec); | ||
370 | |||
371 | ret = snd_soc_init_card(socdev); | ||
372 | if (ret < 0) { | ||
373 | printk(KERN_ERR "wm9705: failed to register card\n"); | ||
374 | goto pcm_err; | ||
375 | } | ||
376 | |||
377 | return 0; | ||
378 | |||
379 | reset_err: | ||
380 | snd_soc_free_pcms(socdev); | ||
381 | pcm_err: | ||
382 | snd_soc_free_ac97_codec(codec); | ||
383 | codec_err: | ||
384 | kfree(codec->reg_cache); | ||
385 | cache_err: | ||
386 | kfree(socdev->card->codec); | ||
387 | socdev->card->codec = NULL; | ||
388 | return ret; | ||
389 | } | ||
390 | |||
391 | static int wm9705_soc_remove(struct platform_device *pdev) | ||
392 | { | ||
393 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
394 | struct snd_soc_codec *codec = socdev->card->codec; | ||
395 | |||
396 | if (codec == NULL) | ||
397 | return 0; | ||
398 | |||
399 | snd_soc_dapm_free(socdev); | ||
400 | snd_soc_free_pcms(socdev); | ||
401 | snd_soc_free_ac97_codec(codec); | ||
402 | kfree(codec->reg_cache); | ||
403 | kfree(codec); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | struct snd_soc_codec_device soc_codec_dev_wm9705 = { | ||
408 | .probe = wm9705_soc_probe, | ||
409 | .remove = wm9705_soc_remove, | ||
410 | }; | ||
411 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705); | ||
412 | |||
413 | MODULE_DESCRIPTION("ASoC WM9705 driver"); | ||
414 | MODULE_AUTHOR("Ian Molton"); | ||
415 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/wm9705.h b/sound/soc/codecs/wm9705.h new file mode 100644 index 000000000000..d380f110f9e2 --- /dev/null +++ b/sound/soc/codecs/wm9705.h | |||
@@ -0,0 +1,14 @@ | |||
1 | /* | ||
2 | * wm9705.h -- WM9705 Soc Audio driver | ||
3 | */ | ||
4 | |||
5 | #ifndef _WM9705_H | ||
6 | #define _WM9705_H | ||
7 | |||
8 | #define WM9705_DAI_AC97_HIFI 0 | ||
9 | #define WM9705_DAI_AC97_AUX 1 | ||
10 | |||
11 | extern struct snd_soc_dai wm9705_dai[2]; | ||
12 | extern struct snd_soc_codec_device soc_codec_dev_wm9705; | ||
13 | |||
14 | #endif | ||
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index af83d629078a..765cf1e7369e 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -154,21 +154,6 @@ SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), | |||
154 | SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), | 154 | SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), |
155 | }; | 155 | }; |
156 | 156 | ||
157 | /* add non dapm controls */ | ||
158 | static int wm9712_add_controls(struct snd_soc_codec *codec) | ||
159 | { | ||
160 | int err, i; | ||
161 | |||
162 | for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) { | ||
163 | err = snd_ctl_add(codec->card, | ||
164 | snd_soc_cnew(&wm9712_snd_ac97_controls[i], | ||
165 | codec, NULL)); | ||
166 | if (err < 0) | ||
167 | return err; | ||
168 | } | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | /* We have to create a fake left and right HP mixers because | 157 | /* We have to create a fake left and right HP mixers because |
173 | * the codec only has a single control that is shared by both channels. | 158 | * the codec only has a single control that is shared by both channels. |
174 | * This makes it impossible to determine the audio path. | 159 | * This makes it impossible to determine the audio path. |
@@ -467,7 +452,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
467 | else { | 452 | else { |
468 | reg = reg >> 1; | 453 | reg = reg >> 1; |
469 | 454 | ||
470 | if (reg > (ARRAY_SIZE(wm9712_reg))) | 455 | if (reg >= (ARRAY_SIZE(wm9712_reg))) |
471 | return -EIO; | 456 | return -EIO; |
472 | 457 | ||
473 | return cache[reg]; | 458 | return cache[reg]; |
@@ -481,7 +466,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
481 | 466 | ||
482 | soc_ac97_ops.write(codec->ac97, reg, val); | 467 | soc_ac97_ops.write(codec->ac97, reg, val); |
483 | reg = reg >> 1; | 468 | reg = reg >> 1; |
484 | if (reg <= (ARRAY_SIZE(wm9712_reg))) | 469 | if (reg < (ARRAY_SIZE(wm9712_reg))) |
485 | cache[reg] = val; | 470 | cache[reg] = val; |
486 | 471 | ||
487 | return 0; | 472 | return 0; |
@@ -493,7 +478,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream, | |||
493 | struct snd_pcm_runtime *runtime = substream->runtime; | 478 | struct snd_pcm_runtime *runtime = substream->runtime; |
494 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 479 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
495 | struct snd_soc_device *socdev = rtd->socdev; | 480 | struct snd_soc_device *socdev = rtd->socdev; |
496 | struct snd_soc_codec *codec = socdev->codec; | 481 | struct snd_soc_codec *codec = socdev->card->codec; |
497 | int reg; | 482 | int reg; |
498 | u16 vra; | 483 | u16 vra; |
499 | 484 | ||
@@ -514,7 +499,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, | |||
514 | struct snd_pcm_runtime *runtime = substream->runtime; | 499 | struct snd_pcm_runtime *runtime = substream->runtime; |
515 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 500 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
516 | struct snd_soc_device *socdev = rtd->socdev; | 501 | struct snd_soc_device *socdev = rtd->socdev; |
517 | struct snd_soc_codec *codec = socdev->codec; | 502 | struct snd_soc_codec *codec = socdev->card->codec; |
518 | u16 vra, xsle; | 503 | u16 vra, xsle; |
519 | 504 | ||
520 | vra = ac97_read(codec, AC97_EXTENDED_STATUS); | 505 | vra = ac97_read(codec, AC97_EXTENDED_STATUS); |
@@ -532,6 +517,14 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, | |||
532 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 517 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ |
533 | SNDRV_PCM_RATE_48000) | 518 | SNDRV_PCM_RATE_48000) |
534 | 519 | ||
520 | static struct snd_soc_dai_ops wm9712_dai_ops_hifi = { | ||
521 | .prepare = ac97_prepare, | ||
522 | }; | ||
523 | |||
524 | static struct snd_soc_dai_ops wm9712_dai_ops_aux = { | ||
525 | .prepare = ac97_aux_prepare, | ||
526 | }; | ||
527 | |||
535 | struct snd_soc_dai wm9712_dai[] = { | 528 | struct snd_soc_dai wm9712_dai[] = { |
536 | { | 529 | { |
537 | .name = "AC97 HiFi", | 530 | .name = "AC97 HiFi", |
@@ -548,8 +541,7 @@ struct snd_soc_dai wm9712_dai[] = { | |||
548 | .channels_max = 2, | 541 | .channels_max = 2, |
549 | .rates = WM9712_AC97_RATES, | 542 | .rates = WM9712_AC97_RATES, |
550 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 543 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
551 | .ops = { | 544 | .ops = &wm9712_dai_ops_hifi, |
552 | .prepare = ac97_prepare,}, | ||
553 | }, | 545 | }, |
554 | { | 546 | { |
555 | .name = "AC97 Aux", | 547 | .name = "AC97 Aux", |
@@ -559,8 +551,7 @@ struct snd_soc_dai wm9712_dai[] = { | |||
559 | .channels_max = 1, | 551 | .channels_max = 1, |
560 | .rates = WM9712_AC97_RATES, | 552 | .rates = WM9712_AC97_RATES, |
561 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 553 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
562 | .ops = { | 554 | .ops = &wm9712_dai_ops_aux, |
563 | .prepare = ac97_aux_prepare,}, | ||
564 | } | 555 | } |
565 | }; | 556 | }; |
566 | EXPORT_SYMBOL_GPL(wm9712_dai); | 557 | EXPORT_SYMBOL_GPL(wm9712_dai); |
@@ -607,7 +598,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev, | |||
607 | pm_message_t state) | 598 | pm_message_t state) |
608 | { | 599 | { |
609 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 600 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
610 | struct snd_soc_codec *codec = socdev->codec; | 601 | struct snd_soc_codec *codec = socdev->card->codec; |
611 | 602 | ||
612 | wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF); | 603 | wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF); |
613 | return 0; | 604 | return 0; |
@@ -616,7 +607,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev, | |||
616 | static int wm9712_soc_resume(struct platform_device *pdev) | 607 | static int wm9712_soc_resume(struct platform_device *pdev) |
617 | { | 608 | { |
618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 609 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
619 | struct snd_soc_codec *codec = socdev->codec; | 610 | struct snd_soc_codec *codec = socdev->card->codec; |
620 | int i, ret; | 611 | int i, ret; |
621 | u16 *cache = codec->reg_cache; | 612 | u16 *cache = codec->reg_cache; |
622 | 613 | ||
@@ -652,10 +643,11 @@ static int wm9712_soc_probe(struct platform_device *pdev) | |||
652 | 643 | ||
653 | printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION); | 644 | printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION); |
654 | 645 | ||
655 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 646 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), |
656 | if (socdev->codec == NULL) | 647 | GFP_KERNEL); |
648 | if (socdev->card->codec == NULL) | ||
657 | return -ENOMEM; | 649 | return -ENOMEM; |
658 | codec = socdev->codec; | 650 | codec = socdev->card->codec; |
659 | mutex_init(&codec->mutex); | 651 | mutex_init(&codec->mutex); |
660 | 652 | ||
661 | codec->reg_cache = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL); | 653 | codec->reg_cache = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL); |
@@ -698,7 +690,8 @@ static int wm9712_soc_probe(struct platform_device *pdev) | |||
698 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); | 690 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); |
699 | 691 | ||
700 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 692 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
701 | wm9712_add_controls(codec); | 693 | snd_soc_add_controls(codec, wm9712_snd_ac97_controls, |
694 | ARRAY_SIZE(wm9712_snd_ac97_controls)); | ||
702 | wm9712_add_widgets(codec); | 695 | wm9712_add_widgets(codec); |
703 | ret = snd_soc_init_card(socdev); | 696 | ret = snd_soc_init_card(socdev); |
704 | if (ret < 0) { | 697 | if (ret < 0) { |
@@ -718,15 +711,15 @@ codec_err: | |||
718 | kfree(codec->reg_cache); | 711 | kfree(codec->reg_cache); |
719 | 712 | ||
720 | cache_err: | 713 | cache_err: |
721 | kfree(socdev->codec); | 714 | kfree(socdev->card->codec); |
722 | socdev->codec = NULL; | 715 | socdev->card->codec = NULL; |
723 | return ret; | 716 | return ret; |
724 | } | 717 | } |
725 | 718 | ||
726 | static int wm9712_soc_remove(struct platform_device *pdev) | 719 | static int wm9712_soc_remove(struct platform_device *pdev) |
727 | { | 720 | { |
728 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 721 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
729 | struct snd_soc_codec *codec = socdev->codec; | 722 | struct snd_soc_codec *codec = socdev->card->codec; |
730 | 723 | ||
731 | if (codec == NULL) | 724 | if (codec == NULL) |
732 | return 0; | 725 | return 0; |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index f3ca8aaf0139..523bad077fa0 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -32,7 +32,6 @@ | |||
32 | 32 | ||
33 | struct wm9713_priv { | 33 | struct wm9713_priv { |
34 | u32 pll_in; /* PLL input frequency */ | 34 | u32 pll_in; /* PLL input frequency */ |
35 | u32 pll_out; /* PLL output frequency */ | ||
36 | }; | 35 | }; |
37 | 36 | ||
38 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 37 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
@@ -190,21 +189,6 @@ SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0), | |||
190 | SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1), | 189 | SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1), |
191 | }; | 190 | }; |
192 | 191 | ||
193 | /* add non dapm controls */ | ||
194 | static int wm9713_add_controls(struct snd_soc_codec *codec) | ||
195 | { | ||
196 | int err, i; | ||
197 | |||
198 | for (i = 0; i < ARRAY_SIZE(wm9713_snd_ac97_controls); i++) { | ||
199 | err = snd_ctl_add(codec->card, | ||
200 | snd_soc_cnew(&wm9713_snd_ac97_controls[i], | ||
201 | codec, NULL)); | ||
202 | if (err < 0) | ||
203 | return err; | ||
204 | } | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* We have to create a fake left and right HP mixers because | 192 | /* We have to create a fake left and right HP mixers because |
209 | * the codec only has a single control that is shared by both channels. | 193 | * the codec only has a single control that is shared by both channels. |
210 | * This makes it impossible to determine the audio path using the current | 194 | * This makes it impossible to determine the audio path using the current |
@@ -636,7 +620,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
636 | else { | 620 | else { |
637 | reg = reg >> 1; | 621 | reg = reg >> 1; |
638 | 622 | ||
639 | if (reg > (ARRAY_SIZE(wm9713_reg))) | 623 | if (reg >= (ARRAY_SIZE(wm9713_reg))) |
640 | return -EIO; | 624 | return -EIO; |
641 | 625 | ||
642 | return cache[reg]; | 626 | return cache[reg]; |
@@ -650,7 +634,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
650 | if (reg < 0x7c) | 634 | if (reg < 0x7c) |
651 | soc_ac97_ops.write(codec->ac97, reg, val); | 635 | soc_ac97_ops.write(codec->ac97, reg, val); |
652 | reg = reg >> 1; | 636 | reg = reg >> 1; |
653 | if (reg <= (ARRAY_SIZE(wm9713_reg))) | 637 | if (reg < (ARRAY_SIZE(wm9713_reg))) |
654 | cache[reg] = val; | 638 | cache[reg] = val; |
655 | 639 | ||
656 | return 0; | 640 | return 0; |
@@ -738,13 +722,13 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
738 | struct _pll_div pll_div; | 722 | struct _pll_div pll_div; |
739 | 723 | ||
740 | /* turn PLL off ? */ | 724 | /* turn PLL off ? */ |
741 | if (freq_in == 0 || freq_out == 0) { | 725 | if (freq_in == 0) { |
742 | /* disable PLL power and select ext source */ | 726 | /* disable PLL power and select ext source */ |
743 | reg = ac97_read(codec, AC97_HANDSET_RATE); | 727 | reg = ac97_read(codec, AC97_HANDSET_RATE); |
744 | ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080); | 728 | ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080); |
745 | reg = ac97_read(codec, AC97_EXTENDED_MID); | 729 | reg = ac97_read(codec, AC97_EXTENDED_MID); |
746 | ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200); | 730 | ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200); |
747 | wm9713->pll_out = 0; | 731 | wm9713->pll_in = 0; |
748 | return 0; | 732 | return 0; |
749 | } | 733 | } |
750 | 734 | ||
@@ -788,7 +772,6 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
788 | ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff); | 772 | ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff); |
789 | reg = ac97_read(codec, AC97_HANDSET_RATE); | 773 | reg = ac97_read(codec, AC97_HANDSET_RATE); |
790 | ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f); | 774 | ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f); |
791 | wm9713->pll_out = freq_out; | ||
792 | wm9713->pll_in = freq_in; | 775 | wm9713->pll_in = freq_in; |
793 | 776 | ||
794 | /* wait 10ms AC97 link frames for the link to stabilise */ | 777 | /* wait 10ms AC97 link frames for the link to stabilise */ |
@@ -957,13 +940,14 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, | |||
957 | struct snd_soc_dai *dai) | 940 | struct snd_soc_dai *dai) |
958 | { | 941 | { |
959 | struct snd_soc_codec *codec = dai->codec; | 942 | struct snd_soc_codec *codec = dai->codec; |
960 | u16 status; | 943 | u16 status, rate; |
961 | 944 | ||
962 | /* Gracefully shut down the voice interface. */ | 945 | /* Gracefully shut down the voice interface. */ |
963 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; | 946 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; |
964 | ac97_write(codec, AC97_HANDSET_RATE, 0x0280); | 947 | rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; |
948 | ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); | ||
965 | schedule_timeout_interruptible(msecs_to_jiffies(1)); | 949 | schedule_timeout_interruptible(msecs_to_jiffies(1)); |
966 | ac97_write(codec, AC97_HANDSET_RATE, 0x0F80); | 950 | ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); |
967 | ac97_write(codec, AC97_EXTENDED_MID, status); | 951 | ac97_write(codec, AC97_EXTENDED_MID, status); |
968 | } | 952 | } |
969 | 953 | ||
@@ -1021,6 +1005,27 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, | |||
1021 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | 1005 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ |
1022 | SNDRV_PCM_FORMAT_S24_LE) | 1006 | SNDRV_PCM_FORMAT_S24_LE) |
1023 | 1007 | ||
1008 | static struct snd_soc_dai_ops wm9713_dai_ops_hifi = { | ||
1009 | .prepare = ac97_hifi_prepare, | ||
1010 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1011 | .set_pll = wm9713_set_dai_pll, | ||
1012 | }; | ||
1013 | |||
1014 | static struct snd_soc_dai_ops wm9713_dai_ops_aux = { | ||
1015 | .prepare = ac97_aux_prepare, | ||
1016 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1017 | .set_pll = wm9713_set_dai_pll, | ||
1018 | }; | ||
1019 | |||
1020 | static struct snd_soc_dai_ops wm9713_dai_ops_voice = { | ||
1021 | .hw_params = wm9713_pcm_hw_params, | ||
1022 | .shutdown = wm9713_voiceshutdown, | ||
1023 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1024 | .set_pll = wm9713_set_dai_pll, | ||
1025 | .set_fmt = wm9713_set_dai_fmt, | ||
1026 | .set_tristate = wm9713_set_dai_tristate, | ||
1027 | }; | ||
1028 | |||
1024 | struct snd_soc_dai wm9713_dai[] = { | 1029 | struct snd_soc_dai wm9713_dai[] = { |
1025 | { | 1030 | { |
1026 | .name = "AC97 HiFi", | 1031 | .name = "AC97 HiFi", |
@@ -1037,10 +1042,7 @@ struct snd_soc_dai wm9713_dai[] = { | |||
1037 | .channels_max = 2, | 1042 | .channels_max = 2, |
1038 | .rates = WM9713_RATES, | 1043 | .rates = WM9713_RATES, |
1039 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 1044 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
1040 | .ops = { | 1045 | .ops = &wm9713_dai_ops_hifi, |
1041 | .prepare = ac97_hifi_prepare, | ||
1042 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1043 | .set_pll = wm9713_set_dai_pll,}, | ||
1044 | }, | 1046 | }, |
1045 | { | 1047 | { |
1046 | .name = "AC97 Aux", | 1048 | .name = "AC97 Aux", |
@@ -1050,10 +1052,7 @@ struct snd_soc_dai wm9713_dai[] = { | |||
1050 | .channels_max = 1, | 1052 | .channels_max = 1, |
1051 | .rates = WM9713_RATES, | 1053 | .rates = WM9713_RATES, |
1052 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 1054 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
1053 | .ops = { | 1055 | .ops = &wm9713_dai_ops_aux, |
1054 | .prepare = ac97_aux_prepare, | ||
1055 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1056 | .set_pll = wm9713_set_dai_pll,}, | ||
1057 | }, | 1056 | }, |
1058 | { | 1057 | { |
1059 | .name = "WM9713 Voice", | 1058 | .name = "WM9713 Voice", |
@@ -1069,14 +1068,7 @@ struct snd_soc_dai wm9713_dai[] = { | |||
1069 | .channels_max = 2, | 1068 | .channels_max = 2, |
1070 | .rates = WM9713_PCM_RATES, | 1069 | .rates = WM9713_PCM_RATES, |
1071 | .formats = WM9713_PCM_FORMATS,}, | 1070 | .formats = WM9713_PCM_FORMATS,}, |
1072 | .ops = { | 1071 | .ops = &wm9713_dai_ops_voice, |
1073 | .hw_params = wm9713_pcm_hw_params, | ||
1074 | .shutdown = wm9713_voiceshutdown, | ||
1075 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1076 | .set_pll = wm9713_set_dai_pll, | ||
1077 | .set_fmt = wm9713_set_dai_fmt, | ||
1078 | .set_tristate = wm9713_set_dai_tristate, | ||
1079 | }, | ||
1080 | }, | 1072 | }, |
1081 | }; | 1073 | }; |
1082 | EXPORT_SYMBOL_GPL(wm9713_dai); | 1074 | EXPORT_SYMBOL_GPL(wm9713_dai); |
@@ -1132,7 +1124,7 @@ static int wm9713_soc_suspend(struct platform_device *pdev, | |||
1132 | pm_message_t state) | 1124 | pm_message_t state) |
1133 | { | 1125 | { |
1134 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1126 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1135 | struct snd_soc_codec *codec = socdev->codec; | 1127 | struct snd_soc_codec *codec = socdev->card->codec; |
1136 | u16 reg; | 1128 | u16 reg; |
1137 | 1129 | ||
1138 | /* Disable everything except touchpanel - that will be handled | 1130 | /* Disable everything except touchpanel - that will be handled |
@@ -1150,7 +1142,7 @@ static int wm9713_soc_suspend(struct platform_device *pdev, | |||
1150 | static int wm9713_soc_resume(struct platform_device *pdev) | 1142 | static int wm9713_soc_resume(struct platform_device *pdev) |
1151 | { | 1143 | { |
1152 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1144 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1153 | struct snd_soc_codec *codec = socdev->codec; | 1145 | struct snd_soc_codec *codec = socdev->card->codec; |
1154 | struct wm9713_priv *wm9713 = codec->private_data; | 1146 | struct wm9713_priv *wm9713 = codec->private_data; |
1155 | int i, ret; | 1147 | int i, ret; |
1156 | u16 *cache = codec->reg_cache; | 1148 | u16 *cache = codec->reg_cache; |
@@ -1164,8 +1156,8 @@ static int wm9713_soc_resume(struct platform_device *pdev) | |||
1164 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1156 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1165 | 1157 | ||
1166 | /* do we need to re-start the PLL ? */ | 1158 | /* do we need to re-start the PLL ? */ |
1167 | if (wm9713->pll_out) | 1159 | if (wm9713->pll_in) |
1168 | wm9713_set_pll(codec, 0, wm9713->pll_in, wm9713->pll_out); | 1160 | wm9713_set_pll(codec, 0, wm9713->pll_in, 0); |
1169 | 1161 | ||
1170 | /* only synchronise the codec if warm reset failed */ | 1162 | /* only synchronise the codec if warm reset failed */ |
1171 | if (ret == 0) { | 1163 | if (ret == 0) { |
@@ -1191,10 +1183,11 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1191 | 1183 | ||
1192 | printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION); | 1184 | printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION); |
1193 | 1185 | ||
1194 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1186 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), |
1195 | if (socdev->codec == NULL) | 1187 | GFP_KERNEL); |
1188 | if (socdev->card->codec == NULL) | ||
1196 | return -ENOMEM; | 1189 | return -ENOMEM; |
1197 | codec = socdev->codec; | 1190 | codec = socdev->card->codec; |
1198 | mutex_init(&codec->mutex); | 1191 | mutex_init(&codec->mutex); |
1199 | 1192 | ||
1200 | codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL); | 1193 | codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL); |
@@ -1245,7 +1238,8 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1245 | reg = ac97_read(codec, AC97_CD) & 0x7fff; | 1238 | reg = ac97_read(codec, AC97_CD) & 0x7fff; |
1246 | ac97_write(codec, AC97_CD, reg); | 1239 | ac97_write(codec, AC97_CD, reg); |
1247 | 1240 | ||
1248 | wm9713_add_controls(codec); | 1241 | snd_soc_add_controls(codec, wm9713_snd_ac97_controls, |
1242 | ARRAY_SIZE(wm9713_snd_ac97_controls)); | ||
1249 | wm9713_add_widgets(codec); | 1243 | wm9713_add_widgets(codec); |
1250 | ret = snd_soc_init_card(socdev); | 1244 | ret = snd_soc_init_card(socdev); |
1251 | if (ret < 0) | 1245 | if (ret < 0) |
@@ -1265,15 +1259,15 @@ priv_err: | |||
1265 | kfree(codec->reg_cache); | 1259 | kfree(codec->reg_cache); |
1266 | 1260 | ||
1267 | cache_err: | 1261 | cache_err: |
1268 | kfree(socdev->codec); | 1262 | kfree(socdev->card->codec); |
1269 | socdev->codec = NULL; | 1263 | socdev->card->codec = NULL; |
1270 | return ret; | 1264 | return ret; |
1271 | } | 1265 | } |
1272 | 1266 | ||
1273 | static int wm9713_soc_remove(struct platform_device *pdev) | 1267 | static int wm9713_soc_remove(struct platform_device *pdev) |
1274 | { | 1268 | { |
1275 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1269 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1276 | struct snd_soc_codec *codec = socdev->codec; | 1270 | struct snd_soc_codec *codec = socdev->card->codec; |
1277 | 1271 | ||
1278 | if (codec == NULL) | 1272 | if (codec == NULL) |
1279 | return 0; | 1273 | return 0; |
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index b502741692d6..bd7392c9657e 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig | |||
@@ -20,7 +20,7 @@ config SND_DAVINCI_SOC_EVM | |||
20 | 20 | ||
21 | config SND_DAVINCI_SOC_SFFSDR | 21 | config SND_DAVINCI_SOC_SFFSDR |
22 | tristate "SoC Audio support for SFFSDR" | 22 | tristate "SoC Audio support for SFFSDR" |
23 | depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR | 23 | depends on SND_DAVINCI_SOC && MACH_SFFSDR |
24 | select SND_DAVINCI_SOC_I2S | 24 | select SND_DAVINCI_SOC_I2S |
25 | select SND_SOC_PCM3008 | 25 | select SND_SOC_PCM3008 |
26 | select SFFSDR_FPGA | 26 | select SFFSDR_FPGA |
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 54851f318568..9b90b347007c 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
@@ -186,7 +186,8 @@ static int __init evm_init(void) | |||
186 | 186 | ||
187 | platform_set_drvdata(evm_snd_device, &evm_snd_devdata); | 187 | platform_set_drvdata(evm_snd_device, &evm_snd_devdata); |
188 | evm_snd_devdata.dev = &evm_snd_device->dev; | 188 | evm_snd_devdata.dev = &evm_snd_device->dev; |
189 | evm_snd_device->dev.platform_data = &evm_snd_data; | 189 | platform_device_add_data(evm_snd_device, &evm_snd_data, |
190 | sizeof(evm_snd_data)); | ||
190 | 191 | ||
191 | ret = platform_device_add_resources(evm_snd_device, evm_snd_resources, | 192 | ret = platform_device_add_resources(evm_snd_device, evm_snd_resources, |
192 | ARRAY_SIZE(evm_snd_resources)); | 193 | ARRAY_SIZE(evm_snd_resources)); |
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 0fee779e3c76..ffdb9439d3d8 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
@@ -499,6 +499,13 @@ static void davinci_i2s_remove(struct platform_device *pdev, | |||
499 | 499 | ||
500 | #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 | 500 | #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 |
501 | 501 | ||
502 | static struct snd_soc_dai_ops davinci_i2s_dai_ops = { | ||
503 | .startup = davinci_i2s_startup, | ||
504 | .trigger = davinci_i2s_trigger, | ||
505 | .hw_params = davinci_i2s_hw_params, | ||
506 | .set_fmt = davinci_i2s_set_dai_fmt, | ||
507 | }; | ||
508 | |||
502 | struct snd_soc_dai davinci_i2s_dai = { | 509 | struct snd_soc_dai davinci_i2s_dai = { |
503 | .name = "davinci-i2s", | 510 | .name = "davinci-i2s", |
504 | .id = 0, | 511 | .id = 0, |
@@ -514,12 +521,7 @@ struct snd_soc_dai davinci_i2s_dai = { | |||
514 | .channels_max = 2, | 521 | .channels_max = 2, |
515 | .rates = DAVINCI_I2S_RATES, | 522 | .rates = DAVINCI_I2S_RATES, |
516 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 523 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
517 | .ops = { | 524 | .ops = &davinci_i2s_dai_ops, |
518 | .startup = davinci_i2s_startup, | ||
519 | .trigger = davinci_i2s_trigger, | ||
520 | .hw_params = davinci_i2s_hw_params, | ||
521 | .set_fmt = davinci_i2s_set_dai_fmt, | ||
522 | }, | ||
523 | }; | 525 | }; |
524 | EXPORT_SYMBOL_GPL(davinci_i2s_dai); | 526 | EXPORT_SYMBOL_GPL(davinci_i2s_dai); |
525 | 527 | ||
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 366049d8578c..7af3b5b3a53d 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c | |||
@@ -286,7 +286,7 @@ static int davinci_pcm_mmap(struct snd_pcm_substream *substream, | |||
286 | runtime->dma_bytes); | 286 | runtime->dma_bytes); |
287 | } | 287 | } |
288 | 288 | ||
289 | struct snd_pcm_ops davinci_pcm_ops = { | 289 | static struct snd_pcm_ops davinci_pcm_ops = { |
290 | .open = davinci_pcm_open, | 290 | .open = davinci_pcm_open, |
291 | .close = davinci_pcm_close, | 291 | .close = davinci_pcm_close, |
292 | .ioctl = snd_pcm_lib_ioctl, | 292 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 4935d1bcbd8d..40eccfe9e358 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c | |||
@@ -25,7 +25,9 @@ | |||
25 | 25 | ||
26 | #include <asm/dma.h> | 26 | #include <asm/dma.h> |
27 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
28 | #ifdef CONFIG_SFFSDR_FPGA | ||
28 | #include <asm/plat-sffsdr/sffsdr-fpga.h> | 29 | #include <asm/plat-sffsdr/sffsdr-fpga.h> |
30 | #endif | ||
29 | 31 | ||
30 | #include <mach/mcbsp.h> | 32 | #include <mach/mcbsp.h> |
31 | #include <mach/edma.h> | 33 | #include <mach/edma.h> |
@@ -34,31 +36,45 @@ | |||
34 | #include "davinci-pcm.h" | 36 | #include "davinci-pcm.h" |
35 | #include "davinci-i2s.h" | 37 | #include "davinci-i2s.h" |
36 | 38 | ||
39 | /* | ||
40 | * CLKX and CLKR are the inputs for the Sample Rate Generator. | ||
41 | * FSX and FSR are outputs, driven by the sample Rate Generator. | ||
42 | */ | ||
43 | #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ | ||
44 | SND_SOC_DAIFMT_CBM_CFS | \ | ||
45 | SND_SOC_DAIFMT_IB_NF) | ||
46 | |||
37 | static int sffsdr_hw_params(struct snd_pcm_substream *substream, | 47 | static int sffsdr_hw_params(struct snd_pcm_substream *substream, |
38 | struct snd_pcm_hw_params *params, | 48 | struct snd_pcm_hw_params *params) |
39 | struct snd_soc_dai *dai) | ||
40 | { | 49 | { |
41 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 50 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
42 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 51 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
43 | int fs; | 52 | int fs; |
44 | int ret = 0; | 53 | int ret = 0; |
45 | 54 | ||
46 | /* Set cpu DAI configuration: | ||
47 | * CLKX and CLKR are the inputs for the Sample Rate Generator. | ||
48 | * FSX and FSR are outputs, driven by the sample Rate Generator. */ | ||
49 | ret = snd_soc_dai_set_fmt(cpu_dai, | ||
50 | SND_SOC_DAIFMT_RIGHT_J | | ||
51 | SND_SOC_DAIFMT_CBM_CFS | | ||
52 | SND_SOC_DAIFMT_IB_NF); | ||
53 | if (ret < 0) | ||
54 | return ret; | ||
55 | |||
56 | /* Fsref can be 32000, 44100 or 48000. */ | 55 | /* Fsref can be 32000, 44100 or 48000. */ |
57 | fs = params_rate(params); | 56 | fs = params_rate(params); |
58 | 57 | ||
58 | #ifndef CONFIG_SFFSDR_FPGA | ||
59 | /* Without the FPGA module, the Fs is fixed at 44100 Hz */ | ||
60 | if (fs != 44100) { | ||
61 | pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n"); | ||
62 | return -EINVAL; | ||
63 | } | ||
64 | #endif | ||
65 | |||
66 | /* set cpu DAI configuration */ | ||
67 | ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); | ||
68 | if (ret < 0) | ||
69 | return ret; | ||
70 | |||
59 | pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); | 71 | pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); |
60 | 72 | ||
73 | #ifndef CONFIG_SFFSDR_FPGA | ||
74 | return 0; | ||
75 | #else | ||
61 | return sffsdr_fpga_set_codec_fs(fs); | 76 | return sffsdr_fpga_set_codec_fs(fs); |
77 | #endif | ||
62 | } | 78 | } |
63 | 79 | ||
64 | static struct snd_soc_ops sffsdr_ops = { | 80 | static struct snd_soc_ops sffsdr_ops = { |
@@ -127,7 +143,8 @@ static int __init sffsdr_init(void) | |||
127 | 143 | ||
128 | platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata); | 144 | platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata); |
129 | sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev; | 145 | sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev; |
130 | sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data; | 146 | platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data, |
147 | sizeof(sffsdr_snd_data)); | ||
131 | 148 | ||
132 | ret = platform_device_add_resources(sffsdr_snd_device, | 149 | ret = platform_device_add_resources(sffsdr_snd_device, |
133 | sffsdr_snd_resources, | 150 | sffsdr_snd_resources, |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 95c12b26fe37..9fc908283371 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -1,17 +1,18 @@ | |||
1 | config SND_SOC_OF_SIMPLE | 1 | config SND_SOC_OF_SIMPLE |
2 | tristate | 2 | tristate |
3 | 3 | ||
4 | # ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers | ||
5 | # for the SSI and the Elo DMA controller. You will still need to select | ||
6 | # a platform driver and a codec driver. | ||
4 | config SND_SOC_MPC8610 | 7 | config SND_SOC_MPC8610 |
5 | bool "ALSA SoC support for the MPC8610 SOC" | 8 | tristate |
6 | depends on MPC8610_HPCD | 9 | depends on MPC8610 |
7 | default y if MPC8610 | ||
8 | help | ||
9 | Say Y if you want to add support for codecs attached to the SSI | ||
10 | device on an MPC8610. | ||
11 | 10 | ||
12 | config SND_SOC_MPC8610_HPCD | 11 | config SND_SOC_MPC8610_HPCD |
13 | bool "ALSA SoC support for the Freescale MPC8610 HPCD board" | 12 | tristate "ALSA SoC support for the Freescale MPC8610 HPCD board" |
14 | depends on SND_SOC_MPC8610 | 13 | # I2C is necessary for the CS4270 driver |
14 | depends on MPC8610_HPCD && I2C | ||
15 | select SND_SOC_MPC8610 | ||
15 | select SND_SOC_CS4270 | 16 | select SND_SOC_CS4270 |
16 | select SND_SOC_CS4270_VD33_ERRATA | 17 | select SND_SOC_CS4270_VD33_ERRATA |
17 | default y if MPC8610_HPCD | 18 | default y if MPC8610_HPCD |
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 035da4afec34..f85134c86387 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile | |||
@@ -2,10 +2,13 @@ | |||
2 | obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o | 2 | obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o |
3 | 3 | ||
4 | # MPC8610 HPCD Machine Support | 4 | # MPC8610 HPCD Machine Support |
5 | obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o | 5 | snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o |
6 | obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o | ||
6 | 7 | ||
7 | # MPC8610 Platform Support | 8 | # MPC8610 Platform Support |
8 | obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o | 9 | snd-soc-fsl-ssi-objs := fsl_ssi.o |
10 | snd-soc-fsl-dma-objs := fsl_dma.o | ||
11 | obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o | ||
9 | 12 | ||
10 | obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o | 13 | obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o |
11 | 14 | ||
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 64993eda5679..b3eb8570cd7b 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -142,7 +142,8 @@ static const struct snd_pcm_hardware fsl_dma_hardware = { | |||
142 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 142 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
143 | SNDRV_PCM_INFO_MMAP | | 143 | SNDRV_PCM_INFO_MMAP | |
144 | SNDRV_PCM_INFO_MMAP_VALID | | 144 | SNDRV_PCM_INFO_MMAP_VALID | |
145 | SNDRV_PCM_INFO_JOINT_DUPLEX, | 145 | SNDRV_PCM_INFO_JOINT_DUPLEX | |
146 | SNDRV_PCM_INFO_PAUSE, | ||
146 | .formats = FSLDMA_PCM_FORMATS, | 147 | .formats = FSLDMA_PCM_FORMATS, |
147 | .rates = FSLDMA_PCM_RATES, | 148 | .rates = FSLDMA_PCM_RATES, |
148 | .rate_min = 5512, | 149 | .rate_min = 5512, |
@@ -464,11 +465,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) | |||
464 | sizeof(struct fsl_dma_link_descriptor); | 465 | sizeof(struct fsl_dma_link_descriptor); |
465 | 466 | ||
466 | for (i = 0; i < NUM_DMA_LINKS; i++) { | 467 | for (i = 0; i < NUM_DMA_LINKS; i++) { |
467 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | 468 | dma_private->link[i].next = cpu_to_be64(temp_link); |
468 | |||
469 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
470 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
471 | link->next = cpu_to_be64(temp_link); | ||
472 | 469 | ||
473 | temp_link += sizeof(struct fsl_dma_link_descriptor); | 470 | temp_link += sizeof(struct fsl_dma_link_descriptor); |
474 | } | 471 | } |
@@ -525,79 +522,9 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) | |||
525 | * This function obtains hardware parameters about the opened stream and | 522 | * This function obtains hardware parameters about the opened stream and |
526 | * programs the DMA controller accordingly. | 523 | * programs the DMA controller accordingly. |
527 | * | 524 | * |
528 | * Note that due to a quirk of the SSI's STX register, the target address | 525 | * One drawback of big-endian is that when copying integers of different |
529 | * for the DMA operations depends on the sample size. So we don't program | 526 | * sizes to a fixed-sized register, the address to which the integer must be |
530 | * the dest_addr (for playback -- source_addr for capture) fields in the | 527 | * copied is dependent on the size of the integer. |
531 | * link descriptors here. We do that in fsl_dma_prepare() | ||
532 | */ | ||
533 | static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | ||
534 | struct snd_pcm_hw_params *hw_params) | ||
535 | { | ||
536 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
537 | struct fsl_dma_private *dma_private = runtime->private_data; | ||
538 | |||
539 | dma_addr_t temp_addr; /* Pointer to next period */ | ||
540 | |||
541 | unsigned int i; | ||
542 | |||
543 | /* Get all the parameters we need */ | ||
544 | size_t buffer_size = params_buffer_bytes(hw_params); | ||
545 | size_t period_size = params_period_bytes(hw_params); | ||
546 | |||
547 | /* Initialize our DMA tracking variables */ | ||
548 | dma_private->period_size = period_size; | ||
549 | dma_private->num_periods = params_periods(hw_params); | ||
550 | dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size; | ||
551 | dma_private->dma_buf_next = dma_private->dma_buf_phys + | ||
552 | (NUM_DMA_LINKS * period_size); | ||
553 | if (dma_private->dma_buf_next >= dma_private->dma_buf_end) | ||
554 | dma_private->dma_buf_next = dma_private->dma_buf_phys; | ||
555 | |||
556 | /* | ||
557 | * The actual address in STX0 (destination for playback, source for | ||
558 | * capture) is based on the sample size, but we don't know the sample | ||
559 | * size in this function, so we'll have to adjust that later. See | ||
560 | * comments in fsl_dma_prepare(). | ||
561 | * | ||
562 | * The DMA controller does not have a cache, so the CPU does not | ||
563 | * need to tell it to flush its cache. However, the DMA | ||
564 | * controller does need to tell the CPU to flush its cache. | ||
565 | * That's what the SNOOP bit does. | ||
566 | * | ||
567 | * Also, even though the DMA controller supports 36-bit addressing, for | ||
568 | * simplicity we currently support only 32-bit addresses for the audio | ||
569 | * buffer itself. | ||
570 | */ | ||
571 | temp_addr = substream->dma_buffer.addr; | ||
572 | |||
573 | for (i = 0; i < NUM_DMA_LINKS; i++) { | ||
574 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | ||
575 | |||
576 | link->count = cpu_to_be32(period_size); | ||
577 | |||
578 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
579 | link->source_addr = cpu_to_be32(temp_addr); | ||
580 | else | ||
581 | link->dest_addr = cpu_to_be32(temp_addr); | ||
582 | |||
583 | temp_addr += period_size; | ||
584 | } | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | /** | ||
590 | * fsl_dma_prepare - prepare the DMA registers for playback. | ||
591 | * | ||
592 | * This function is called after the specifics of the audio data are known, | ||
593 | * i.e. snd_pcm_runtime is initialized. | ||
594 | * | ||
595 | * In this function, we finish programming the registers of the DMA | ||
596 | * controller that are dependent on the sample size. | ||
597 | * | ||
598 | * One of the drawbacks with big-endian is that when copying integers of | ||
599 | * different sizes to a fixed-sized register, the address to which the | ||
600 | * integer must be copied is dependent on the size of the integer. | ||
601 | * | 528 | * |
602 | * For example, if P is the address of a 32-bit register, and X is a 32-bit | 529 | * For example, if P is the address of a 32-bit register, and X is a 32-bit |
603 | * integer, then X should be copied to address P. However, if X is a 16-bit | 530 | * integer, then X should be copied to address P. However, if X is a 16-bit |
@@ -613,22 +540,58 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
613 | * and 8 bytes at a time). So we do not support packed 24-bit samples. | 540 | * and 8 bytes at a time). So we do not support packed 24-bit samples. |
614 | * 24-bit data must be padded to 32 bits. | 541 | * 24-bit data must be padded to 32 bits. |
615 | */ | 542 | */ |
616 | static int fsl_dma_prepare(struct snd_pcm_substream *substream) | 543 | static int fsl_dma_hw_params(struct snd_pcm_substream *substream, |
544 | struct snd_pcm_hw_params *hw_params) | ||
617 | { | 545 | { |
618 | struct snd_pcm_runtime *runtime = substream->runtime; | 546 | struct snd_pcm_runtime *runtime = substream->runtime; |
619 | struct fsl_dma_private *dma_private = runtime->private_data; | 547 | struct fsl_dma_private *dma_private = runtime->private_data; |
548 | |||
549 | /* Number of bits per sample */ | ||
550 | unsigned int sample_size = | ||
551 | snd_pcm_format_physical_width(params_format(hw_params)); | ||
552 | |||
553 | /* Number of bytes per frame */ | ||
554 | unsigned int frame_size = 2 * (sample_size / 8); | ||
555 | |||
556 | /* Bus address of SSI STX register */ | ||
557 | dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys; | ||
558 | |||
559 | /* Size of the DMA buffer, in bytes */ | ||
560 | size_t buffer_size = params_buffer_bytes(hw_params); | ||
561 | |||
562 | /* Number of bytes per period */ | ||
563 | size_t period_size = params_period_bytes(hw_params); | ||
564 | |||
565 | /* Pointer to next period */ | ||
566 | dma_addr_t temp_addr = substream->dma_buffer.addr; | ||
567 | |||
568 | /* Pointer to DMA controller */ | ||
620 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; | 569 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; |
621 | u32 mr; | 570 | |
571 | u32 mr; /* DMA Mode Register */ | ||
572 | |||
622 | unsigned int i; | 573 | unsigned int i; |
623 | dma_addr_t ssi_sxx_phys; /* Bus address of SSI STX register */ | ||
624 | unsigned int frame_size; /* Number of bytes per frame */ | ||
625 | 574 | ||
626 | ssi_sxx_phys = dma_private->ssi_sxx_phys; | 575 | /* Initialize our DMA tracking variables */ |
576 | dma_private->period_size = period_size; | ||
577 | dma_private->num_periods = params_periods(hw_params); | ||
578 | dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size; | ||
579 | dma_private->dma_buf_next = dma_private->dma_buf_phys + | ||
580 | (NUM_DMA_LINKS * period_size); | ||
581 | |||
582 | if (dma_private->dma_buf_next >= dma_private->dma_buf_end) | ||
583 | /* This happens if the number of periods == NUM_DMA_LINKS */ | ||
584 | dma_private->dma_buf_next = dma_private->dma_buf_phys; | ||
627 | 585 | ||
628 | mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK | | 586 | mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK | |
629 | CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK); | 587 | CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK); |
630 | 588 | ||
631 | switch (runtime->sample_bits) { | 589 | /* Due to a quirk of the SSI's STX register, the target address |
590 | * for the DMA operations depends on the sample size. So we calculate | ||
591 | * that offset here. While we're at it, also tell the DMA controller | ||
592 | * how much data to transfer per sample. | ||
593 | */ | ||
594 | switch (sample_size) { | ||
632 | case 8: | 595 | case 8: |
633 | mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; | 596 | mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; |
634 | ssi_sxx_phys += 3; | 597 | ssi_sxx_phys += 3; |
@@ -641,12 +604,12 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream) | |||
641 | mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4; | 604 | mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4; |
642 | break; | 605 | break; |
643 | default: | 606 | default: |
607 | /* We should never get here */ | ||
644 | dev_err(substream->pcm->card->dev, | 608 | dev_err(substream->pcm->card->dev, |
645 | "unsupported sample size %u\n", runtime->sample_bits); | 609 | "unsupported sample size %u\n", sample_size); |
646 | return -EINVAL; | 610 | return -EINVAL; |
647 | } | 611 | } |
648 | 612 | ||
649 | frame_size = runtime->frame_bits / 8; | ||
650 | /* | 613 | /* |
651 | * BWC should always be a multiple of the frame size. BWC determines | 614 | * BWC should always be a multiple of the frame size. BWC determines |
652 | * how many bytes are sent/received before the DMA controller checks the | 615 | * how many bytes are sent/received before the DMA controller checks the |
@@ -655,7 +618,6 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream) | |||
655 | * capture, the receive FIFO is triggered when it contains one frame, so | 618 | * capture, the receive FIFO is triggered when it contains one frame, so |
656 | * we want to receive one frame at a time. | 619 | * we want to receive one frame at a time. |
657 | */ | 620 | */ |
658 | |||
659 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 621 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
660 | mr |= CCSR_DMA_MR_BWC(2 * frame_size); | 622 | mr |= CCSR_DMA_MR_BWC(2 * frame_size); |
661 | else | 623 | else |
@@ -663,16 +625,48 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream) | |||
663 | 625 | ||
664 | out_be32(&dma_channel->mr, mr); | 626 | out_be32(&dma_channel->mr, mr); |
665 | 627 | ||
666 | /* | ||
667 | * Program the address of the DMA transfer to/from the SSI. | ||
668 | */ | ||
669 | for (i = 0; i < NUM_DMA_LINKS; i++) { | 628 | for (i = 0; i < NUM_DMA_LINKS; i++) { |
670 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | 629 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; |
671 | 630 | ||
672 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 631 | link->count = cpu_to_be32(period_size); |
632 | |||
633 | /* Even though the DMA controller supports 36-bit addressing, | ||
634 | * for simplicity we allow only 32-bit addresses for the audio | ||
635 | * buffer itself. This was enforced in fsl_dma_new() with the | ||
636 | * DMA mask. | ||
637 | * | ||
638 | * The snoop bit tells the DMA controller whether it should tell | ||
639 | * the ECM to snoop during a read or write to an address. For | ||
640 | * audio, we use DMA to transfer data between memory and an I/O | ||
641 | * device (the SSI's STX0 or SRX0 register). Snooping is only | ||
642 | * needed if there is a cache, so we need to snoop memory | ||
643 | * addresses only. For playback, that means we snoop the source | ||
644 | * but not the destination. For capture, we snoop the | ||
645 | * destination but not the source. | ||
646 | * | ||
647 | * Note that failing to snoop properly is unlikely to cause | ||
648 | * cache incoherency if the period size is larger than the | ||
649 | * size of L1 cache. This is because filling in one period will | ||
650 | * flush out the data for the previous period. So if you | ||
651 | * increased period_bytes_min to a large enough size, you might | ||
652 | * get more performance by not snooping, and you'll still be | ||
653 | * okay. | ||
654 | */ | ||
655 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
656 | link->source_addr = cpu_to_be32(temp_addr); | ||
657 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
658 | |||
673 | link->dest_addr = cpu_to_be32(ssi_sxx_phys); | 659 | link->dest_addr = cpu_to_be32(ssi_sxx_phys); |
674 | else | 660 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP); |
661 | } else { | ||
675 | link->source_addr = cpu_to_be32(ssi_sxx_phys); | 662 | link->source_addr = cpu_to_be32(ssi_sxx_phys); |
663 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP); | ||
664 | |||
665 | link->dest_addr = cpu_to_be32(temp_addr); | ||
666 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
667 | } | ||
668 | |||
669 | temp_addr += period_size; | ||
676 | } | 670 | } |
677 | 671 | ||
678 | return 0; | 672 | return 0; |
@@ -808,7 +802,6 @@ static struct snd_pcm_ops fsl_dma_ops = { | |||
808 | .ioctl = snd_pcm_lib_ioctl, | 802 | .ioctl = snd_pcm_lib_ioctl, |
809 | .hw_params = fsl_dma_hw_params, | 803 | .hw_params = fsl_dma_hw_params, |
810 | .hw_free = fsl_dma_hw_free, | 804 | .hw_free = fsl_dma_hw_free, |
811 | .prepare = fsl_dma_prepare, | ||
812 | .pointer = fsl_dma_pointer, | 805 | .pointer = fsl_dma_pointer, |
813 | }; | 806 | }; |
814 | 807 | ||
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c6d6eb71dc1d..169bca295b78 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -72,6 +72,7 @@ | |||
72 | * @dev: struct device pointer | 72 | * @dev: struct device pointer |
73 | * @playback: the number of playback streams opened | 73 | * @playback: the number of playback streams opened |
74 | * @capture: the number of capture streams opened | 74 | * @capture: the number of capture streams opened |
75 | * @asynchronous: 0=synchronous mode, 1=asynchronous mode | ||
75 | * @cpu_dai: the CPU DAI for this device | 76 | * @cpu_dai: the CPU DAI for this device |
76 | * @dev_attr: the sysfs device attribute structure | 77 | * @dev_attr: the sysfs device attribute structure |
77 | * @stats: SSI statistics | 78 | * @stats: SSI statistics |
@@ -86,6 +87,7 @@ struct fsl_ssi_private { | |||
86 | struct device *dev; | 87 | struct device *dev; |
87 | unsigned int playback; | 88 | unsigned int playback; |
88 | unsigned int capture; | 89 | unsigned int capture; |
90 | int asynchronous; | ||
89 | struct snd_soc_dai cpu_dai; | 91 | struct snd_soc_dai cpu_dai; |
90 | struct device_attribute dev_attr; | 92 | struct device_attribute dev_attr; |
91 | 93 | ||
@@ -301,9 +303,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
301 | * | 303 | * |
302 | * FIXME: Little-endian samples require a different shift dir | 304 | * FIXME: Little-endian samples require a different shift dir |
303 | */ | 305 | */ |
304 | clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK, | 306 | clrsetbits_be32(&ssi->scr, |
305 | CCSR_SSI_SCR_TFR_CLK_DIS | | 307 | CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, |
306 | CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN); | 308 | CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE |
309 | | (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN)); | ||
307 | 310 | ||
308 | out_be32(&ssi->stcr, | 311 | out_be32(&ssi->stcr, |
309 | CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | | 312 | CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | |
@@ -382,10 +385,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
382 | SNDRV_PCM_HW_PARAM_RATE, | 385 | SNDRV_PCM_HW_PARAM_RATE, |
383 | first_runtime->rate, first_runtime->rate); | 386 | first_runtime->rate, first_runtime->rate); |
384 | 387 | ||
385 | snd_pcm_hw_constraint_minmax(substream->runtime, | 388 | /* If we're in synchronous mode, then we need to constrain |
386 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | 389 | * the sample size as well. We don't support independent sample |
387 | first_runtime->sample_bits, | 390 | * rates in asynchronous mode. |
388 | first_runtime->sample_bits); | 391 | */ |
392 | if (!ssi_private->asynchronous) | ||
393 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
394 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
395 | first_runtime->sample_bits, | ||
396 | first_runtime->sample_bits); | ||
389 | 397 | ||
390 | ssi_private->second_stream = substream; | 398 | ssi_private->second_stream = substream; |
391 | } | 399 | } |
@@ -400,7 +408,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
400 | } | 408 | } |
401 | 409 | ||
402 | /** | 410 | /** |
403 | * fsl_ssi_prepare: prepare the SSI. | 411 | * fsl_ssi_hw_params - program the sample size |
404 | * | 412 | * |
405 | * Most of the SSI registers have been programmed in the startup function, | 413 | * Most of the SSI registers have been programmed in the startup function, |
406 | * but the word length must be programmed here. Unfortunately, programming | 414 | * but the word length must be programmed here. Unfortunately, programming |
@@ -412,23 +420,27 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
412 | * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the | 420 | * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the |
413 | * clock master. | 421 | * clock master. |
414 | */ | 422 | */ |
415 | static int fsl_ssi_prepare(struct snd_pcm_substream *substream, | 423 | static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, |
416 | struct snd_soc_dai *dai) | 424 | struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai) |
417 | { | 425 | { |
418 | struct snd_pcm_runtime *runtime = substream->runtime; | 426 | struct fsl_ssi_private *ssi_private = cpu_dai->private_data; |
419 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
420 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | ||
421 | |||
422 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
423 | 427 | ||
424 | if (substream == ssi_private->first_stream) { | 428 | if (substream == ssi_private->first_stream) { |
425 | u32 wl; | 429 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
430 | unsigned int sample_size = | ||
431 | snd_pcm_format_width(params_format(hw_params)); | ||
432 | u32 wl = CCSR_SSI_SxCCR_WL(sample_size); | ||
426 | 433 | ||
427 | /* The SSI should always be disabled at this points (SSIEN=0) */ | 434 | /* The SSI should always be disabled at this points (SSIEN=0) */ |
428 | wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format)); | ||
429 | 435 | ||
430 | /* In synchronous mode, the SSI uses STCCR for capture */ | 436 | /* In synchronous mode, the SSI uses STCCR for capture */ |
431 | clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl); | 437 | if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) || |
438 | !ssi_private->asynchronous) | ||
439 | clrsetbits_be32(&ssi->stccr, | ||
440 | CCSR_SSI_SxCCR_WL_MASK, wl); | ||
441 | else | ||
442 | clrsetbits_be32(&ssi->srccr, | ||
443 | CCSR_SSI_SxCCR_WL_MASK, wl); | ||
432 | } | 444 | } |
433 | 445 | ||
434 | return 0; | 446 | return 0; |
@@ -452,28 +464,33 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, | |||
452 | 464 | ||
453 | switch (cmd) { | 465 | switch (cmd) { |
454 | case SNDRV_PCM_TRIGGER_START: | 466 | case SNDRV_PCM_TRIGGER_START: |
455 | case SNDRV_PCM_TRIGGER_RESUME: | 467 | clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); |
456 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 468 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
457 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 469 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
458 | clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); | ||
459 | setbits32(&ssi->scr, | 470 | setbits32(&ssi->scr, |
460 | CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE); | 471 | CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE); |
461 | } else { | 472 | } else { |
462 | clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); | 473 | long timeout = jiffies + 10; |
474 | |||
463 | setbits32(&ssi->scr, | 475 | setbits32(&ssi->scr, |
464 | CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE); | 476 | CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE); |
465 | 477 | ||
466 | /* | 478 | /* Wait until the SSI has filled its FIFO. Without this |
467 | * I think we need this delay to allow time for the SSI | 479 | * delay, ALSA complains about overruns. When the FIFO |
468 | * to put data into its FIFO. Without it, ALSA starts | 480 | * is full, the DMA controller initiates its first |
469 | * to complain about overruns. | 481 | * transfer. Until then, however, the DMA's DAR |
482 | * register is zero, which translates to an | ||
483 | * out-of-bounds pointer. This makes ALSA think an | ||
484 | * overrun has occurred. | ||
470 | */ | 485 | */ |
471 | mdelay(1); | 486 | while (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0) && |
487 | (jiffies < timeout)); | ||
488 | if (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0)) | ||
489 | return -EIO; | ||
472 | } | 490 | } |
473 | break; | 491 | break; |
474 | 492 | ||
475 | case SNDRV_PCM_TRIGGER_STOP: | 493 | case SNDRV_PCM_TRIGGER_STOP: |
476 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
477 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 494 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
478 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 495 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
479 | clrbits32(&ssi->scr, CCSR_SSI_SCR_TE); | 496 | clrbits32(&ssi->scr, CCSR_SSI_SCR_TE); |
@@ -563,6 +580,15 @@ static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) | |||
563 | /** | 580 | /** |
564 | * fsl_ssi_dai_template: template CPU DAI for the SSI | 581 | * fsl_ssi_dai_template: template CPU DAI for the SSI |
565 | */ | 582 | */ |
583 | static struct snd_soc_dai_ops fsl_ssi_dai_ops = { | ||
584 | .startup = fsl_ssi_startup, | ||
585 | .hw_params = fsl_ssi_hw_params, | ||
586 | .shutdown = fsl_ssi_shutdown, | ||
587 | .trigger = fsl_ssi_trigger, | ||
588 | .set_sysclk = fsl_ssi_set_sysclk, | ||
589 | .set_fmt = fsl_ssi_set_fmt, | ||
590 | }; | ||
591 | |||
566 | static struct snd_soc_dai fsl_ssi_dai_template = { | 592 | static struct snd_soc_dai fsl_ssi_dai_template = { |
567 | .playback = { | 593 | .playback = { |
568 | /* The SSI does not support monaural audio. */ | 594 | /* The SSI does not support monaural audio. */ |
@@ -577,14 +603,7 @@ static struct snd_soc_dai fsl_ssi_dai_template = { | |||
577 | .rates = FSLSSI_I2S_RATES, | 603 | .rates = FSLSSI_I2S_RATES, |
578 | .formats = FSLSSI_I2S_FORMATS, | 604 | .formats = FSLSSI_I2S_FORMATS, |
579 | }, | 605 | }, |
580 | .ops = { | 606 | .ops = &fsl_ssi_dai_ops, |
581 | .startup = fsl_ssi_startup, | ||
582 | .prepare = fsl_ssi_prepare, | ||
583 | .shutdown = fsl_ssi_shutdown, | ||
584 | .trigger = fsl_ssi_trigger, | ||
585 | .set_sysclk = fsl_ssi_set_sysclk, | ||
586 | .set_fmt = fsl_ssi_set_fmt, | ||
587 | }, | ||
588 | }; | 607 | }; |
589 | 608 | ||
590 | /** | 609 | /** |
@@ -654,6 +673,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | |||
654 | ssi_private->ssi_phys = ssi_info->ssi_phys; | 673 | ssi_private->ssi_phys = ssi_info->ssi_phys; |
655 | ssi_private->irq = ssi_info->irq; | 674 | ssi_private->irq = ssi_info->irq; |
656 | ssi_private->dev = ssi_info->dev; | 675 | ssi_private->dev = ssi_info->dev; |
676 | ssi_private->asynchronous = ssi_info->asynchronous; | ||
657 | 677 | ||
658 | ssi_private->dev->driver_data = fsl_ssi_dai; | 678 | ssi_private->dev->driver_data = fsl_ssi_dai; |
659 | 679 | ||
@@ -704,6 +724,14 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) | |||
704 | } | 724 | } |
705 | EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); | 725 | EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); |
706 | 726 | ||
727 | static int __init fsl_ssi_init(void) | ||
728 | { | ||
729 | printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n"); | ||
730 | |||
731 | return 0; | ||
732 | } | ||
733 | module_init(fsl_ssi_init); | ||
734 | |||
707 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | 735 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); |
708 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); | 736 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); |
709 | MODULE_LICENSE("GPL"); | 737 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index 83b44d700e33..eade01feaab6 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h | |||
@@ -208,6 +208,7 @@ struct ccsr_ssi { | |||
208 | * ssi_phys: physical address of the SSI registers | 208 | * ssi_phys: physical address of the SSI registers |
209 | * irq: IRQ of this SSI | 209 | * irq: IRQ of this SSI |
210 | * dev: struct device, used to create the sysfs statistics file | 210 | * dev: struct device, used to create the sysfs statistics file |
211 | * asynchronous: 0=synchronous mode, 1=asynchronous mode | ||
211 | */ | 212 | */ |
212 | struct fsl_ssi_info { | 213 | struct fsl_ssi_info { |
213 | unsigned int id; | 214 | unsigned int id; |
@@ -215,6 +216,7 @@ struct fsl_ssi_info { | |||
215 | dma_addr_t ssi_phys; | 216 | dma_addr_t ssi_phys; |
216 | unsigned int irq; | 217 | unsigned int irq; |
217 | struct device *dev; | 218 | struct device *dev; |
219 | int asynchronous; | ||
218 | }; | 220 | }; |
219 | 221 | ||
220 | struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); | 222 | struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); |
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 9eb1ce185bd0..3aa729df27b5 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c | |||
@@ -468,6 +468,16 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) | |||
468 | /** | 468 | /** |
469 | * psc_i2s_dai_template: template CPU Digital Audio Interface | 469 | * psc_i2s_dai_template: template CPU Digital Audio Interface |
470 | */ | 470 | */ |
471 | static struct snd_soc_dai_ops psc_i2s_dai_ops = { | ||
472 | .startup = psc_i2s_startup, | ||
473 | .hw_params = psc_i2s_hw_params, | ||
474 | .hw_free = psc_i2s_hw_free, | ||
475 | .shutdown = psc_i2s_shutdown, | ||
476 | .trigger = psc_i2s_trigger, | ||
477 | .set_sysclk = psc_i2s_set_sysclk, | ||
478 | .set_fmt = psc_i2s_set_fmt, | ||
479 | }; | ||
480 | |||
471 | static struct snd_soc_dai psc_i2s_dai_template = { | 481 | static struct snd_soc_dai psc_i2s_dai_template = { |
472 | .playback = { | 482 | .playback = { |
473 | .channels_min = 2, | 483 | .channels_min = 2, |
@@ -481,15 +491,7 @@ static struct snd_soc_dai psc_i2s_dai_template = { | |||
481 | .rates = PSC_I2S_RATES, | 491 | .rates = PSC_I2S_RATES, |
482 | .formats = PSC_I2S_FORMATS, | 492 | .formats = PSC_I2S_FORMATS, |
483 | }, | 493 | }, |
484 | .ops = { | 494 | .ops = &psc_i2s_dai_ops, |
485 | .startup = psc_i2s_startup, | ||
486 | .hw_params = psc_i2s_hw_params, | ||
487 | .hw_free = psc_i2s_hw_free, | ||
488 | .shutdown = psc_i2s_shutdown, | ||
489 | .trigger = psc_i2s_trigger, | ||
490 | .set_sysclk = psc_i2s_set_sysclk, | ||
491 | .set_fmt = psc_i2s_set_fmt, | ||
492 | }, | ||
493 | }; | 495 | }; |
494 | 496 | ||
495 | /* --------------------------------------------------------------------- | 497 | /* --------------------------------------------------------------------- |
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index acf39a646b2f..ef67d1cdffe7 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
@@ -353,6 +353,11 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, | |||
353 | } | 353 | } |
354 | ssi_info.irq = machine_data->ssi_irq; | 354 | ssi_info.irq = machine_data->ssi_irq; |
355 | 355 | ||
356 | /* Do we want to use asynchronous mode? */ | ||
357 | ssi_info.asynchronous = | ||
358 | of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0; | ||
359 | if (ssi_info.asynchronous) | ||
360 | dev_info(&ofdev->dev, "using asynchronous mode\n"); | ||
356 | 361 | ||
357 | /* Map the global utilities registers. */ | 362 | /* Map the global utilities registers. */ |
358 | guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); | 363 | guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 4f7f04014585..675732e724d5 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -8,7 +8,7 @@ config SND_OMAP_SOC_MCBSP | |||
8 | 8 | ||
9 | config SND_OMAP_SOC_N810 | 9 | config SND_OMAP_SOC_N810 |
10 | tristate "SoC Audio support for Nokia N810" | 10 | tristate "SoC Audio support for Nokia N810" |
11 | depends on SND_OMAP_SOC && MACH_NOKIA_N810 | 11 | depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C |
12 | select SND_OMAP_SOC_MCBSP | 12 | select SND_OMAP_SOC_MCBSP |
13 | select OMAP_MUX | 13 | select OMAP_MUX |
14 | select SND_SOC_TLV320AIC3X | 14 | select SND_SOC_TLV320AIC3X |
@@ -17,7 +17,7 @@ config SND_OMAP_SOC_N810 | |||
17 | 17 | ||
18 | config SND_OMAP_SOC_OSK5912 | 18 | config SND_OMAP_SOC_OSK5912 |
19 | tristate "SoC Audio support for omap osk5912" | 19 | tristate "SoC Audio support for omap osk5912" |
20 | depends on SND_OMAP_SOC && MACH_OMAP_OSK | 20 | depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C |
21 | select SND_OMAP_SOC_MCBSP | 21 | select SND_OMAP_SOC_MCBSP |
22 | select SND_SOC_TLV320AIC23 | 22 | select SND_SOC_TLV320AIC23 |
23 | help | 23 | help |
@@ -55,3 +55,13 @@ config SND_OMAP_SOC_OMAP3_PANDORA | |||
55 | select SND_SOC_TWL4030 | 55 | select SND_SOC_TWL4030 |
56 | help | 56 | help |
57 | Say Y if you want to add support for SoC audio on the OMAP3 Pandora. | 57 | Say Y if you want to add support for SoC audio on the OMAP3 Pandora. |
58 | |||
59 | config SND_OMAP_SOC_OMAP3_BEAGLE | ||
60 | tristate "SoC Audio support for OMAP3 Beagle" | ||
61 | depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_BEAGLE | ||
62 | select SND_OMAP_SOC_MCBSP | ||
63 | select SND_SOC_TWL4030 | ||
64 | help | ||
65 | Say Y if you want to add support for SoC audio on the Beagleboard. | ||
66 | |||
67 | |||
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 76fedd96e365..0c9e4ac37660 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile | |||
@@ -12,6 +12,7 @@ snd-soc-overo-objs := overo.o | |||
12 | snd-soc-omap2evm-objs := omap2evm.o | 12 | snd-soc-omap2evm-objs := omap2evm.o |
13 | snd-soc-sdp3430-objs := sdp3430.o | 13 | snd-soc-sdp3430-objs := sdp3430.o |
14 | snd-soc-omap3pandora-objs := omap3pandora.o | 14 | snd-soc-omap3pandora-objs := omap3pandora.o |
15 | snd-soc-omap3beagle-objs := omap3beagle.o | ||
15 | 16 | ||
16 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | 17 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o |
17 | obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o | 18 | obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o |
@@ -19,3 +20,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o | |||
19 | obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o | 20 | obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o |
20 | obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o | 21 | obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o |
21 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o | 22 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o |
23 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o | ||
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 25593fee9121..a6d1178ce128 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c | |||
@@ -40,6 +40,13 @@ | |||
40 | #define N810_HEADSET_AMP_GPIO 10 | 40 | #define N810_HEADSET_AMP_GPIO 10 |
41 | #define N810_SPEAKER_AMP_GPIO 101 | 41 | #define N810_SPEAKER_AMP_GPIO 101 |
42 | 42 | ||
43 | enum { | ||
44 | N810_JACK_DISABLED, | ||
45 | N810_JACK_HP, | ||
46 | N810_JACK_HS, | ||
47 | N810_JACK_MIC, | ||
48 | }; | ||
49 | |||
43 | static struct clk *sys_clkout2; | 50 | static struct clk *sys_clkout2; |
44 | static struct clk *sys_clkout2_src; | 51 | static struct clk *sys_clkout2_src; |
45 | static struct clk *func96m_clk; | 52 | static struct clk *func96m_clk; |
@@ -50,15 +57,32 @@ static int n810_dmic_func; | |||
50 | 57 | ||
51 | static void n810_ext_control(struct snd_soc_codec *codec) | 58 | static void n810_ext_control(struct snd_soc_codec *codec) |
52 | { | 59 | { |
60 | int hp = 0, line1l = 0; | ||
61 | |||
62 | switch (n810_jack_func) { | ||
63 | case N810_JACK_HS: | ||
64 | line1l = 1; | ||
65 | case N810_JACK_HP: | ||
66 | hp = 1; | ||
67 | break; | ||
68 | case N810_JACK_MIC: | ||
69 | line1l = 1; | ||
70 | break; | ||
71 | } | ||
72 | |||
53 | if (n810_spk_func) | 73 | if (n810_spk_func) |
54 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | 74 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); |
55 | else | 75 | else |
56 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); | 76 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); |
57 | 77 | ||
58 | if (n810_jack_func) | 78 | if (hp) |
59 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | 79 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
60 | else | 80 | else |
61 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | 81 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
82 | if (line1l) | ||
83 | snd_soc_dapm_enable_pin(codec, "LINE1L"); | ||
84 | else | ||
85 | snd_soc_dapm_disable_pin(codec, "LINE1L"); | ||
62 | 86 | ||
63 | if (n810_dmic_func) | 87 | if (n810_dmic_func) |
64 | snd_soc_dapm_enable_pin(codec, "DMic"); | 88 | snd_soc_dapm_enable_pin(codec, "DMic"); |
@@ -72,7 +96,7 @@ static int n810_startup(struct snd_pcm_substream *substream) | |||
72 | { | 96 | { |
73 | struct snd_pcm_runtime *runtime = substream->runtime; | 97 | struct snd_pcm_runtime *runtime = substream->runtime; |
74 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 98 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
75 | struct snd_soc_codec *codec = rtd->socdev->codec; | 99 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
76 | 100 | ||
77 | snd_pcm_hw_constraint_minmax(runtime, | 101 | snd_pcm_hw_constraint_minmax(runtime, |
78 | SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); | 102 | SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); |
@@ -229,7 +253,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
229 | }; | 253 | }; |
230 | 254 | ||
231 | static const char *spk_function[] = {"Off", "On"}; | 255 | static const char *spk_function[] = {"Off", "On"}; |
232 | static const char *jack_function[] = {"Off", "Headphone"}; | 256 | static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"}; |
233 | static const char *input_function[] = {"ADC", "Digital Mic"}; | 257 | static const char *input_function[] = {"ADC", "Digital Mic"}; |
234 | static const struct soc_enum n810_enum[] = { | 258 | static const struct soc_enum n810_enum[] = { |
235 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), | 259 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), |
@@ -248,20 +272,23 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = { | |||
248 | 272 | ||
249 | static int n810_aic33_init(struct snd_soc_codec *codec) | 273 | static int n810_aic33_init(struct snd_soc_codec *codec) |
250 | { | 274 | { |
251 | int i, err; | 275 | int err; |
252 | 276 | ||
253 | /* Not connected */ | 277 | /* Not connected */ |
254 | snd_soc_dapm_nc_pin(codec, "MONO_LOUT"); | 278 | snd_soc_dapm_nc_pin(codec, "MONO_LOUT"); |
255 | snd_soc_dapm_nc_pin(codec, "HPLCOM"); | 279 | snd_soc_dapm_nc_pin(codec, "HPLCOM"); |
256 | snd_soc_dapm_nc_pin(codec, "HPRCOM"); | 280 | snd_soc_dapm_nc_pin(codec, "HPRCOM"); |
281 | snd_soc_dapm_nc_pin(codec, "MIC3L"); | ||
282 | snd_soc_dapm_nc_pin(codec, "MIC3R"); | ||
283 | snd_soc_dapm_nc_pin(codec, "LINE1R"); | ||
284 | snd_soc_dapm_nc_pin(codec, "LINE2L"); | ||
285 | snd_soc_dapm_nc_pin(codec, "LINE2R"); | ||
257 | 286 | ||
258 | /* Add N810 specific controls */ | 287 | /* Add N810 specific controls */ |
259 | for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { | 288 | err = snd_soc_add_controls(codec, aic33_n810_controls, |
260 | err = snd_ctl_add(codec->card, | 289 | ARRAY_SIZE(aic33_n810_controls)); |
261 | snd_soc_cnew(&aic33_n810_controls[i], codec, NULL)); | 290 | if (err < 0) |
262 | if (err < 0) | 291 | return err; |
263 | return err; | ||
264 | } | ||
265 | 292 | ||
266 | /* Add N810 specific widgets */ | 293 | /* Add N810 specific widgets */ |
267 | snd_soc_dapm_new_controls(codec, aic33_dapm_widgets, | 294 | snd_soc_dapm_new_controls(codec, aic33_dapm_widgets, |
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 05dd5abcddf4..d6882be33452 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -461,6 +461,16 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
461 | return err; | 461 | return err; |
462 | } | 462 | } |
463 | 463 | ||
464 | static struct snd_soc_dai_ops omap_mcbsp_dai_ops = { | ||
465 | .startup = omap_mcbsp_dai_startup, | ||
466 | .shutdown = omap_mcbsp_dai_shutdown, | ||
467 | .trigger = omap_mcbsp_dai_trigger, | ||
468 | .hw_params = omap_mcbsp_dai_hw_params, | ||
469 | .set_fmt = omap_mcbsp_dai_set_dai_fmt, | ||
470 | .set_clkdiv = omap_mcbsp_dai_set_clkdiv, | ||
471 | .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, | ||
472 | }; | ||
473 | |||
464 | #define OMAP_MCBSP_DAI_BUILDER(link_id) \ | 474 | #define OMAP_MCBSP_DAI_BUILDER(link_id) \ |
465 | { \ | 475 | { \ |
466 | .name = "omap-mcbsp-dai-"#link_id, \ | 476 | .name = "omap-mcbsp-dai-"#link_id, \ |
@@ -477,15 +487,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
477 | .rates = OMAP_MCBSP_RATES, \ | 487 | .rates = OMAP_MCBSP_RATES, \ |
478 | .formats = SNDRV_PCM_FMTBIT_S16_LE, \ | 488 | .formats = SNDRV_PCM_FMTBIT_S16_LE, \ |
479 | }, \ | 489 | }, \ |
480 | .ops = { \ | 490 | .ops = &omap_mcbsp_dai_ops, \ |
481 | .startup = omap_mcbsp_dai_startup, \ | ||
482 | .shutdown = omap_mcbsp_dai_shutdown, \ | ||
483 | .trigger = omap_mcbsp_dai_trigger, \ | ||
484 | .hw_params = omap_mcbsp_dai_hw_params, \ | ||
485 | .set_fmt = omap_mcbsp_dai_set_dai_fmt, \ | ||
486 | .set_clkdiv = omap_mcbsp_dai_set_clkdiv, \ | ||
487 | .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \ | ||
488 | }, \ | ||
489 | .private_data = &mcbsp_data[(link_id)].bus_id, \ | 491 | .private_data = &mcbsp_data[(link_id)].bus_id, \ |
490 | } | 492 | } |
491 | 493 | ||
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index dd3bb2933762..8e1431cb46bb 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -265,7 +265,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream, | |||
265 | runtime->dma_bytes); | 265 | runtime->dma_bytes); |
266 | } | 266 | } |
267 | 267 | ||
268 | struct snd_pcm_ops omap_pcm_ops = { | 268 | static struct snd_pcm_ops omap_pcm_ops = { |
269 | .open = omap_pcm_open, | 269 | .open = omap_pcm_open, |
270 | .close = omap_pcm_close, | 270 | .close = omap_pcm_close, |
271 | .ioctl = snd_pcm_lib_ioctl, | 271 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index fcc2f5d9a878..fe282d4ef422 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c | |||
@@ -143,7 +143,7 @@ static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { | |||
143 | }; | 143 | }; |
144 | 144 | ||
145 | static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = { | 145 | static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = { |
146 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), | 146 | SND_SOC_DAPM_MIC("Mic (internal)", NULL), |
147 | SND_SOC_DAPM_MIC("Mic (external)", NULL), | 147 | SND_SOC_DAPM_MIC("Mic (external)", NULL), |
148 | SND_SOC_DAPM_LINE("Line In", NULL), | 148 | SND_SOC_DAPM_LINE("Line In", NULL), |
149 | }; | 149 | }; |
@@ -155,16 +155,33 @@ static const struct snd_soc_dapm_route omap3pandora_out_map[] = { | |||
155 | }; | 155 | }; |
156 | 156 | ||
157 | static const struct snd_soc_dapm_route omap3pandora_in_map[] = { | 157 | static const struct snd_soc_dapm_route omap3pandora_in_map[] = { |
158 | {"INL", NULL, "Line In"}, | 158 | {"AUXL", NULL, "Line In"}, |
159 | {"INR", NULL, "Line In"}, | 159 | {"AUXR", NULL, "Line In"}, |
160 | {"INL", NULL, "Mic (Internal)"}, | 160 | |
161 | {"INR", NULL, "Mic (external)"}, | 161 | {"MAINMIC", NULL, "Mic Bias 1"}, |
162 | {"Mic Bias 1", NULL, "Mic (internal)"}, | ||
163 | |||
164 | {"SUBMIC", NULL, "Mic Bias 2"}, | ||
165 | {"Mic Bias 2", NULL, "Mic (external)"}, | ||
162 | }; | 166 | }; |
163 | 167 | ||
164 | static int omap3pandora_out_init(struct snd_soc_codec *codec) | 168 | static int omap3pandora_out_init(struct snd_soc_codec *codec) |
165 | { | 169 | { |
166 | int ret; | 170 | int ret; |
167 | 171 | ||
172 | /* All TWL4030 output pins are floating */ | ||
173 | snd_soc_dapm_nc_pin(codec, "OUTL"); | ||
174 | snd_soc_dapm_nc_pin(codec, "OUTR"); | ||
175 | snd_soc_dapm_nc_pin(codec, "EARPIECE"); | ||
176 | snd_soc_dapm_nc_pin(codec, "PREDRIVEL"); | ||
177 | snd_soc_dapm_nc_pin(codec, "PREDRIVER"); | ||
178 | snd_soc_dapm_nc_pin(codec, "HSOL"); | ||
179 | snd_soc_dapm_nc_pin(codec, "HSOR"); | ||
180 | snd_soc_dapm_nc_pin(codec, "CARKITL"); | ||
181 | snd_soc_dapm_nc_pin(codec, "CARKITR"); | ||
182 | snd_soc_dapm_nc_pin(codec, "HFL"); | ||
183 | snd_soc_dapm_nc_pin(codec, "HFR"); | ||
184 | |||
168 | ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets, | 185 | ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets, |
169 | ARRAY_SIZE(omap3pandora_out_dapm_widgets)); | 186 | ARRAY_SIZE(omap3pandora_out_dapm_widgets)); |
170 | if (ret < 0) | 187 | if (ret < 0) |
@@ -180,18 +197,11 @@ static int omap3pandora_in_init(struct snd_soc_codec *codec) | |||
180 | { | 197 | { |
181 | int ret; | 198 | int ret; |
182 | 199 | ||
183 | /* All TWL4030 output pins are floating */ | 200 | /* Not comnnected */ |
184 | snd_soc_dapm_nc_pin(codec, "OUTL"), | 201 | snd_soc_dapm_nc_pin(codec, "HSMIC"); |
185 | snd_soc_dapm_nc_pin(codec, "OUTR"), | 202 | snd_soc_dapm_nc_pin(codec, "CARKITMIC"); |
186 | snd_soc_dapm_nc_pin(codec, "EARPIECE"), | 203 | snd_soc_dapm_nc_pin(codec, "DIGIMIC0"); |
187 | snd_soc_dapm_nc_pin(codec, "PREDRIVEL"), | 204 | snd_soc_dapm_nc_pin(codec, "DIGIMIC1"); |
188 | snd_soc_dapm_nc_pin(codec, "PREDRIVER"), | ||
189 | snd_soc_dapm_nc_pin(codec, "HSOL"), | ||
190 | snd_soc_dapm_nc_pin(codec, "HSOR"), | ||
191 | snd_soc_dapm_nc_pin(codec, "CARKITL"), | ||
192 | snd_soc_dapm_nc_pin(codec, "CARKITR"), | ||
193 | snd_soc_dapm_nc_pin(codec, "HFL"), | ||
194 | snd_soc_dapm_nc_pin(codec, "HFR"), | ||
195 | 205 | ||
196 | ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, | 206 | ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, |
197 | ARRAY_SIZE(omap3pandora_in_dapm_widgets)); | 207 | ARRAY_SIZE(omap3pandora_in_dapm_widgets)); |
@@ -251,10 +261,9 @@ static int __init omap3pandora_soc_init(void) | |||
251 | { | 261 | { |
252 | int ret; | 262 | int ret; |
253 | 263 | ||
254 | if (!machine_is_omap3_pandora()) { | 264 | if (!machine_is_omap3_pandora()) |
255 | pr_debug(PREFIX "Not OMAP3 Pandora\n"); | ||
256 | return -ENODEV; | 265 | return -ENODEV; |
257 | } | 266 | |
258 | pr_info("OMAP3 Pandora SoC init\n"); | 267 | pr_info("OMAP3 Pandora SoC init\n"); |
259 | 268 | ||
260 | ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power"); | 269 | ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power"); |
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index cd41a948df7b..a952a4eb3361 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c | |||
@@ -186,13 +186,6 @@ static int __init osk_soc_init(void) | |||
186 | return -ENODEV; | 186 | return -ENODEV; |
187 | } | 187 | } |
188 | 188 | ||
189 | if (clk_get_usecount(tlv320aic23_mclk) > 0) { | ||
190 | /* MCLK is already in use */ | ||
191 | printk(KERN_WARNING | ||
192 | "MCLK in use at %d Hz. We change it to %d Hz\n", | ||
193 | (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK); | ||
194 | } | ||
195 | |||
196 | /* | 189 | /* |
197 | * Configure 12 MHz output on MCLK. | 190 | * Configure 12 MHz output on MCLK. |
198 | */ | 191 | */ |
@@ -205,9 +198,8 @@ static int __init osk_soc_init(void) | |||
205 | } | 198 | } |
206 | } | 199 | } |
207 | 200 | ||
208 | printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n", | 201 | printk(KERN_INFO "MCLK = %d [%d]\n", |
209 | (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK, | 202 | (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK); |
210 | clk_get_usecount(tlv320aic23_mclk)); | ||
211 | 203 | ||
212 | return 0; | 204 | return 0; |
213 | err1: | 205 | err1: |
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index e226fa75669c..10f1c867f11d 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
29 | #include <sound/soc.h> | 29 | #include <sound/soc.h> |
30 | #include <sound/soc-dapm.h> | 30 | #include <sound/soc-dapm.h> |
31 | #include <sound/jack.h> | ||
31 | 32 | ||
32 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
33 | #include <mach/hardware.h> | 34 | #include <mach/hardware.h> |
@@ -38,6 +39,8 @@ | |||
38 | #include "omap-pcm.h" | 39 | #include "omap-pcm.h" |
39 | #include "../codecs/twl4030.h" | 40 | #include "../codecs/twl4030.h" |
40 | 41 | ||
42 | static struct snd_soc_card snd_soc_sdp3430; | ||
43 | |||
41 | static int sdp3430_hw_params(struct snd_pcm_substream *substream, | 44 | static int sdp3430_hw_params(struct snd_pcm_substream *substream, |
42 | struct snd_pcm_hw_params *params) | 45 | struct snd_pcm_hw_params *params) |
43 | { | 46 | { |
@@ -81,12 +84,121 @@ static struct snd_soc_ops sdp3430_ops = { | |||
81 | .hw_params = sdp3430_hw_params, | 84 | .hw_params = sdp3430_hw_params, |
82 | }; | 85 | }; |
83 | 86 | ||
87 | /* Headset jack */ | ||
88 | static struct snd_soc_jack hs_jack; | ||
89 | |||
90 | /* Headset jack detection DAPM pins */ | ||
91 | static struct snd_soc_jack_pin hs_jack_pins[] = { | ||
92 | { | ||
93 | .pin = "Headset Mic", | ||
94 | .mask = SND_JACK_MICROPHONE, | ||
95 | }, | ||
96 | { | ||
97 | .pin = "Headset Stereophone", | ||
98 | .mask = SND_JACK_HEADPHONE, | ||
99 | }, | ||
100 | }; | ||
101 | |||
102 | /* Headset jack detection gpios */ | ||
103 | static struct snd_soc_jack_gpio hs_jack_gpios[] = { | ||
104 | { | ||
105 | .gpio = (OMAP_MAX_GPIO_LINES + 2), | ||
106 | .name = "hsdet-gpio", | ||
107 | .report = SND_JACK_HEADSET, | ||
108 | .debounce_time = 200, | ||
109 | }, | ||
110 | }; | ||
111 | |||
112 | /* SDP3430 machine DAPM */ | ||
113 | static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = { | ||
114 | SND_SOC_DAPM_MIC("Ext Mic", NULL), | ||
115 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
116 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
117 | SND_SOC_DAPM_HP("Headset Stereophone", NULL), | ||
118 | }; | ||
119 | |||
120 | static const struct snd_soc_dapm_route audio_map[] = { | ||
121 | /* External Mics: MAINMIC, SUBMIC with bias*/ | ||
122 | {"MAINMIC", NULL, "Mic Bias 1"}, | ||
123 | {"SUBMIC", NULL, "Mic Bias 2"}, | ||
124 | {"Mic Bias 1", NULL, "Ext Mic"}, | ||
125 | {"Mic Bias 2", NULL, "Ext Mic"}, | ||
126 | |||
127 | /* External Speakers: HFL, HFR */ | ||
128 | {"Ext Spk", NULL, "HFL"}, | ||
129 | {"Ext Spk", NULL, "HFR"}, | ||
130 | |||
131 | /* Headset Mic: HSMIC with bias */ | ||
132 | {"HSMIC", NULL, "Headset Mic Bias"}, | ||
133 | {"Headset Mic Bias", NULL, "Headset Mic"}, | ||
134 | |||
135 | /* Headset Stereophone (Headphone): HSOL, HSOR */ | ||
136 | {"Headset Stereophone", NULL, "HSOL"}, | ||
137 | {"Headset Stereophone", NULL, "HSOR"}, | ||
138 | }; | ||
139 | |||
140 | static int sdp3430_twl4030_init(struct snd_soc_codec *codec) | ||
141 | { | ||
142 | int ret; | ||
143 | |||
144 | /* Add SDP3430 specific widgets */ | ||
145 | ret = snd_soc_dapm_new_controls(codec, sdp3430_twl4030_dapm_widgets, | ||
146 | ARRAY_SIZE(sdp3430_twl4030_dapm_widgets)); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | |||
150 | /* Set up SDP3430 specific audio path audio_map */ | ||
151 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
152 | |||
153 | /* SDP3430 connected pins */ | ||
154 | snd_soc_dapm_enable_pin(codec, "Ext Mic"); | ||
155 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
156 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); | ||
157 | snd_soc_dapm_disable_pin(codec, "Headset Stereophone"); | ||
158 | |||
159 | /* TWL4030 not connected pins */ | ||
160 | snd_soc_dapm_nc_pin(codec, "AUXL"); | ||
161 | snd_soc_dapm_nc_pin(codec, "AUXR"); | ||
162 | snd_soc_dapm_nc_pin(codec, "CARKITMIC"); | ||
163 | snd_soc_dapm_nc_pin(codec, "DIGIMIC0"); | ||
164 | snd_soc_dapm_nc_pin(codec, "DIGIMIC1"); | ||
165 | |||
166 | snd_soc_dapm_nc_pin(codec, "OUTL"); | ||
167 | snd_soc_dapm_nc_pin(codec, "OUTR"); | ||
168 | snd_soc_dapm_nc_pin(codec, "EARPIECE"); | ||
169 | snd_soc_dapm_nc_pin(codec, "PREDRIVEL"); | ||
170 | snd_soc_dapm_nc_pin(codec, "PREDRIVER"); | ||
171 | snd_soc_dapm_nc_pin(codec, "CARKITL"); | ||
172 | snd_soc_dapm_nc_pin(codec, "CARKITR"); | ||
173 | |||
174 | ret = snd_soc_dapm_sync(codec); | ||
175 | if (ret) | ||
176 | return ret; | ||
177 | |||
178 | /* Headset jack detection */ | ||
179 | ret = snd_soc_jack_new(&snd_soc_sdp3430, "Headset Jack", | ||
180 | SND_JACK_HEADSET, &hs_jack); | ||
181 | if (ret) | ||
182 | return ret; | ||
183 | |||
184 | ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), | ||
185 | hs_jack_pins); | ||
186 | if (ret) | ||
187 | return ret; | ||
188 | |||
189 | ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), | ||
190 | hs_jack_gpios); | ||
191 | |||
192 | return ret; | ||
193 | } | ||
194 | |||
84 | /* Digital audio interface glue - connects codec <--> CPU */ | 195 | /* Digital audio interface glue - connects codec <--> CPU */ |
85 | static struct snd_soc_dai_link sdp3430_dai = { | 196 | static struct snd_soc_dai_link sdp3430_dai = { |
86 | .name = "TWL4030", | 197 | .name = "TWL4030", |
87 | .stream_name = "TWL4030", | 198 | .stream_name = "TWL4030", |
88 | .cpu_dai = &omap_mcbsp_dai[0], | 199 | .cpu_dai = &omap_mcbsp_dai[0], |
89 | .codec_dai = &twl4030_dai, | 200 | .codec_dai = &twl4030_dai, |
201 | .init = sdp3430_twl4030_init, | ||
90 | .ops = &sdp3430_ops, | 202 | .ops = &sdp3430_ops, |
91 | }; | 203 | }; |
92 | 204 | ||
@@ -142,6 +254,9 @@ module_init(sdp3430_soc_init); | |||
142 | 254 | ||
143 | static void __exit sdp3430_soc_exit(void) | 255 | static void __exit sdp3430_soc_exit(void) |
144 | { | 256 | { |
257 | snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), | ||
258 | hs_jack_gpios); | ||
259 | |||
145 | platform_device_unregister(sdp3430_snd_device); | 260 | platform_device_unregister(sdp3430_snd_device); |
146 | } | 261 | } |
147 | module_exit(sdp3430_soc_exit); | 262 | module_exit(sdp3430_soc_exit); |
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 1ba25a559524..02263e5d8f03 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> |
@@ -100,7 +101,7 @@ static void corgi_ext_control(struct snd_soc_codec *codec) | |||
100 | static int corgi_startup(struct snd_pcm_substream *substream) | 101 | static int corgi_startup(struct snd_pcm_substream *substream) |
101 | { | 102 | { |
102 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 103 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
103 | struct snd_soc_codec *codec = rtd->socdev->codec; | 104 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
104 | 105 | ||
105 | /* check the jack status at stream startup */ | 106 | /* check the jack status at stream startup */ |
106 | corgi_ext_control(codec); | 107 | corgi_ext_control(codec); |
@@ -275,18 +276,16 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = { | |||
275 | */ | 276 | */ |
276 | static int corgi_wm8731_init(struct snd_soc_codec *codec) | 277 | static int corgi_wm8731_init(struct snd_soc_codec *codec) |
277 | { | 278 | { |
278 | int i, err; | 279 | int err; |
279 | 280 | ||
280 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); | 281 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); |
281 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); | 282 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); |
282 | 283 | ||
283 | /* Add corgi specific controls */ | 284 | /* Add corgi specific controls */ |
284 | for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { | 285 | err = snd_soc_add_controls(codec, wm8731_corgi_controls, |
285 | err = snd_ctl_add(codec->card, | 286 | ARRAY_SIZE(wm8731_corgi_controls)); |
286 | snd_soc_cnew(&wm8731_corgi_controls[i], codec, NULL)); | 287 | if (err < 0) |
287 | if (err < 0) | 288 | return err; |
288 | return err; | ||
289 | } | ||
290 | 289 | ||
291 | /* Add corgi specific widgets */ | 290 | /* Add corgi specific widgets */ |
292 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, | 291 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
@@ -317,19 +316,44 @@ static struct snd_soc_card snd_soc_corgi = { | |||
317 | .num_links = 1, | 316 | .num_links = 1, |
318 | }; | 317 | }; |
319 | 318 | ||
320 | /* corgi audio private data */ | ||
321 | static struct wm8731_setup_data corgi_wm8731_setup = { | ||
322 | .i2c_bus = 0, | ||
323 | .i2c_address = 0x1b, | ||
324 | }; | ||
325 | |||
326 | /* corgi audio subsystem */ | 319 | /* corgi audio subsystem */ |
327 | static struct snd_soc_device corgi_snd_devdata = { | 320 | static struct snd_soc_device corgi_snd_devdata = { |
328 | .card = &snd_soc_corgi, | 321 | .card = &snd_soc_corgi, |
329 | .codec_dev = &soc_codec_dev_wm8731, | 322 | .codec_dev = &soc_codec_dev_wm8731, |
330 | .codec_data = &corgi_wm8731_setup, | ||
331 | }; | 323 | }; |
332 | 324 | ||
325 | /* | ||
326 | * FIXME: This is a temporary bodge to avoid cross-tree merge issues. | ||
327 | * New drivers should register the wm8731 I2C device in the machine | ||
328 | * setup code (under arch/arm for ARM systems). | ||
329 | */ | ||
330 | static int wm8731_i2c_register(void) | ||
331 | { | ||
332 | struct i2c_board_info info; | ||
333 | struct i2c_adapter *adapter; | ||
334 | struct i2c_client *client; | ||
335 | |||
336 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
337 | info.addr = 0x1b; | ||
338 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
339 | |||
340 | adapter = i2c_get_adapter(0); | ||
341 | if (!adapter) { | ||
342 | printk(KERN_ERR "can't get i2c adapter 0\n"); | ||
343 | return -ENODEV; | ||
344 | } | ||
345 | |||
346 | client = i2c_new_device(adapter, &info); | ||
347 | i2c_put_adapter(adapter); | ||
348 | if (!client) { | ||
349 | printk(KERN_ERR "can't add i2c device at 0x%x\n", | ||
350 | (unsigned int)info.addr); | ||
351 | return -ENODEV; | ||
352 | } | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
333 | static struct platform_device *corgi_snd_device; | 357 | static struct platform_device *corgi_snd_device; |
334 | 358 | ||
335 | static int __init corgi_init(void) | 359 | static int __init corgi_init(void) |
@@ -340,6 +364,10 @@ static int __init corgi_init(void) | |||
340 | machine_is_husky())) | 364 | machine_is_husky())) |
341 | return -ENODEV; | 365 | return -ENODEV; |
342 | 366 | ||
367 | ret = wm8731_i2c_register(); | ||
368 | if (ret != 0) | ||
369 | return ret; | ||
370 | |||
343 | corgi_snd_device = platform_device_alloc("soc-audio", -1); | 371 | corgi_snd_device = platform_device_alloc("soc-audio", -1); |
344 | if (!corgi_snd_device) | 372 | if (!corgi_snd_device) |
345 | return -ENOMEM; | 373 | 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 2e3386dfa0f0..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> |
@@ -21,23 +19,85 @@ | |||
21 | #include <sound/soc-dapm.h> | 19 | #include <sound/soc-dapm.h> |
22 | 20 | ||
23 | #include <asm/mach-types.h> | 21 | #include <asm/mach-types.h> |
24 | #include <mach/pxa-regs.h> | ||
25 | #include <mach/hardware.h> | ||
26 | #include <mach/audio.h> | 22 | #include <mach/audio.h> |
23 | #include <mach/eseries-gpio.h> | ||
27 | 24 | ||
28 | #include "../codecs/wm9712.h" | 25 | #include "../codecs/wm9712.h" |
29 | #include "pxa2xx-pcm.h" | 26 | #include "pxa2xx-pcm.h" |
30 | #include "pxa2xx-ac97.h" | 27 | #include "pxa2xx-ac97.h" |
31 | 28 | ||
32 | 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); | ||
33 | 36 | ||
34 | 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) | ||
35 | { | 77 | { |
36 | .name = "AC97 Aux", | 78 | snd_soc_dapm_new_controls(codec, e800_dapm_widgets, |
37 | .stream_name = "AC97 Aux", | 79 | ARRAY_SIZE(e800_dapm_widgets)); |
38 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | 80 | |
39 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | 81 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
40 | }, | 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 | }, | ||
41 | }; | 101 | }; |
42 | 102 | ||
43 | static struct snd_soc_card e800 = { | 103 | static struct snd_soc_card e800 = { |
@@ -61,6 +121,22 @@ static int __init e800_init(void) | |||
61 | if (!machine_is_e800()) | 121 | if (!machine_is_e800()) |
62 | return -ENODEV; | 122 | return -ENODEV; |
63 | 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 | |||
64 | e800_snd_device = platform_device_alloc("soc-audio", -1); | 140 | e800_snd_device = platform_device_alloc("soc-audio", -1); |
65 | if (!e800_snd_device) | 141 | if (!e800_snd_device) |
66 | return -ENOMEM; | 142 | return -ENOMEM; |
@@ -69,8 +145,15 @@ static int __init e800_init(void) | |||
69 | e800_snd_devdata.dev = &e800_snd_device->dev; | 145 | e800_snd_devdata.dev = &e800_snd_device->dev; |
70 | ret = platform_device_add(e800_snd_device); | 146 | ret = platform_device_add(e800_snd_device); |
71 | 147 | ||
72 | if (ret) | 148 | if (!ret) |
73 | 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); | ||
74 | 157 | ||
75 | return ret; | 158 | return ret; |
76 | } | 159 | } |
@@ -78,6 +161,8 @@ static int __init e800_init(void) | |||
78 | static void __exit e800_exit(void) | 161 | static void __exit e800_exit(void) |
79 | { | 162 | { |
80 | 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); | ||
81 | } | 166 | } |
82 | 167 | ||
83 | module_init(e800_init); | 168 | module_init(e800_init); |
@@ -86,4 +171,4 @@ module_exit(e800_exit); | |||
86 | /* Module information */ | 171 | /* Module information */ |
87 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | 172 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); |
88 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); | 173 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); |
89 | 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 6e9827189fff..ef7c6c8dc8f1 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> |
@@ -77,7 +78,7 @@ static void poodle_ext_control(struct snd_soc_codec *codec) | |||
77 | static int poodle_startup(struct snd_pcm_substream *substream) | 78 | static int poodle_startup(struct snd_pcm_substream *substream) |
78 | { | 79 | { |
79 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 80 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
80 | struct snd_soc_codec *codec = rtd->socdev->codec; | 81 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
81 | 82 | ||
82 | /* check the jack status at stream startup */ | 83 | /* check the jack status at stream startup */ |
83 | poodle_ext_control(codec); | 84 | poodle_ext_control(codec); |
@@ -240,19 +241,17 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = { | |||
240 | */ | 241 | */ |
241 | static int poodle_wm8731_init(struct snd_soc_codec *codec) | 242 | static int poodle_wm8731_init(struct snd_soc_codec *codec) |
242 | { | 243 | { |
243 | int i, err; | 244 | int err; |
244 | 245 | ||
245 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); | 246 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); |
246 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); | 247 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); |
247 | snd_soc_dapm_enable_pin(codec, "MICIN"); | 248 | snd_soc_dapm_enable_pin(codec, "MICIN"); |
248 | 249 | ||
249 | /* Add poodle specific controls */ | 250 | /* Add poodle specific controls */ |
250 | for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) { | 251 | err = snd_soc_add_controls(codec, wm8731_poodle_controls, |
251 | err = snd_ctl_add(codec->card, | 252 | ARRAY_SIZE(wm8731_poodle_controls)); |
252 | snd_soc_cnew(&wm8731_poodle_controls[i], codec, NULL)); | 253 | if (err < 0) |
253 | if (err < 0) | 254 | return err; |
254 | return err; | ||
255 | } | ||
256 | 255 | ||
257 | /* Add poodle specific widgets */ | 256 | /* Add poodle specific widgets */ |
258 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, | 257 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
@@ -283,17 +282,42 @@ static struct snd_soc_card snd_soc_poodle = { | |||
283 | .num_links = 1, | 282 | .num_links = 1, |
284 | }; | 283 | }; |
285 | 284 | ||
286 | /* poodle audio private data */ | 285 | /* |
287 | static struct wm8731_setup_data poodle_wm8731_setup = { | 286 | * FIXME: This is a temporary bodge to avoid cross-tree merge issues. |
288 | .i2c_bus = 0, | 287 | * New drivers should register the wm8731 I2C device in the machine |
289 | .i2c_address = 0x1b, | 288 | * setup code (under arch/arm for ARM systems). |
290 | }; | 289 | */ |
290 | static int wm8731_i2c_register(void) | ||
291 | { | ||
292 | struct i2c_board_info info; | ||
293 | struct i2c_adapter *adapter; | ||
294 | struct i2c_client *client; | ||
295 | |||
296 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
297 | info.addr = 0x1b; | ||
298 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
299 | |||
300 | adapter = i2c_get_adapter(0); | ||
301 | if (!adapter) { | ||
302 | printk(KERN_ERR "can't get i2c adapter 0\n"); | ||
303 | return -ENODEV; | ||
304 | } | ||
305 | |||
306 | client = i2c_new_device(adapter, &info); | ||
307 | i2c_put_adapter(adapter); | ||
308 | if (!client) { | ||
309 | printk(KERN_ERR "can't add i2c device at 0x%x\n", | ||
310 | (unsigned int)info.addr); | ||
311 | return -ENODEV; | ||
312 | } | ||
313 | |||
314 | return 0; | ||
315 | } | ||
291 | 316 | ||
292 | /* poodle audio subsystem */ | 317 | /* poodle audio subsystem */ |
293 | static struct snd_soc_device poodle_snd_devdata = { | 318 | static struct snd_soc_device poodle_snd_devdata = { |
294 | .card = &snd_soc_poodle, | 319 | .card = &snd_soc_poodle, |
295 | .codec_dev = &soc_codec_dev_wm8731, | 320 | .codec_dev = &soc_codec_dev_wm8731, |
296 | .codec_data = &poodle_wm8731_setup, | ||
297 | }; | 321 | }; |
298 | 322 | ||
299 | static struct platform_device *poodle_snd_device; | 323 | static struct platform_device *poodle_snd_device; |
@@ -305,6 +329,10 @@ static int __init poodle_init(void) | |||
305 | if (!machine_is_poodle()) | 329 | if (!machine_is_poodle()) |
306 | return -ENODEV; | 330 | return -ENODEV; |
307 | 331 | ||
332 | ret = wm8731_i2c_register(); | ||
333 | if (ret != 0) | ||
334 | return ret; | ||
335 | |||
308 | locomo_gpio_set_dir(&poodle_locomo_device.dev, | 336 | locomo_gpio_set_dir(&poodle_locomo_device.dev, |
309 | POODLE_LOCOMO_GPIO_AMP_ON, 0); | 337 | POODLE_LOCOMO_GPIO_AMP_ON, 0); |
310 | /* should we mute HP at startup - burning power ?*/ | 338 | /* 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 73cb6b4c2f2d..b0bf40973d5b 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 812c2b4d3e07..01c21c6cdbbc 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 517991fb1099..e6c24408c5f9 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/pxa-regs.h> | 27 | #include <mach/pxa-regs.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 a3b9e6bdf979..6ca9f53080c6 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
@@ -109,7 +109,7 @@ static void spitz_ext_control(struct snd_soc_codec *codec) | |||
109 | static int spitz_startup(struct snd_pcm_substream *substream) | 109 | static int spitz_startup(struct snd_pcm_substream *substream) |
110 | { | 110 | { |
111 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 111 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
112 | struct snd_soc_codec *codec = rtd->socdev->codec; | 112 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
113 | 113 | ||
114 | /* check the jack status at stream startup */ | 114 | /* check the jack status at stream startup */ |
115 | spitz_ext_control(codec); | 115 | spitz_ext_control(codec); |
@@ -278,7 +278,7 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = { | |||
278 | */ | 278 | */ |
279 | static int spitz_wm8750_init(struct snd_soc_codec *codec) | 279 | static int spitz_wm8750_init(struct snd_soc_codec *codec) |
280 | { | 280 | { |
281 | int i, err; | 281 | int err; |
282 | 282 | ||
283 | /* NC codec pins */ | 283 | /* NC codec pins */ |
284 | snd_soc_dapm_nc_pin(codec, "RINPUT1"); | 284 | snd_soc_dapm_nc_pin(codec, "RINPUT1"); |
@@ -290,12 +290,10 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) | |||
290 | snd_soc_dapm_nc_pin(codec, "MONO1"); | 290 | snd_soc_dapm_nc_pin(codec, "MONO1"); |
291 | 291 | ||
292 | /* Add spitz specific controls */ | 292 | /* Add spitz specific controls */ |
293 | for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { | 293 | err = snd_soc_add_controls(codec, wm8750_spitz_controls, |
294 | err = snd_ctl_add(codec->card, | 294 | ARRAY_SIZE(wm8750_spitz_controls)); |
295 | snd_soc_cnew(&wm8750_spitz_controls[i], codec, NULL)); | 295 | if (err < 0) |
296 | if (err < 0) | 296 | return err; |
297 | return err; | ||
298 | } | ||
299 | 297 | ||
300 | /* Add spitz specific widgets */ | 298 | /* Add spitz specific widgets */ |
301 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, | 299 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, |
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index c77194f74c9b..fc781374b1bf 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
@@ -82,7 +82,7 @@ static void tosa_ext_control(struct snd_soc_codec *codec) | |||
82 | static int tosa_startup(struct snd_pcm_substream *substream) | 82 | static int tosa_startup(struct snd_pcm_substream *substream) |
83 | { | 83 | { |
84 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 84 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
85 | struct snd_soc_codec *codec = rtd->socdev->codec; | 85 | struct snd_soc_codec *codec = rtd->socdev->card->codec; |
86 | 86 | ||
87 | /* check the jack status at stream startup */ | 87 | /* check the jack status at stream startup */ |
88 | tosa_ext_control(codec); | 88 | tosa_ext_control(codec); |
@@ -188,18 +188,16 @@ static const struct snd_kcontrol_new tosa_controls[] = { | |||
188 | 188 | ||
189 | static int tosa_ac97_init(struct snd_soc_codec *codec) | 189 | static int tosa_ac97_init(struct snd_soc_codec *codec) |
190 | { | 190 | { |
191 | int i, err; | 191 | int err; |
192 | 192 | ||
193 | snd_soc_dapm_nc_pin(codec, "OUT3"); | 193 | snd_soc_dapm_nc_pin(codec, "OUT3"); |
194 | snd_soc_dapm_nc_pin(codec, "MONOOUT"); | 194 | snd_soc_dapm_nc_pin(codec, "MONOOUT"); |
195 | 195 | ||
196 | /* add tosa specific controls */ | 196 | /* add tosa specific controls */ |
197 | for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { | 197 | err = snd_soc_add_controls(codec, tosa_controls, |
198 | err = snd_ctl_add(codec->card, | 198 | ARRAY_SIZE(tosa_controls)); |
199 | snd_soc_cnew(&tosa_controls[i],codec, NULL)); | 199 | if (err < 0) |
200 | if (err < 0) | 200 | return err; |
201 | return err; | ||
202 | } | ||
203 | 201 | ||
204 | /* add tosa specific widgets */ | 202 | /* add tosa specific widgets */ |
205 | snd_soc_dapm_new_controls(codec, tosa_dapm_widgets, | 203 | 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), |
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index fcd03acf10f6..2f3a21eee051 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
@@ -1,19 +1,31 @@ | |||
1 | config SND_S3C24XX_SOC | 1 | config SND_S3C24XX_SOC |
2 | tristate "SoC Audio for the Samsung S3C24XX chips" | 2 | tristate "SoC Audio for the Samsung S3CXXXX chips" |
3 | depends on ARCH_S3C2410 | 3 | depends on ARCH_S3C2410 || ARCH_S3C64XX |
4 | help | 4 | help |
5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
6 | the S3C24XX AC97, I2S or SSP interface. You will also need | 6 | the S3C24XX and S3C64XX AC97, I2S or SSP interface. You will |
7 | to select the audio interfaces to support below. | 7 | also need to select the audio interfaces to support below. |
8 | 8 | ||
9 | config SND_S3C24XX_SOC_I2S | 9 | config SND_S3C24XX_SOC_I2S |
10 | tristate | 10 | tristate |
11 | select S3C2410_DMA | ||
12 | |||
13 | config SND_S3C_I2SV2_SOC | ||
14 | tristate | ||
11 | 15 | ||
12 | config SND_S3C2412_SOC_I2S | 16 | config SND_S3C2412_SOC_I2S |
13 | tristate | 17 | tristate |
18 | select SND_S3C_I2SV2_SOC | ||
19 | select S3C2410_DMA | ||
20 | |||
21 | config SND_S3C64XX_SOC_I2S | ||
22 | tristate | ||
23 | select SND_S3C_I2SV2_SOC | ||
24 | select S3C64XX_DMA | ||
14 | 25 | ||
15 | config SND_S3C2443_SOC_AC97 | 26 | config SND_S3C2443_SOC_AC97 |
16 | tristate | 27 | tristate |
28 | select S3C2410_DMA | ||
17 | select AC97_BUS | 29 | select AC97_BUS |
18 | select SND_SOC_AC97_BUS | 30 | select SND_SOC_AC97_BUS |
19 | 31 | ||
@@ -26,6 +38,14 @@ config SND_S3C24XX_SOC_NEO1973_WM8753 | |||
26 | Say Y if you want to add support for SoC audio on smdk2440 | 38 | Say Y if you want to add support for SoC audio on smdk2440 |
27 | with the WM8753. | 39 | with the WM8753. |
28 | 40 | ||
41 | config SND_S3C24XX_SOC_JIVE_WM8750 | ||
42 | tristate "SoC I2S Audio support for Jive" | ||
43 | depends on SND_S3C24XX_SOC && MACH_JIVE | ||
44 | select SND_SOC_WM8750 | ||
45 | select SND_S3C2412_SOC_I2S | ||
46 | help | ||
47 | Sat Y if you want to add support for SoC audio on the Jive. | ||
48 | |||
29 | config SND_S3C24XX_SOC_SMDK2443_WM9710 | 49 | config SND_S3C24XX_SOC_SMDK2443_WM9710 |
30 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" | 50 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" |
31 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 | 51 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 |
@@ -48,4 +68,5 @@ config SND_S3C24XX_SOC_S3C24XX_UDA134X | |||
48 | tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" | 68 | tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" |
49 | depends on SND_S3C24XX_SOC | 69 | depends on SND_S3C24XX_SOC |
50 | select SND_S3C24XX_SOC_I2S | 70 | select SND_S3C24XX_SOC_I2S |
71 | select SND_SOC_L3 | ||
51 | select SND_SOC_UDA134X | 72 | select SND_SOC_UDA134X |
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 96b3f3f617d4..07a93a2ebe5f 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile | |||
@@ -2,19 +2,25 @@ | |||
2 | snd-soc-s3c24xx-objs := s3c24xx-pcm.o | 2 | snd-soc-s3c24xx-objs := s3c24xx-pcm.o |
3 | snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o | 3 | snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o |
4 | snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o | 4 | snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o |
5 | snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o | ||
5 | snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o | 6 | snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o |
7 | snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o | ||
6 | 8 | ||
7 | obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o | 9 | obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o |
8 | obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o | 10 | obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o |
9 | obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o | 11 | obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o |
10 | obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o | 12 | obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o |
13 | obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o | ||
14 | obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o | ||
11 | 15 | ||
12 | # S3C24XX Machine Support | 16 | # S3C24XX Machine Support |
17 | snd-soc-jive-wm8750-objs := jive_wm8750.o | ||
13 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o | 18 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o |
14 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o | 19 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o |
15 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o | 20 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o |
16 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o | 21 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o |
17 | 22 | ||
23 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o | ||
18 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 24 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
19 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o | 25 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o |
20 | obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o | 26 | obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o |
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c new file mode 100644 index 000000000000..32063790d95b --- /dev/null +++ b/sound/soc/s3c24xx/jive_wm8750.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* sound/soc/s3c24xx/jive_wm8750.c | ||
2 | * | ||
3 | * Copyright 2007,2008 Simtec Electronics | ||
4 | * | ||
5 | * Based on sound/soc/pxa/spitz.c | ||
6 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
7 | * Copyright 2005 Openedhand Ltd. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/timer.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/clk.h> | ||
20 | |||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/soc-dapm.h> | ||
25 | |||
26 | #include <asm/mach-types.h> | ||
27 | |||
28 | #include "s3c24xx-pcm.h" | ||
29 | #include "s3c2412-i2s.h" | ||
30 | |||
31 | #include "../codecs/wm8750.h" | ||
32 | |||
33 | static const struct snd_soc_dapm_route audio_map[] = { | ||
34 | { "Headphone Jack", NULL, "LOUT1" }, | ||
35 | { "Headphone Jack", NULL, "ROUT1" }, | ||
36 | { "Internal Speaker", NULL, "LOUT2" }, | ||
37 | { "Internal Speaker", NULL, "ROUT2" }, | ||
38 | { "LINPUT1", NULL, "Line Input" }, | ||
39 | { "RINPUT1", NULL, "Line Input" }, | ||
40 | }; | ||
41 | |||
42 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | ||
43 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
44 | SND_SOC_DAPM_SPK("Internal Speaker", NULL), | ||
45 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
46 | }; | ||
47 | |||
48 | static int jive_hw_params(struct snd_pcm_substream *substream, | ||
49 | struct snd_pcm_hw_params *params) | ||
50 | { | ||
51 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
52 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
53 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
54 | struct s3c_i2sv2_rate_calc div; | ||
55 | unsigned int clk = 0; | ||
56 | int ret = 0; | ||
57 | |||
58 | switch (params_rate(params)) { | ||
59 | case 8000: | ||
60 | case 16000: | ||
61 | case 48000: | ||
62 | case 96000: | ||
63 | clk = 12288000; | ||
64 | break; | ||
65 | case 11025: | ||
66 | case 22050: | ||
67 | case 44100: | ||
68 | clk = 11289600; | ||
69 | break; | ||
70 | } | ||
71 | |||
72 | s3c_i2sv2_calc_rate(&div, NULL, params_rate(params), | ||
73 | s3c2412_get_iisclk()); | ||
74 | |||
75 | /* set codec DAI configuration */ | ||
76 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
77 | SND_SOC_DAIFMT_NB_NF | | ||
78 | SND_SOC_DAIFMT_CBS_CFS); | ||
79 | if (ret < 0) | ||
80 | return ret; | ||
81 | |||
82 | /* set cpu DAI configuration */ | ||
83 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
84 | SND_SOC_DAIFMT_NB_NF | | ||
85 | SND_SOC_DAIFMT_CBS_CFS); | ||
86 | if (ret < 0) | ||
87 | return ret; | ||
88 | |||
89 | /* set the codec system clock for DAC and ADC */ | ||
90 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, | ||
91 | SND_SOC_CLOCK_IN); | ||
92 | if (ret < 0) | ||
93 | return ret; | ||
94 | |||
95 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div); | ||
96 | if (ret < 0) | ||
97 | return ret; | ||
98 | |||
99 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER, | ||
100 | div.clk_div - 1); | ||
101 | if (ret < 0) | ||
102 | return ret; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static struct snd_soc_ops jive_ops = { | ||
108 | .hw_params = jive_hw_params, | ||
109 | }; | ||
110 | |||
111 | static int jive_wm8750_init(struct snd_soc_codec *codec) | ||
112 | { | ||
113 | int err; | ||
114 | |||
115 | /* These endpoints are not being used. */ | ||
116 | snd_soc_dapm_nc_pin(codec, "LINPUT2"); | ||
117 | snd_soc_dapm_nc_pin(codec, "RINPUT2"); | ||
118 | snd_soc_dapm_nc_pin(codec, "LINPUT3"); | ||
119 | snd_soc_dapm_nc_pin(codec, "RINPUT3"); | ||
120 | snd_soc_dapm_nc_pin(codec, "OUT3"); | ||
121 | snd_soc_dapm_nc_pin(codec, "MONO"); | ||
122 | |||
123 | /* Add jive specific widgets */ | ||
124 | err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, | ||
125 | ARRAY_SIZE(wm8750_dapm_widgets)); | ||
126 | if (err) { | ||
127 | printk(KERN_ERR "%s: failed to add widgets (%d)\n", | ||
128 | __func__, err); | ||
129 | return err; | ||
130 | } | ||
131 | |||
132 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
133 | snd_soc_dapm_sync(codec); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static struct snd_soc_dai_link jive_dai = { | ||
139 | .name = "wm8750", | ||
140 | .stream_name = "WM8750", | ||
141 | .cpu_dai = &s3c2412_i2s_dai, | ||
142 | .codec_dai = &wm8750_dai, | ||
143 | .init = jive_wm8750_init, | ||
144 | .ops = &jive_ops, | ||
145 | }; | ||
146 | |||
147 | /* jive audio machine driver */ | ||
148 | static struct snd_soc_machine snd_soc_machine_jive = { | ||
149 | .name = "Jive", | ||
150 | .dai_link = &jive_dai, | ||
151 | .num_links = 1, | ||
152 | }; | ||
153 | |||
154 | /* jive audio private data */ | ||
155 | static struct wm8750_setup_data jive_wm8750_setup = { | ||
156 | }; | ||
157 | |||
158 | /* jive audio subsystem */ | ||
159 | static struct snd_soc_device jive_snd_devdata = { | ||
160 | .machine = &snd_soc_machine_jive, | ||
161 | .platform = &s3c24xx_soc_platform, | ||
162 | .codec_dev = &soc_codec_dev_wm8750_spi, | ||
163 | .codec_data = &jive_wm8750_setup, | ||
164 | }; | ||
165 | |||
166 | static struct platform_device *jive_snd_device; | ||
167 | |||
168 | static int __init jive_init(void) | ||
169 | { | ||
170 | int ret; | ||
171 | |||
172 | if (!machine_is_jive()) | ||
173 | return 0; | ||
174 | |||
175 | printk("JIVE WM8750 Audio support\n"); | ||
176 | |||
177 | jive_snd_device = platform_device_alloc("soc-audio", -1); | ||
178 | if (!jive_snd_device) | ||
179 | return -ENOMEM; | ||
180 | |||
181 | platform_set_drvdata(jive_snd_device, &jive_snd_devdata); | ||
182 | jive_snd_devdata.dev = &jive_snd_device->dev; | ||
183 | ret = platform_device_add(jive_snd_device); | ||
184 | |||
185 | if (ret) | ||
186 | platform_device_put(jive_snd_device); | ||
187 | |||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | static void __exit jive_exit(void) | ||
192 | { | ||
193 | platform_device_unregister(jive_snd_device); | ||
194 | } | ||
195 | |||
196 | module_init(jive_init); | ||
197 | module_exit(jive_exit); | ||
198 | |||
199 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
200 | MODULE_DESCRIPTION("ALSA SoC Jive Audio support"); | ||
201 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 45bb12e8ea44..289fadf60b10 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
@@ -29,25 +29,17 @@ | |||
29 | #include <mach/regs-clock.h> | 29 | #include <mach/regs-clock.h> |
30 | #include <mach/regs-gpio.h> | 30 | #include <mach/regs-gpio.h> |
31 | #include <mach/hardware.h> | 31 | #include <mach/hardware.h> |
32 | #include <mach/audio.h> | 32 | #include <plat/audio.h> |
33 | #include <linux/io.h> | 33 | #include <linux/io.h> |
34 | #include <mach/spi-gpio.h> | 34 | #include <mach/spi-gpio.h> |
35 | 35 | ||
36 | #include <asm/plat-s3c24xx/regs-iis.h> | 36 | #include <plat/regs-iis.h> |
37 | 37 | ||
38 | #include "../codecs/wm8753.h" | 38 | #include "../codecs/wm8753.h" |
39 | #include "lm4857.h" | 39 | #include "lm4857.h" |
40 | #include "s3c24xx-pcm.h" | 40 | #include "s3c24xx-pcm.h" |
41 | #include "s3c24xx-i2s.h" | 41 | #include "s3c24xx-i2s.h" |
42 | 42 | ||
43 | /* Debugging stuff */ | ||
44 | #define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0 | ||
45 | #if S3C24XX_SOC_NEO1973_WM8753_DEBUG | ||
46 | #define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x) | ||
47 | #else | ||
48 | #define DBG(x...) | ||
49 | #endif | ||
50 | |||
51 | /* define the scenarios */ | 43 | /* define the scenarios */ |
52 | #define NEO_AUDIO_OFF 0 | 44 | #define NEO_AUDIO_OFF 0 |
53 | #define NEO_GSM_CALL_AUDIO_HANDSET 1 | 45 | #define NEO_GSM_CALL_AUDIO_HANDSET 1 |
@@ -72,7 +64,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
72 | int ret = 0; | 64 | int ret = 0; |
73 | unsigned long iis_clkrate; | 65 | unsigned long iis_clkrate; |
74 | 66 | ||
75 | DBG("Entered %s\n", __func__); | 67 | pr_debug("Entered %s\n", __func__); |
76 | 68 | ||
77 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 69 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
78 | 70 | ||
@@ -158,7 +150,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) | |||
158 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 150 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
159 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 151 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
160 | 152 | ||
161 | DBG("Entered %s\n", __func__); | 153 | pr_debug("Entered %s\n", __func__); |
162 | 154 | ||
163 | /* disable the PLL */ | 155 | /* disable the PLL */ |
164 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); | 156 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); |
@@ -181,7 +173,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
181 | int ret = 0; | 173 | int ret = 0; |
182 | unsigned long iis_clkrate; | 174 | unsigned long iis_clkrate; |
183 | 175 | ||
184 | DBG("Entered %s\n", __func__); | 176 | pr_debug("Entered %s\n", __func__); |
185 | 177 | ||
186 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 178 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
187 | 179 | ||
@@ -224,7 +216,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) | |||
224 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 216 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
225 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 217 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
226 | 218 | ||
227 | DBG("Entered %s\n", __func__); | 219 | pr_debug("Entered %s\n", __func__); |
228 | 220 | ||
229 | /* disable the PLL */ | 221 | /* disable the PLL */ |
230 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); | 222 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); |
@@ -246,7 +238,7 @@ static int neo1973_get_scenario(struct snd_kcontrol *kcontrol, | |||
246 | 238 | ||
247 | static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) | 239 | static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) |
248 | { | 240 | { |
249 | DBG("Entered %s\n", __func__); | 241 | pr_debug("Entered %s\n", __func__); |
250 | 242 | ||
251 | switch (neo1973_scenario) { | 243 | switch (neo1973_scenario) { |
252 | case NEO_AUDIO_OFF: | 244 | case NEO_AUDIO_OFF: |
@@ -330,7 +322,7 @@ static int neo1973_set_scenario(struct snd_kcontrol *kcontrol, | |||
330 | { | 322 | { |
331 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 323 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
332 | 324 | ||
333 | DBG("Entered %s\n", __func__); | 325 | pr_debug("Entered %s\n", __func__); |
334 | 326 | ||
335 | if (neo1973_scenario == ucontrol->value.integer.value[0]) | 327 | if (neo1973_scenario == ucontrol->value.integer.value[0]) |
336 | return 0; | 328 | return 0; |
@@ -344,7 +336,7 @@ static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0}; | |||
344 | 336 | ||
345 | static void lm4857_write_regs(void) | 337 | static void lm4857_write_regs(void) |
346 | { | 338 | { |
347 | DBG("Entered %s\n", __func__); | 339 | pr_debug("Entered %s\n", __func__); |
348 | 340 | ||
349 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) | 341 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) |
350 | printk(KERN_ERR "lm4857: i2c write failed\n"); | 342 | printk(KERN_ERR "lm4857: i2c write failed\n"); |
@@ -357,7 +349,7 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol, | |||
357 | int shift = (kcontrol->private_value >> 8) & 0x0F; | 349 | int shift = (kcontrol->private_value >> 8) & 0x0F; |
358 | int mask = (kcontrol->private_value >> 16) & 0xFF; | 350 | int mask = (kcontrol->private_value >> 16) & 0xFF; |
359 | 351 | ||
360 | DBG("Entered %s\n", __func__); | 352 | pr_debug("Entered %s\n", __func__); |
361 | 353 | ||
362 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; | 354 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; |
363 | return 0; | 355 | return 0; |
@@ -385,7 +377,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | |||
385 | { | 377 | { |
386 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; | 378 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; |
387 | 379 | ||
388 | DBG("Entered %s\n", __func__); | 380 | pr_debug("Entered %s\n", __func__); |
389 | 381 | ||
390 | if (value) | 382 | if (value) |
391 | value -= 5; | 383 | value -= 5; |
@@ -399,7 +391,7 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | |||
399 | { | 391 | { |
400 | u8 value = ucontrol->value.integer.value[0]; | 392 | u8 value = ucontrol->value.integer.value[0]; |
401 | 393 | ||
402 | DBG("Entered %s\n", __func__); | 394 | pr_debug("Entered %s\n", __func__); |
403 | 395 | ||
404 | if (value) | 396 | if (value) |
405 | value += 5; | 397 | value += 5; |
@@ -506,9 +498,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { | |||
506 | */ | 498 | */ |
507 | static int neo1973_wm8753_init(struct snd_soc_codec *codec) | 499 | static int neo1973_wm8753_init(struct snd_soc_codec *codec) |
508 | { | 500 | { |
509 | int i, err; | 501 | int err; |
510 | 502 | ||
511 | DBG("Entered %s\n", __func__); | 503 | pr_debug("Entered %s\n", __func__); |
512 | 504 | ||
513 | /* set up NC codec pins */ | 505 | /* set up NC codec pins */ |
514 | snd_soc_dapm_nc_pin(codec, "LOUT2"); | 506 | snd_soc_dapm_nc_pin(codec, "LOUT2"); |
@@ -526,13 +518,10 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) | |||
526 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); | 518 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); |
527 | 519 | ||
528 | /* add neo1973 specific controls */ | 520 | /* add neo1973 specific controls */ |
529 | for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { | 521 | err = snd_soc_add_controls(codec, wm8753_neo1973_controls, |
530 | err = snd_ctl_add(codec->card, | 522 | ARRAY_SIZE(8753_neo1973_controls)); |
531 | snd_soc_cnew(&wm8753_neo1973_controls[i], | 523 | if (err < 0) |
532 | codec, NULL)); | 524 | return err; |
533 | if (err < 0) | ||
534 | return err; | ||
535 | } | ||
536 | 525 | ||
537 | /* set up neo1973 specific audio routes */ | 526 | /* set up neo1973 specific audio routes */ |
538 | err = snd_soc_dapm_add_routes(codec, dapm_routes, | 527 | err = snd_soc_dapm_add_routes(codec, dapm_routes, |
@@ -585,21 +574,15 @@ static struct snd_soc_card neo1973 = { | |||
585 | .num_links = ARRAY_SIZE(neo1973_dai), | 574 | .num_links = ARRAY_SIZE(neo1973_dai), |
586 | }; | 575 | }; |
587 | 576 | ||
588 | static struct wm8753_setup_data neo1973_wm8753_setup = { | ||
589 | .i2c_bus = 0, | ||
590 | .i2c_address = 0x1a, | ||
591 | }; | ||
592 | |||
593 | static struct snd_soc_device neo1973_snd_devdata = { | 577 | static struct snd_soc_device neo1973_snd_devdata = { |
594 | .card = &neo1973, | 578 | .card = &neo1973, |
595 | .codec_dev = &soc_codec_dev_wm8753, | 579 | .codec_dev = &soc_codec_dev_wm8753, |
596 | .codec_data = &neo1973_wm8753_setup, | ||
597 | }; | 580 | }; |
598 | 581 | ||
599 | static int lm4857_i2c_probe(struct i2c_client *client, | 582 | static int lm4857_i2c_probe(struct i2c_client *client, |
600 | const struct i2c_device_id *id) | 583 | const struct i2c_device_id *id) |
601 | { | 584 | { |
602 | DBG("Entered %s\n", __func__); | 585 | pr_debug("Entered %s\n", __func__); |
603 | 586 | ||
604 | i2c = client; | 587 | i2c = client; |
605 | 588 | ||
@@ -609,7 +592,7 @@ static int lm4857_i2c_probe(struct i2c_client *client, | |||
609 | 592 | ||
610 | static int lm4857_i2c_remove(struct i2c_client *client) | 593 | static int lm4857_i2c_remove(struct i2c_client *client) |
611 | { | 594 | { |
612 | DBG("Entered %s\n", __func__); | 595 | pr_debug("Entered %s\n", __func__); |
613 | 596 | ||
614 | i2c = NULL; | 597 | i2c = NULL; |
615 | 598 | ||
@@ -620,7 +603,7 @@ static u8 lm4857_state; | |||
620 | 603 | ||
621 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | 604 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) |
622 | { | 605 | { |
623 | DBG("Entered %s\n", __func__); | 606 | pr_debug("Entered %s\n", __func__); |
624 | 607 | ||
625 | dev_dbg(&dev->dev, "lm4857_suspend\n"); | 608 | dev_dbg(&dev->dev, "lm4857_suspend\n"); |
626 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; | 609 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; |
@@ -633,7 +616,7 @@ static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | |||
633 | 616 | ||
634 | static int lm4857_resume(struct i2c_client *dev) | 617 | static int lm4857_resume(struct i2c_client *dev) |
635 | { | 618 | { |
636 | DBG("Entered %s\n", __func__); | 619 | pr_debug("Entered %s\n", __func__); |
637 | 620 | ||
638 | if (lm4857_state) { | 621 | if (lm4857_state) { |
639 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); | 622 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); |
@@ -644,7 +627,7 @@ static int lm4857_resume(struct i2c_client *dev) | |||
644 | 627 | ||
645 | static void lm4857_shutdown(struct i2c_client *dev) | 628 | static void lm4857_shutdown(struct i2c_client *dev) |
646 | { | 629 | { |
647 | DBG("Entered %s\n", __func__); | 630 | pr_debug("Entered %s\n", __func__); |
648 | 631 | ||
649 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); | 632 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); |
650 | lm4857_regs[LM4857_CTRL] &= 0xf0; | 633 | lm4857_regs[LM4857_CTRL] &= 0xf0; |
@@ -675,7 +658,7 @@ static int __init neo1973_init(void) | |||
675 | { | 658 | { |
676 | int ret; | 659 | int ret; |
677 | 660 | ||
678 | DBG("Entered %s\n", __func__); | 661 | pr_debug("Entered %s\n", __func__); |
679 | 662 | ||
680 | if (!machine_is_neo1973_gta01()) { | 663 | if (!machine_is_neo1973_gta01()) { |
681 | printk(KERN_INFO | 664 | printk(KERN_INFO |
@@ -706,7 +689,7 @@ static int __init neo1973_init(void) | |||
706 | 689 | ||
707 | static void __exit neo1973_exit(void) | 690 | static void __exit neo1973_exit(void) |
708 | { | 691 | { |
709 | DBG("Entered %s\n", __func__); | 692 | pr_debug("Entered %s\n", __func__); |
710 | 693 | ||
711 | i2c_del_driver(&lm4857_i2c_driver); | 694 | i2c_del_driver(&lm4857_i2c_driver); |
712 | platform_device_unregister(neo1973_snd_device); | 695 | platform_device_unregister(neo1973_snd_device); |
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c new file mode 100644 index 000000000000..295a4c910262 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c | |||
@@ -0,0 +1,638 @@ | |||
1 | /* sound/soc/s3c24xx/s3c-i2c-v2.c | ||
2 | * | ||
3 | * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs. | ||
4 | * | ||
5 | * Copyright (c) 2006 Wolfson Microelectronics PLC. | ||
6 | * Graeme Gregory graeme.gregory@wolfsonmicro.com | ||
7 | * linux@wolfsonmicro.com | ||
8 | * | ||
9 | * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics | ||
10 | * http://armlinux.simtec.co.uk/ | ||
11 | * Ben Dooks <ben@simtec.co.uk> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/init.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/pcm_params.h> | ||
30 | #include <sound/initval.h> | ||
31 | #include <sound/soc.h> | ||
32 | |||
33 | #include <plat/regs-s3c2412-iis.h> | ||
34 | |||
35 | #include <plat/audio.h> | ||
36 | #include <mach/dma.h> | ||
37 | |||
38 | #include "s3c-i2s-v2.h" | ||
39 | |||
40 | #define S3C2412_I2S_DEBUG_CON 0 | ||
41 | |||
42 | static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) | ||
43 | { | ||
44 | return cpu_dai->private_data; | ||
45 | } | ||
46 | |||
47 | #define bit_set(v, b) (((v) & (b)) ? 1 : 0) | ||
48 | |||
49 | #if S3C2412_I2S_DEBUG_CON | ||
50 | static void dbg_showcon(const char *fn, u32 con) | ||
51 | { | ||
52 | printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn, | ||
53 | bit_set(con, S3C2412_IISCON_LRINDEX), | ||
54 | bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY), | ||
55 | bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY), | ||
56 | bit_set(con, S3C2412_IISCON_TXFIFO_FULL), | ||
57 | bit_set(con, S3C2412_IISCON_RXFIFO_FULL)); | ||
58 | |||
59 | printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n", | ||
60 | fn, | ||
61 | bit_set(con, S3C2412_IISCON_TXDMA_PAUSE), | ||
62 | bit_set(con, S3C2412_IISCON_RXDMA_PAUSE), | ||
63 | bit_set(con, S3C2412_IISCON_TXCH_PAUSE), | ||
64 | bit_set(con, S3C2412_IISCON_RXCH_PAUSE)); | ||
65 | printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn, | ||
66 | bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE), | ||
67 | bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE), | ||
68 | bit_set(con, S3C2412_IISCON_IIS_ACTIVE)); | ||
69 | } | ||
70 | #else | ||
71 | static inline void dbg_showcon(const char *fn, u32 con) | ||
72 | { | ||
73 | } | ||
74 | #endif | ||
75 | |||
76 | |||
77 | /* Turn on or off the transmission path. */ | ||
78 | void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) | ||
79 | { | ||
80 | void __iomem *regs = i2s->regs; | ||
81 | u32 fic, con, mod; | ||
82 | |||
83 | pr_debug("%s(%d)\n", __func__, on); | ||
84 | |||
85 | fic = readl(regs + S3C2412_IISFIC); | ||
86 | con = readl(regs + S3C2412_IISCON); | ||
87 | mod = readl(regs + S3C2412_IISMOD); | ||
88 | |||
89 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
90 | |||
91 | if (on) { | ||
92 | con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
93 | con &= ~S3C2412_IISCON_TXDMA_PAUSE; | ||
94 | con &= ~S3C2412_IISCON_TXCH_PAUSE; | ||
95 | |||
96 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
97 | case S3C2412_IISMOD_MODE_TXONLY: | ||
98 | case S3C2412_IISMOD_MODE_TXRX: | ||
99 | /* do nothing, we are in the right mode */ | ||
100 | break; | ||
101 | |||
102 | case S3C2412_IISMOD_MODE_RXONLY: | ||
103 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
104 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
105 | break; | ||
106 | |||
107 | default: | ||
108 | dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n"); | ||
109 | } | ||
110 | |||
111 | writel(con, regs + S3C2412_IISCON); | ||
112 | writel(mod, regs + S3C2412_IISMOD); | ||
113 | } else { | ||
114 | /* Note, we do not have any indication that the FIFO problems | ||
115 | * tha the S3C2410/2440 had apply here, so we should be able | ||
116 | * to disable the DMA and TX without resetting the FIFOS. | ||
117 | */ | ||
118 | |||
119 | con |= S3C2412_IISCON_TXDMA_PAUSE; | ||
120 | con |= S3C2412_IISCON_TXCH_PAUSE; | ||
121 | con &= ~S3C2412_IISCON_TXDMA_ACTIVE; | ||
122 | |||
123 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
124 | case S3C2412_IISMOD_MODE_TXRX: | ||
125 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
126 | mod |= S3C2412_IISMOD_MODE_RXONLY; | ||
127 | break; | ||
128 | |||
129 | case S3C2412_IISMOD_MODE_TXONLY: | ||
130 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
131 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
132 | break; | ||
133 | |||
134 | default: | ||
135 | dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n"); | ||
136 | } | ||
137 | |||
138 | writel(mod, regs + S3C2412_IISMOD); | ||
139 | writel(con, regs + S3C2412_IISCON); | ||
140 | } | ||
141 | |||
142 | fic = readl(regs + S3C2412_IISFIC); | ||
143 | dbg_showcon(__func__, con); | ||
144 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
145 | } | ||
146 | EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl); | ||
147 | |||
148 | void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) | ||
149 | { | ||
150 | void __iomem *regs = i2s->regs; | ||
151 | u32 fic, con, mod; | ||
152 | |||
153 | pr_debug("%s(%d)\n", __func__, on); | ||
154 | |||
155 | fic = readl(regs + S3C2412_IISFIC); | ||
156 | con = readl(regs + S3C2412_IISCON); | ||
157 | mod = readl(regs + S3C2412_IISMOD); | ||
158 | |||
159 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
160 | |||
161 | if (on) { | ||
162 | con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
163 | con &= ~S3C2412_IISCON_RXDMA_PAUSE; | ||
164 | con &= ~S3C2412_IISCON_RXCH_PAUSE; | ||
165 | |||
166 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
167 | case S3C2412_IISMOD_MODE_TXRX: | ||
168 | case S3C2412_IISMOD_MODE_RXONLY: | ||
169 | /* do nothing, we are in the right mode */ | ||
170 | break; | ||
171 | |||
172 | case S3C2412_IISMOD_MODE_TXONLY: | ||
173 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
174 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
175 | break; | ||
176 | |||
177 | default: | ||
178 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
179 | } | ||
180 | |||
181 | writel(mod, regs + S3C2412_IISMOD); | ||
182 | writel(con, regs + S3C2412_IISCON); | ||
183 | } else { | ||
184 | /* See txctrl notes on FIFOs. */ | ||
185 | |||
186 | con &= ~S3C2412_IISCON_RXDMA_ACTIVE; | ||
187 | con |= S3C2412_IISCON_RXDMA_PAUSE; | ||
188 | con |= S3C2412_IISCON_RXCH_PAUSE; | ||
189 | |||
190 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
191 | case S3C2412_IISMOD_MODE_RXONLY: | ||
192 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
193 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
194 | break; | ||
195 | |||
196 | case S3C2412_IISMOD_MODE_TXRX: | ||
197 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
198 | mod |= S3C2412_IISMOD_MODE_TXONLY; | ||
199 | break; | ||
200 | |||
201 | default: | ||
202 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
203 | } | ||
204 | |||
205 | writel(con, regs + S3C2412_IISCON); | ||
206 | writel(mod, regs + S3C2412_IISMOD); | ||
207 | } | ||
208 | |||
209 | fic = readl(regs + S3C2412_IISFIC); | ||
210 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
211 | } | ||
212 | EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl); | ||
213 | |||
214 | /* | ||
215 | * Wait for the LR signal to allow synchronisation to the L/R clock | ||
216 | * from the codec. May only be needed for slave mode. | ||
217 | */ | ||
218 | static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s) | ||
219 | { | ||
220 | u32 iiscon; | ||
221 | unsigned long timeout = jiffies + msecs_to_jiffies(5); | ||
222 | |||
223 | pr_debug("Entered %s\n", __func__); | ||
224 | |||
225 | while (1) { | ||
226 | iiscon = readl(i2s->regs + S3C2412_IISCON); | ||
227 | if (iiscon & S3C2412_IISCON_LRINDEX) | ||
228 | break; | ||
229 | |||
230 | if (timeout < jiffies) { | ||
231 | printk(KERN_ERR "%s: timeout\n", __func__); | ||
232 | return -ETIMEDOUT; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * Set S3C2412 I2S DAI format | ||
241 | */ | ||
242 | static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | ||
243 | unsigned int fmt) | ||
244 | { | ||
245 | struct s3c_i2sv2_info *i2s = to_info(cpu_dai); | ||
246 | u32 iismod; | ||
247 | |||
248 | pr_debug("Entered %s\n", __func__); | ||
249 | |||
250 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
251 | pr_debug("hw_params r: IISMOD: %x \n", iismod); | ||
252 | |||
253 | #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) | ||
254 | #define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK | ||
255 | #define IISMOD_SLAVE S3C2412_IISMOD_SLAVE | ||
256 | #define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL | ||
257 | #endif | ||
258 | |||
259 | #if defined(CONFIG_PLAT_S3C64XX) | ||
260 | /* From Rev1.1 datasheet, we have two master and two slave modes: | ||
261 | * IMS[11:10]: | ||
262 | * 00 = master mode, fed from PCLK | ||
263 | * 01 = master mode, fed from CLKAUDIO | ||
264 | * 10 = slave mode, using PCLK | ||
265 | * 11 = slave mode, using I2SCLK | ||
266 | */ | ||
267 | #define IISMOD_MASTER_MASK (1 << 11) | ||
268 | #define IISMOD_SLAVE (1 << 11) | ||
269 | #define IISMOD_MASTER (0x0) | ||
270 | #endif | ||
271 | |||
272 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
273 | case SND_SOC_DAIFMT_CBM_CFM: | ||
274 | i2s->master = 0; | ||
275 | iismod &= ~IISMOD_MASTER_MASK; | ||
276 | iismod |= IISMOD_SLAVE; | ||
277 | break; | ||
278 | case SND_SOC_DAIFMT_CBS_CFS: | ||
279 | i2s->master = 1; | ||
280 | iismod &= ~IISMOD_MASTER_MASK; | ||
281 | iismod |= IISMOD_MASTER; | ||
282 | break; | ||
283 | default: | ||
284 | pr_debug("unknwon master/slave format\n"); | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | |||
288 | iismod &= ~S3C2412_IISMOD_SDF_MASK; | ||
289 | |||
290 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
291 | case SND_SOC_DAIFMT_RIGHT_J: | ||
292 | iismod |= S3C2412_IISMOD_SDF_MSB; | ||
293 | break; | ||
294 | case SND_SOC_DAIFMT_LEFT_J: | ||
295 | iismod |= S3C2412_IISMOD_SDF_LSB; | ||
296 | break; | ||
297 | case SND_SOC_DAIFMT_I2S: | ||
298 | iismod |= S3C2412_IISMOD_SDF_IIS; | ||
299 | break; | ||
300 | default: | ||
301 | pr_debug("Unknown data format\n"); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | writel(iismod, i2s->regs + S3C2412_IISMOD); | ||
306 | pr_debug("hw_params w: IISMOD: %x \n", iismod); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | ||
311 | struct snd_pcm_hw_params *params, | ||
312 | struct snd_soc_dai *socdai) | ||
313 | { | ||
314 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
315 | struct snd_soc_dai_link *dai = rtd->dai; | ||
316 | struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai); | ||
317 | u32 iismod; | ||
318 | |||
319 | pr_debug("Entered %s\n", __func__); | ||
320 | |||
321 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
322 | dai->cpu_dai->dma_data = i2s->dma_playback; | ||
323 | else | ||
324 | dai->cpu_dai->dma_data = i2s->dma_capture; | ||
325 | |||
326 | /* Working copies of register */ | ||
327 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
328 | pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); | ||
329 | |||
330 | switch (params_format(params)) { | ||
331 | case SNDRV_PCM_FORMAT_S8: | ||
332 | iismod |= S3C2412_IISMOD_8BIT; | ||
333 | break; | ||
334 | case SNDRV_PCM_FORMAT_S16_LE: | ||
335 | iismod &= ~S3C2412_IISMOD_8BIT; | ||
336 | break; | ||
337 | } | ||
338 | |||
339 | writel(iismod, i2s->regs + S3C2412_IISMOD); | ||
340 | pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
345 | struct snd_soc_dai *dai) | ||
346 | { | ||
347 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
348 | struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai); | ||
349 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
350 | unsigned long irqs; | ||
351 | int ret = 0; | ||
352 | |||
353 | pr_debug("Entered %s\n", __func__); | ||
354 | |||
355 | switch (cmd) { | ||
356 | case SNDRV_PCM_TRIGGER_START: | ||
357 | /* On start, ensure that the FIFOs are cleared and reset. */ | ||
358 | |||
359 | writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH, | ||
360 | i2s->regs + S3C2412_IISFIC); | ||
361 | |||
362 | /* clear again, just in case */ | ||
363 | writel(0x0, i2s->regs + S3C2412_IISFIC); | ||
364 | |||
365 | case SNDRV_PCM_TRIGGER_RESUME: | ||
366 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
367 | if (!i2s->master) { | ||
368 | ret = s3c2412_snd_lrsync(i2s); | ||
369 | if (ret) | ||
370 | goto exit_err; | ||
371 | } | ||
372 | |||
373 | local_irq_save(irqs); | ||
374 | |||
375 | if (capture) | ||
376 | s3c2412_snd_rxctrl(i2s, 1); | ||
377 | else | ||
378 | s3c2412_snd_txctrl(i2s, 1); | ||
379 | |||
380 | local_irq_restore(irqs); | ||
381 | break; | ||
382 | |||
383 | case SNDRV_PCM_TRIGGER_STOP: | ||
384 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
385 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
386 | local_irq_save(irqs); | ||
387 | |||
388 | if (capture) | ||
389 | s3c2412_snd_rxctrl(i2s, 0); | ||
390 | else | ||
391 | s3c2412_snd_txctrl(i2s, 0); | ||
392 | |||
393 | local_irq_restore(irqs); | ||
394 | break; | ||
395 | default: | ||
396 | ret = -EINVAL; | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | exit_err: | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * Set S3C2412 Clock dividers | ||
406 | */ | ||
407 | static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, | ||
408 | int div_id, int div) | ||
409 | { | ||
410 | struct s3c_i2sv2_info *i2s = to_info(cpu_dai); | ||
411 | u32 reg; | ||
412 | |||
413 | pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div); | ||
414 | |||
415 | switch (div_id) { | ||
416 | case S3C_I2SV2_DIV_BCLK: | ||
417 | reg = readl(i2s->regs + S3C2412_IISMOD); | ||
418 | reg &= ~S3C2412_IISMOD_BCLK_MASK; | ||
419 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
420 | |||
421 | pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
422 | break; | ||
423 | |||
424 | case S3C_I2SV2_DIV_RCLK: | ||
425 | if (div > 3) { | ||
426 | /* convert value to bit field */ | ||
427 | |||
428 | switch (div) { | ||
429 | case 256: | ||
430 | div = S3C2412_IISMOD_RCLK_256FS; | ||
431 | break; | ||
432 | |||
433 | case 384: | ||
434 | div = S3C2412_IISMOD_RCLK_384FS; | ||
435 | break; | ||
436 | |||
437 | case 512: | ||
438 | div = S3C2412_IISMOD_RCLK_512FS; | ||
439 | break; | ||
440 | |||
441 | case 768: | ||
442 | div = S3C2412_IISMOD_RCLK_768FS; | ||
443 | break; | ||
444 | |||
445 | default: | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | reg = readl(i2s->regs + S3C2412_IISMOD); | ||
451 | reg &= ~S3C2412_IISMOD_RCLK_MASK; | ||
452 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
453 | pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
454 | break; | ||
455 | |||
456 | case S3C_I2SV2_DIV_PRESCALER: | ||
457 | if (div >= 0) { | ||
458 | writel((div << 8) | S3C2412_IISPSR_PSREN, | ||
459 | i2s->regs + S3C2412_IISPSR); | ||
460 | } else { | ||
461 | writel(0x0, i2s->regs + S3C2412_IISPSR); | ||
462 | } | ||
463 | pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR)); | ||
464 | break; | ||
465 | |||
466 | default: | ||
467 | return -EINVAL; | ||
468 | } | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | /* default table of all avaialable root fs divisors */ | ||
474 | static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 }; | ||
475 | |||
476 | int s3c2412_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, | ||
477 | unsigned int *fstab, | ||
478 | unsigned int rate, struct clk *clk) | ||
479 | { | ||
480 | unsigned long clkrate = clk_get_rate(clk); | ||
481 | unsigned int div; | ||
482 | unsigned int fsclk; | ||
483 | unsigned int actual; | ||
484 | unsigned int fs; | ||
485 | unsigned int fsdiv; | ||
486 | signed int deviation = 0; | ||
487 | unsigned int best_fs = 0; | ||
488 | unsigned int best_div = 0; | ||
489 | unsigned int best_rate = 0; | ||
490 | unsigned int best_deviation = INT_MAX; | ||
491 | |||
492 | if (fstab == NULL) | ||
493 | fstab = iis_fs_tab; | ||
494 | |||
495 | for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) { | ||
496 | fsdiv = iis_fs_tab[fs]; | ||
497 | |||
498 | fsclk = clkrate / fsdiv; | ||
499 | div = fsclk / rate; | ||
500 | |||
501 | if ((fsclk % rate) > (rate / 2)) | ||
502 | div++; | ||
503 | |||
504 | if (div <= 1) | ||
505 | continue; | ||
506 | |||
507 | actual = clkrate / (fsdiv * div); | ||
508 | deviation = actual - rate; | ||
509 | |||
510 | printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n", | ||
511 | fsdiv, div, actual, deviation); | ||
512 | |||
513 | deviation = abs(deviation); | ||
514 | |||
515 | if (deviation < best_deviation) { | ||
516 | best_fs = fsdiv; | ||
517 | best_div = div; | ||
518 | best_rate = actual; | ||
519 | best_deviation = deviation; | ||
520 | } | ||
521 | |||
522 | if (deviation == 0) | ||
523 | break; | ||
524 | } | ||
525 | |||
526 | printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n", | ||
527 | best_fs, best_div, best_rate); | ||
528 | |||
529 | info->fs_div = best_fs; | ||
530 | info->clk_div = best_div; | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate); | ||
535 | |||
536 | int s3c_i2sv2_probe(struct platform_device *pdev, | ||
537 | struct snd_soc_dai *dai, | ||
538 | struct s3c_i2sv2_info *i2s, | ||
539 | unsigned long base) | ||
540 | { | ||
541 | struct device *dev = &pdev->dev; | ||
542 | |||
543 | i2s->dev = dev; | ||
544 | |||
545 | /* record our i2s structure for later use in the callbacks */ | ||
546 | dai->private_data = i2s; | ||
547 | |||
548 | i2s->regs = ioremap(base, 0x100); | ||
549 | if (i2s->regs == NULL) { | ||
550 | dev_err(dev, "cannot ioremap registers\n"); | ||
551 | return -ENXIO; | ||
552 | } | ||
553 | |||
554 | i2s->iis_pclk = clk_get(dev, "iis"); | ||
555 | if (i2s->iis_pclk == NULL) { | ||
556 | dev_err(dev, "failed to get iis_clock\n"); | ||
557 | iounmap(i2s->regs); | ||
558 | return -ENOENT; | ||
559 | } | ||
560 | |||
561 | clk_enable(i2s->iis_pclk); | ||
562 | |||
563 | s3c2412_snd_txctrl(i2s, 0); | ||
564 | s3c2412_snd_rxctrl(i2s, 0); | ||
565 | |||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); | ||
570 | |||
571 | #ifdef CONFIG_PM | ||
572 | static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) | ||
573 | { | ||
574 | struct s3c_i2sv2_info *i2s = to_info(dai); | ||
575 | u32 iismod; | ||
576 | |||
577 | if (dai->active) { | ||
578 | i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
579 | i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON); | ||
580 | i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR); | ||
581 | |||
582 | /* some basic suspend checks */ | ||
583 | |||
584 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
585 | |||
586 | if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) | ||
587 | pr_warning("%s: RXDMA active?\n", __func__); | ||
588 | |||
589 | if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) | ||
590 | pr_warning("%s: TXDMA active?\n", __func__); | ||
591 | |||
592 | if (iismod & S3C2412_IISCON_IIS_ACTIVE) | ||
593 | pr_warning("%s: IIS active\n", __func__); | ||
594 | } | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int s3c2412_i2s_resume(struct snd_soc_dai *dai) | ||
600 | { | ||
601 | struct s3c_i2sv2_info *i2s = to_info(dai); | ||
602 | |||
603 | pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n", | ||
604 | dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); | ||
605 | |||
606 | if (dai->active) { | ||
607 | writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); | ||
608 | writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD); | ||
609 | writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR); | ||
610 | |||
611 | writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH, | ||
612 | i2s->regs + S3C2412_IISFIC); | ||
613 | |||
614 | ndelay(250); | ||
615 | writel(0x0, i2s->regs + S3C2412_IISFIC); | ||
616 | } | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | #else | ||
621 | #define s3c2412_i2s_suspend NULL | ||
622 | #define s3c2412_i2s_resume NULL | ||
623 | #endif | ||
624 | |||
625 | int s3c_i2sv2_register_dai(struct snd_soc_dai *dai) | ||
626 | { | ||
627 | dai->ops.trigger = s3c2412_i2s_trigger; | ||
628 | dai->ops.hw_params = s3c2412_i2s_hw_params; | ||
629 | dai->ops.set_fmt = s3c2412_i2s_set_fmt; | ||
630 | dai->ops.set_clkdiv = s3c2412_i2s_set_clkdiv; | ||
631 | |||
632 | dai->suspend = s3c2412_i2s_suspend; | ||
633 | dai->resume = s3c2412_i2s_resume; | ||
634 | |||
635 | return snd_soc_register_dai(dai); | ||
636 | } | ||
637 | |||
638 | EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai); | ||
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h new file mode 100644 index 000000000000..f66854a77fb2 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-i2s-v2.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* sound/soc/s3c24xx/s3c-i2s-v2.h | ||
2 | * | ||
3 | * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver | ||
4 | * | ||
5 | * Copyright (c) 2007 Simtec Electronics | ||
6 | * http://armlinux.simtec.co.uk/ | ||
7 | * Ben Dooks <ben@simtec.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | /* This code is the core support for the I2S block found in a number of | ||
16 | * Samsung SoC devices which is unofficially named I2S-V2. Currently the | ||
17 | * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S | ||
18 | * channels via configurable GPIO. | ||
19 | */ | ||
20 | |||
21 | #ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H | ||
22 | #define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__ | ||
23 | |||
24 | #define S3C_I2SV2_DIV_BCLK (1) | ||
25 | #define S3C_I2SV2_DIV_RCLK (2) | ||
26 | #define S3C_I2SV2_DIV_PRESCALER (3) | ||
27 | |||
28 | /** | ||
29 | * struct s3c_i2sv2_info - S3C I2S-V2 information | ||
30 | * @dev: The parent device passed to use from the probe. | ||
31 | * @regs: The pointer to the device registe block. | ||
32 | * @master: True if the I2S core is the I2S bit clock master. | ||
33 | * @dma_playback: DMA information for playback channel. | ||
34 | * @dma_capture: DMA information for capture channel. | ||
35 | * @suspend_iismod: PM save for the IISMOD register. | ||
36 | * @suspend_iiscon: PM save for the IISCON register. | ||
37 | * @suspend_iispsr: PM save for the IISPSR register. | ||
38 | * | ||
39 | * This is the private codec state for the hardware associated with an | ||
40 | * I2S channel such as the register mappings and clock sources. | ||
41 | */ | ||
42 | struct s3c_i2sv2_info { | ||
43 | struct device *dev; | ||
44 | void __iomem *regs; | ||
45 | |||
46 | struct clk *iis_pclk; | ||
47 | struct clk *iis_cclk; | ||
48 | struct clk *iis_clk; | ||
49 | |||
50 | unsigned char master; | ||
51 | |||
52 | struct s3c24xx_pcm_dma_params *dma_playback; | ||
53 | struct s3c24xx_pcm_dma_params *dma_capture; | ||
54 | |||
55 | u32 suspend_iismod; | ||
56 | u32 suspend_iiscon; | ||
57 | u32 suspend_iispsr; | ||
58 | }; | ||
59 | |||
60 | struct s3c_i2sv2_rate_calc { | ||
61 | unsigned int clk_div; /* for prescaler */ | ||
62 | unsigned int fs_div; /* for root frame clock */ | ||
63 | }; | ||
64 | |||
65 | extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, | ||
66 | unsigned int *fstab, | ||
67 | unsigned int rate, struct clk *clk); | ||
68 | |||
69 | /** | ||
70 | * s3c_i2sv2_probe - probe for i2s device helper | ||
71 | * @pdev: The platform device supplied to the original probe. | ||
72 | * @dai: The ASoC DAI structure supplied to the original probe. | ||
73 | * @i2s: Our local i2s structure to fill in. | ||
74 | * @base: The base address for the registers. | ||
75 | */ | ||
76 | extern int s3c_i2sv2_probe(struct platform_device *pdev, | ||
77 | struct snd_soc_dai *dai, | ||
78 | struct s3c_i2sv2_info *i2s, | ||
79 | unsigned long base); | ||
80 | |||
81 | /** | ||
82 | * s3c_i2sv2_register_dai - register dai with soc core | ||
83 | * @dai: The snd_soc_dai structure to register | ||
84 | * | ||
85 | * Fill in any missing fields and then register the given dai with the | ||
86 | * soc core. | ||
87 | */ | ||
88 | extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai); | ||
89 | |||
90 | #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */ | ||
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index f3fc0aba0aaf..1ca3cdaa8213 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/io.h> | ||
25 | 26 | ||
26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
@@ -30,26 +31,16 @@ | |||
30 | #include <sound/soc.h> | 31 | #include <sound/soc.h> |
31 | #include <mach/hardware.h> | 32 | #include <mach/hardware.h> |
32 | 33 | ||
33 | #include <linux/io.h> | 34 | #include <plat/regs-s3c2412-iis.h> |
34 | #include <asm/dma.h> | ||
35 | |||
36 | #include <asm/plat-s3c24xx/regs-s3c2412-iis.h> | ||
37 | 35 | ||
38 | #include <mach/regs-gpio.h> | 36 | #include <plat/regs-gpio.h> |
39 | #include <mach/audio.h> | 37 | #include <plat/audio.h> |
40 | #include <mach/dma.h> | 38 | #include <mach/dma.h> |
41 | 39 | ||
42 | #include "s3c24xx-pcm.h" | 40 | #include "s3c24xx-pcm.h" |
43 | #include "s3c2412-i2s.h" | 41 | #include "s3c2412-i2s.h" |
44 | 42 | ||
45 | #define S3C2412_I2S_DEBUG 0 | 43 | #define S3C2412_I2S_DEBUG 0 |
46 | #define S3C2412_I2S_DEBUG_CON 0 | ||
47 | |||
48 | #if S3C2412_I2S_DEBUG | ||
49 | #define DBG(x...) printk(KERN_INFO x) | ||
50 | #else | ||
51 | #define DBG(x...) do { } while (0) | ||
52 | #endif | ||
53 | 44 | ||
54 | static struct s3c2410_dma_client s3c2412_dma_client_out = { | 45 | static struct s3c2410_dma_client s3c2412_dma_client_out = { |
55 | .name = "I2S PCM Stereo out" | 46 | .name = "I2S PCM Stereo out" |
@@ -73,431 +64,7 @@ static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = { | |||
73 | .dma_size = 4, | 64 | .dma_size = 4, |
74 | }; | 65 | }; |
75 | 66 | ||
76 | struct s3c2412_i2s_info { | 67 | static struct s3c_i2sv2_info s3c2412_i2s; |
77 | struct device *dev; | ||
78 | void __iomem *regs; | ||
79 | struct clk *iis_clk; | ||
80 | struct clk *iis_pclk; | ||
81 | struct clk *iis_cclk; | ||
82 | |||
83 | u32 suspend_iismod; | ||
84 | u32 suspend_iiscon; | ||
85 | u32 suspend_iispsr; | ||
86 | }; | ||
87 | |||
88 | static struct s3c2412_i2s_info s3c2412_i2s; | ||
89 | |||
90 | #define bit_set(v, b) (((v) & (b)) ? 1 : 0) | ||
91 | |||
92 | #if S3C2412_I2S_DEBUG_CON | ||
93 | static void dbg_showcon(const char *fn, u32 con) | ||
94 | { | ||
95 | printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn, | ||
96 | bit_set(con, S3C2412_IISCON_LRINDEX), | ||
97 | bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY), | ||
98 | bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY), | ||
99 | bit_set(con, S3C2412_IISCON_TXFIFO_FULL), | ||
100 | bit_set(con, S3C2412_IISCON_RXFIFO_FULL)); | ||
101 | |||
102 | printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n", | ||
103 | fn, | ||
104 | bit_set(con, S3C2412_IISCON_TXDMA_PAUSE), | ||
105 | bit_set(con, S3C2412_IISCON_RXDMA_PAUSE), | ||
106 | bit_set(con, S3C2412_IISCON_TXCH_PAUSE), | ||
107 | bit_set(con, S3C2412_IISCON_RXCH_PAUSE)); | ||
108 | printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn, | ||
109 | bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE), | ||
110 | bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE), | ||
111 | bit_set(con, S3C2412_IISCON_IIS_ACTIVE)); | ||
112 | } | ||
113 | #else | ||
114 | static inline void dbg_showcon(const char *fn, u32 con) | ||
115 | { | ||
116 | } | ||
117 | #endif | ||
118 | |||
119 | /* Turn on or off the transmission path. */ | ||
120 | static void s3c2412_snd_txctrl(int on) | ||
121 | { | ||
122 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
123 | void __iomem *regs = i2s->regs; | ||
124 | u32 fic, con, mod; | ||
125 | |||
126 | DBG("%s(%d)\n", __func__, on); | ||
127 | |||
128 | fic = readl(regs + S3C2412_IISFIC); | ||
129 | con = readl(regs + S3C2412_IISCON); | ||
130 | mod = readl(regs + S3C2412_IISMOD); | ||
131 | |||
132 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
133 | |||
134 | if (on) { | ||
135 | con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
136 | con &= ~S3C2412_IISCON_TXDMA_PAUSE; | ||
137 | con &= ~S3C2412_IISCON_TXCH_PAUSE; | ||
138 | |||
139 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
140 | case S3C2412_IISMOD_MODE_TXONLY: | ||
141 | case S3C2412_IISMOD_MODE_TXRX: | ||
142 | /* do nothing, we are in the right mode */ | ||
143 | break; | ||
144 | |||
145 | case S3C2412_IISMOD_MODE_RXONLY: | ||
146 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
147 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
148 | break; | ||
149 | |||
150 | default: | ||
151 | dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n"); | ||
152 | } | ||
153 | |||
154 | writel(con, regs + S3C2412_IISCON); | ||
155 | writel(mod, regs + S3C2412_IISMOD); | ||
156 | } else { | ||
157 | /* Note, we do not have any indication that the FIFO problems | ||
158 | * tha the S3C2410/2440 had apply here, so we should be able | ||
159 | * to disable the DMA and TX without resetting the FIFOS. | ||
160 | */ | ||
161 | |||
162 | con |= S3C2412_IISCON_TXDMA_PAUSE; | ||
163 | con |= S3C2412_IISCON_TXCH_PAUSE; | ||
164 | con &= ~S3C2412_IISCON_TXDMA_ACTIVE; | ||
165 | |||
166 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
167 | case S3C2412_IISMOD_MODE_TXRX: | ||
168 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
169 | mod |= S3C2412_IISMOD_MODE_RXONLY; | ||
170 | break; | ||
171 | |||
172 | case S3C2412_IISMOD_MODE_TXONLY: | ||
173 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
174 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
175 | break; | ||
176 | |||
177 | default: | ||
178 | dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n"); | ||
179 | } | ||
180 | |||
181 | writel(mod, regs + S3C2412_IISMOD); | ||
182 | writel(con, regs + S3C2412_IISCON); | ||
183 | } | ||
184 | |||
185 | fic = readl(regs + S3C2412_IISFIC); | ||
186 | dbg_showcon(__func__, con); | ||
187 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
188 | } | ||
189 | |||
190 | static void s3c2412_snd_rxctrl(int on) | ||
191 | { | ||
192 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
193 | void __iomem *regs = i2s->regs; | ||
194 | u32 fic, con, mod; | ||
195 | |||
196 | DBG("%s(%d)\n", __func__, on); | ||
197 | |||
198 | fic = readl(regs + S3C2412_IISFIC); | ||
199 | con = readl(regs + S3C2412_IISCON); | ||
200 | mod = readl(regs + S3C2412_IISMOD); | ||
201 | |||
202 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
203 | |||
204 | if (on) { | ||
205 | con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
206 | con &= ~S3C2412_IISCON_RXDMA_PAUSE; | ||
207 | con &= ~S3C2412_IISCON_RXCH_PAUSE; | ||
208 | |||
209 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
210 | case S3C2412_IISMOD_MODE_TXRX: | ||
211 | case S3C2412_IISMOD_MODE_RXONLY: | ||
212 | /* do nothing, we are in the right mode */ | ||
213 | break; | ||
214 | |||
215 | case S3C2412_IISMOD_MODE_TXONLY: | ||
216 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
217 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
218 | break; | ||
219 | |||
220 | default: | ||
221 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
222 | } | ||
223 | |||
224 | writel(mod, regs + S3C2412_IISMOD); | ||
225 | writel(con, regs + S3C2412_IISCON); | ||
226 | } else { | ||
227 | /* See txctrl notes on FIFOs. */ | ||
228 | |||
229 | con &= ~S3C2412_IISCON_RXDMA_ACTIVE; | ||
230 | con |= S3C2412_IISCON_RXDMA_PAUSE; | ||
231 | con |= S3C2412_IISCON_RXCH_PAUSE; | ||
232 | |||
233 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
234 | case S3C2412_IISMOD_MODE_RXONLY: | ||
235 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
236 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
237 | break; | ||
238 | |||
239 | case S3C2412_IISMOD_MODE_TXRX: | ||
240 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
241 | mod |= S3C2412_IISMOD_MODE_TXONLY; | ||
242 | break; | ||
243 | |||
244 | default: | ||
245 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
246 | } | ||
247 | |||
248 | writel(con, regs + S3C2412_IISCON); | ||
249 | writel(mod, regs + S3C2412_IISMOD); | ||
250 | } | ||
251 | |||
252 | fic = readl(regs + S3C2412_IISFIC); | ||
253 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
254 | } | ||
255 | |||
256 | |||
257 | /* | ||
258 | * Wait for the LR signal to allow synchronisation to the L/R clock | ||
259 | * from the codec. May only be needed for slave mode. | ||
260 | */ | ||
261 | static int s3c2412_snd_lrsync(void) | ||
262 | { | ||
263 | u32 iiscon; | ||
264 | unsigned long timeout = jiffies + msecs_to_jiffies(5); | ||
265 | |||
266 | DBG("Entered %s\n", __func__); | ||
267 | |||
268 | while (1) { | ||
269 | iiscon = readl(s3c2412_i2s.regs + S3C2412_IISCON); | ||
270 | if (iiscon & S3C2412_IISCON_LRINDEX) | ||
271 | break; | ||
272 | |||
273 | if (timeout < jiffies) { | ||
274 | printk(KERN_ERR "%s: timeout\n", __func__); | ||
275 | return -ETIMEDOUT; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * Check whether CPU is the master or slave | ||
284 | */ | ||
285 | static inline int s3c2412_snd_is_clkmaster(void) | ||
286 | { | ||
287 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
288 | |||
289 | DBG("Entered %s\n", __func__); | ||
290 | |||
291 | iismod &= S3C2412_IISMOD_MASTER_MASK; | ||
292 | return !(iismod == S3C2412_IISMOD_SLAVE); | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Set S3C2412 I2S DAI format | ||
297 | */ | ||
298 | static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | ||
299 | unsigned int fmt) | ||
300 | { | ||
301 | u32 iismod; | ||
302 | |||
303 | |||
304 | DBG("Entered %s\n", __func__); | ||
305 | |||
306 | iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
307 | DBG("hw_params r: IISMOD: %x \n", iismod); | ||
308 | |||
309 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
310 | case SND_SOC_DAIFMT_CBM_CFM: | ||
311 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | ||
312 | iismod |= S3C2412_IISMOD_SLAVE; | ||
313 | break; | ||
314 | case SND_SOC_DAIFMT_CBS_CFS: | ||
315 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | ||
316 | iismod |= S3C2412_IISMOD_MASTER_INTERNAL; | ||
317 | break; | ||
318 | default: | ||
319 | DBG("unknwon master/slave format\n"); | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | |||
323 | iismod &= ~S3C2412_IISMOD_SDF_MASK; | ||
324 | |||
325 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
326 | case SND_SOC_DAIFMT_RIGHT_J: | ||
327 | iismod |= S3C2412_IISMOD_SDF_MSB; | ||
328 | break; | ||
329 | case SND_SOC_DAIFMT_LEFT_J: | ||
330 | iismod |= S3C2412_IISMOD_SDF_LSB; | ||
331 | break; | ||
332 | case SND_SOC_DAIFMT_I2S: | ||
333 | iismod |= S3C2412_IISMOD_SDF_IIS; | ||
334 | break; | ||
335 | default: | ||
336 | DBG("Unknown data format\n"); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD); | ||
341 | DBG("hw_params w: IISMOD: %x \n", iismod); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | ||
346 | struct snd_pcm_hw_params *params, | ||
347 | struct snd_soc_dai *dai) | ||
348 | { | ||
349 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
350 | u32 iismod; | ||
351 | |||
352 | DBG("Entered %s\n", __func__); | ||
353 | |||
354 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
355 | rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_out; | ||
356 | else | ||
357 | rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_in; | ||
358 | |||
359 | /* Working copies of register */ | ||
360 | iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
361 | DBG("%s: r: IISMOD: %x\n", __func__, iismod); | ||
362 | |||
363 | switch (params_format(params)) { | ||
364 | case SNDRV_PCM_FORMAT_S8: | ||
365 | iismod |= S3C2412_IISMOD_8BIT; | ||
366 | break; | ||
367 | case SNDRV_PCM_FORMAT_S16_LE: | ||
368 | iismod &= ~S3C2412_IISMOD_8BIT; | ||
369 | break; | ||
370 | } | ||
371 | |||
372 | writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD); | ||
373 | DBG("%s: w: IISMOD: %x\n", __func__, iismod); | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
378 | struct snd_soc_dai *dai) | ||
379 | { | ||
380 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
381 | unsigned long irqs; | ||
382 | int ret = 0; | ||
383 | |||
384 | DBG("Entered %s\n", __func__); | ||
385 | |||
386 | switch (cmd) { | ||
387 | case SNDRV_PCM_TRIGGER_START: | ||
388 | /* On start, ensure that the FIFOs are cleared and reset. */ | ||
389 | |||
390 | writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH, | ||
391 | s3c2412_i2s.regs + S3C2412_IISFIC); | ||
392 | |||
393 | /* clear again, just in case */ | ||
394 | writel(0x0, s3c2412_i2s.regs + S3C2412_IISFIC); | ||
395 | |||
396 | case SNDRV_PCM_TRIGGER_RESUME: | ||
397 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
398 | if (!s3c2412_snd_is_clkmaster()) { | ||
399 | ret = s3c2412_snd_lrsync(); | ||
400 | if (ret) | ||
401 | goto exit_err; | ||
402 | } | ||
403 | |||
404 | local_irq_save(irqs); | ||
405 | |||
406 | if (capture) | ||
407 | s3c2412_snd_rxctrl(1); | ||
408 | else | ||
409 | s3c2412_snd_txctrl(1); | ||
410 | |||
411 | local_irq_restore(irqs); | ||
412 | break; | ||
413 | |||
414 | case SNDRV_PCM_TRIGGER_STOP: | ||
415 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
416 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
417 | local_irq_save(irqs); | ||
418 | |||
419 | if (capture) | ||
420 | s3c2412_snd_rxctrl(0); | ||
421 | else | ||
422 | s3c2412_snd_txctrl(0); | ||
423 | |||
424 | local_irq_restore(irqs); | ||
425 | break; | ||
426 | default: | ||
427 | ret = -EINVAL; | ||
428 | break; | ||
429 | } | ||
430 | |||
431 | exit_err: | ||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | /* default table of all avaialable root fs divisors */ | ||
436 | static unsigned int s3c2412_iis_fs[] = { 256, 512, 384, 768, 0 }; | ||
437 | |||
438 | int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info, | ||
439 | unsigned int *fstab, | ||
440 | unsigned int rate, struct clk *clk) | ||
441 | { | ||
442 | unsigned long clkrate = clk_get_rate(clk); | ||
443 | unsigned int div; | ||
444 | unsigned int fsclk; | ||
445 | unsigned int actual; | ||
446 | unsigned int fs; | ||
447 | unsigned int fsdiv; | ||
448 | signed int deviation = 0; | ||
449 | unsigned int best_fs = 0; | ||
450 | unsigned int best_div = 0; | ||
451 | unsigned int best_rate = 0; | ||
452 | unsigned int best_deviation = INT_MAX; | ||
453 | |||
454 | |||
455 | if (fstab == NULL) | ||
456 | fstab = s3c2412_iis_fs; | ||
457 | |||
458 | for (fs = 0;; fs++) { | ||
459 | fsdiv = s3c2412_iis_fs[fs]; | ||
460 | |||
461 | if (fsdiv == 0) | ||
462 | break; | ||
463 | |||
464 | fsclk = clkrate / fsdiv; | ||
465 | div = fsclk / rate; | ||
466 | |||
467 | if ((fsclk % rate) > (rate / 2)) | ||
468 | div++; | ||
469 | |||
470 | if (div <= 1) | ||
471 | continue; | ||
472 | |||
473 | actual = clkrate / (fsdiv * div); | ||
474 | deviation = actual - rate; | ||
475 | |||
476 | printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n", | ||
477 | fsdiv, div, actual, deviation); | ||
478 | |||
479 | deviation = abs(deviation); | ||
480 | |||
481 | if (deviation < best_deviation) { | ||
482 | best_fs = fsdiv; | ||
483 | best_div = div; | ||
484 | best_rate = actual; | ||
485 | best_deviation = deviation; | ||
486 | } | ||
487 | |||
488 | if (deviation == 0) | ||
489 | break; | ||
490 | } | ||
491 | |||
492 | printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n", | ||
493 | best_fs, best_div, best_rate); | ||
494 | |||
495 | info->fs_div = best_fs; | ||
496 | info->clk_div = best_div; | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate); | ||
501 | 68 | ||
502 | /* | 69 | /* |
503 | * Set S3C2412 Clock source | 70 | * Set S3C2412 Clock source |
@@ -507,15 +74,17 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
507 | { | 74 | { |
508 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | 75 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); |
509 | 76 | ||
510 | DBG("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id, | 77 | pr_debug("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id, |
511 | freq, dir); | 78 | freq, dir); |
512 | 79 | ||
513 | switch (clk_id) { | 80 | switch (clk_id) { |
514 | case S3C2412_CLKSRC_PCLK: | 81 | case S3C2412_CLKSRC_PCLK: |
82 | s3c2412_i2s.master = 1; | ||
515 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | 83 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; |
516 | iismod |= S3C2412_IISMOD_MASTER_INTERNAL; | 84 | iismod |= S3C2412_IISMOD_MASTER_INTERNAL; |
517 | break; | 85 | break; |
518 | case S3C2412_CLKSRC_I2SCLK: | 86 | case S3C2412_CLKSRC_I2SCLK: |
87 | s3c2412_i2s.master = 0; | ||
519 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | 88 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; |
520 | iismod |= S3C2412_IISMOD_MASTER_EXTERNAL; | 89 | iismod |= S3C2412_IISMOD_MASTER_EXTERNAL; |
521 | break; | 90 | break; |
@@ -527,74 +96,6 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
527 | return 0; | 96 | return 0; |
528 | } | 97 | } |
529 | 98 | ||
530 | /* | ||
531 | * Set S3C2412 Clock dividers | ||
532 | */ | ||
533 | static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, | ||
534 | int div_id, int div) | ||
535 | { | ||
536 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
537 | u32 reg; | ||
538 | |||
539 | DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div); | ||
540 | |||
541 | switch (div_id) { | ||
542 | case S3C2412_DIV_BCLK: | ||
543 | reg = readl(i2s->regs + S3C2412_IISMOD); | ||
544 | reg &= ~S3C2412_IISMOD_BCLK_MASK; | ||
545 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
546 | |||
547 | DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
548 | break; | ||
549 | |||
550 | case S3C2412_DIV_RCLK: | ||
551 | if (div > 3) { | ||
552 | /* convert value to bit field */ | ||
553 | |||
554 | switch (div) { | ||
555 | case 256: | ||
556 | div = S3C2412_IISMOD_RCLK_256FS; | ||
557 | break; | ||
558 | |||
559 | case 384: | ||
560 | div = S3C2412_IISMOD_RCLK_384FS; | ||
561 | break; | ||
562 | |||
563 | case 512: | ||
564 | div = S3C2412_IISMOD_RCLK_512FS; | ||
565 | break; | ||
566 | |||
567 | case 768: | ||
568 | div = S3C2412_IISMOD_RCLK_768FS; | ||
569 | break; | ||
570 | |||
571 | default: | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | reg = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
577 | reg &= ~S3C2412_IISMOD_RCLK_MASK; | ||
578 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
579 | DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
580 | break; | ||
581 | |||
582 | case S3C2412_DIV_PRESCALER: | ||
583 | if (div >= 0) { | ||
584 | writel((div << 8) | S3C2412_IISPSR_PSREN, | ||
585 | i2s->regs + S3C2412_IISPSR); | ||
586 | } else { | ||
587 | writel(0x0, i2s->regs + S3C2412_IISPSR); | ||
588 | } | ||
589 | DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR)); | ||
590 | break; | ||
591 | |||
592 | default: | ||
593 | return -EINVAL; | ||
594 | } | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | 99 | ||
599 | struct clk *s3c2412_get_iisclk(void) | 100 | struct clk *s3c2412_get_iisclk(void) |
600 | { | 101 | { |
@@ -606,34 +107,30 @@ EXPORT_SYMBOL_GPL(s3c2412_get_iisclk); | |||
606 | static int s3c2412_i2s_probe(struct platform_device *pdev, | 107 | static int s3c2412_i2s_probe(struct platform_device *pdev, |
607 | struct snd_soc_dai *dai) | 108 | struct snd_soc_dai *dai) |
608 | { | 109 | { |
609 | DBG("Entered %s\n", __func__); | 110 | int ret; |
610 | 111 | ||
611 | s3c2412_i2s.dev = &pdev->dev; | 112 | pr_debug("Entered %s\n", __func__); |
612 | 113 | ||
613 | s3c2412_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); | 114 | ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS); |
614 | if (s3c2412_i2s.regs == NULL) | 115 | if (ret) |
615 | return -ENXIO; | 116 | return ret; |
616 | 117 | ||
617 | s3c2412_i2s.iis_pclk = clk_get(&pdev->dev, "iis"); | 118 | s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in; |
618 | if (s3c2412_i2s.iis_pclk == NULL) { | 119 | s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out; |
619 | DBG("failed to get iis_clock\n"); | ||
620 | iounmap(s3c2412_i2s.regs); | ||
621 | return -ENODEV; | ||
622 | } | ||
623 | 120 | ||
624 | s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); | 121 | s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); |
625 | if (s3c2412_i2s.iis_cclk == NULL) { | 122 | if (s3c2412_i2s.iis_cclk == NULL) { |
626 | DBG("failed to get i2sclk clock\n"); | 123 | pr_debug("failed to get i2sclk clock\n"); |
627 | iounmap(s3c2412_i2s.regs); | 124 | iounmap(s3c2412_i2s.regs); |
628 | return -ENODEV; | 125 | return -ENODEV; |
629 | } | 126 | } |
630 | 127 | ||
631 | clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); | 128 | /* Set MPLL as the source for IIS CLK */ |
632 | 129 | ||
633 | clk_enable(s3c2412_i2s.iis_pclk); | 130 | clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); |
634 | clk_enable(s3c2412_i2s.iis_cclk); | 131 | clk_enable(s3c2412_i2s.iis_cclk); |
635 | 132 | ||
636 | s3c2412_i2s.iis_clk = s3c2412_i2s.iis_pclk; | 133 | s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk; |
637 | 134 | ||
638 | /* Configure the I2S pins in correct mode */ | 135 | /* Configure the I2S pins in correct mode */ |
639 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); | 136 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); |
@@ -642,78 +139,22 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, | |||
642 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); | 139 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); |
643 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); | 140 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); |
644 | 141 | ||
645 | s3c2412_snd_txctrl(0); | ||
646 | s3c2412_snd_rxctrl(0); | ||
647 | |||
648 | return 0; | 142 | return 0; |
649 | } | 143 | } |
650 | 144 | ||
651 | #ifdef CONFIG_PM | ||
652 | static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) | ||
653 | { | ||
654 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
655 | u32 iismod; | ||
656 | |||
657 | if (dai->active) { | ||
658 | i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
659 | i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON); | ||
660 | i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR); | ||
661 | |||
662 | /* some basic suspend checks */ | ||
663 | |||
664 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
665 | |||
666 | if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) | ||
667 | pr_warning("%s: RXDMA active?\n", __func__); | ||
668 | |||
669 | if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) | ||
670 | pr_warning("%s: TXDMA active?\n", __func__); | ||
671 | |||
672 | if (iismod & S3C2412_IISCON_IIS_ACTIVE) | ||
673 | pr_warning("%s: IIS active\n", __func__); | ||
674 | } | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int s3c2412_i2s_resume(struct snd_soc_dai *dai) | ||
680 | { | ||
681 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
682 | |||
683 | pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n", | ||
684 | dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); | ||
685 | |||
686 | if (dai->active) { | ||
687 | writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); | ||
688 | writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD); | ||
689 | writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR); | ||
690 | |||
691 | writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH, | ||
692 | i2s->regs + S3C2412_IISFIC); | ||
693 | |||
694 | ndelay(250); | ||
695 | writel(0x0, i2s->regs + S3C2412_IISFIC); | ||
696 | |||
697 | } | ||
698 | |||
699 | return 0; | ||
700 | } | ||
701 | #else | ||
702 | #define s3c2412_i2s_suspend NULL | ||
703 | #define s3c2412_i2s_resume NULL | ||
704 | #endif /* CONFIG_PM */ | ||
705 | |||
706 | #define S3C2412_I2S_RATES \ | 145 | #define S3C2412_I2S_RATES \ |
707 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | 146 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ |
708 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 147 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
709 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 148 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
710 | 149 | ||
150 | static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = { | ||
151 | .set_sysclk = s3c2412_i2s_set_sysclk, | ||
152 | }; | ||
153 | |||
711 | struct snd_soc_dai s3c2412_i2s_dai = { | 154 | struct snd_soc_dai s3c2412_i2s_dai = { |
712 | .name = "s3c2412-i2s", | 155 | .name = "s3c2412-i2s", |
713 | .id = 0, | 156 | .id = 0, |
714 | .probe = s3c2412_i2s_probe, | 157 | .probe = s3c2412_i2s_probe, |
715 | .suspend = s3c2412_i2s_suspend, | ||
716 | .resume = s3c2412_i2s_resume, | ||
717 | .playback = { | 158 | .playback = { |
718 | .channels_min = 2, | 159 | .channels_min = 2, |
719 | .channels_max = 2, | 160 | .channels_max = 2, |
@@ -726,19 +167,13 @@ struct snd_soc_dai s3c2412_i2s_dai = { | |||
726 | .rates = S3C2412_I2S_RATES, | 167 | .rates = S3C2412_I2S_RATES, |
727 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, | 168 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, |
728 | }, | 169 | }, |
729 | .ops = { | 170 | .ops = &s3c2412_i2s_dai_ops, |
730 | .trigger = s3c2412_i2s_trigger, | ||
731 | .hw_params = s3c2412_i2s_hw_params, | ||
732 | .set_fmt = s3c2412_i2s_set_fmt, | ||
733 | .set_clkdiv = s3c2412_i2s_set_clkdiv, | ||
734 | .set_sysclk = s3c2412_i2s_set_sysclk, | ||
735 | }, | ||
736 | }; | 171 | }; |
737 | EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); | 172 | EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); |
738 | 173 | ||
739 | static int __init s3c2412_i2s_init(void) | 174 | static int __init s3c2412_i2s_init(void) |
740 | { | 175 | { |
741 | return snd_soc_register_dai(&s3c2412_i2s_dai); | 176 | return s3c_i2sv2_register_dai(&s3c2412_i2s_dai); |
742 | } | 177 | } |
743 | module_init(s3c2412_i2s_init); | 178 | module_init(s3c2412_i2s_init); |
744 | 179 | ||
@@ -748,7 +183,6 @@ static void __exit s3c2412_i2s_exit(void) | |||
748 | } | 183 | } |
749 | module_exit(s3c2412_i2s_exit); | 184 | module_exit(s3c2412_i2s_exit); |
750 | 185 | ||
751 | |||
752 | /* Module information */ | 186 | /* Module information */ |
753 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | 187 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); |
754 | MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); | 188 | MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); |
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h index aac08a25e541..92848e54be16 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.h +++ b/sound/soc/s3c24xx/s3c2412-i2s.h | |||
@@ -15,9 +15,11 @@ | |||
15 | #ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H | 15 | #ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H |
16 | #define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__ | 16 | #define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__ |
17 | 17 | ||
18 | #define S3C2412_DIV_BCLK (1) | 18 | #include "s3c-i2s-v2.h" |
19 | #define S3C2412_DIV_RCLK (2) | 19 | |
20 | #define S3C2412_DIV_PRESCALER (3) | 20 | #define S3C2412_DIV_BCLK S3C_I2SV2_DIV_BCLK |
21 | #define S3C2412_DIV_RCLK S3C_I2SV2_DIV_RCLK | ||
22 | #define S3C2412_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER | ||
21 | 23 | ||
22 | #define S3C2412_CLKSRC_PCLK (0) | 24 | #define S3C2412_CLKSRC_PCLK (0) |
23 | #define S3C2412_CLKSRC_I2SCLK (1) | 25 | #define S3C2412_CLKSRC_I2SCLK (1) |
@@ -26,13 +28,4 @@ extern struct clk *s3c2412_get_iisclk(void); | |||
26 | 28 | ||
27 | extern struct snd_soc_dai s3c2412_i2s_dai; | 29 | extern struct snd_soc_dai s3c2412_i2s_dai; |
28 | 30 | ||
29 | struct s3c2412_rate_calc { | ||
30 | unsigned int clk_div; /* for prescaler */ | ||
31 | unsigned int fs_div; /* for root frame clock */ | ||
32 | }; | ||
33 | |||
34 | extern int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info, | ||
35 | unsigned int *fstab, | ||
36 | unsigned int rate, struct clk *clk); | ||
37 | |||
38 | #endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */ | 31 | #endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */ |
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 5822d2dd49ba..3698f707c44d 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <plat/regs-ac97.h> | 31 | #include <plat/regs-ac97.h> |
32 | #include <mach/regs-gpio.h> | 32 | #include <mach/regs-gpio.h> |
33 | #include <mach/regs-clock.h> | 33 | #include <mach/regs-clock.h> |
34 | #include <mach/audio.h> | 34 | #include <plat/audio.h> |
35 | #include <asm/dma.h> | 35 | #include <asm/dma.h> |
36 | #include <mach/dma.h> | 36 | #include <mach/dma.h> |
37 | 37 | ||
@@ -355,6 +355,16 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, | |||
355 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | 355 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ |
356 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 356 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
357 | 357 | ||
358 | static struct snd_soc_dai_ops s3c2443_ac97_dai_ops = { | ||
359 | .hw_params = s3c2443_ac97_hw_params, | ||
360 | .trigger = s3c2443_ac97_trigger, | ||
361 | }; | ||
362 | |||
363 | static struct snd_soc_dai_ops s3c2443_ac97_mic_dai_ops = { | ||
364 | .hw_params = s3c2443_ac97_hw_mic_params, | ||
365 | .trigger = s3c2443_ac97_mic_trigger, | ||
366 | }; | ||
367 | |||
358 | struct snd_soc_dai s3c2443_ac97_dai[] = { | 368 | struct snd_soc_dai s3c2443_ac97_dai[] = { |
359 | { | 369 | { |
360 | .name = "s3c2443-ac97", | 370 | .name = "s3c2443-ac97", |
@@ -374,9 +384,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { | |||
374 | .channels_max = 2, | 384 | .channels_max = 2, |
375 | .rates = s3c2443_AC97_RATES, | 385 | .rates = s3c2443_AC97_RATES, |
376 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 386 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
377 | .ops = { | 387 | .ops = &s3c2443_ac97_dai_ops, |
378 | .hw_params = s3c2443_ac97_hw_params, | ||
379 | .trigger = s3c2443_ac97_trigger}, | ||
380 | }, | 388 | }, |
381 | { | 389 | { |
382 | .name = "pxa2xx-ac97-mic", | 390 | .name = "pxa2xx-ac97-mic", |
@@ -388,9 +396,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { | |||
388 | .channels_max = 1, | 396 | .channels_max = 1, |
389 | .rates = s3c2443_AC97_RATES, | 397 | .rates = s3c2443_AC97_RATES, |
390 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 398 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
391 | .ops = { | 399 | .ops = &s3c2443_ac97_mic_dai_ops, |
392 | .hw_params = s3c2443_ac97_hw_mic_params, | ||
393 | .trigger = s3c2443_ac97_mic_trigger,}, | ||
394 | }, | 400 | }, |
395 | }; | 401 | }; |
396 | EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); | 402 | EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); |
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 6f4d439b57aa..cc066964dad6 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (c) 2006 Wolfson Microelectronics PLC. | 4 | * (c) 2006 Wolfson Microelectronics PLC. |
5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | 5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com |
6 | * | 6 | * |
7 | * (c) 2004-2005 Simtec Electronics | 7 | * Copyright 2004-2005 Simtec Electronics |
8 | * http://armlinux.simtec.co.uk/ | 8 | * http://armlinux.simtec.co.uk/ |
9 | * Ben Dooks <ben@simtec.co.uk> | 9 | * Ben Dooks <ben@simtec.co.uk> |
10 | * | 10 | * |
@@ -30,22 +30,15 @@ | |||
30 | #include <mach/hardware.h> | 30 | #include <mach/hardware.h> |
31 | #include <mach/regs-gpio.h> | 31 | #include <mach/regs-gpio.h> |
32 | #include <mach/regs-clock.h> | 32 | #include <mach/regs-clock.h> |
33 | #include <mach/audio.h> | 33 | #include <plat/audio.h> |
34 | #include <asm/dma.h> | 34 | #include <asm/dma.h> |
35 | #include <mach/dma.h> | 35 | #include <mach/dma.h> |
36 | 36 | ||
37 | #include <asm/plat-s3c24xx/regs-iis.h> | 37 | #include <plat/regs-iis.h> |
38 | 38 | ||
39 | #include "s3c24xx-pcm.h" | 39 | #include "s3c24xx-pcm.h" |
40 | #include "s3c24xx-i2s.h" | 40 | #include "s3c24xx-i2s.h" |
41 | 41 | ||
42 | #define S3C24XX_I2S_DEBUG 0 | ||
43 | #if S3C24XX_I2S_DEBUG | ||
44 | #define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x) | ||
45 | #else | ||
46 | #define DBG(x...) | ||
47 | #endif | ||
48 | |||
49 | static struct s3c2410_dma_client s3c24xx_dma_client_out = { | 42 | static struct s3c2410_dma_client s3c24xx_dma_client_out = { |
50 | .name = "I2S PCM Stereo out" | 43 | .name = "I2S PCM Stereo out" |
51 | }; | 44 | }; |
@@ -84,13 +77,13 @@ static void s3c24xx_snd_txctrl(int on) | |||
84 | u32 iiscon; | 77 | u32 iiscon; |
85 | u32 iismod; | 78 | u32 iismod; |
86 | 79 | ||
87 | DBG("Entered %s\n", __func__); | 80 | pr_debug("Entered %s\n", __func__); |
88 | 81 | ||
89 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); | 82 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); |
90 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | 83 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); |
91 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 84 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
92 | 85 | ||
93 | DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); | 86 | pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
94 | 87 | ||
95 | if (on) { | 88 | if (on) { |
96 | iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE; | 89 | iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE; |
@@ -120,7 +113,7 @@ static void s3c24xx_snd_txctrl(int on) | |||
120 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | 113 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); |
121 | } | 114 | } |
122 | 115 | ||
123 | DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); | 116 | pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
124 | } | 117 | } |
125 | 118 | ||
126 | static void s3c24xx_snd_rxctrl(int on) | 119 | static void s3c24xx_snd_rxctrl(int on) |
@@ -129,13 +122,13 @@ static void s3c24xx_snd_rxctrl(int on) | |||
129 | u32 iiscon; | 122 | u32 iiscon; |
130 | u32 iismod; | 123 | u32 iismod; |
131 | 124 | ||
132 | DBG("Entered %s\n", __func__); | 125 | pr_debug("Entered %s\n", __func__); |
133 | 126 | ||
134 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); | 127 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); |
135 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | 128 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); |
136 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 129 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
137 | 130 | ||
138 | DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); | 131 | pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
139 | 132 | ||
140 | if (on) { | 133 | if (on) { |
141 | iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE; | 134 | iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE; |
@@ -165,7 +158,7 @@ static void s3c24xx_snd_rxctrl(int on) | |||
165 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | 158 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); |
166 | } | 159 | } |
167 | 160 | ||
168 | DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); | 161 | pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
169 | } | 162 | } |
170 | 163 | ||
171 | /* | 164 | /* |
@@ -177,7 +170,7 @@ static int s3c24xx_snd_lrsync(void) | |||
177 | u32 iiscon; | 170 | u32 iiscon; |
178 | int timeout = 50; /* 5ms */ | 171 | int timeout = 50; /* 5ms */ |
179 | 172 | ||
180 | DBG("Entered %s\n", __func__); | 173 | pr_debug("Entered %s\n", __func__); |
181 | 174 | ||
182 | while (1) { | 175 | while (1) { |
183 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | 176 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); |
@@ -197,7 +190,7 @@ static int s3c24xx_snd_lrsync(void) | |||
197 | */ | 190 | */ |
198 | static inline int s3c24xx_snd_is_clkmaster(void) | 191 | static inline int s3c24xx_snd_is_clkmaster(void) |
199 | { | 192 | { |
200 | DBG("Entered %s\n", __func__); | 193 | pr_debug("Entered %s\n", __func__); |
201 | 194 | ||
202 | return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; | 195 | return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; |
203 | } | 196 | } |
@@ -210,10 +203,10 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
210 | { | 203 | { |
211 | u32 iismod; | 204 | u32 iismod; |
212 | 205 | ||
213 | DBG("Entered %s\n", __func__); | 206 | pr_debug("Entered %s\n", __func__); |
214 | 207 | ||
215 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 208 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
216 | DBG("hw_params r: IISMOD: %lx \n", iismod); | 209 | pr_debug("hw_params r: IISMOD: %x \n", iismod); |
217 | 210 | ||
218 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 211 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
219 | case SND_SOC_DAIFMT_CBM_CFM: | 212 | case SND_SOC_DAIFMT_CBM_CFM: |
@@ -238,7 +231,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
238 | } | 231 | } |
239 | 232 | ||
240 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | 233 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); |
241 | DBG("hw_params w: IISMOD: %lx \n", iismod); | 234 | pr_debug("hw_params w: IISMOD: %x \n", iismod); |
242 | return 0; | 235 | return 0; |
243 | } | 236 | } |
244 | 237 | ||
@@ -249,7 +242,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
249 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 242 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
250 | u32 iismod; | 243 | u32 iismod; |
251 | 244 | ||
252 | DBG("Entered %s\n", __func__); | 245 | pr_debug("Entered %s\n", __func__); |
253 | 246 | ||
254 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 247 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
255 | rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; | 248 | rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; |
@@ -258,7 +251,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
258 | 251 | ||
259 | /* Working copies of register */ | 252 | /* Working copies of register */ |
260 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 253 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
261 | DBG("hw_params r: IISMOD: %lx\n", iismod); | 254 | pr_debug("hw_params r: IISMOD: %x\n", iismod); |
262 | 255 | ||
263 | switch (params_format(params)) { | 256 | switch (params_format(params)) { |
264 | case SNDRV_PCM_FORMAT_S8: | 257 | case SNDRV_PCM_FORMAT_S8: |
@@ -276,7 +269,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
276 | } | 269 | } |
277 | 270 | ||
278 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | 271 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); |
279 | DBG("hw_params w: IISMOD: %lx\n", iismod); | 272 | pr_debug("hw_params w: IISMOD: %x\n", iismod); |
280 | return 0; | 273 | return 0; |
281 | } | 274 | } |
282 | 275 | ||
@@ -285,7 +278,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
285 | { | 278 | { |
286 | int ret = 0; | 279 | int ret = 0; |
287 | 280 | ||
288 | DBG("Entered %s\n", __func__); | 281 | pr_debug("Entered %s\n", __func__); |
289 | 282 | ||
290 | switch (cmd) { | 283 | switch (cmd) { |
291 | case SNDRV_PCM_TRIGGER_START: | 284 | case SNDRV_PCM_TRIGGER_START: |
@@ -327,7 +320,7 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
327 | { | 320 | { |
328 | u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 321 | u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
329 | 322 | ||
330 | DBG("Entered %s\n", __func__); | 323 | pr_debug("Entered %s\n", __func__); |
331 | 324 | ||
332 | iismod &= ~S3C2440_IISMOD_MPLL; | 325 | iismod &= ~S3C2440_IISMOD_MPLL; |
333 | 326 | ||
@@ -353,7 +346,7 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, | |||
353 | { | 346 | { |
354 | u32 reg; | 347 | u32 reg; |
355 | 348 | ||
356 | DBG("Entered %s\n", __func__); | 349 | pr_debug("Entered %s\n", __func__); |
357 | 350 | ||
358 | switch (div_id) { | 351 | switch (div_id) { |
359 | case S3C24XX_DIV_BCLK: | 352 | case S3C24XX_DIV_BCLK: |
@@ -389,7 +382,7 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); | |||
389 | static int s3c24xx_i2s_probe(struct platform_device *pdev, | 382 | static int s3c24xx_i2s_probe(struct platform_device *pdev, |
390 | struct snd_soc_dai *dai) | 383 | struct snd_soc_dai *dai) |
391 | { | 384 | { |
392 | DBG("Entered %s\n", __func__); | 385 | pr_debug("Entered %s\n", __func__); |
393 | 386 | ||
394 | s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); | 387 | s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); |
395 | if (s3c24xx_i2s.regs == NULL) | 388 | if (s3c24xx_i2s.regs == NULL) |
@@ -397,7 +390,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev, | |||
397 | 390 | ||
398 | s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis"); | 391 | s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis"); |
399 | if (s3c24xx_i2s.iis_clk == NULL) { | 392 | if (s3c24xx_i2s.iis_clk == NULL) { |
400 | DBG("failed to get iis_clock\n"); | 393 | pr_err("failed to get iis_clock\n"); |
401 | iounmap(s3c24xx_i2s.regs); | 394 | iounmap(s3c24xx_i2s.regs); |
402 | return -ENODEV; | 395 | return -ENODEV; |
403 | } | 396 | } |
@@ -421,7 +414,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev, | |||
421 | #ifdef CONFIG_PM | 414 | #ifdef CONFIG_PM |
422 | static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) | 415 | static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) |
423 | { | 416 | { |
424 | DBG("Entered %s\n", __func__); | 417 | pr_debug("Entered %s\n", __func__); |
425 | 418 | ||
426 | s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | 419 | s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); |
427 | s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 420 | s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
@@ -435,7 +428,7 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) | |||
435 | 428 | ||
436 | static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) | 429 | static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) |
437 | { | 430 | { |
438 | DBG("Entered %s\n", __func__); | 431 | pr_debug("Entered %s\n", __func__); |
439 | clk_enable(s3c24xx_i2s.iis_clk); | 432 | clk_enable(s3c24xx_i2s.iis_clk); |
440 | 433 | ||
441 | writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); | 434 | writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); |
@@ -456,6 +449,14 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) | |||
456 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 449 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
457 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 450 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
458 | 451 | ||
452 | static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = { | ||
453 | .trigger = s3c24xx_i2s_trigger, | ||
454 | .hw_params = s3c24xx_i2s_hw_params, | ||
455 | .set_fmt = s3c24xx_i2s_set_fmt, | ||
456 | .set_clkdiv = s3c24xx_i2s_set_clkdiv, | ||
457 | .set_sysclk = s3c24xx_i2s_set_sysclk, | ||
458 | }; | ||
459 | |||
459 | struct snd_soc_dai s3c24xx_i2s_dai = { | 460 | struct snd_soc_dai s3c24xx_i2s_dai = { |
460 | .name = "s3c24xx-i2s", | 461 | .name = "s3c24xx-i2s", |
461 | .id = 0, | 462 | .id = 0, |
@@ -472,13 +473,7 @@ struct snd_soc_dai s3c24xx_i2s_dai = { | |||
472 | .channels_max = 2, | 473 | .channels_max = 2, |
473 | .rates = S3C24XX_I2S_RATES, | 474 | .rates = S3C24XX_I2S_RATES, |
474 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, | 475 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, |
475 | .ops = { | 476 | .ops = &s3c24xx_i2s_dai_ops, |
476 | .trigger = s3c24xx_i2s_trigger, | ||
477 | .hw_params = s3c24xx_i2s_hw_params, | ||
478 | .set_fmt = s3c24xx_i2s_set_fmt, | ||
479 | .set_clkdiv = s3c24xx_i2s_set_clkdiv, | ||
480 | .set_sysclk = s3c24xx_i2s_set_sysclk, | ||
481 | }, | ||
482 | }; | 477 | }; |
483 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); | 478 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); |
484 | 479 | ||
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 7c64d31d067e..a9d68fa2b34a 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (c) 2006 Wolfson Microelectronics PLC. | 4 | * (c) 2006 Wolfson Microelectronics PLC. |
5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | 5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com |
6 | * | 6 | * |
7 | * (c) 2004-2005 Simtec Electronics | 7 | * Copyright 2004-2005 Simtec Electronics |
8 | * http://armlinux.simtec.co.uk/ | 8 | * http://armlinux.simtec.co.uk/ |
9 | * Ben Dooks <ben@simtec.co.uk> | 9 | * Ben Dooks <ben@simtec.co.uk> |
10 | * | 10 | * |
@@ -29,17 +29,10 @@ | |||
29 | #include <asm/dma.h> | 29 | #include <asm/dma.h> |
30 | #include <mach/hardware.h> | 30 | #include <mach/hardware.h> |
31 | #include <mach/dma.h> | 31 | #include <mach/dma.h> |
32 | #include <mach/audio.h> | 32 | #include <plat/audio.h> |
33 | 33 | ||
34 | #include "s3c24xx-pcm.h" | 34 | #include "s3c24xx-pcm.h" |
35 | 35 | ||
36 | #define S3C24XX_PCM_DEBUG 0 | ||
37 | #if S3C24XX_PCM_DEBUG | ||
38 | #define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x) | ||
39 | #else | ||
40 | #define DBG(x...) | ||
41 | #endif | ||
42 | |||
43 | static const struct snd_pcm_hardware s3c24xx_pcm_hardware = { | 36 | static const struct snd_pcm_hardware s3c24xx_pcm_hardware = { |
44 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 37 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
45 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 38 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -84,16 +77,16 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) | |||
84 | dma_addr_t pos = prtd->dma_pos; | 77 | dma_addr_t pos = prtd->dma_pos; |
85 | int ret; | 78 | int ret; |
86 | 79 | ||
87 | DBG("Entered %s\n", __func__); | 80 | pr_debug("Entered %s\n", __func__); |
88 | 81 | ||
89 | while (prtd->dma_loaded < prtd->dma_limit) { | 82 | while (prtd->dma_loaded < prtd->dma_limit) { |
90 | unsigned long len = prtd->dma_period; | 83 | unsigned long len = prtd->dma_period; |
91 | 84 | ||
92 | DBG("dma_loaded: %d\n", prtd->dma_loaded); | 85 | pr_debug("dma_loaded: %d\n", prtd->dma_loaded); |
93 | 86 | ||
94 | if ((pos + len) > prtd->dma_end) { | 87 | if ((pos + len) > prtd->dma_end) { |
95 | len = prtd->dma_end - pos; | 88 | len = prtd->dma_end - pos; |
96 | DBG(KERN_DEBUG "%s: corrected dma len %ld\n", | 89 | pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n", |
97 | __func__, len); | 90 | __func__, len); |
98 | } | 91 | } |
99 | 92 | ||
@@ -119,7 +112,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, | |||
119 | struct snd_pcm_substream *substream = dev_id; | 112 | struct snd_pcm_substream *substream = dev_id; |
120 | struct s3c24xx_runtime_data *prtd; | 113 | struct s3c24xx_runtime_data *prtd; |
121 | 114 | ||
122 | DBG("Entered %s\n", __func__); | 115 | pr_debug("Entered %s\n", __func__); |
123 | 116 | ||
124 | if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) | 117 | if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) |
125 | return; | 118 | return; |
@@ -148,7 +141,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
148 | unsigned long totbytes = params_buffer_bytes(params); | 141 | unsigned long totbytes = params_buffer_bytes(params); |
149 | int ret = 0; | 142 | int ret = 0; |
150 | 143 | ||
151 | DBG("Entered %s\n", __func__); | 144 | pr_debug("Entered %s\n", __func__); |
152 | 145 | ||
153 | /* return if this is a bufferless transfer e.g. | 146 | /* return if this is a bufferless transfer e.g. |
154 | * codec <--> BT codec or GSM modem -- lg FIXME */ | 147 | * codec <--> BT codec or GSM modem -- lg FIXME */ |
@@ -161,14 +154,14 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
161 | /* prepare DMA */ | 154 | /* prepare DMA */ |
162 | prtd->params = dma; | 155 | prtd->params = dma; |
163 | 156 | ||
164 | DBG("params %p, client %p, channel %d\n", prtd->params, | 157 | pr_debug("params %p, client %p, channel %d\n", prtd->params, |
165 | prtd->params->client, prtd->params->channel); | 158 | prtd->params->client, prtd->params->channel); |
166 | 159 | ||
167 | ret = s3c2410_dma_request(prtd->params->channel, | 160 | ret = s3c2410_dma_request(prtd->params->channel, |
168 | prtd->params->client, NULL); | 161 | prtd->params->client, NULL); |
169 | 162 | ||
170 | if (ret < 0) { | 163 | if (ret < 0) { |
171 | DBG(KERN_ERR "failed to get dma channel\n"); | 164 | printk(KERN_ERR "failed to get dma channel\n"); |
172 | return ret; | 165 | return ret; |
173 | } | 166 | } |
174 | } | 167 | } |
@@ -196,7 +189,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream) | |||
196 | { | 189 | { |
197 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; | 190 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; |
198 | 191 | ||
199 | DBG("Entered %s\n", __func__); | 192 | pr_debug("Entered %s\n", __func__); |
200 | 193 | ||
201 | /* TODO - do we need to ensure DMA flushed */ | 194 | /* TODO - do we need to ensure DMA flushed */ |
202 | snd_pcm_set_runtime_buffer(substream, NULL); | 195 | snd_pcm_set_runtime_buffer(substream, NULL); |
@@ -214,7 +207,7 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) | |||
214 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; | 207 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; |
215 | int ret = 0; | 208 | int ret = 0; |
216 | 209 | ||
217 | DBG("Entered %s\n", __func__); | 210 | pr_debug("Entered %s\n", __func__); |
218 | 211 | ||
219 | /* return if this is a bufferless transfer e.g. | 212 | /* return if this is a bufferless transfer e.g. |
220 | * codec <--> BT codec or GSM modem -- lg FIXME */ | 213 | * codec <--> BT codec or GSM modem -- lg FIXME */ |
@@ -259,7 +252,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
259 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; | 252 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; |
260 | int ret = 0; | 253 | int ret = 0; |
261 | 254 | ||
262 | DBG("Entered %s\n", __func__); | 255 | pr_debug("Entered %s\n", __func__); |
263 | 256 | ||
264 | spin_lock(&prtd->lock); | 257 | spin_lock(&prtd->lock); |
265 | 258 | ||
@@ -297,7 +290,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream) | |||
297 | unsigned long res; | 290 | unsigned long res; |
298 | dma_addr_t src, dst; | 291 | dma_addr_t src, dst; |
299 | 292 | ||
300 | DBG("Entered %s\n", __func__); | 293 | pr_debug("Entered %s\n", __func__); |
301 | 294 | ||
302 | spin_lock(&prtd->lock); | 295 | spin_lock(&prtd->lock); |
303 | s3c2410_dma_getposition(prtd->params->channel, &src, &dst); | 296 | s3c2410_dma_getposition(prtd->params->channel, &src, &dst); |
@@ -309,7 +302,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream) | |||
309 | 302 | ||
310 | spin_unlock(&prtd->lock); | 303 | spin_unlock(&prtd->lock); |
311 | 304 | ||
312 | DBG("Pointer %x %x\n", src, dst); | 305 | pr_debug("Pointer %x %x\n", src, dst); |
313 | 306 | ||
314 | /* we seem to be getting the odd error from the pcm library due | 307 | /* we seem to be getting the odd error from the pcm library due |
315 | * to out-of-bounds pointers. this is maybe due to the dma engine | 308 | * to out-of-bounds pointers. this is maybe due to the dma engine |
@@ -330,7 +323,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) | |||
330 | struct snd_pcm_runtime *runtime = substream->runtime; | 323 | struct snd_pcm_runtime *runtime = substream->runtime; |
331 | struct s3c24xx_runtime_data *prtd; | 324 | struct s3c24xx_runtime_data *prtd; |
332 | 325 | ||
333 | DBG("Entered %s\n", __func__); | 326 | pr_debug("Entered %s\n", __func__); |
334 | 327 | ||
335 | snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); | 328 | snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); |
336 | 329 | ||
@@ -349,10 +342,10 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream) | |||
349 | struct snd_pcm_runtime *runtime = substream->runtime; | 342 | struct snd_pcm_runtime *runtime = substream->runtime; |
350 | struct s3c24xx_runtime_data *prtd = runtime->private_data; | 343 | struct s3c24xx_runtime_data *prtd = runtime->private_data; |
351 | 344 | ||
352 | DBG("Entered %s\n", __func__); | 345 | pr_debug("Entered %s\n", __func__); |
353 | 346 | ||
354 | if (!prtd) | 347 | if (!prtd) |
355 | DBG("s3c24xx_pcm_close called with prtd == NULL\n"); | 348 | pr_debug("s3c24xx_pcm_close called with prtd == NULL\n"); |
356 | 349 | ||
357 | kfree(prtd); | 350 | kfree(prtd); |
358 | 351 | ||
@@ -364,7 +357,7 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream, | |||
364 | { | 357 | { |
365 | struct snd_pcm_runtime *runtime = substream->runtime; | 358 | struct snd_pcm_runtime *runtime = substream->runtime; |
366 | 359 | ||
367 | DBG("Entered %s\n", __func__); | 360 | pr_debug("Entered %s\n", __func__); |
368 | 361 | ||
369 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | 362 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, |
370 | runtime->dma_area, | 363 | runtime->dma_area, |
@@ -390,7 +383,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
390 | struct snd_dma_buffer *buf = &substream->dma_buffer; | 383 | struct snd_dma_buffer *buf = &substream->dma_buffer; |
391 | size_t size = s3c24xx_pcm_hardware.buffer_bytes_max; | 384 | size_t size = s3c24xx_pcm_hardware.buffer_bytes_max; |
392 | 385 | ||
393 | DBG("Entered %s\n", __func__); | 386 | pr_debug("Entered %s\n", __func__); |
394 | 387 | ||
395 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | 388 | buf->dev.type = SNDRV_DMA_TYPE_DEV; |
396 | buf->dev.dev = pcm->card->dev; | 389 | buf->dev.dev = pcm->card->dev; |
@@ -409,7 +402,7 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
409 | struct snd_dma_buffer *buf; | 402 | struct snd_dma_buffer *buf; |
410 | int stream; | 403 | int stream; |
411 | 404 | ||
412 | DBG("Entered %s\n", __func__); | 405 | pr_debug("Entered %s\n", __func__); |
413 | 406 | ||
414 | for (stream = 0; stream < 2; stream++) { | 407 | for (stream = 0; stream < 2; stream++) { |
415 | substream = pcm->streams[stream].substream; | 408 | substream = pcm->streams[stream].substream; |
@@ -433,7 +426,7 @@ static int s3c24xx_pcm_new(struct snd_card *card, | |||
433 | { | 426 | { |
434 | int ret = 0; | 427 | int ret = 0; |
435 | 428 | ||
436 | DBG("Entered %s\n", __func__); | 429 | pr_debug("Entered %s\n", __func__); |
437 | 430 | ||
438 | if (!card->dev->dma_mask) | 431 | if (!card->dev->dma_mask) |
439 | card->dev->dma_mask = &s3c24xx_pcm_dmamask; | 432 | card->dev->dma_mask = &s3c24xx_pcm_dmamask; |
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index a0a4d1832a14..8e79a416db57 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <sound/s3c24xx_uda134x.h> | 22 | #include <sound/s3c24xx_uda134x.h> |
23 | #include <sound/uda134x.h> | 23 | #include <sound/uda134x.h> |
24 | 24 | ||
25 | #include <asm/plat-s3c24xx/regs-iis.h> | 25 | #include <plat/regs-iis.h> |
26 | 26 | ||
27 | #include "s3c24xx-pcm.h" | 27 | #include "s3c24xx-pcm.h" |
28 | #include "s3c24xx-i2s.h" | 28 | #include "s3c24xx-i2s.h" |
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c new file mode 100644 index 000000000000..33c5de7e255f --- /dev/null +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* sound/soc/s3c24xx/s3c64xx-i2s.c | ||
2 | * | ||
3 | * ALSA SoC Audio Layer - S3C64XX I2S driver | ||
4 | * | ||
5 | * Copyright 2008 Openmoko, Inc. | ||
6 | * Copyright 2008 Simtec Electronics | ||
7 | * Ben Dooks <ben@simtec.co.uk> | ||
8 | * http://armlinux.simtec.co.uk/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/clk.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/io.h> | ||
23 | |||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/soc.h> | ||
29 | |||
30 | #include <plat/regs-s3c2412-iis.h> | ||
31 | #include <plat/gpio-bank-d.h> | ||
32 | #include <plat/gpio-bank-e.h> | ||
33 | #include <plat/gpio-cfg.h> | ||
34 | #include <plat/audio.h> | ||
35 | |||
36 | #include <mach/map.h> | ||
37 | #include <mach/dma.h> | ||
38 | |||
39 | #include "s3c24xx-pcm.h" | ||
40 | #include "s3c64xx-i2s.h" | ||
41 | |||
42 | static struct s3c2410_dma_client s3c64xx_dma_client_out = { | ||
43 | .name = "I2S PCM Stereo out" | ||
44 | }; | ||
45 | |||
46 | static struct s3c2410_dma_client s3c64xx_dma_client_in = { | ||
47 | .name = "I2S PCM Stereo in" | ||
48 | }; | ||
49 | |||
50 | static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { | ||
51 | [0] = { | ||
52 | .channel = DMACH_I2S0_OUT, | ||
53 | .client = &s3c64xx_dma_client_out, | ||
54 | .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD, | ||
55 | .dma_size = 4, | ||
56 | }, | ||
57 | [1] = { | ||
58 | .channel = DMACH_I2S1_OUT, | ||
59 | .client = &s3c64xx_dma_client_out, | ||
60 | .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD, | ||
61 | .dma_size = 4, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = { | ||
66 | [0] = { | ||
67 | .channel = DMACH_I2S0_IN, | ||
68 | .client = &s3c64xx_dma_client_in, | ||
69 | .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD, | ||
70 | .dma_size = 4, | ||
71 | }, | ||
72 | [1] = { | ||
73 | .channel = DMACH_I2S1_IN, | ||
74 | .client = &s3c64xx_dma_client_in, | ||
75 | .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD, | ||
76 | .dma_size = 4, | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | static struct s3c_i2sv2_info s3c64xx_i2s[2]; | ||
81 | |||
82 | static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) | ||
83 | { | ||
84 | return cpu_dai->private_data; | ||
85 | } | ||
86 | |||
87 | static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | ||
88 | int clk_id, unsigned int freq, int dir) | ||
89 | { | ||
90 | struct s3c_i2sv2_info *i2s = to_info(cpu_dai); | ||
91 | u32 iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
92 | |||
93 | switch (clk_id) { | ||
94 | case S3C64XX_CLKSRC_PCLK: | ||
95 | iismod &= ~S3C64XX_IISMOD_IMS_SYSMUX; | ||
96 | break; | ||
97 | |||
98 | case S3C64XX_CLKSRC_MUX: | ||
99 | iismod |= S3C64XX_IISMOD_IMS_SYSMUX; | ||
100 | break; | ||
101 | |||
102 | default: | ||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | writel(iismod, i2s->regs + S3C2412_IISMOD); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | |||
112 | unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai) | ||
113 | { | ||
114 | struct s3c_i2sv2_info *i2s = to_info(dai); | ||
115 | |||
116 | return clk_get_rate(i2s->iis_cclk); | ||
117 | } | ||
118 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clockrate); | ||
119 | |||
120 | static int s3c64xx_i2s_probe(struct platform_device *pdev, | ||
121 | struct snd_soc_dai *dai) | ||
122 | { | ||
123 | struct device *dev = &pdev->dev; | ||
124 | struct s3c_i2sv2_info *i2s; | ||
125 | int ret; | ||
126 | |||
127 | dev_dbg(dev, "%s: probing dai %d\n", __func__, pdev->id); | ||
128 | |||
129 | if (pdev->id < 0 || pdev->id > ARRAY_SIZE(s3c64xx_i2s)) { | ||
130 | dev_err(dev, "id %d out of range\n", pdev->id); | ||
131 | return -EINVAL; | ||
132 | } | ||
133 | |||
134 | i2s = &s3c64xx_i2s[pdev->id]; | ||
135 | |||
136 | ret = s3c_i2sv2_probe(pdev, dai, i2s, | ||
137 | pdev->id ? S3C64XX_PA_IIS1 : S3C64XX_PA_IIS0); | ||
138 | if (ret) | ||
139 | return ret; | ||
140 | |||
141 | i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; | ||
142 | i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; | ||
143 | |||
144 | i2s->iis_cclk = clk_get(dev, "audio-bus"); | ||
145 | if (IS_ERR(i2s->iis_cclk)) { | ||
146 | dev_err(dev, "failed to get audio-bus"); | ||
147 | iounmap(i2s->regs); | ||
148 | return -ENODEV; | ||
149 | } | ||
150 | |||
151 | /* configure GPIO for i2s port */ | ||
152 | switch (pdev->id) { | ||
153 | case 0: | ||
154 | s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK); | ||
155 | s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK); | ||
156 | s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK); | ||
157 | s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI); | ||
158 | s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0); | ||
159 | break; | ||
160 | case 1: | ||
161 | s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK); | ||
162 | s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK); | ||
163 | s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK); | ||
164 | s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI); | ||
165 | s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0); | ||
166 | } | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | |||
172 | #define S3C64XX_I2S_RATES \ | ||
173 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | ||
174 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
175 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
176 | |||
177 | #define S3C64XX_I2S_FMTS \ | ||
178 | (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE) | ||
179 | |||
180 | static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = { | ||
181 | .set_sysclk = s3c64xx_i2s_set_sysclk, | ||
182 | }; | ||
183 | |||
184 | struct snd_soc_dai s3c64xx_i2s_dai = { | ||
185 | .name = "s3c64xx-i2s", | ||
186 | .id = 0, | ||
187 | .probe = s3c64xx_i2s_probe, | ||
188 | .playback = { | ||
189 | .channels_min = 2, | ||
190 | .channels_max = 2, | ||
191 | .rates = S3C64XX_I2S_RATES, | ||
192 | .formats = S3C64XX_I2S_FMTS, | ||
193 | }, | ||
194 | .capture = { | ||
195 | .channels_min = 2, | ||
196 | .channels_max = 2, | ||
197 | .rates = S3C64XX_I2S_RATES, | ||
198 | .formats = S3C64XX_I2S_FMTS, | ||
199 | }, | ||
200 | .ops = &s3c64xx_i2s_dai_ops, | ||
201 | }; | ||
202 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); | ||
203 | |||
204 | static int __init s3c64xx_i2s_init(void) | ||
205 | { | ||
206 | return s3c_i2sv2_register_dai(&s3c64xx_i2s_dai); | ||
207 | } | ||
208 | module_init(s3c64xx_i2s_init); | ||
209 | |||
210 | static void __exit s3c64xx_i2s_exit(void) | ||
211 | { | ||
212 | snd_soc_unregister_dai(&s3c64xx_i2s_dai); | ||
213 | } | ||
214 | module_exit(s3c64xx_i2s_exit); | ||
215 | |||
216 | /* Module information */ | ||
217 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | ||
218 | MODULE_DESCRIPTION("S3C64XX I2S SoC Interface"); | ||
219 | MODULE_LICENSE("GPL"); | ||
220 | |||
221 | |||
222 | |||
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h new file mode 100644 index 000000000000..b7ffe3c38b66 --- /dev/null +++ b/sound/soc/s3c24xx/s3c64xx-i2s.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* sound/soc/s3c24xx/s3c64xx-i2s.h | ||
2 | * | ||
3 | * ALSA SoC Audio Layer - S3C64XX I2S driver | ||
4 | * | ||
5 | * Copyright 2008 Openmoko, Inc. | ||
6 | * Copyright 2008 Simtec Electronics | ||
7 | * Ben Dooks <ben@simtec.co.uk> | ||
8 | * http://armlinux.simtec.co.uk/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H | ||
16 | #define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__ | ||
17 | |||
18 | #include "s3c-i2s-v2.h" | ||
19 | |||
20 | #define S3C64XX_DIV_BCLK S3C_I2SV2_DIV_BCLK | ||
21 | #define S3C64XX_DIV_RCLK S3C_I2SV2_DIV_RCLK | ||
22 | #define S3C64XX_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER | ||
23 | |||
24 | #define S3C64XX_CLKSRC_PCLK (0) | ||
25 | #define S3C64XX_CLKSRC_MUX (1) | ||
26 | |||
27 | extern struct snd_soc_dai s3c64xx_i2s_dai; | ||
28 | |||
29 | extern unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *cpu_dai); | ||
30 | |||
31 | #endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */ | ||
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index eab31838badf..41db75af3c69 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c | |||
@@ -267,6 +267,10 @@ static int hac_hw_params(struct snd_pcm_substream *substream, | |||
267 | #define AC97_FMTS \ | 267 | #define AC97_FMTS \ |
268 | SNDRV_PCM_FMTBIT_S16_LE | 268 | SNDRV_PCM_FMTBIT_S16_LE |
269 | 269 | ||
270 | static struct snd_soc_dai_ops hac_dai_ops = { | ||
271 | .hw_params = hac_hw_params, | ||
272 | }; | ||
273 | |||
270 | struct snd_soc_dai sh4_hac_dai[] = { | 274 | struct snd_soc_dai sh4_hac_dai[] = { |
271 | { | 275 | { |
272 | .name = "HAC0", | 276 | .name = "HAC0", |
@@ -284,9 +288,7 @@ struct snd_soc_dai sh4_hac_dai[] = { | |||
284 | .channels_min = 2, | 288 | .channels_min = 2, |
285 | .channels_max = 2, | 289 | .channels_max = 2, |
286 | }, | 290 | }, |
287 | .ops = { | 291 | .ops = &hac_dai_ops, |
288 | .hw_params = hac_hw_params, | ||
289 | }, | ||
290 | }, | 292 | }, |
291 | #ifdef CONFIG_CPU_SUBTYPE_SH7760 | 293 | #ifdef CONFIG_CPU_SUBTYPE_SH7760 |
292 | { | 294 | { |
@@ -305,9 +307,7 @@ struct snd_soc_dai sh4_hac_dai[] = { | |||
305 | .channels_min = 2, | 307 | .channels_min = 2, |
306 | .channels_max = 2, | 308 | .channels_max = 2, |
307 | }, | 309 | }, |
308 | .ops = { | 310 | .ops = &hac_dai_ops, |
309 | .hw_params = hac_hw_params, | ||
310 | }, | ||
311 | 311 | ||
312 | }, | 312 | }, |
313 | #endif | 313 | #endif |
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index d1e5390fddeb..56fa0872abbb 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c | |||
@@ -336,6 +336,16 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
336 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ | 336 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ |
337 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) | 337 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) |
338 | 338 | ||
339 | static struct snd_soc_dai_ops ssi_dai_ops = { | ||
340 | .startup = ssi_startup, | ||
341 | .shutdown = ssi_shutdown, | ||
342 | .trigger = ssi_trigger, | ||
343 | .hw_params = ssi_hw_params, | ||
344 | .set_sysclk = ssi_set_sysclk, | ||
345 | .set_clkdiv = ssi_set_clkdiv, | ||
346 | .set_fmt = ssi_set_fmt, | ||
347 | }; | ||
348 | |||
339 | struct snd_soc_dai sh4_ssi_dai[] = { | 349 | struct snd_soc_dai sh4_ssi_dai[] = { |
340 | { | 350 | { |
341 | .name = "SSI0", | 351 | .name = "SSI0", |
@@ -352,15 +362,7 @@ struct snd_soc_dai sh4_ssi_dai[] = { | |||
352 | .channels_min = 2, | 362 | .channels_min = 2, |
353 | .channels_max = 8, | 363 | .channels_max = 8, |
354 | }, | 364 | }, |
355 | .ops = { | 365 | .ops = &ssi_dai_ops, |
356 | .startup = ssi_startup, | ||
357 | .shutdown = ssi_shutdown, | ||
358 | .trigger = ssi_trigger, | ||
359 | .hw_params = ssi_hw_params, | ||
360 | .set_sysclk = ssi_set_sysclk, | ||
361 | .set_clkdiv = ssi_set_clkdiv, | ||
362 | .set_fmt = ssi_set_fmt, | ||
363 | }, | ||
364 | }, | 366 | }, |
365 | #ifdef CONFIG_CPU_SUBTYPE_SH7760 | 367 | #ifdef CONFIG_CPU_SUBTYPE_SH7760 |
366 | { | 368 | { |
@@ -378,15 +380,7 @@ struct snd_soc_dai sh4_ssi_dai[] = { | |||
378 | .channels_min = 2, | 380 | .channels_min = 2, |
379 | .channels_max = 8, | 381 | .channels_max = 8, |
380 | }, | 382 | }, |
381 | .ops = { | 383 | .ops = &ssi_dai_ops, |
382 | .startup = ssi_startup, | ||
383 | .shutdown = ssi_shutdown, | ||
384 | .trigger = ssi_trigger, | ||
385 | .hw_params = ssi_hw_params, | ||
386 | .set_sysclk = ssi_set_sysclk, | ||
387 | .set_clkdiv = ssi_set_clkdiv, | ||
388 | .set_fmt = ssi_set_fmt, | ||
389 | }, | ||
390 | }, | 384 | }, |
391 | #endif | 385 | #endif |
392 | }; | 386 | }; |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 637f0d1ea98e..6e710f705a74 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -133,8 +133,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
133 | mutex_lock(&pcm_mutex); | 133 | mutex_lock(&pcm_mutex); |
134 | 134 | ||
135 | /* startup the audio subsystem */ | 135 | /* startup the audio subsystem */ |
136 | if (cpu_dai->ops.startup) { | 136 | if (cpu_dai->ops->startup) { |
137 | ret = cpu_dai->ops.startup(substream, cpu_dai); | 137 | ret = cpu_dai->ops->startup(substream, cpu_dai); |
138 | if (ret < 0) { | 138 | if (ret < 0) { |
139 | printk(KERN_ERR "asoc: can't open interface %s\n", | 139 | printk(KERN_ERR "asoc: can't open interface %s\n", |
140 | cpu_dai->name); | 140 | cpu_dai->name); |
@@ -150,8 +150,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
150 | } | 150 | } |
151 | } | 151 | } |
152 | 152 | ||
153 | if (codec_dai->ops.startup) { | 153 | if (codec_dai->ops->startup) { |
154 | ret = codec_dai->ops.startup(substream, codec_dai); | 154 | ret = codec_dai->ops->startup(substream, codec_dai); |
155 | if (ret < 0) { | 155 | if (ret < 0) { |
156 | printk(KERN_ERR "asoc: can't open codec %s\n", | 156 | printk(KERN_ERR "asoc: can't open codec %s\n", |
157 | codec_dai->name); | 157 | codec_dai->name); |
@@ -234,7 +234,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
234 | cpu_dai->capture.active = codec_dai->capture.active = 1; | 234 | cpu_dai->capture.active = codec_dai->capture.active = 1; |
235 | cpu_dai->active = codec_dai->active = 1; | 235 | cpu_dai->active = codec_dai->active = 1; |
236 | cpu_dai->runtime = runtime; | 236 | cpu_dai->runtime = runtime; |
237 | socdev->codec->active++; | 237 | card->codec->active++; |
238 | mutex_unlock(&pcm_mutex); | 238 | mutex_unlock(&pcm_mutex); |
239 | return 0; | 239 | return 0; |
240 | 240 | ||
@@ -247,8 +247,8 @@ codec_dai_err: | |||
247 | platform->pcm_ops->close(substream); | 247 | platform->pcm_ops->close(substream); |
248 | 248 | ||
249 | platform_err: | 249 | platform_err: |
250 | if (cpu_dai->ops.shutdown) | 250 | if (cpu_dai->ops->shutdown) |
251 | cpu_dai->ops.shutdown(substream, cpu_dai); | 251 | cpu_dai->ops->shutdown(substream, cpu_dai); |
252 | out: | 252 | out: |
253 | mutex_unlock(&pcm_mutex); | 253 | mutex_unlock(&pcm_mutex); |
254 | return ret; | 254 | return ret; |
@@ -264,7 +264,7 @@ static void close_delayed_work(struct work_struct *work) | |||
264 | struct snd_soc_card *card = container_of(work, struct snd_soc_card, | 264 | struct snd_soc_card *card = container_of(work, struct snd_soc_card, |
265 | delayed_work.work); | 265 | delayed_work.work); |
266 | struct snd_soc_device *socdev = card->socdev; | 266 | struct snd_soc_device *socdev = card->socdev; |
267 | struct snd_soc_codec *codec = socdev->codec; | 267 | struct snd_soc_codec *codec = card->codec; |
268 | struct snd_soc_dai *codec_dai; | 268 | struct snd_soc_dai *codec_dai; |
269 | int i; | 269 | int i; |
270 | 270 | ||
@@ -319,7 +319,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
319 | struct snd_soc_platform *platform = card->platform; | 319 | struct snd_soc_platform *platform = card->platform; |
320 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; | 320 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
321 | struct snd_soc_dai *codec_dai = machine->codec_dai; | 321 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
322 | struct snd_soc_codec *codec = socdev->codec; | 322 | struct snd_soc_codec *codec = card->codec; |
323 | 323 | ||
324 | mutex_lock(&pcm_mutex); | 324 | mutex_lock(&pcm_mutex); |
325 | 325 | ||
@@ -340,11 +340,11 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
340 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 340 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
341 | snd_soc_dai_digital_mute(codec_dai, 1); | 341 | snd_soc_dai_digital_mute(codec_dai, 1); |
342 | 342 | ||
343 | if (cpu_dai->ops.shutdown) | 343 | if (cpu_dai->ops->shutdown) |
344 | cpu_dai->ops.shutdown(substream, cpu_dai); | 344 | cpu_dai->ops->shutdown(substream, cpu_dai); |
345 | 345 | ||
346 | if (codec_dai->ops.shutdown) | 346 | if (codec_dai->ops->shutdown) |
347 | codec_dai->ops.shutdown(substream, codec_dai); | 347 | codec_dai->ops->shutdown(substream, codec_dai); |
348 | 348 | ||
349 | if (machine->ops && machine->ops->shutdown) | 349 | if (machine->ops && machine->ops->shutdown) |
350 | machine->ops->shutdown(substream); | 350 | machine->ops->shutdown(substream); |
@@ -387,7 +387,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
387 | struct snd_soc_platform *platform = card->platform; | 387 | struct snd_soc_platform *platform = card->platform; |
388 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; | 388 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
389 | struct snd_soc_dai *codec_dai = machine->codec_dai; | 389 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
390 | struct snd_soc_codec *codec = socdev->codec; | 390 | struct snd_soc_codec *codec = card->codec; |
391 | int ret = 0; | 391 | int ret = 0; |
392 | 392 | ||
393 | mutex_lock(&pcm_mutex); | 393 | mutex_lock(&pcm_mutex); |
@@ -408,16 +408,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
408 | } | 408 | } |
409 | } | 409 | } |
410 | 410 | ||
411 | if (codec_dai->ops.prepare) { | 411 | if (codec_dai->ops->prepare) { |
412 | ret = codec_dai->ops.prepare(substream, codec_dai); | 412 | ret = codec_dai->ops->prepare(substream, codec_dai); |
413 | if (ret < 0) { | 413 | if (ret < 0) { |
414 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); | 414 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); |
415 | goto out; | 415 | goto out; |
416 | } | 416 | } |
417 | } | 417 | } |
418 | 418 | ||
419 | if (cpu_dai->ops.prepare) { | 419 | if (cpu_dai->ops->prepare) { |
420 | ret = cpu_dai->ops.prepare(substream, cpu_dai); | 420 | ret = cpu_dai->ops->prepare(substream, cpu_dai); |
421 | if (ret < 0) { | 421 | if (ret < 0) { |
422 | printk(KERN_ERR "asoc: cpu DAI prepare error\n"); | 422 | printk(KERN_ERR "asoc: cpu DAI prepare error\n"); |
423 | goto out; | 423 | goto out; |
@@ -494,8 +494,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
494 | } | 494 | } |
495 | } | 495 | } |
496 | 496 | ||
497 | if (codec_dai->ops.hw_params) { | 497 | if (codec_dai->ops->hw_params) { |
498 | ret = codec_dai->ops.hw_params(substream, params, codec_dai); | 498 | ret = codec_dai->ops->hw_params(substream, params, codec_dai); |
499 | if (ret < 0) { | 499 | if (ret < 0) { |
500 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", | 500 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", |
501 | codec_dai->name); | 501 | codec_dai->name); |
@@ -503,8 +503,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
503 | } | 503 | } |
504 | } | 504 | } |
505 | 505 | ||
506 | if (cpu_dai->ops.hw_params) { | 506 | if (cpu_dai->ops->hw_params) { |
507 | ret = cpu_dai->ops.hw_params(substream, params, cpu_dai); | 507 | ret = cpu_dai->ops->hw_params(substream, params, cpu_dai); |
508 | if (ret < 0) { | 508 | if (ret < 0) { |
509 | printk(KERN_ERR "asoc: interface %s hw params failed\n", | 509 | printk(KERN_ERR "asoc: interface %s hw params failed\n", |
510 | cpu_dai->name); | 510 | cpu_dai->name); |
@@ -526,12 +526,12 @@ out: | |||
526 | return ret; | 526 | return ret; |
527 | 527 | ||
528 | platform_err: | 528 | platform_err: |
529 | if (cpu_dai->ops.hw_free) | 529 | if (cpu_dai->ops->hw_free) |
530 | cpu_dai->ops.hw_free(substream, cpu_dai); | 530 | cpu_dai->ops->hw_free(substream, cpu_dai); |
531 | 531 | ||
532 | interface_err: | 532 | interface_err: |
533 | if (codec_dai->ops.hw_free) | 533 | if (codec_dai->ops->hw_free) |
534 | codec_dai->ops.hw_free(substream, codec_dai); | 534 | codec_dai->ops->hw_free(substream, codec_dai); |
535 | 535 | ||
536 | codec_err: | 536 | codec_err: |
537 | if (machine->ops && machine->ops->hw_free) | 537 | if (machine->ops && machine->ops->hw_free) |
@@ -553,7 +553,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
553 | struct snd_soc_platform *platform = card->platform; | 553 | struct snd_soc_platform *platform = card->platform; |
554 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; | 554 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
555 | struct snd_soc_dai *codec_dai = machine->codec_dai; | 555 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
556 | struct snd_soc_codec *codec = socdev->codec; | 556 | struct snd_soc_codec *codec = card->codec; |
557 | 557 | ||
558 | mutex_lock(&pcm_mutex); | 558 | mutex_lock(&pcm_mutex); |
559 | 559 | ||
@@ -570,11 +570,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
570 | platform->pcm_ops->hw_free(substream); | 570 | platform->pcm_ops->hw_free(substream); |
571 | 571 | ||
572 | /* now free hw params for the DAI's */ | 572 | /* now free hw params for the DAI's */ |
573 | if (codec_dai->ops.hw_free) | 573 | if (codec_dai->ops->hw_free) |
574 | codec_dai->ops.hw_free(substream, codec_dai); | 574 | codec_dai->ops->hw_free(substream, codec_dai); |
575 | 575 | ||
576 | if (cpu_dai->ops.hw_free) | 576 | if (cpu_dai->ops->hw_free) |
577 | cpu_dai->ops.hw_free(substream, cpu_dai); | 577 | cpu_dai->ops->hw_free(substream, cpu_dai); |
578 | 578 | ||
579 | mutex_unlock(&pcm_mutex); | 579 | mutex_unlock(&pcm_mutex); |
580 | return 0; | 580 | return 0; |
@@ -591,8 +591,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
591 | struct snd_soc_dai *codec_dai = machine->codec_dai; | 591 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
592 | int ret; | 592 | int ret; |
593 | 593 | ||
594 | if (codec_dai->ops.trigger) { | 594 | if (codec_dai->ops->trigger) { |
595 | ret = codec_dai->ops.trigger(substream, cmd, codec_dai); | 595 | ret = codec_dai->ops->trigger(substream, cmd, codec_dai); |
596 | if (ret < 0) | 596 | if (ret < 0) |
597 | return ret; | 597 | return ret; |
598 | } | 598 | } |
@@ -603,8 +603,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
603 | return ret; | 603 | return ret; |
604 | } | 604 | } |
605 | 605 | ||
606 | if (cpu_dai->ops.trigger) { | 606 | if (cpu_dai->ops->trigger) { |
607 | ret = cpu_dai->ops.trigger(substream, cmd, cpu_dai); | 607 | ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai); |
608 | if (ret < 0) | 608 | if (ret < 0) |
609 | return ret; | 609 | return ret; |
610 | } | 610 | } |
@@ -629,7 +629,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
629 | struct snd_soc_card *card = socdev->card; | 629 | struct snd_soc_card *card = socdev->card; |
630 | struct snd_soc_platform *platform = card->platform; | 630 | struct snd_soc_platform *platform = card->platform; |
631 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | 631 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; |
632 | struct snd_soc_codec *codec = socdev->codec; | 632 | struct snd_soc_codec *codec = card->codec; |
633 | int i; | 633 | int i; |
634 | 634 | ||
635 | /* Due to the resume being scheduled into a workqueue we could | 635 | /* Due to the resume being scheduled into a workqueue we could |
@@ -645,8 +645,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
645 | /* mute any active DAC's */ | 645 | /* mute any active DAC's */ |
646 | for (i = 0; i < card->num_links; i++) { | 646 | for (i = 0; i < card->num_links; i++) { |
647 | struct snd_soc_dai *dai = card->dai_link[i].codec_dai; | 647 | struct snd_soc_dai *dai = card->dai_link[i].codec_dai; |
648 | if (dai->ops.digital_mute && dai->playback.active) | 648 | if (dai->ops->digital_mute && dai->playback.active) |
649 | dai->ops.digital_mute(dai, 1); | 649 | dai->ops->digital_mute(dai, 1); |
650 | } | 650 | } |
651 | 651 | ||
652 | /* suspend all pcms */ | 652 | /* suspend all pcms */ |
@@ -705,7 +705,7 @@ static void soc_resume_deferred(struct work_struct *work) | |||
705 | struct snd_soc_device *socdev = card->socdev; | 705 | struct snd_soc_device *socdev = card->socdev; |
706 | struct snd_soc_platform *platform = card->platform; | 706 | struct snd_soc_platform *platform = card->platform; |
707 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | 707 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; |
708 | struct snd_soc_codec *codec = socdev->codec; | 708 | struct snd_soc_codec *codec = card->codec; |
709 | struct platform_device *pdev = to_platform_device(socdev->dev); | 709 | struct platform_device *pdev = to_platform_device(socdev->dev); |
710 | int i; | 710 | int i; |
711 | 711 | ||
@@ -741,8 +741,8 @@ static void soc_resume_deferred(struct work_struct *work) | |||
741 | /* unmute any active DACs */ | 741 | /* unmute any active DACs */ |
742 | for (i = 0; i < card->num_links; i++) { | 742 | for (i = 0; i < card->num_links; i++) { |
743 | struct snd_soc_dai *dai = card->dai_link[i].codec_dai; | 743 | struct snd_soc_dai *dai = card->dai_link[i].codec_dai; |
744 | if (dai->ops.digital_mute && dai->playback.active) | 744 | if (dai->ops->digital_mute && dai->playback.active) |
745 | dai->ops.digital_mute(dai, 0); | 745 | dai->ops->digital_mute(dai, 0); |
746 | } | 746 | } |
747 | 747 | ||
748 | for (i = 0; i < card->num_links; i++) { | 748 | for (i = 0; i < card->num_links; i++) { |
@@ -982,8 +982,8 @@ static struct platform_driver soc_driver = { | |||
982 | static int soc_new_pcm(struct snd_soc_device *socdev, | 982 | static int soc_new_pcm(struct snd_soc_device *socdev, |
983 | struct snd_soc_dai_link *dai_link, int num) | 983 | struct snd_soc_dai_link *dai_link, int num) |
984 | { | 984 | { |
985 | struct snd_soc_codec *codec = socdev->codec; | ||
986 | struct snd_soc_card *card = socdev->card; | 985 | struct snd_soc_card *card = socdev->card; |
986 | struct snd_soc_codec *codec = card->codec; | ||
987 | struct snd_soc_platform *platform = card->platform; | 987 | struct snd_soc_platform *platform = card->platform; |
988 | struct snd_soc_dai *codec_dai = dai_link->codec_dai; | 988 | struct snd_soc_dai *codec_dai = dai_link->codec_dai; |
989 | struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; | 989 | struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; |
@@ -998,7 +998,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
998 | 998 | ||
999 | rtd->dai = dai_link; | 999 | rtd->dai = dai_link; |
1000 | rtd->socdev = socdev; | 1000 | rtd->socdev = socdev; |
1001 | codec_dai->codec = socdev->codec; | 1001 | codec_dai->codec = card->codec; |
1002 | 1002 | ||
1003 | /* check client and interface hw capabilities */ | 1003 | /* check client and interface hw capabilities */ |
1004 | sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, | 1004 | sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, |
@@ -1048,9 +1048,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
1048 | } | 1048 | } |
1049 | 1049 | ||
1050 | /* codec register dump */ | 1050 | /* codec register dump */ |
1051 | static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf) | 1051 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) |
1052 | { | 1052 | { |
1053 | struct snd_soc_codec *codec = devdata->codec; | ||
1054 | int i, step = 1, count = 0; | 1053 | int i, step = 1, count = 0; |
1055 | 1054 | ||
1056 | if (!codec->reg_cache_size) | 1055 | if (!codec->reg_cache_size) |
@@ -1090,7 +1089,7 @@ static ssize_t codec_reg_show(struct device *dev, | |||
1090 | struct device_attribute *attr, char *buf) | 1089 | struct device_attribute *attr, char *buf) |
1091 | { | 1090 | { |
1092 | struct snd_soc_device *devdata = dev_get_drvdata(dev); | 1091 | struct snd_soc_device *devdata = dev_get_drvdata(dev); |
1093 | return soc_codec_reg_show(devdata, buf); | 1092 | return soc_codec_reg_show(devdata->card->codec, buf); |
1094 | } | 1093 | } |
1095 | 1094 | ||
1096 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); | 1095 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); |
@@ -1107,12 +1106,10 @@ static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, | |||
1107 | { | 1106 | { |
1108 | ssize_t ret; | 1107 | ssize_t ret; |
1109 | struct snd_soc_codec *codec = file->private_data; | 1108 | struct snd_soc_codec *codec = file->private_data; |
1110 | struct device *card_dev = codec->card->dev; | ||
1111 | struct snd_soc_device *devdata = card_dev->driver_data; | ||
1112 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 1109 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
1113 | if (!buf) | 1110 | if (!buf) |
1114 | return -ENOMEM; | 1111 | return -ENOMEM; |
1115 | ret = soc_codec_reg_show(devdata, buf); | 1112 | ret = soc_codec_reg_show(codec, buf); |
1116 | if (ret >= 0) | 1113 | if (ret >= 0) |
1117 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); | 1114 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); |
1118 | kfree(buf); | 1115 | kfree(buf); |
@@ -1309,8 +1306,8 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits); | |||
1309 | */ | 1306 | */ |
1310 | int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) | 1307 | int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) |
1311 | { | 1308 | { |
1312 | struct snd_soc_codec *codec = socdev->codec; | ||
1313 | struct snd_soc_card *card = socdev->card; | 1309 | struct snd_soc_card *card = socdev->card; |
1310 | struct snd_soc_codec *codec = card->codec; | ||
1314 | int ret, i; | 1311 | int ret, i; |
1315 | 1312 | ||
1316 | mutex_lock(&codec->mutex); | 1313 | mutex_lock(&codec->mutex); |
@@ -1355,8 +1352,8 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms); | |||
1355 | */ | 1352 | */ |
1356 | int snd_soc_init_card(struct snd_soc_device *socdev) | 1353 | int snd_soc_init_card(struct snd_soc_device *socdev) |
1357 | { | 1354 | { |
1358 | struct snd_soc_codec *codec = socdev->codec; | ||
1359 | struct snd_soc_card *card = socdev->card; | 1355 | struct snd_soc_card *card = socdev->card; |
1356 | struct snd_soc_codec *codec = card->codec; | ||
1360 | int ret = 0, i, ac97 = 0, err = 0; | 1357 | int ret = 0, i, ac97 = 0, err = 0; |
1361 | 1358 | ||
1362 | for (i = 0; i < card->num_links; i++) { | 1359 | for (i = 0; i < card->num_links; i++) { |
@@ -1407,7 +1404,7 @@ int snd_soc_init_card(struct snd_soc_device *socdev) | |||
1407 | if (err < 0) | 1404 | if (err < 0) |
1408 | printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); | 1405 | printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); |
1409 | 1406 | ||
1410 | soc_init_codec_debugfs(socdev->codec); | 1407 | soc_init_codec_debugfs(codec); |
1411 | mutex_unlock(&codec->mutex); | 1408 | mutex_unlock(&codec->mutex); |
1412 | 1409 | ||
1413 | out: | 1410 | out: |
@@ -1424,18 +1421,19 @@ EXPORT_SYMBOL_GPL(snd_soc_init_card); | |||
1424 | */ | 1421 | */ |
1425 | void snd_soc_free_pcms(struct snd_soc_device *socdev) | 1422 | void snd_soc_free_pcms(struct snd_soc_device *socdev) |
1426 | { | 1423 | { |
1427 | struct snd_soc_codec *codec = socdev->codec; | 1424 | struct snd_soc_codec *codec = socdev->card->codec; |
1428 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1425 | #ifdef CONFIG_SND_SOC_AC97_BUS |
1429 | struct snd_soc_dai *codec_dai; | 1426 | struct snd_soc_dai *codec_dai; |
1430 | int i; | 1427 | int i; |
1431 | #endif | 1428 | #endif |
1432 | 1429 | ||
1433 | mutex_lock(&codec->mutex); | 1430 | mutex_lock(&codec->mutex); |
1434 | soc_cleanup_codec_debugfs(socdev->codec); | 1431 | soc_cleanup_codec_debugfs(codec); |
1435 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1432 | #ifdef CONFIG_SND_SOC_AC97_BUS |
1436 | for (i = 0; i < codec->num_dai; i++) { | 1433 | for (i = 0; i < codec->num_dai; i++) { |
1437 | codec_dai = &codec->dai[i]; | 1434 | codec_dai = &codec->dai[i]; |
1438 | if (codec_dai->ac97_control && codec->ac97) { | 1435 | if (codec_dai->ac97_control && codec->ac97 && |
1436 | strcmp(codec->name, "AC97") != 0) { | ||
1439 | soc_ac97_dev_unregister(codec); | 1437 | soc_ac97_dev_unregister(codec); |
1440 | goto free_card; | 1438 | goto free_card; |
1441 | } | 1439 | } |
@@ -1498,6 +1496,37 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | |||
1498 | EXPORT_SYMBOL_GPL(snd_soc_cnew); | 1496 | EXPORT_SYMBOL_GPL(snd_soc_cnew); |
1499 | 1497 | ||
1500 | /** | 1498 | /** |
1499 | * snd_soc_add_controls - add an array of controls to a codec. | ||
1500 | * Convienience function to add a list of controls. Many codecs were | ||
1501 | * duplicating this code. | ||
1502 | * | ||
1503 | * @codec: codec to add controls to | ||
1504 | * @controls: array of controls to add | ||
1505 | * @num_controls: number of elements in the array | ||
1506 | * | ||
1507 | * Return 0 for success, else error. | ||
1508 | */ | ||
1509 | int snd_soc_add_controls(struct snd_soc_codec *codec, | ||
1510 | const struct snd_kcontrol_new *controls, int num_controls) | ||
1511 | { | ||
1512 | struct snd_card *card = codec->card; | ||
1513 | int err, i; | ||
1514 | |||
1515 | for (i = 0; i < num_controls; i++) { | ||
1516 | const struct snd_kcontrol_new *control = &controls[i]; | ||
1517 | err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL)); | ||
1518 | if (err < 0) { | ||
1519 | dev_err(codec->dev, "%s: Failed to add %s\n", | ||
1520 | codec->name, control->name); | ||
1521 | return err; | ||
1522 | } | ||
1523 | } | ||
1524 | |||
1525 | return 0; | ||
1526 | } | ||
1527 | EXPORT_SYMBOL_GPL(snd_soc_add_controls); | ||
1528 | |||
1529 | /** | ||
1501 | * snd_soc_info_enum_double - enumerated double mixer info callback | 1530 | * snd_soc_info_enum_double - enumerated double mixer info callback |
1502 | * @kcontrol: mixer control | 1531 | * @kcontrol: mixer control |
1503 | * @uinfo: control element information | 1532 | * @uinfo: control element information |
@@ -2023,8 +2052,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); | |||
2023 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 2052 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
2024 | unsigned int freq, int dir) | 2053 | unsigned int freq, int dir) |
2025 | { | 2054 | { |
2026 | if (dai->ops.set_sysclk) | 2055 | if (dai->ops->set_sysclk) |
2027 | return dai->ops.set_sysclk(dai, clk_id, freq, dir); | 2056 | return dai->ops->set_sysclk(dai, clk_id, freq, dir); |
2028 | else | 2057 | else |
2029 | return -EINVAL; | 2058 | return -EINVAL; |
2030 | } | 2059 | } |
@@ -2043,8 +2072,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); | |||
2043 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, | 2072 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, |
2044 | int div_id, int div) | 2073 | int div_id, int div) |
2045 | { | 2074 | { |
2046 | if (dai->ops.set_clkdiv) | 2075 | if (dai->ops->set_clkdiv) |
2047 | return dai->ops.set_clkdiv(dai, div_id, div); | 2076 | return dai->ops->set_clkdiv(dai, div_id, div); |
2048 | else | 2077 | else |
2049 | return -EINVAL; | 2078 | return -EINVAL; |
2050 | } | 2079 | } |
@@ -2062,8 +2091,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); | |||
2062 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, | 2091 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, |
2063 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 2092 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
2064 | { | 2093 | { |
2065 | if (dai->ops.set_pll) | 2094 | if (dai->ops->set_pll) |
2066 | return dai->ops.set_pll(dai, pll_id, freq_in, freq_out); | 2095 | return dai->ops->set_pll(dai, pll_id, freq_in, freq_out); |
2067 | else | 2096 | else |
2068 | return -EINVAL; | 2097 | return -EINVAL; |
2069 | } | 2098 | } |
@@ -2078,8 +2107,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); | |||
2078 | */ | 2107 | */ |
2079 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | 2108 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
2080 | { | 2109 | { |
2081 | if (dai->ops.set_fmt) | 2110 | if (dai->ops->set_fmt) |
2082 | return dai->ops.set_fmt(dai, fmt); | 2111 | return dai->ops->set_fmt(dai, fmt); |
2083 | else | 2112 | else |
2084 | return -EINVAL; | 2113 | return -EINVAL; |
2085 | } | 2114 | } |
@@ -2097,8 +2126,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | |||
2097 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | 2126 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, |
2098 | unsigned int mask, int slots) | 2127 | unsigned int mask, int slots) |
2099 | { | 2128 | { |
2100 | if (dai->ops.set_sysclk) | 2129 | if (dai->ops->set_sysclk) |
2101 | return dai->ops.set_tdm_slot(dai, mask, slots); | 2130 | return dai->ops->set_tdm_slot(dai, mask, slots); |
2102 | else | 2131 | else |
2103 | return -EINVAL; | 2132 | return -EINVAL; |
2104 | } | 2133 | } |
@@ -2113,8 +2142,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | |||
2113 | */ | 2142 | */ |
2114 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) | 2143 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) |
2115 | { | 2144 | { |
2116 | if (dai->ops.set_sysclk) | 2145 | if (dai->ops->set_sysclk) |
2117 | return dai->ops.set_tristate(dai, tristate); | 2146 | return dai->ops->set_tristate(dai, tristate); |
2118 | else | 2147 | else |
2119 | return -EINVAL; | 2148 | return -EINVAL; |
2120 | } | 2149 | } |
@@ -2129,8 +2158,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); | |||
2129 | */ | 2158 | */ |
2130 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) | 2159 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) |
2131 | { | 2160 | { |
2132 | if (dai->ops.digital_mute) | 2161 | if (dai->ops->digital_mute) |
2133 | return dai->ops.digital_mute(dai, mute); | 2162 | return dai->ops->digital_mute(dai, mute); |
2134 | else | 2163 | else |
2135 | return -EINVAL; | 2164 | return -EINVAL; |
2136 | } | 2165 | } |
@@ -2183,6 +2212,9 @@ static int snd_soc_unregister_card(struct snd_soc_card *card) | |||
2183 | return 0; | 2212 | return 0; |
2184 | } | 2213 | } |
2185 | 2214 | ||
2215 | static struct snd_soc_dai_ops null_dai_ops = { | ||
2216 | }; | ||
2217 | |||
2186 | /** | 2218 | /** |
2187 | * snd_soc_register_dai - Register a DAI with the ASoC core | 2219 | * snd_soc_register_dai - Register a DAI with the ASoC core |
2188 | * | 2220 | * |
@@ -2197,6 +2229,9 @@ int snd_soc_register_dai(struct snd_soc_dai *dai) | |||
2197 | if (!dai->dev) | 2229 | if (!dai->dev) |
2198 | printk(KERN_WARNING "No device for DAI %s\n", dai->name); | 2230 | printk(KERN_WARNING "No device for DAI %s\n", dai->name); |
2199 | 2231 | ||
2232 | if (!dai->ops) | ||
2233 | dai->ops = &null_dai_ops; | ||
2234 | |||
2200 | INIT_LIST_HEAD(&dai->list); | 2235 | INIT_LIST_HEAD(&dai->list); |
2201 | 2236 | ||
2202 | mutex_lock(&client_mutex); | 2237 | mutex_lock(&client_mutex); |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a2f1da8b4646..735903a74675 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -54,14 +54,15 @@ | |||
54 | static int dapm_up_seq[] = { | 54 | static int dapm_up_seq[] = { |
55 | snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, | 55 | snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, |
56 | snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, | 56 | snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, |
57 | snd_soc_dapm_mixer, snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, | 57 | snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga, |
58 | snd_soc_dapm_spk, snd_soc_dapm_post | 58 | snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post |
59 | }; | 59 | }; |
60 | |||
60 | static int dapm_down_seq[] = { | 61 | static int dapm_down_seq[] = { |
61 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, | 62 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, |
62 | snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, | 63 | snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer, |
63 | snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_value_mux, | 64 | snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias, |
64 | snd_soc_dapm_post | 65 | snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post |
65 | }; | 66 | }; |
66 | 67 | ||
67 | static int dapm_status = 1; | 68 | static int dapm_status = 1; |
@@ -101,7 +102,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
101 | { | 102 | { |
102 | switch (w->id) { | 103 | switch (w->id) { |
103 | case snd_soc_dapm_switch: | 104 | case snd_soc_dapm_switch: |
104 | case snd_soc_dapm_mixer: { | 105 | case snd_soc_dapm_mixer: |
106 | case snd_soc_dapm_mixer_named_ctl: { | ||
105 | int val; | 107 | int val; |
106 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | 108 | struct soc_mixer_control *mc = (struct soc_mixer_control *) |
107 | w->kcontrols[i].private_value; | 109 | w->kcontrols[i].private_value; |
@@ -323,15 +325,32 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, | |||
323 | if (path->name != (char*)w->kcontrols[i].name) | 325 | if (path->name != (char*)w->kcontrols[i].name) |
324 | continue; | 326 | continue; |
325 | 327 | ||
326 | /* add dapm control with long name */ | 328 | /* add dapm control with long name. |
327 | name_len = 2 + strlen(w->name) | 329 | * for dapm_mixer this is the concatenation of the |
328 | + strlen(w->kcontrols[i].name); | 330 | * mixer and kcontrol name. |
331 | * for dapm_mixer_named_ctl this is simply the | ||
332 | * kcontrol name. | ||
333 | */ | ||
334 | name_len = strlen(w->kcontrols[i].name) + 1; | ||
335 | if (w->id != snd_soc_dapm_mixer_named_ctl) | ||
336 | name_len += 1 + strlen(w->name); | ||
337 | |||
329 | path->long_name = kmalloc(name_len, GFP_KERNEL); | 338 | path->long_name = kmalloc(name_len, GFP_KERNEL); |
339 | |||
330 | if (path->long_name == NULL) | 340 | if (path->long_name == NULL) |
331 | return -ENOMEM; | 341 | return -ENOMEM; |
332 | 342 | ||
333 | snprintf(path->long_name, name_len, "%s %s", | 343 | switch (w->id) { |
334 | w->name, w->kcontrols[i].name); | 344 | default: |
345 | snprintf(path->long_name, name_len, "%s %s", | ||
346 | w->name, w->kcontrols[i].name); | ||
347 | break; | ||
348 | case snd_soc_dapm_mixer_named_ctl: | ||
349 | snprintf(path->long_name, name_len, "%s", | ||
350 | w->kcontrols[i].name); | ||
351 | break; | ||
352 | } | ||
353 | |||
335 | path->long_name[name_len - 1] = '\0'; | 354 | path->long_name[name_len - 1] = '\0'; |
336 | 355 | ||
337 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, | 356 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, |
@@ -503,6 +522,137 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, | |||
503 | EXPORT_SYMBOL_GPL(dapm_reg_event); | 522 | EXPORT_SYMBOL_GPL(dapm_reg_event); |
504 | 523 | ||
505 | /* | 524 | /* |
525 | * Scan a single DAPM widget for a complete audio path and update the | ||
526 | * power status appropriately. | ||
527 | */ | ||
528 | static int dapm_power_widget(struct snd_soc_codec *codec, int event, | ||
529 | struct snd_soc_dapm_widget *w) | ||
530 | { | ||
531 | int in, out, power_change, power, ret; | ||
532 | |||
533 | /* vmid - no action */ | ||
534 | if (w->id == snd_soc_dapm_vmid) | ||
535 | return 0; | ||
536 | |||
537 | /* active ADC */ | ||
538 | if (w->id == snd_soc_dapm_adc && w->active) { | ||
539 | in = is_connected_input_ep(w); | ||
540 | dapm_clear_walk(w->codec); | ||
541 | w->power = (in != 0) ? 1 : 0; | ||
542 | dapm_update_bits(w); | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | /* active DAC */ | ||
547 | if (w->id == snd_soc_dapm_dac && w->active) { | ||
548 | out = is_connected_output_ep(w); | ||
549 | dapm_clear_walk(w->codec); | ||
550 | w->power = (out != 0) ? 1 : 0; | ||
551 | dapm_update_bits(w); | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | /* pre and post event widgets */ | ||
556 | if (w->id == snd_soc_dapm_pre) { | ||
557 | if (!w->event) | ||
558 | return 0; | ||
559 | |||
560 | if (event == SND_SOC_DAPM_STREAM_START) { | ||
561 | ret = w->event(w, | ||
562 | NULL, SND_SOC_DAPM_PRE_PMU); | ||
563 | if (ret < 0) | ||
564 | return ret; | ||
565 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | ||
566 | ret = w->event(w, | ||
567 | NULL, SND_SOC_DAPM_PRE_PMD); | ||
568 | if (ret < 0) | ||
569 | return ret; | ||
570 | } | ||
571 | return 0; | ||
572 | } | ||
573 | if (w->id == snd_soc_dapm_post) { | ||
574 | if (!w->event) | ||
575 | return 0; | ||
576 | |||
577 | if (event == SND_SOC_DAPM_STREAM_START) { | ||
578 | ret = w->event(w, | ||
579 | NULL, SND_SOC_DAPM_POST_PMU); | ||
580 | if (ret < 0) | ||
581 | return ret; | ||
582 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | ||
583 | ret = w->event(w, | ||
584 | NULL, SND_SOC_DAPM_POST_PMD); | ||
585 | if (ret < 0) | ||
586 | return ret; | ||
587 | } | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | /* all other widgets */ | ||
592 | in = is_connected_input_ep(w); | ||
593 | dapm_clear_walk(w->codec); | ||
594 | out = is_connected_output_ep(w); | ||
595 | dapm_clear_walk(w->codec); | ||
596 | power = (out != 0 && in != 0) ? 1 : 0; | ||
597 | power_change = (w->power == power) ? 0 : 1; | ||
598 | w->power = power; | ||
599 | |||
600 | if (!power_change) | ||
601 | return 0; | ||
602 | |||
603 | /* call any power change event handlers */ | ||
604 | if (w->event) | ||
605 | pr_debug("power %s event for %s flags %x\n", | ||
606 | w->power ? "on" : "off", | ||
607 | w->name, w->event_flags); | ||
608 | |||
609 | /* power up pre event */ | ||
610 | if (power && w->event && | ||
611 | (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { | ||
612 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); | ||
613 | if (ret < 0) | ||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | /* power down pre event */ | ||
618 | if (!power && w->event && | ||
619 | (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { | ||
620 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); | ||
621 | if (ret < 0) | ||
622 | return ret; | ||
623 | } | ||
624 | |||
625 | /* Lower PGA volume to reduce pops */ | ||
626 | if (w->id == snd_soc_dapm_pga && !power) | ||
627 | dapm_set_pga(w, power); | ||
628 | |||
629 | dapm_update_bits(w); | ||
630 | |||
631 | /* Raise PGA volume to reduce pops */ | ||
632 | if (w->id == snd_soc_dapm_pga && power) | ||
633 | dapm_set_pga(w, power); | ||
634 | |||
635 | /* power up post event */ | ||
636 | if (power && w->event && | ||
637 | (w->event_flags & SND_SOC_DAPM_POST_PMU)) { | ||
638 | ret = w->event(w, | ||
639 | NULL, SND_SOC_DAPM_POST_PMU); | ||
640 | if (ret < 0) | ||
641 | return ret; | ||
642 | } | ||
643 | |||
644 | /* power down post event */ | ||
645 | if (!power && w->event && | ||
646 | (w->event_flags & SND_SOC_DAPM_POST_PMD)) { | ||
647 | ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); | ||
648 | if (ret < 0) | ||
649 | return ret; | ||
650 | } | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | /* | ||
506 | * Scan each dapm widget for complete audio path. | 656 | * Scan each dapm widget for complete audio path. |
507 | * A complete path is a route that has valid endpoints i.e.:- | 657 | * A complete path is a route that has valid endpoints i.e.:- |
508 | * | 658 | * |
@@ -514,7 +664,7 @@ EXPORT_SYMBOL_GPL(dapm_reg_event); | |||
514 | static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | 664 | static int dapm_power_widgets(struct snd_soc_codec *codec, int event) |
515 | { | 665 | { |
516 | struct snd_soc_dapm_widget *w; | 666 | struct snd_soc_dapm_widget *w; |
517 | int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power; | 667 | int i, c = 1, *seq = NULL, ret = 0; |
518 | 668 | ||
519 | /* do we have a sequenced stream event */ | 669 | /* do we have a sequenced stream event */ |
520 | if (event == SND_SOC_DAPM_STREAM_START) { | 670 | if (event == SND_SOC_DAPM_STREAM_START) { |
@@ -525,135 +675,20 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
525 | seq = dapm_down_seq; | 675 | seq = dapm_down_seq; |
526 | } | 676 | } |
527 | 677 | ||
528 | for(i = 0; i < c; i++) { | 678 | for (i = 0; i < c; i++) { |
529 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 679 | list_for_each_entry(w, &codec->dapm_widgets, list) { |
530 | 680 | ||
531 | /* is widget in stream order */ | 681 | /* is widget in stream order */ |
532 | if (seq && seq[i] && w->id != seq[i]) | 682 | if (seq && seq[i] && w->id != seq[i]) |
533 | continue; | 683 | continue; |
534 | 684 | ||
535 | /* vmid - no action */ | 685 | ret = dapm_power_widget(codec, event, w); |
536 | if (w->id == snd_soc_dapm_vmid) | 686 | if (ret != 0) |
537 | continue; | 687 | return ret; |
538 | |||
539 | /* active ADC */ | ||
540 | if (w->id == snd_soc_dapm_adc && w->active) { | ||
541 | in = is_connected_input_ep(w); | ||
542 | dapm_clear_walk(w->codec); | ||
543 | w->power = (in != 0) ? 1 : 0; | ||
544 | dapm_update_bits(w); | ||
545 | continue; | ||
546 | } | ||
547 | |||
548 | /* active DAC */ | ||
549 | if (w->id == snd_soc_dapm_dac && w->active) { | ||
550 | out = is_connected_output_ep(w); | ||
551 | dapm_clear_walk(w->codec); | ||
552 | w->power = (out != 0) ? 1 : 0; | ||
553 | dapm_update_bits(w); | ||
554 | continue; | ||
555 | } | ||
556 | |||
557 | /* pre and post event widgets */ | ||
558 | if (w->id == snd_soc_dapm_pre) { | ||
559 | if (!w->event) | ||
560 | continue; | ||
561 | |||
562 | if (event == SND_SOC_DAPM_STREAM_START) { | ||
563 | ret = w->event(w, | ||
564 | NULL, SND_SOC_DAPM_PRE_PMU); | ||
565 | if (ret < 0) | ||
566 | return ret; | ||
567 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | ||
568 | ret = w->event(w, | ||
569 | NULL, SND_SOC_DAPM_PRE_PMD); | ||
570 | if (ret < 0) | ||
571 | return ret; | ||
572 | } | ||
573 | continue; | ||
574 | } | ||
575 | if (w->id == snd_soc_dapm_post) { | ||
576 | if (!w->event) | ||
577 | continue; | ||
578 | |||
579 | if (event == SND_SOC_DAPM_STREAM_START) { | ||
580 | ret = w->event(w, | ||
581 | NULL, SND_SOC_DAPM_POST_PMU); | ||
582 | if (ret < 0) | ||
583 | return ret; | ||
584 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | ||
585 | ret = w->event(w, | ||
586 | NULL, SND_SOC_DAPM_POST_PMD); | ||
587 | if (ret < 0) | ||
588 | return ret; | ||
589 | } | ||
590 | continue; | ||
591 | } | ||
592 | |||
593 | /* all other widgets */ | ||
594 | in = is_connected_input_ep(w); | ||
595 | dapm_clear_walk(w->codec); | ||
596 | out = is_connected_output_ep(w); | ||
597 | dapm_clear_walk(w->codec); | ||
598 | power = (out != 0 && in != 0) ? 1 : 0; | ||
599 | power_change = (w->power == power) ? 0: 1; | ||
600 | w->power = power; | ||
601 | |||
602 | if (!power_change) | ||
603 | continue; | ||
604 | |||
605 | /* call any power change event handlers */ | ||
606 | if (w->event) | ||
607 | pr_debug("power %s event for %s flags %x\n", | ||
608 | w->power ? "on" : "off", | ||
609 | w->name, w->event_flags); | ||
610 | |||
611 | /* power up pre event */ | ||
612 | if (power && w->event && | ||
613 | (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { | ||
614 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); | ||
615 | if (ret < 0) | ||
616 | return ret; | ||
617 | } | ||
618 | |||
619 | /* power down pre event */ | ||
620 | if (!power && w->event && | ||
621 | (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { | ||
622 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); | ||
623 | if (ret < 0) | ||
624 | return ret; | ||
625 | } | ||
626 | |||
627 | /* Lower PGA volume to reduce pops */ | ||
628 | if (w->id == snd_soc_dapm_pga && !power) | ||
629 | dapm_set_pga(w, power); | ||
630 | |||
631 | dapm_update_bits(w); | ||
632 | |||
633 | /* Raise PGA volume to reduce pops */ | ||
634 | if (w->id == snd_soc_dapm_pga && power) | ||
635 | dapm_set_pga(w, power); | ||
636 | |||
637 | /* power up post event */ | ||
638 | if (power && w->event && | ||
639 | (w->event_flags & SND_SOC_DAPM_POST_PMU)) { | ||
640 | ret = w->event(w, | ||
641 | NULL, SND_SOC_DAPM_POST_PMU); | ||
642 | if (ret < 0) | ||
643 | return ret; | ||
644 | } | ||
645 | |||
646 | /* power down post event */ | ||
647 | if (!power && w->event && | ||
648 | (w->event_flags & SND_SOC_DAPM_POST_PMD)) { | ||
649 | ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); | ||
650 | if (ret < 0) | ||
651 | return ret; | ||
652 | } | ||
653 | } | 688 | } |
654 | } | 689 | } |
655 | 690 | ||
656 | return ret; | 691 | return 0; |
657 | } | 692 | } |
658 | 693 | ||
659 | #ifdef DEBUG | 694 | #ifdef DEBUG |
@@ -687,6 +722,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | |||
687 | case snd_soc_dapm_adc: | 722 | case snd_soc_dapm_adc: |
688 | case snd_soc_dapm_pga: | 723 | case snd_soc_dapm_pga: |
689 | case snd_soc_dapm_mixer: | 724 | case snd_soc_dapm_mixer: |
725 | case snd_soc_dapm_mixer_named_ctl: | ||
690 | if (w->name) { | 726 | if (w->name) { |
691 | in = is_connected_input_ep(w); | 727 | in = is_connected_input_ep(w); |
692 | dapm_clear_walk(w->codec); | 728 | dapm_clear_walk(w->codec); |
@@ -760,6 +796,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
760 | int found = 0; | 796 | int found = 0; |
761 | 797 | ||
762 | if (widget->id != snd_soc_dapm_mixer && | 798 | if (widget->id != snd_soc_dapm_mixer && |
799 | widget->id != snd_soc_dapm_mixer_named_ctl && | ||
763 | widget->id != snd_soc_dapm_switch) | 800 | widget->id != snd_soc_dapm_switch) |
764 | return -ENODEV; | 801 | return -ENODEV; |
765 | 802 | ||
@@ -795,7 +832,7 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
795 | struct device_attribute *attr, char *buf) | 832 | struct device_attribute *attr, char *buf) |
796 | { | 833 | { |
797 | struct snd_soc_device *devdata = dev_get_drvdata(dev); | 834 | struct snd_soc_device *devdata = dev_get_drvdata(dev); |
798 | struct snd_soc_codec *codec = devdata->codec; | 835 | struct snd_soc_codec *codec = devdata->card->codec; |
799 | struct snd_soc_dapm_widget *w; | 836 | struct snd_soc_dapm_widget *w; |
800 | int count = 0; | 837 | int count = 0; |
801 | char *state = "not set"; | 838 | char *state = "not set"; |
@@ -813,6 +850,7 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
813 | case snd_soc_dapm_adc: | 850 | case snd_soc_dapm_adc: |
814 | case snd_soc_dapm_pga: | 851 | case snd_soc_dapm_pga: |
815 | case snd_soc_dapm_mixer: | 852 | case snd_soc_dapm_mixer: |
853 | case snd_soc_dapm_mixer_named_ctl: | ||
816 | if (w->name) | 854 | if (w->name) |
817 | count += sprintf(buf + count, "%s: %s\n", | 855 | count += sprintf(buf + count, "%s: %s\n", |
818 | w->name, w->power ? "On":"Off"); | 856 | w->name, w->power ? "On":"Off"); |
@@ -876,7 +914,7 @@ static void dapm_free_widgets(struct snd_soc_codec *codec) | |||
876 | } | 914 | } |
877 | 915 | ||
878 | static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, | 916 | static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, |
879 | char *pin, int status) | 917 | const char *pin, int status) |
880 | { | 918 | { |
881 | struct snd_soc_dapm_widget *w; | 919 | struct snd_soc_dapm_widget *w; |
882 | 920 | ||
@@ -991,6 +1029,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
991 | break; | 1029 | break; |
992 | case snd_soc_dapm_switch: | 1030 | case snd_soc_dapm_switch: |
993 | case snd_soc_dapm_mixer: | 1031 | case snd_soc_dapm_mixer: |
1032 | case snd_soc_dapm_mixer_named_ctl: | ||
994 | ret = dapm_connect_mixer(codec, wsource, wsink, path, control); | 1033 | ret = dapm_connect_mixer(codec, wsource, wsink, path, control); |
995 | if (ret != 0) | 1034 | if (ret != 0) |
996 | goto err; | 1035 | goto err; |
@@ -1068,6 +1107,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | |||
1068 | switch(w->id) { | 1107 | switch(w->id) { |
1069 | case snd_soc_dapm_switch: | 1108 | case snd_soc_dapm_switch: |
1070 | case snd_soc_dapm_mixer: | 1109 | case snd_soc_dapm_mixer: |
1110 | case snd_soc_dapm_mixer_named_ctl: | ||
1071 | dapm_new_mixer(codec, w); | 1111 | dapm_new_mixer(codec, w); |
1072 | break; | 1112 | break; |
1073 | case snd_soc_dapm_mux: | 1113 | case snd_soc_dapm_mux: |
@@ -1396,6 +1436,76 @@ out: | |||
1396 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | 1436 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); |
1397 | 1437 | ||
1398 | /** | 1438 | /** |
1439 | * snd_soc_dapm_info_pin_switch - Info for a pin switch | ||
1440 | * | ||
1441 | * @kcontrol: mixer control | ||
1442 | * @uinfo: control element information | ||
1443 | * | ||
1444 | * Callback to provide information about a pin switch control. | ||
1445 | */ | ||
1446 | int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol, | ||
1447 | struct snd_ctl_elem_info *uinfo) | ||
1448 | { | ||
1449 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1450 | uinfo->count = 1; | ||
1451 | uinfo->value.integer.min = 0; | ||
1452 | uinfo->value.integer.max = 1; | ||
1453 | |||
1454 | return 0; | ||
1455 | } | ||
1456 | EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch); | ||
1457 | |||
1458 | /** | ||
1459 | * snd_soc_dapm_get_pin_switch - Get information for a pin switch | ||
1460 | * | ||
1461 | * @kcontrol: mixer control | ||
1462 | * @ucontrol: Value | ||
1463 | */ | ||
1464 | int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, | ||
1465 | struct snd_ctl_elem_value *ucontrol) | ||
1466 | { | ||
1467 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1468 | const char *pin = (const char *)kcontrol->private_value; | ||
1469 | |||
1470 | mutex_lock(&codec->mutex); | ||
1471 | |||
1472 | ucontrol->value.integer.value[0] = | ||
1473 | snd_soc_dapm_get_pin_status(codec, pin); | ||
1474 | |||
1475 | mutex_unlock(&codec->mutex); | ||
1476 | |||
1477 | return 0; | ||
1478 | } | ||
1479 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch); | ||
1480 | |||
1481 | /** | ||
1482 | * snd_soc_dapm_put_pin_switch - Set information for a pin switch | ||
1483 | * | ||
1484 | * @kcontrol: mixer control | ||
1485 | * @ucontrol: Value | ||
1486 | */ | ||
1487 | int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, | ||
1488 | struct snd_ctl_elem_value *ucontrol) | ||
1489 | { | ||
1490 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1491 | const char *pin = (const char *)kcontrol->private_value; | ||
1492 | |||
1493 | mutex_lock(&codec->mutex); | ||
1494 | |||
1495 | if (ucontrol->value.integer.value[0]) | ||
1496 | snd_soc_dapm_enable_pin(codec, pin); | ||
1497 | else | ||
1498 | snd_soc_dapm_disable_pin(codec, pin); | ||
1499 | |||
1500 | snd_soc_dapm_sync(codec); | ||
1501 | |||
1502 | mutex_unlock(&codec->mutex); | ||
1503 | |||
1504 | return 0; | ||
1505 | } | ||
1506 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); | ||
1507 | |||
1508 | /** | ||
1399 | * snd_soc_dapm_new_control - create new dapm control | 1509 | * snd_soc_dapm_new_control - create new dapm control |
1400 | * @codec: audio codec | 1510 | * @codec: audio codec |
1401 | * @widget: widget template | 1511 | * @widget: widget template |
@@ -1527,8 +1637,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | |||
1527 | int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, | 1637 | int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, |
1528 | enum snd_soc_bias_level level) | 1638 | enum snd_soc_bias_level level) |
1529 | { | 1639 | { |
1530 | struct snd_soc_codec *codec = socdev->codec; | ||
1531 | struct snd_soc_card *card = socdev->card; | 1640 | struct snd_soc_card *card = socdev->card; |
1641 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1532 | int ret = 0; | 1642 | int ret = 0; |
1533 | 1643 | ||
1534 | if (card->set_bias_level) | 1644 | if (card->set_bias_level) |
@@ -1549,7 +1659,7 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, | |||
1549 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 1659 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
1550 | * do any widget power switching. | 1660 | * do any widget power switching. |
1551 | */ | 1661 | */ |
1552 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin) | 1662 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin) |
1553 | { | 1663 | { |
1554 | return snd_soc_dapm_set_pin(codec, pin, 1); | 1664 | return snd_soc_dapm_set_pin(codec, pin, 1); |
1555 | } | 1665 | } |
@@ -1564,7 +1674,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | |||
1564 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 1674 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
1565 | * do any widget power switching. | 1675 | * do any widget power switching. |
1566 | */ | 1676 | */ |
1567 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin) | 1677 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin) |
1568 | { | 1678 | { |
1569 | return snd_soc_dapm_set_pin(codec, pin, 0); | 1679 | return snd_soc_dapm_set_pin(codec, pin, 0); |
1570 | } | 1680 | } |
@@ -1584,7 +1694,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | |||
1584 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 1694 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
1585 | * do any widget power switching. | 1695 | * do any widget power switching. |
1586 | */ | 1696 | */ |
1587 | int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin) | 1697 | int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin) |
1588 | { | 1698 | { |
1589 | return snd_soc_dapm_set_pin(codec, pin, 0); | 1699 | return snd_soc_dapm_set_pin(codec, pin, 0); |
1590 | } | 1700 | } |
@@ -1599,7 +1709,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); | |||
1599 | * | 1709 | * |
1600 | * Returns 1 for connected otherwise 0. | 1710 | * Returns 1 for connected otherwise 0. |
1601 | */ | 1711 | */ |
1602 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin) | 1712 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin) |
1603 | { | 1713 | { |
1604 | struct snd_soc_dapm_widget *w; | 1714 | struct snd_soc_dapm_widget *w; |
1605 | 1715 | ||
@@ -1620,7 +1730,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); | |||
1620 | */ | 1730 | */ |
1621 | void snd_soc_dapm_free(struct snd_soc_device *socdev) | 1731 | void snd_soc_dapm_free(struct snd_soc_device *socdev) |
1622 | { | 1732 | { |
1623 | struct snd_soc_codec *codec = socdev->codec; | 1733 | struct snd_soc_codec *codec = socdev->card->codec; |
1624 | 1734 | ||
1625 | snd_soc_dapm_sys_remove(socdev->dev); | 1735 | snd_soc_dapm_sys_remove(socdev->dev); |
1626 | dapm_free_widgets(codec); | 1736 | dapm_free_widgets(codec); |
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c new file mode 100644 index 000000000000..28346fb2e70c --- /dev/null +++ b/sound/soc/soc-jack.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * soc-jack.c -- ALSA SoC jack handling | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <sound/jack.h> | ||
15 | #include <sound/soc.h> | ||
16 | #include <sound/soc-dapm.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/workqueue.h> | ||
20 | #include <linux/delay.h> | ||
21 | |||
22 | /** | ||
23 | * snd_soc_jack_new - Create a new jack | ||
24 | * @card: ASoC card | ||
25 | * @id: an identifying string for this jack | ||
26 | * @type: a bitmask of enum snd_jack_type values that can be detected by | ||
27 | * this jack | ||
28 | * @jack: structure to use for the jack | ||
29 | * | ||
30 | * Creates a new jack object. | ||
31 | * | ||
32 | * Returns zero if successful, or a negative error code on failure. | ||
33 | * On success jack will be initialised. | ||
34 | */ | ||
35 | int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type, | ||
36 | struct snd_soc_jack *jack) | ||
37 | { | ||
38 | jack->card = card; | ||
39 | INIT_LIST_HEAD(&jack->pins); | ||
40 | |||
41 | return snd_jack_new(card->codec->card, id, type, &jack->jack); | ||
42 | } | ||
43 | EXPORT_SYMBOL_GPL(snd_soc_jack_new); | ||
44 | |||
45 | /** | ||
46 | * snd_soc_jack_report - Report the current status for a jack | ||
47 | * | ||
48 | * @jack: the jack | ||
49 | * @status: a bitmask of enum snd_jack_type values that are currently detected. | ||
50 | * @mask: a bitmask of enum snd_jack_type values that being reported. | ||
51 | * | ||
52 | * If configured using snd_soc_jack_add_pins() then the associated | ||
53 | * DAPM pins will be enabled or disabled as appropriate and DAPM | ||
54 | * synchronised. | ||
55 | * | ||
56 | * Note: This function uses mutexes and should be called from a | ||
57 | * context which can sleep (such as a workqueue). | ||
58 | */ | ||
59 | void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) | ||
60 | { | ||
61 | struct snd_soc_codec *codec = jack->card->codec; | ||
62 | struct snd_soc_jack_pin *pin; | ||
63 | int enable; | ||
64 | int oldstatus; | ||
65 | |||
66 | if (!jack) { | ||
67 | WARN_ON_ONCE(!jack); | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | mutex_lock(&codec->mutex); | ||
72 | |||
73 | oldstatus = jack->status; | ||
74 | |||
75 | jack->status &= ~mask; | ||
76 | jack->status |= status; | ||
77 | |||
78 | /* The DAPM sync is expensive enough to be worth skipping */ | ||
79 | if (jack->status == oldstatus) | ||
80 | goto out; | ||
81 | |||
82 | list_for_each_entry(pin, &jack->pins, list) { | ||
83 | enable = pin->mask & status; | ||
84 | |||
85 | if (pin->invert) | ||
86 | enable = !enable; | ||
87 | |||
88 | if (enable) | ||
89 | snd_soc_dapm_enable_pin(codec, pin->pin); | ||
90 | else | ||
91 | snd_soc_dapm_disable_pin(codec, pin->pin); | ||
92 | } | ||
93 | |||
94 | snd_soc_dapm_sync(codec); | ||
95 | |||
96 | snd_jack_report(jack->jack, status); | ||
97 | |||
98 | out: | ||
99 | mutex_unlock(&codec->mutex); | ||
100 | } | ||
101 | EXPORT_SYMBOL_GPL(snd_soc_jack_report); | ||
102 | |||
103 | /** | ||
104 | * snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack | ||
105 | * | ||
106 | * @jack: ASoC jack | ||
107 | * @count: Number of pins | ||
108 | * @pins: Array of pins | ||
109 | * | ||
110 | * After this function has been called the DAPM pins specified in the | ||
111 | * pins array will have their status updated to reflect the current | ||
112 | * state of the jack whenever the jack status is updated. | ||
113 | */ | ||
114 | int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, | ||
115 | struct snd_soc_jack_pin *pins) | ||
116 | { | ||
117 | int i; | ||
118 | |||
119 | for (i = 0; i < count; i++) { | ||
120 | if (!pins[i].pin) { | ||
121 | printk(KERN_ERR "No name for pin %d\n", i); | ||
122 | return -EINVAL; | ||
123 | } | ||
124 | if (!pins[i].mask) { | ||
125 | printk(KERN_ERR "No mask for pin %d (%s)\n", i, | ||
126 | pins[i].pin); | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | |||
130 | INIT_LIST_HEAD(&pins[i].list); | ||
131 | list_add(&(pins[i].list), &jack->pins); | ||
132 | } | ||
133 | |||
134 | /* Update to reflect the last reported status; canned jack | ||
135 | * implementations are likely to set their state before the | ||
136 | * card has an opportunity to associate pins. | ||
137 | */ | ||
138 | snd_soc_jack_report(jack, 0, 0); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins); | ||
143 | |||
144 | #ifdef CONFIG_GPIOLIB | ||
145 | /* gpio detect */ | ||
146 | static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio) | ||
147 | { | ||
148 | struct snd_soc_jack *jack = gpio->jack; | ||
149 | int enable; | ||
150 | int report; | ||
151 | |||
152 | if (gpio->debounce_time > 0) | ||
153 | mdelay(gpio->debounce_time); | ||
154 | |||
155 | enable = gpio_get_value(gpio->gpio); | ||
156 | if (gpio->invert) | ||
157 | enable = !enable; | ||
158 | |||
159 | if (enable) | ||
160 | report = gpio->report; | ||
161 | else | ||
162 | report = 0; | ||
163 | |||
164 | snd_soc_jack_report(jack, report, gpio->report); | ||
165 | } | ||
166 | |||
167 | /* irq handler for gpio pin */ | ||
168 | static irqreturn_t gpio_handler(int irq, void *data) | ||
169 | { | ||
170 | struct snd_soc_jack_gpio *gpio = data; | ||
171 | |||
172 | schedule_work(&gpio->work); | ||
173 | |||
174 | return IRQ_HANDLED; | ||
175 | } | ||
176 | |||
177 | /* gpio work */ | ||
178 | static void gpio_work(struct work_struct *work) | ||
179 | { | ||
180 | struct snd_soc_jack_gpio *gpio; | ||
181 | |||
182 | gpio = container_of(work, struct snd_soc_jack_gpio, work); | ||
183 | snd_soc_jack_gpio_detect(gpio); | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack | ||
188 | * | ||
189 | * @jack: ASoC jack | ||
190 | * @count: number of pins | ||
191 | * @gpios: array of gpio pins | ||
192 | * | ||
193 | * This function will request gpio, set data direction and request irq | ||
194 | * for each gpio in the array. | ||
195 | */ | ||
196 | int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | ||
197 | struct snd_soc_jack_gpio *gpios) | ||
198 | { | ||
199 | int i, ret; | ||
200 | |||
201 | for (i = 0; i < count; i++) { | ||
202 | if (!gpio_is_valid(gpios[i].gpio)) { | ||
203 | printk(KERN_ERR "Invalid gpio %d\n", | ||
204 | gpios[i].gpio); | ||
205 | ret = -EINVAL; | ||
206 | goto undo; | ||
207 | } | ||
208 | if (!gpios[i].name) { | ||
209 | printk(KERN_ERR "No name for gpio %d\n", | ||
210 | gpios[i].gpio); | ||
211 | ret = -EINVAL; | ||
212 | goto undo; | ||
213 | } | ||
214 | |||
215 | ret = gpio_request(gpios[i].gpio, gpios[i].name); | ||
216 | if (ret) | ||
217 | goto undo; | ||
218 | |||
219 | ret = gpio_direction_input(gpios[i].gpio); | ||
220 | if (ret) | ||
221 | goto err; | ||
222 | |||
223 | ret = request_irq(gpio_to_irq(gpios[i].gpio), | ||
224 | gpio_handler, | ||
225 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
226 | jack->card->dev->driver->name, | ||
227 | &gpios[i]); | ||
228 | if (ret) | ||
229 | goto err; | ||
230 | |||
231 | INIT_WORK(&gpios[i].work, gpio_work); | ||
232 | gpios[i].jack = jack; | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | |||
237 | err: | ||
238 | gpio_free(gpios[i].gpio); | ||
239 | undo: | ||
240 | snd_soc_jack_free_gpios(jack, i, gpios); | ||
241 | |||
242 | return ret; | ||
243 | } | ||
244 | EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpios); | ||
245 | |||
246 | /** | ||
247 | * snd_soc_jack_free_gpios - Release GPIO pins' resources of an ASoC jack | ||
248 | * | ||
249 | * @jack: ASoC jack | ||
250 | * @count: number of pins | ||
251 | * @gpios: array of gpio pins | ||
252 | * | ||
253 | * Release gpio and irq resources for gpio pins associated with an ASoC jack. | ||
254 | */ | ||
255 | void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, | ||
256 | struct snd_soc_jack_gpio *gpios) | ||
257 | { | ||
258 | int i; | ||
259 | |||
260 | for (i = 0; i < count; i++) { | ||
261 | free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]); | ||
262 | gpio_free(gpios[i].gpio); | ||
263 | gpios[i].jack = NULL; | ||
264 | } | ||
265 | } | ||
266 | EXPORT_SYMBOL_GPL(snd_soc_jack_free_gpios); | ||
267 | #endif /* CONFIG_GPIOLIB */ | ||