diff options
Diffstat (limited to 'sound/soc')
76 files changed, 14164 insertions, 1339 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index f743530add8..4dfda6674be 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -5,6 +5,7 @@ | |||
5 | menuconfig SND_SOC | 5 | 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 | ---help--- | 9 | ---help--- |
9 | 10 | ||
10 | If you want ASoC support, you should say Y here and also to the | 11 | If you want ASoC support, you should say Y here and also to the |
@@ -31,6 +32,7 @@ source "sound/soc/sh/Kconfig" | |||
31 | source "sound/soc/fsl/Kconfig" | 32 | source "sound/soc/fsl/Kconfig" |
32 | source "sound/soc/davinci/Kconfig" | 33 | source "sound/soc/davinci/Kconfig" |
33 | source "sound/soc/omap/Kconfig" | 34 | source "sound/soc/omap/Kconfig" |
35 | source "sound/soc/blackfin/Kconfig" | ||
34 | 36 | ||
35 | # Supported codecs | 37 | # Supported codecs |
36 | source "sound/soc/codecs/Kconfig" | 38 | source "sound/soc/codecs/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 933a66d3080..d849349f2c6 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -2,4 +2,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.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/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ | 4 | obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ |
5 | obj-$(CONFIG_SND_SOC) += omap/ au1x/ | 5 | obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ |
diff --git a/sound/soc/at32/at32-pcm.c b/sound/soc/at32/at32-pcm.c index 435f1daf177..c83584f989a 100644 --- a/sound/soc/at32/at32-pcm.c +++ b/sound/soc/at32/at32-pcm.c | |||
@@ -434,7 +434,8 @@ static int at32_pcm_suspend(struct platform_device *pdev, | |||
434 | params = prtd->params; | 434 | params = prtd->params; |
435 | 435 | ||
436 | /* Disable the PDC and save the PDC registers */ | 436 | /* Disable the PDC and save the PDC registers */ |
437 | ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); | 437 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, |
438 | params->mask->pdc_disable); | ||
438 | 439 | ||
439 | prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); | 440 | prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); |
440 | prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); | 441 | prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); |
@@ -464,7 +465,7 @@ static int at32_pcm_resume(struct platform_device *pdev, | |||
464 | ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); | 465 | ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); |
465 | ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); | 466 | ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); |
466 | 467 | ||
467 | ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); | 468 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, params->mask->pdc_enable); |
468 | return 0; | 469 | return 0; |
469 | } | 470 | } |
470 | #else /* CONFIG_PM */ | 471 | #else /* CONFIG_PM */ |
diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c index 3f326219f1e..98a2d5826a8 100644 --- a/sound/soc/at32/playpaq_wm8510.c +++ b/sound/soc/at32/playpaq_wm8510.c | |||
@@ -377,6 +377,7 @@ static struct snd_soc_machine snd_soc_machine_playpaq = { | |||
377 | 377 | ||
378 | 378 | ||
379 | static struct wm8510_setup_data playpaq_wm8510_setup = { | 379 | static struct wm8510_setup_data playpaq_wm8510_setup = { |
380 | .i2c_bus = 0, | ||
380 | .i2c_address = 0x1a, | 381 | .i2c_address = 0x1a, |
381 | }; | 382 | }; |
382 | 383 | ||
@@ -405,7 +406,6 @@ static int __init playpaq_asoc_init(void) | |||
405 | ssc = ssc_request(0); | 406 | ssc = ssc_request(0); |
406 | if (IS_ERR(ssc)) { | 407 | if (IS_ERR(ssc)) { |
407 | ret = PTR_ERR(ssc); | 408 | ret = PTR_ERR(ssc); |
408 | ssc = NULL; | ||
409 | goto err_ssc; | 409 | goto err_ssc; |
410 | } | 410 | } |
411 | ssc_p->ssc = ssc; | 411 | ssc_p->ssc = ssc; |
@@ -476,10 +476,7 @@ err_pll0: | |||
476 | _gclk0 = NULL; | 476 | _gclk0 = NULL; |
477 | } | 477 | } |
478 | err_gclk0: | 478 | err_gclk0: |
479 | if (ssc != NULL) { | 479 | ssc_free(ssc); |
480 | ssc_free(ssc); | ||
481 | ssc = NULL; | ||
482 | } | ||
483 | err_ssc: | 480 | err_ssc: |
484 | return ret; | 481 | return ret; |
485 | } | 482 | } |
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c index 5d44515e62e..a5b1a79ebff 100644 --- a/sound/soc/at91/at91-ssc.c +++ b/sound/soc/at91/at91-ssc.c | |||
@@ -408,7 +408,7 @@ static int at91_ssc_hw_params(struct snd_pcm_substream *substream, | |||
408 | dma_params->pdc_xfer_size = 4; | 408 | dma_params->pdc_xfer_size = 4; |
409 | break; | 409 | break; |
410 | default: | 410 | default: |
411 | printk(KERN_WARNING "at91-ssc: unsupported PCM format"); | 411 | printk(KERN_WARNING "at91-ssc: unsupported PCM format\n"); |
412 | return -EINVAL; | 412 | return -EINVAL; |
413 | } | 413 | } |
414 | 414 | ||
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c index b81d6b2cfa1..684781e4088 100644 --- a/sound/soc/at91/eti_b1_wm8731.c +++ b/sound/soc/at91/eti_b1_wm8731.c | |||
@@ -243,6 +243,7 @@ static struct snd_soc_machine snd_soc_machine_eti_b1 = { | |||
243 | }; | 243 | }; |
244 | 244 | ||
245 | static struct wm8731_setup_data eti_b1_wm8731_setup = { | 245 | static struct wm8731_setup_data eti_b1_wm8731_setup = { |
246 | .i2c_bus = 0, | ||
246 | .i2c_address = 0x1a, | 247 | .i2c_address = 0x1a, |
247 | }; | 248 | }; |
248 | 249 | ||
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig new file mode 100644 index 00000000000..f98331d099e --- /dev/null +++ b/sound/soc/blackfin/Kconfig | |||
@@ -0,0 +1,85 @@ | |||
1 | config SND_BF5XX_I2S | ||
2 | tristate "SoC I2S Audio for the ADI BF5xx chip" | ||
3 | depends on BLACKFIN && SND_SOC | ||
4 | help | ||
5 | Say Y or M if you want to add support for codecs attached to | ||
6 | the Blackfin SPORT (synchronous serial ports) interface in I2S | ||
7 | mode (supports single stereo In/Out). | ||
8 | You will also need to select the audio interfaces to support below. | ||
9 | |||
10 | config SND_BF5XX_SOC_SSM2602 | ||
11 | tristate "SoC SSM2602 Audio support for BF52x ezkit" | ||
12 | depends on SND_BF5XX_I2S | ||
13 | select SND_BF5XX_SOC_I2S | ||
14 | select SND_SOC_SSM2602 | ||
15 | select I2C | ||
16 | select I2C_BLACKFIN_TWI | ||
17 | help | ||
18 | Say Y if you want to add support for SoC audio on BF527-EZKIT. | ||
19 | |||
20 | config SND_BF5XX_AC97 | ||
21 | tristate "SoC AC97 Audio for the ADI BF5xx chip" | ||
22 | depends on BLACKFIN && SND_SOC | ||
23 | help | ||
24 | Say Y or M if you want to add support for codecs attached to | ||
25 | the Blackfin SPORT (synchronous serial ports) interface in slot 16 | ||
26 | mode (pseudo AC97 interface). | ||
27 | You will also need to select the audio interfaces to support below. | ||
28 | |||
29 | Note: | ||
30 | AC97 codecs which do not implment the slot-16 mode will not function | ||
31 | properly with this driver. This driver is known to work with the | ||
32 | Analog Devices line of AC97 codecs. | ||
33 | |||
34 | config SND_MMAP_SUPPORT | ||
35 | bool "Enable MMAP Support" | ||
36 | depends on SND_BF5XX_AC97 | ||
37 | default y | ||
38 | help | ||
39 | Say y if you want AC97 driver to support mmap mode. | ||
40 | We introduce an intermediate buffer to simulate mmap. | ||
41 | |||
42 | config SND_BF5XX_SOC_SPORT | ||
43 | tristate | ||
44 | |||
45 | config SND_BF5XX_SOC_I2S | ||
46 | tristate | ||
47 | select SND_BF5XX_SOC_SPORT | ||
48 | |||
49 | config SND_BF5XX_SOC_AC97 | ||
50 | tristate | ||
51 | select AC97_BUS | ||
52 | select SND_SOC_AC97_BUS | ||
53 | select SND_BF5XX_SOC_SPORT | ||
54 | |||
55 | config SND_BF5XX_SOC_AD1980 | ||
56 | tristate "SoC AD1980/1 Audio support for BF5xx" | ||
57 | depends on SND_BF5XX_AC97 | ||
58 | select SND_BF5XX_SOC_AC97 | ||
59 | select SND_SOC_AD1980 | ||
60 | help | ||
61 | Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT. | ||
62 | |||
63 | config SND_BF5XX_SPORT_NUM | ||
64 | int "Set a SPORT for Sound chip" | ||
65 | depends on (SND_BF5XX_I2S || SND_BF5XX_AC97) | ||
66 | range 0 3 if BF54x | ||
67 | range 0 1 if (BF53x || BF561) | ||
68 | default 0 | ||
69 | help | ||
70 | Set the correct SPORT for sound chip. | ||
71 | |||
72 | config SND_BF5XX_HAVE_COLD_RESET | ||
73 | bool "BOARD has COLD Reset GPIO" | ||
74 | depends on SND_BF5XX_AC97 | ||
75 | default y if BFIN548_EZKIT | ||
76 | default n if !BFIN548_EZKIT | ||
77 | |||
78 | config SND_BF5XX_RESET_GPIO_NUM | ||
79 | int "Set a GPIO for cold reset" | ||
80 | depends on SND_BF5XX_HAVE_COLD_RESET | ||
81 | range 0 159 | ||
82 | default 19 if BFIN548_EZKIT | ||
83 | default 5 if BFIN537_STAMP | ||
84 | help | ||
85 | Set the correct GPIO for RESET the sound chip. | ||
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile new file mode 100644 index 00000000000..9ea8bd9e0ba --- /dev/null +++ b/sound/soc/blackfin/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | # Blackfin Platform Support | ||
2 | snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o | ||
3 | snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o | ||
4 | snd-soc-bf5xx-sport-objs := bf5xx-sport.o | ||
5 | snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o | ||
6 | snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o | ||
7 | |||
8 | obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o | ||
9 | obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o | ||
10 | obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o | ||
11 | obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o | ||
12 | obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o | ||
13 | |||
14 | # Blackfin Machine Support | ||
15 | snd-ad1980-objs := bf5xx-ad1980.o | ||
16 | snd-ssm2602-objs := bf5xx-ssm2602.o | ||
17 | |||
18 | |||
19 | obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o | ||
20 | obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o | ||
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c new file mode 100644 index 00000000000..51f4907c483 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /* | ||
2 | * File: sound/soc/blackfin/bf5xx-ac97-pcm.c | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Tue June 06 2008 | ||
6 | * Description: DMA Driver for AC97 sound chip | ||
7 | * | ||
8 | * Modified: | ||
9 | * Copyright 2008 Analog Devices Inc. | ||
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, see the file COPYING, or write | ||
25 | * to the Free Software Foundation, Inc., | ||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/dma-mapping.h> | ||
34 | |||
35 | #include <sound/core.h> | ||
36 | #include <sound/pcm.h> | ||
37 | #include <sound/pcm_params.h> | ||
38 | #include <sound/soc.h> | ||
39 | |||
40 | #include <asm/dma.h> | ||
41 | |||
42 | #include "bf5xx-ac97-pcm.h" | ||
43 | #include "bf5xx-ac97.h" | ||
44 | #include "bf5xx-sport.h" | ||
45 | |||
46 | #if defined(CONFIG_SND_MMAP_SUPPORT) | ||
47 | static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, | ||
48 | snd_pcm_uframes_t count) | ||
49 | { | ||
50 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
51 | struct sport_device *sport = runtime->private_data; | ||
52 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
53 | bf5xx_pcm_to_ac97( | ||
54 | (struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos, | ||
55 | (__u32 *)runtime->dma_area + sport->tx_pos, count); | ||
56 | sport->tx_pos += runtime->period_size; | ||
57 | if (sport->tx_pos >= runtime->buffer_size) | ||
58 | sport->tx_pos %= runtime->buffer_size; | ||
59 | } else { | ||
60 | bf5xx_ac97_to_pcm( | ||
61 | (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, | ||
62 | (__u32 *)runtime->dma_area + sport->rx_pos, count); | ||
63 | sport->rx_pos += runtime->period_size; | ||
64 | if (sport->rx_pos >= runtime->buffer_size) | ||
65 | sport->rx_pos %= runtime->buffer_size; | ||
66 | } | ||
67 | } | ||
68 | #endif | ||
69 | |||
70 | static void bf5xx_dma_irq(void *data) | ||
71 | { | ||
72 | struct snd_pcm_substream *pcm = data; | ||
73 | #if defined(CONFIG_SND_MMAP_SUPPORT) | ||
74 | struct snd_pcm_runtime *runtime = pcm->runtime; | ||
75 | bf5xx_mmap_copy(pcm, runtime->period_size); | ||
76 | #endif | ||
77 | snd_pcm_period_elapsed(pcm); | ||
78 | } | ||
79 | |||
80 | /* The memory size for pure pcm data is 128*1024 = 0x20000 bytes. | ||
81 | * The total rx/tx buffer is for ac97 frame to hold all pcm data | ||
82 | * is 0x20000 * sizeof(struct ac97_frame) / 4. | ||
83 | */ | ||
84 | #ifdef CONFIG_SND_MMAP_SUPPORT | ||
85 | static const struct snd_pcm_hardware bf5xx_pcm_hardware = { | ||
86 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
87 | SNDRV_PCM_INFO_MMAP | | ||
88 | SNDRV_PCM_INFO_MMAP_VALID | | ||
89 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
90 | #else | ||
91 | static const struct snd_pcm_hardware bf5xx_pcm_hardware = { | ||
92 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
93 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
94 | #endif | ||
95 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
96 | .period_bytes_min = 32, | ||
97 | .period_bytes_max = 0x10000, | ||
98 | .periods_min = 1, | ||
99 | .periods_max = PAGE_SIZE/32, | ||
100 | .buffer_bytes_max = 0x20000, /* 128 kbytes */ | ||
101 | .fifo_size = 16, | ||
102 | }; | ||
103 | |||
104 | static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
105 | struct snd_pcm_hw_params *params) | ||
106 | { | ||
107 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max | ||
108 | * sizeof(struct ac97_frame) / 4; | ||
109 | |||
110 | snd_pcm_lib_malloc_pages(substream, size); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
116 | { | ||
117 | snd_pcm_lib_free_pages(substream); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) | ||
122 | { | ||
123 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
124 | struct sport_device *sport = runtime->private_data; | ||
125 | |||
126 | /* An intermediate buffer is introduced for implementing mmap for | ||
127 | * SPORT working in TMD mode(include AC97). | ||
128 | */ | ||
129 | #if defined(CONFIG_SND_MMAP_SUPPORT) | ||
130 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max | ||
131 | * sizeof(struct ac97_frame) / 4; | ||
132 | /*clean up intermediate buffer*/ | ||
133 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
134 | memset(sport->tx_dma_buf, 0, size); | ||
135 | sport_set_tx_callback(sport, bf5xx_dma_irq, substream); | ||
136 | sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, | ||
137 | runtime->period_size * sizeof(struct ac97_frame)); | ||
138 | } else { | ||
139 | memset(sport->rx_dma_buf, 0, size); | ||
140 | sport_set_rx_callback(sport, bf5xx_dma_irq, substream); | ||
141 | sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods, | ||
142 | runtime->period_size * sizeof(struct ac97_frame)); | ||
143 | } | ||
144 | #else | ||
145 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
146 | sport_set_tx_callback(sport, bf5xx_dma_irq, substream); | ||
147 | sport_config_tx_dma(sport, runtime->dma_area, runtime->periods, | ||
148 | runtime->period_size * sizeof(struct ac97_frame)); | ||
149 | } else { | ||
150 | sport_set_rx_callback(sport, bf5xx_dma_irq, substream); | ||
151 | sport_config_rx_dma(sport, runtime->dma_area, runtime->periods, | ||
152 | runtime->period_size * sizeof(struct ac97_frame)); | ||
153 | } | ||
154 | #endif | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
159 | { | ||
160 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
161 | struct sport_device *sport = runtime->private_data; | ||
162 | int ret = 0; | ||
163 | |||
164 | pr_debug("%s enter\n", __func__); | ||
165 | switch (cmd) { | ||
166 | case SNDRV_PCM_TRIGGER_START: | ||
167 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
168 | sport_tx_start(sport); | ||
169 | else | ||
170 | sport_rx_start(sport); | ||
171 | break; | ||
172 | case SNDRV_PCM_TRIGGER_STOP: | ||
173 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
174 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
175 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
176 | #if defined(CONFIG_SND_MMAP_SUPPORT) | ||
177 | sport->tx_pos = 0; | ||
178 | #endif | ||
179 | sport_tx_stop(sport); | ||
180 | } else { | ||
181 | #if defined(CONFIG_SND_MMAP_SUPPORT) | ||
182 | sport->rx_pos = 0; | ||
183 | #endif | ||
184 | sport_rx_stop(sport); | ||
185 | } | ||
186 | break; | ||
187 | default: | ||
188 | ret = -EINVAL; | ||
189 | } | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) | ||
194 | { | ||
195 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
196 | struct sport_device *sport = runtime->private_data; | ||
197 | unsigned int curr; | ||
198 | |||
199 | #if defined(CONFIG_SND_MMAP_SUPPORT) | ||
200 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
201 | curr = sport->tx_pos; | ||
202 | else | ||
203 | curr = sport->rx_pos; | ||
204 | #else | ||
205 | |||
206 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
207 | curr = sport_curr_offset_tx(sport) / sizeof(struct ac97_frame); | ||
208 | else | ||
209 | curr = sport_curr_offset_rx(sport) / sizeof(struct ac97_frame); | ||
210 | |||
211 | #endif | ||
212 | return curr; | ||
213 | } | ||
214 | |||
215 | static int bf5xx_pcm_open(struct snd_pcm_substream *substream) | ||
216 | { | ||
217 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
218 | int ret; | ||
219 | |||
220 | pr_debug("%s enter\n", __func__); | ||
221 | snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); | ||
222 | |||
223 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
224 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
225 | if (ret < 0) | ||
226 | goto out; | ||
227 | |||
228 | if (sport_handle != NULL) | ||
229 | runtime->private_data = sport_handle; | ||
230 | else { | ||
231 | pr_err("sport_handle is NULL\n"); | ||
232 | return -1; | ||
233 | } | ||
234 | return 0; | ||
235 | |||
236 | out: | ||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | #ifdef CONFIG_SND_MMAP_SUPPORT | ||
241 | static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, | ||
242 | struct vm_area_struct *vma) | ||
243 | { | ||
244 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
245 | size_t size = vma->vm_end - vma->vm_start; | ||
246 | vma->vm_start = (unsigned long)runtime->dma_area; | ||
247 | vma->vm_end = vma->vm_start + size; | ||
248 | vma->vm_flags |= VM_SHARED; | ||
249 | return 0 ; | ||
250 | } | ||
251 | #else | ||
252 | static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | ||
253 | snd_pcm_uframes_t pos, | ||
254 | void __user *buf, snd_pcm_uframes_t count) | ||
255 | { | ||
256 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
257 | |||
258 | pr_debug("%s copy pos:0x%lx count:0x%lx\n", | ||
259 | substream->stream ? "Capture" : "Playback", pos, count); | ||
260 | |||
261 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
262 | bf5xx_pcm_to_ac97( | ||
263 | (struct ac97_frame *)runtime->dma_area + pos, | ||
264 | buf, count); | ||
265 | else | ||
266 | bf5xx_ac97_to_pcm( | ||
267 | (struct ac97_frame *)runtime->dma_area + pos, | ||
268 | buf, count); | ||
269 | return 0; | ||
270 | } | ||
271 | #endif | ||
272 | |||
273 | struct snd_pcm_ops bf5xx_pcm_ac97_ops = { | ||
274 | .open = bf5xx_pcm_open, | ||
275 | .ioctl = snd_pcm_lib_ioctl, | ||
276 | .hw_params = bf5xx_pcm_hw_params, | ||
277 | .hw_free = bf5xx_pcm_hw_free, | ||
278 | .prepare = bf5xx_pcm_prepare, | ||
279 | .trigger = bf5xx_pcm_trigger, | ||
280 | .pointer = bf5xx_pcm_pointer, | ||
281 | #ifdef CONFIG_SND_MMAP_SUPPORT | ||
282 | .mmap = bf5xx_pcm_mmap, | ||
283 | #else | ||
284 | .copy = bf5xx_pcm_copy, | ||
285 | #endif | ||
286 | }; | ||
287 | |||
288 | static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
289 | { | ||
290 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
291 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
292 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max | ||
293 | * sizeof(struct ac97_frame) / 4; | ||
294 | |||
295 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
296 | buf->dev.dev = pcm->card->dev; | ||
297 | buf->private_data = NULL; | ||
298 | buf->area = dma_alloc_coherent(pcm->card->dev, size, | ||
299 | &buf->addr, GFP_KERNEL); | ||
300 | if (!buf->area) { | ||
301 | pr_err("Failed to allocate dma memory\n"); | ||
302 | pr_err("Please increase uncached DMA memory region\n"); | ||
303 | return -ENOMEM; | ||
304 | } | ||
305 | buf->bytes = size; | ||
306 | |||
307 | pr_debug("%s, area:%p, size:0x%08lx\n", __func__, | ||
308 | buf->area, buf->bytes); | ||
309 | |||
310 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
311 | sport_handle->tx_buf = buf->area; | ||
312 | else | ||
313 | sport_handle->rx_buf = buf->area; | ||
314 | |||
315 | /* | ||
316 | * Need to allocate local buffer when enable | ||
317 | * MMAP for SPORT working in TMD mode (include AC97). | ||
318 | */ | ||
319 | #if defined(CONFIG_SND_MMAP_SUPPORT) | ||
320 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
321 | if (!sport_handle->tx_dma_buf) { | ||
322 | sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ | ||
323 | size, &sport_handle->tx_dma_phy, GFP_KERNEL); | ||
324 | if (!sport_handle->tx_dma_buf) { | ||
325 | pr_err("Failed to allocate memory for tx dma \ | ||
326 | buf - Please increase uncached DMA \ | ||
327 | memory region\n"); | ||
328 | return -ENOMEM; | ||
329 | } else | ||
330 | memset(sport_handle->tx_dma_buf, 0, size); | ||
331 | } else | ||
332 | memset(sport_handle->tx_dma_buf, 0, size); | ||
333 | } else { | ||
334 | if (!sport_handle->rx_dma_buf) { | ||
335 | sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \ | ||
336 | size, &sport_handle->rx_dma_phy, GFP_KERNEL); | ||
337 | if (!sport_handle->rx_dma_buf) { | ||
338 | pr_err("Failed to allocate memory for rx dma \ | ||
339 | buf - Please increase uncached DMA \ | ||
340 | memory region\n"); | ||
341 | return -ENOMEM; | ||
342 | } else | ||
343 | memset(sport_handle->rx_dma_buf, 0, size); | ||
344 | } else | ||
345 | memset(sport_handle->rx_dma_buf, 0, size); | ||
346 | } | ||
347 | #endif | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
352 | { | ||
353 | struct snd_pcm_substream *substream; | ||
354 | struct snd_dma_buffer *buf; | ||
355 | int stream; | ||
356 | #if defined(CONFIG_SND_MMAP_SUPPORT) | ||
357 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max * | ||
358 | sizeof(struct ac97_frame) / 4; | ||
359 | #endif | ||
360 | for (stream = 0; stream < 2; stream++) { | ||
361 | substream = pcm->streams[stream].substream; | ||
362 | if (!substream) | ||
363 | continue; | ||
364 | |||
365 | buf = &substream->dma_buffer; | ||
366 | if (!buf->area) | ||
367 | continue; | ||
368 | dma_free_coherent(NULL, buf->bytes, buf->area, 0); | ||
369 | buf->area = NULL; | ||
370 | #if defined(CONFIG_SND_MMAP_SUPPORT) | ||
371 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
372 | if (sport_handle->tx_dma_buf) | ||
373 | dma_free_coherent(NULL, size, \ | ||
374 | sport_handle->tx_dma_buf, 0); | ||
375 | sport_handle->tx_dma_buf = NULL; | ||
376 | } else { | ||
377 | |||
378 | if (sport_handle->rx_dma_buf) | ||
379 | dma_free_coherent(NULL, size, \ | ||
380 | sport_handle->rx_dma_buf, 0); | ||
381 | sport_handle->rx_dma_buf = NULL; | ||
382 | } | ||
383 | #endif | ||
384 | } | ||
385 | if (sport_handle) | ||
386 | sport_done(sport_handle); | ||
387 | } | ||
388 | |||
389 | static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK; | ||
390 | |||
391 | int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
392 | struct snd_pcm *pcm) | ||
393 | { | ||
394 | int ret = 0; | ||
395 | |||
396 | pr_debug("%s enter\n", __func__); | ||
397 | if (!card->dev->dma_mask) | ||
398 | card->dev->dma_mask = &bf5xx_pcm_dmamask; | ||
399 | if (!card->dev->coherent_dma_mask) | ||
400 | card->dev->coherent_dma_mask = DMA_32BIT_MASK; | ||
401 | |||
402 | if (dai->playback.channels_min) { | ||
403 | ret = bf5xx_pcm_preallocate_dma_buffer(pcm, | ||
404 | SNDRV_PCM_STREAM_PLAYBACK); | ||
405 | if (ret) | ||
406 | goto out; | ||
407 | } | ||
408 | |||
409 | if (dai->capture.channels_min) { | ||
410 | ret = bf5xx_pcm_preallocate_dma_buffer(pcm, | ||
411 | SNDRV_PCM_STREAM_CAPTURE); | ||
412 | if (ret) | ||
413 | goto out; | ||
414 | } | ||
415 | out: | ||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | struct snd_soc_platform bf5xx_ac97_soc_platform = { | ||
420 | .name = "bf5xx-audio", | ||
421 | .pcm_ops = &bf5xx_pcm_ac97_ops, | ||
422 | .pcm_new = bf5xx_pcm_ac97_new, | ||
423 | .pcm_free = bf5xx_pcm_free_dma_buffers, | ||
424 | }; | ||
425 | EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform); | ||
426 | |||
427 | MODULE_AUTHOR("Cliff Cai"); | ||
428 | MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module"); | ||
429 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.h b/sound/soc/blackfin/bf5xx-ac97-pcm.h new file mode 100644 index 00000000000..350125a0ae2 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/bf5xx-ac97-pcm.h -- ALSA PCM interface for the Blackfin | ||
3 | * | ||
4 | * Copyright 2007 Analog Device Inc. | ||
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 version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef _BF5XX_AC97_PCM_H | ||
12 | #define _BF5XX_AC97_PCM_H | ||
13 | |||
14 | struct bf5xx_pcm_dma_params { | ||
15 | char *name; /* stream identifier */ | ||
16 | }; | ||
17 | |||
18 | struct bf5xx_gpio { | ||
19 | u32 sys; | ||
20 | u32 rx; | ||
21 | u32 tx; | ||
22 | u32 clk; | ||
23 | u32 frm; | ||
24 | }; | ||
25 | |||
26 | /* platform data */ | ||
27 | extern struct snd_soc_platform bf5xx_ac97_soc_platform; | ||
28 | |||
29 | #endif | ||
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c new file mode 100644 index 00000000000..c782e311fd5 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ac97.c | |||
@@ -0,0 +1,407 @@ | |||
1 | /* | ||
2 | * bf5xx-ac97.c -- AC97 support for the ADI blackfin chip. | ||
3 | * | ||
4 | * Author: Roy Huang | ||
5 | * Created: 11th. June 2007 | ||
6 | * Copyright: Analog Device Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/wait.h> | ||
18 | #include <linux/delay.h> | ||
19 | |||
20 | #include <sound/core.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/ac97_codec.h> | ||
23 | #include <sound/initval.h> | ||
24 | #include <sound/soc.h> | ||
25 | |||
26 | #include <asm/irq.h> | ||
27 | #include <asm/portmux.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/gpio.h> | ||
30 | |||
31 | #include "bf5xx-sport.h" | ||
32 | #include "bf5xx-ac97.h" | ||
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; | ||
55 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; | ||
56 | |||
57 | #if defined(CONFIG_BF54x) | ||
58 | static struct sport_param sport_params[4] = { | ||
59 | { | ||
60 | .dma_rx_chan = CH_SPORT0_RX, | ||
61 | .dma_tx_chan = CH_SPORT0_TX, | ||
62 | .err_irq = IRQ_SPORT0_ERR, | ||
63 | .regs = (struct sport_register *)SPORT0_TCR1, | ||
64 | }, | ||
65 | { | ||
66 | .dma_rx_chan = CH_SPORT1_RX, | ||
67 | .dma_tx_chan = CH_SPORT1_TX, | ||
68 | .err_irq = IRQ_SPORT1_ERR, | ||
69 | .regs = (struct sport_register *)SPORT1_TCR1, | ||
70 | }, | ||
71 | { | ||
72 | .dma_rx_chan = CH_SPORT2_RX, | ||
73 | .dma_tx_chan = CH_SPORT2_TX, | ||
74 | .err_irq = IRQ_SPORT2_ERR, | ||
75 | .regs = (struct sport_register *)SPORT2_TCR1, | ||
76 | }, | ||
77 | { | ||
78 | .dma_rx_chan = CH_SPORT3_RX, | ||
79 | .dma_tx_chan = CH_SPORT3_TX, | ||
80 | .err_irq = IRQ_SPORT3_ERR, | ||
81 | .regs = (struct sport_register *)SPORT3_TCR1, | ||
82 | } | ||
83 | }; | ||
84 | #else | ||
85 | static struct sport_param sport_params[2] = { | ||
86 | { | ||
87 | .dma_rx_chan = CH_SPORT0_RX, | ||
88 | .dma_tx_chan = CH_SPORT0_TX, | ||
89 | .err_irq = IRQ_SPORT0_ERROR, | ||
90 | .regs = (struct sport_register *)SPORT0_TCR1, | ||
91 | }, | ||
92 | { | ||
93 | .dma_rx_chan = CH_SPORT1_RX, | ||
94 | .dma_tx_chan = CH_SPORT1_TX, | ||
95 | .err_irq = IRQ_SPORT1_ERROR, | ||
96 | .regs = (struct sport_register *)SPORT1_TCR1, | ||
97 | } | ||
98 | }; | ||
99 | #endif | ||
100 | |||
101 | void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ | ||
102 | size_t count) | ||
103 | { | ||
104 | while (count--) { | ||
105 | dst->ac97_tag = TAG_VALID | TAG_PCM; | ||
106 | (dst++)->ac97_pcm = *src++; | ||
107 | } | ||
108 | } | ||
109 | EXPORT_SYMBOL(bf5xx_pcm_to_ac97); | ||
110 | |||
111 | void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ | ||
112 | size_t count) | ||
113 | { | ||
114 | while (count--) | ||
115 | *(dst++) = (src++)->ac97_pcm; | ||
116 | } | ||
117 | EXPORT_SYMBOL(bf5xx_ac97_to_pcm); | ||
118 | |||
119 | static unsigned int sport_tx_curr_frag(struct sport_device *sport) | ||
120 | { | ||
121 | return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \ | ||
122 | sport->tx_fragsize; | ||
123 | } | ||
124 | |||
125 | static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) | ||
126 | { | ||
127 | struct sport_device *sport = sport_handle; | ||
128 | int nextfrag = sport_tx_curr_frag(sport); | ||
129 | struct ac97_frame *nextwrite; | ||
130 | |||
131 | sport_incfrag(sport, &nextfrag, 1); | ||
132 | sport_incfrag(sport, &nextfrag, 1); | ||
133 | |||
134 | nextwrite = (struct ac97_frame *)(sport->tx_buf + \ | ||
135 | nextfrag * sport->tx_fragsize); | ||
136 | pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n", | ||
137 | sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]); | ||
138 | nextwrite[cmd_count[nextfrag]].ac97_tag |= TAG_CMD; | ||
139 | nextwrite[cmd_count[nextfrag]].ac97_addr = addr; | ||
140 | nextwrite[cmd_count[nextfrag]].ac97_data = data; | ||
141 | ++cmd_count[nextfrag]; | ||
142 | pr_debug("ac97_sport: Inserting %02x/%04x into fragment %d\n", | ||
143 | addr >> 8, data, nextfrag); | ||
144 | } | ||
145 | |||
146 | static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97, | ||
147 | unsigned short reg) | ||
148 | { | ||
149 | struct ac97_frame out_frame[2], in_frame[2]; | ||
150 | |||
151 | pr_debug("%s enter 0x%x\n", __func__, reg); | ||
152 | |||
153 | /* When dma descriptor is enabled, the register should not be read */ | ||
154 | if (sport_handle->tx_run || sport_handle->rx_run) { | ||
155 | pr_err("Could you send a mail to cliff.cai@analog.com " | ||
156 | "to report this?\n"); | ||
157 | return -EFAULT; | ||
158 | } | ||
159 | |||
160 | memset(&out_frame, 0, 2 * sizeof(struct ac97_frame)); | ||
161 | memset(&in_frame, 0, 2 * sizeof(struct ac97_frame)); | ||
162 | out_frame[0].ac97_tag = TAG_VALID | TAG_CMD; | ||
163 | out_frame[0].ac97_addr = ((reg << 8) | 0x8000); | ||
164 | sport_send_and_recv(sport_handle, (unsigned char *)&out_frame, | ||
165 | (unsigned char *)&in_frame, | ||
166 | 2 * sizeof(struct ac97_frame)); | ||
167 | return in_frame[1].ac97_data; | ||
168 | } | ||
169 | |||
170 | void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
171 | unsigned short val) | ||
172 | { | ||
173 | pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val); | ||
174 | |||
175 | if (sport_handle->tx_run) { | ||
176 | enqueue_cmd(ac97, (reg << 8), val); /* write */ | ||
177 | enqueue_cmd(ac97, (reg << 8) | 0x8000, 0); /* read back */ | ||
178 | } else { | ||
179 | struct ac97_frame frame; | ||
180 | memset(&frame, 0, sizeof(struct ac97_frame)); | ||
181 | frame.ac97_tag = TAG_VALID | TAG_CMD; | ||
182 | frame.ac97_addr = (reg << 8); | ||
183 | frame.ac97_data = val; | ||
184 | sport_send_and_recv(sport_handle, (unsigned char *)&frame, \ | ||
185 | NULL, sizeof(struct ac97_frame)); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97) | ||
190 | { | ||
191 | #if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || \ | ||
192 | (defined(BF537_FAMILY) && (CONFIG_SND_BF5XX_SPORT_NUM == 1)) | ||
193 | |||
194 | #define CONCAT(a, b, c) a ## b ## c | ||
195 | #define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS) | ||
196 | |||
197 | u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM); | ||
198 | u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM)); | ||
199 | |||
200 | pr_debug("%s enter\n", __func__); | ||
201 | |||
202 | peripheral_free(per); | ||
203 | gpio_request(gpio, "bf5xx-ac97"); | ||
204 | gpio_direction_output(gpio, 1); | ||
205 | udelay(2); | ||
206 | gpio_set_value(gpio, 0); | ||
207 | udelay(1); | ||
208 | gpio_free(gpio); | ||
209 | peripheral_request(per, "soc-audio"); | ||
210 | #else | ||
211 | pr_info("%s: Not implemented\n", __func__); | ||
212 | #endif | ||
213 | } | ||
214 | |||
215 | static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97) | ||
216 | { | ||
217 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | ||
218 | pr_debug("%s enter\n", __func__); | ||
219 | |||
220 | /* It is specified for bf548-ezkit */ | ||
221 | gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 0); | ||
222 | /* Keep reset pin low for 1 ms */ | ||
223 | mdelay(1); | ||
224 | gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); | ||
225 | /* Wait for bit clock recover */ | ||
226 | mdelay(1); | ||
227 | #else | ||
228 | pr_info("%s: Not implemented\n", __func__); | ||
229 | #endif | ||
230 | } | ||
231 | |||
232 | struct snd_ac97_bus_ops soc_ac97_ops = { | ||
233 | .read = bf5xx_ac97_read, | ||
234 | .write = bf5xx_ac97_write, | ||
235 | .warm_reset = bf5xx_ac97_warm_reset, | ||
236 | .reset = bf5xx_ac97_cold_reset, | ||
237 | }; | ||
238 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
239 | |||
240 | #ifdef CONFIG_PM | ||
241 | static int bf5xx_ac97_suspend(struct platform_device *pdev, | ||
242 | struct snd_soc_dai *dai) | ||
243 | { | ||
244 | struct sport_device *sport = | ||
245 | (struct sport_device *)dai->private_data; | ||
246 | |||
247 | pr_debug("%s : sport %d\n", __func__, dai->id); | ||
248 | if (!dai->active) | ||
249 | return 0; | ||
250 | if (dai->capture.active) | ||
251 | sport_rx_stop(sport); | ||
252 | if (dai->playback.active) | ||
253 | sport_tx_stop(sport); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int bf5xx_ac97_resume(struct platform_device *pdev, | ||
258 | struct snd_soc_dai *dai) | ||
259 | { | ||
260 | int ret; | ||
261 | struct sport_device *sport = | ||
262 | (struct sport_device *)dai->private_data; | ||
263 | |||
264 | pr_debug("%s : sport %d\n", __func__, dai->id); | ||
265 | if (!dai->active) | ||
266 | return 0; | ||
267 | |||
268 | ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); | ||
269 | if (ret) { | ||
270 | pr_err("SPORT is busy!\n"); | ||
271 | return -EBUSY; | ||
272 | } | ||
273 | |||
274 | ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); | ||
275 | if (ret) { | ||
276 | pr_err("SPORT is busy!\n"); | ||
277 | return -EBUSY; | ||
278 | } | ||
279 | |||
280 | ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); | ||
281 | if (ret) { | ||
282 | pr_err("SPORT is busy!\n"); | ||
283 | return -EBUSY; | ||
284 | } | ||
285 | |||
286 | if (dai->capture.active) | ||
287 | sport_rx_start(sport); | ||
288 | if (dai->playback.active) | ||
289 | sport_tx_start(sport); | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | #else | ||
294 | #define bf5xx_ac97_suspend NULL | ||
295 | #define bf5xx_ac97_resume NULL | ||
296 | #endif | ||
297 | |||
298 | static int bf5xx_ac97_probe(struct platform_device *pdev, | ||
299 | struct snd_soc_dai *dai) | ||
300 | { | ||
301 | int ret; | ||
302 | #if defined(CONFIG_BF54x) | ||
303 | u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1, | ||
304 | PIN_REQ_SPORT_2, PIN_REQ_SPORT_3}; | ||
305 | #else | ||
306 | u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1}; | ||
307 | #endif | ||
308 | cmd_count = (int *)get_zeroed_page(GFP_KERNEL); | ||
309 | if (cmd_count == NULL) | ||
310 | return -ENOMEM; | ||
311 | |||
312 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { | ||
313 | pr_err("Requesting Peripherals failed\n"); | ||
314 | return -EFAULT; | ||
315 | } | ||
316 | |||
317 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | ||
318 | /* Request PB3 as reset pin */ | ||
319 | if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) { | ||
320 | pr_err("Failed to request GPIO_%d for reset\n", | ||
321 | CONFIG_SND_BF5XX_RESET_GPIO_NUM); | ||
322 | peripheral_free_list(&sport_req[sport_num][0]); | ||
323 | return -1; | ||
324 | } | ||
325 | gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); | ||
326 | #endif | ||
327 | sport_handle = sport_init(&sport_params[sport_num], 2, \ | ||
328 | sizeof(struct ac97_frame), NULL); | ||
329 | if (!sport_handle) { | ||
330 | peripheral_free_list(&sport_req[sport_num][0]); | ||
331 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | ||
332 | gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); | ||
333 | #endif | ||
334 | return -ENODEV; | ||
335 | } | ||
336 | /*SPORT works in TDM mode to simulate AC97 transfers*/ | ||
337 | ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); | ||
338 | if (ret) { | ||
339 | pr_err("SPORT is busy!\n"); | ||
340 | kfree(sport_handle); | ||
341 | peripheral_free_list(&sport_req[sport_num][0]); | ||
342 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | ||
343 | gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); | ||
344 | #endif | ||
345 | return -EBUSY; | ||
346 | } | ||
347 | |||
348 | ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); | ||
349 | if (ret) { | ||
350 | pr_err("SPORT is busy!\n"); | ||
351 | kfree(sport_handle); | ||
352 | peripheral_free_list(&sport_req[sport_num][0]); | ||
353 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | ||
354 | gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); | ||
355 | #endif | ||
356 | return -EBUSY; | ||
357 | } | ||
358 | |||
359 | ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); | ||
360 | if (ret) { | ||
361 | pr_err("SPORT is busy!\n"); | ||
362 | kfree(sport_handle); | ||
363 | peripheral_free_list(&sport_req[sport_num][0]); | ||
364 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | ||
365 | gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); | ||
366 | #endif | ||
367 | return -EBUSY; | ||
368 | } | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static void bf5xx_ac97_remove(struct platform_device *pdev, | ||
373 | struct snd_soc_dai *dai) | ||
374 | { | ||
375 | free_page((unsigned long)cmd_count); | ||
376 | cmd_count = NULL; | ||
377 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | ||
378 | gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); | ||
379 | #endif | ||
380 | } | ||
381 | |||
382 | struct snd_soc_dai bfin_ac97_dai = { | ||
383 | .name = "bf5xx-ac97", | ||
384 | .id = 0, | ||
385 | .type = SND_SOC_DAI_AC97, | ||
386 | .probe = bf5xx_ac97_probe, | ||
387 | .remove = bf5xx_ac97_remove, | ||
388 | .suspend = bf5xx_ac97_suspend, | ||
389 | .resume = bf5xx_ac97_resume, | ||
390 | .playback = { | ||
391 | .stream_name = "AC97 Playback", | ||
392 | .channels_min = 2, | ||
393 | .channels_max = 2, | ||
394 | .rates = SNDRV_PCM_RATE_48000, | ||
395 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
396 | .capture = { | ||
397 | .stream_name = "AC97 Capture", | ||
398 | .channels_min = 2, | ||
399 | .channels_max = 2, | ||
400 | .rates = SNDRV_PCM_RATE_48000, | ||
401 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
402 | }; | ||
403 | EXPORT_SYMBOL_GPL(bfin_ac97_dai); | ||
404 | |||
405 | MODULE_AUTHOR("Roy Huang"); | ||
406 | MODULE_DESCRIPTION("AC97 driver for ADI Blackfin"); | ||
407 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h new file mode 100644 index 00000000000..3f77cc558dc --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ac97.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/bf5xx-ac97.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _BF5XX_AC97_H | ||
10 | #define _BF5XX_AC97_H | ||
11 | |||
12 | extern struct snd_ac97_bus_ops bf5xx_ac97_ops; | ||
13 | extern struct snd_ac97 *ac97; | ||
14 | /* Frame format in memory, only support stereo currently */ | ||
15 | struct ac97_frame { | ||
16 | u16 ac97_tag; /* slot 0 */ | ||
17 | u16 ac97_addr; /* slot 1 */ | ||
18 | u16 ac97_data; /* slot 2 */ | ||
19 | u32 ac97_pcm; /* slot 3 and 4: left and right pcm data */ | ||
20 | } __attribute__ ((packed)); | ||
21 | |||
22 | #define TAG_VALID 0x8000 | ||
23 | #define TAG_CMD 0x6000 | ||
24 | #define TAG_PCM_LEFT 0x1000 | ||
25 | #define TAG_PCM_RIGHT 0x0800 | ||
26 | #define TAG_PCM (TAG_PCM_LEFT | TAG_PCM_RIGHT) | ||
27 | |||
28 | extern struct snd_soc_dai bfin_ac97_dai; | ||
29 | |||
30 | void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ | ||
31 | size_t count); | ||
32 | |||
33 | void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ | ||
34 | size_t count); | ||
35 | |||
36 | #endif | ||
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c new file mode 100644 index 00000000000..124425d2232 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ad1980.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * File: sound/soc/blackfin/bf5xx-ad1980.c | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Tue June 06 2008 | ||
6 | * Description: Board driver for AD1980/1 audio codec | ||
7 | * | ||
8 | * Modified: | ||
9 | * Copyright 2008 Analog Devices Inc. | ||
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, see the file COPYING, or write | ||
25 | * to the Free Software Foundation, Inc., | ||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <asm/dma.h> | ||
33 | |||
34 | #include <sound/core.h> | ||
35 | #include <sound/pcm.h> | ||
36 | #include <sound/soc.h> | ||
37 | |||
38 | #include <linux/gpio.h> | ||
39 | #include <asm/portmux.h> | ||
40 | |||
41 | #include "../codecs/ad1980.h" | ||
42 | #include "bf5xx-sport.h" | ||
43 | #include "bf5xx-ac97-pcm.h" | ||
44 | #include "bf5xx-ac97.h" | ||
45 | |||
46 | static struct snd_soc_machine bf5xx_board; | ||
47 | |||
48 | static int bf5xx_board_startup(struct snd_pcm_substream *substream) | ||
49 | { | ||
50 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
51 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
52 | |||
53 | pr_debug("%s enter\n", __func__); | ||
54 | cpu_dai->private_data = sport_handle; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static struct snd_soc_ops bf5xx_board_ops = { | ||
59 | .startup = bf5xx_board_startup, | ||
60 | }; | ||
61 | |||
62 | static struct snd_soc_dai_link bf5xx_board_dai = { | ||
63 | .name = "AC97", | ||
64 | .stream_name = "AC97 HiFi", | ||
65 | .cpu_dai = &bfin_ac97_dai, | ||
66 | .codec_dai = &ad1980_dai, | ||
67 | .ops = &bf5xx_board_ops, | ||
68 | }; | ||
69 | |||
70 | static struct snd_soc_machine bf5xx_board = { | ||
71 | .name = "bf5xx-board", | ||
72 | .dai_link = &bf5xx_board_dai, | ||
73 | .num_links = 1, | ||
74 | }; | ||
75 | |||
76 | static struct snd_soc_device bf5xx_board_snd_devdata = { | ||
77 | .machine = &bf5xx_board, | ||
78 | .platform = &bf5xx_ac97_soc_platform, | ||
79 | .codec_dev = &soc_codec_dev_ad1980, | ||
80 | }; | ||
81 | |||
82 | static struct platform_device *bf5xx_board_snd_device; | ||
83 | |||
84 | static int __init bf5xx_board_init(void) | ||
85 | { | ||
86 | int ret; | ||
87 | |||
88 | bf5xx_board_snd_device = platform_device_alloc("soc-audio", -1); | ||
89 | if (!bf5xx_board_snd_device) | ||
90 | return -ENOMEM; | ||
91 | |||
92 | platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata); | ||
93 | bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev; | ||
94 | ret = platform_device_add(bf5xx_board_snd_device); | ||
95 | |||
96 | if (ret) | ||
97 | platform_device_put(bf5xx_board_snd_device); | ||
98 | |||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | static void __exit bf5xx_board_exit(void) | ||
103 | { | ||
104 | platform_device_unregister(bf5xx_board_snd_device); | ||
105 | } | ||
106 | |||
107 | module_init(bf5xx_board_init); | ||
108 | module_exit(bf5xx_board_exit); | ||
109 | |||
110 | /* Module information */ | ||
111 | MODULE_AUTHOR("Cliff Cai"); | ||
112 | MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board"); | ||
113 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c new file mode 100644 index 00000000000..61fccf92519 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * File: sound/soc/blackfin/bf5xx-i2s-pcm.c | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Tue June 06 2008 | ||
6 | * Description: DMA driver for i2s codec | ||
7 | * | ||
8 | * Modified: | ||
9 | * Copyright 2008 Analog Devices Inc. | ||
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, see the file COPYING, or write | ||
25 | * to the Free Software Foundation, Inc., | ||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/dma-mapping.h> | ||
34 | |||
35 | #include <sound/core.h> | ||
36 | #include <sound/pcm.h> | ||
37 | #include <sound/pcm_params.h> | ||
38 | #include <sound/soc.h> | ||
39 | |||
40 | #include <asm/dma.h> | ||
41 | |||
42 | #include "bf5xx-i2s-pcm.h" | ||
43 | #include "bf5xx-i2s.h" | ||
44 | #include "bf5xx-sport.h" | ||
45 | |||
46 | static void bf5xx_dma_irq(void *data) | ||
47 | { | ||
48 | struct snd_pcm_substream *pcm = data; | ||
49 | snd_pcm_period_elapsed(pcm); | ||
50 | } | ||
51 | |||
52 | static const struct snd_pcm_hardware bf5xx_pcm_hardware = { | ||
53 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
54 | SNDRV_PCM_INFO_MMAP | | ||
55 | SNDRV_PCM_INFO_MMAP_VALID | | ||
56 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
57 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
58 | SNDRV_PCM_FMTBIT_S24_LE | | ||
59 | SNDRV_PCM_FMTBIT_S32_LE, | ||
60 | .period_bytes_min = 32, | ||
61 | .period_bytes_max = 0x10000, | ||
62 | .periods_min = 1, | ||
63 | .periods_max = PAGE_SIZE/32, | ||
64 | .buffer_bytes_max = 0x20000, /* 128 kbytes */ | ||
65 | .fifo_size = 16, | ||
66 | }; | ||
67 | |||
68 | static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
69 | struct snd_pcm_hw_params *params) | ||
70 | { | ||
71 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max; | ||
72 | snd_pcm_lib_malloc_pages(substream, size); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
78 | { | ||
79 | snd_pcm_lib_free_pages(substream); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) | ||
85 | { | ||
86 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
87 | struct sport_device *sport = runtime->private_data; | ||
88 | int period_bytes = frames_to_bytes(runtime, runtime->period_size); | ||
89 | |||
90 | pr_debug("%s enter\n", __func__); | ||
91 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
92 | sport_set_tx_callback(sport, bf5xx_dma_irq, substream); | ||
93 | sport_config_tx_dma(sport, runtime->dma_area, | ||
94 | runtime->periods, period_bytes); | ||
95 | } else { | ||
96 | sport_set_rx_callback(sport, bf5xx_dma_irq, substream); | ||
97 | sport_config_rx_dma(sport, runtime->dma_area, | ||
98 | runtime->periods, period_bytes); | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
105 | { | ||
106 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
107 | struct sport_device *sport = runtime->private_data; | ||
108 | int ret = 0; | ||
109 | |||
110 | pr_debug("%s enter\n", __func__); | ||
111 | switch (cmd) { | ||
112 | case SNDRV_PCM_TRIGGER_START: | ||
113 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
114 | sport_tx_start(sport); | ||
115 | else | ||
116 | sport_rx_start(sport); | ||
117 | break; | ||
118 | case SNDRV_PCM_TRIGGER_STOP: | ||
119 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
120 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
121 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
122 | sport_tx_stop(sport); | ||
123 | else | ||
124 | sport_rx_stop(sport); | ||
125 | break; | ||
126 | default: | ||
127 | ret = -EINVAL; | ||
128 | } | ||
129 | |||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) | ||
134 | { | ||
135 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
136 | struct sport_device *sport = runtime->private_data; | ||
137 | unsigned int diff; | ||
138 | snd_pcm_uframes_t frames; | ||
139 | pr_debug("%s enter\n", __func__); | ||
140 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
141 | diff = sport_curr_offset_tx(sport); | ||
142 | frames = bytes_to_frames(substream->runtime, diff); | ||
143 | } else { | ||
144 | diff = sport_curr_offset_rx(sport); | ||
145 | frames = bytes_to_frames(substream->runtime, diff); | ||
146 | } | ||
147 | return frames; | ||
148 | } | ||
149 | |||
150 | static int bf5xx_pcm_open(struct snd_pcm_substream *substream) | ||
151 | { | ||
152 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
153 | int ret; | ||
154 | |||
155 | pr_debug("%s enter\n", __func__); | ||
156 | snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); | ||
157 | |||
158 | ret = snd_pcm_hw_constraint_integer(runtime, \ | ||
159 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
160 | if (ret < 0) | ||
161 | goto out; | ||
162 | |||
163 | if (sport_handle != NULL) | ||
164 | runtime->private_data = sport_handle; | ||
165 | else { | ||
166 | pr_err("sport_handle is NULL\n"); | ||
167 | return -1; | ||
168 | } | ||
169 | return 0; | ||
170 | |||
171 | out: | ||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, | ||
176 | struct vm_area_struct *vma) | ||
177 | { | ||
178 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
179 | size_t size = vma->vm_end - vma->vm_start; | ||
180 | vma->vm_start = (unsigned long)runtime->dma_area; | ||
181 | vma->vm_end = vma->vm_start + size; | ||
182 | vma->vm_flags |= VM_SHARED; | ||
183 | |||
184 | return 0 ; | ||
185 | } | ||
186 | |||
187 | struct snd_pcm_ops bf5xx_pcm_i2s_ops = { | ||
188 | .open = bf5xx_pcm_open, | ||
189 | .ioctl = snd_pcm_lib_ioctl, | ||
190 | .hw_params = bf5xx_pcm_hw_params, | ||
191 | .hw_free = bf5xx_pcm_hw_free, | ||
192 | .prepare = bf5xx_pcm_prepare, | ||
193 | .trigger = bf5xx_pcm_trigger, | ||
194 | .pointer = bf5xx_pcm_pointer, | ||
195 | .mmap = bf5xx_pcm_mmap, | ||
196 | }; | ||
197 | |||
198 | static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
199 | { | ||
200 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
201 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
202 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max; | ||
203 | |||
204 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
205 | buf->dev.dev = pcm->card->dev; | ||
206 | buf->private_data = NULL; | ||
207 | buf->area = dma_alloc_coherent(pcm->card->dev, size, | ||
208 | &buf->addr, GFP_KERNEL); | ||
209 | if (!buf->area) { | ||
210 | pr_err("Failed to allocate dma memory \ | ||
211 | Please increase uncached DMA memory region\n"); | ||
212 | return -ENOMEM; | ||
213 | } | ||
214 | buf->bytes = size; | ||
215 | |||
216 | pr_debug("%s, area:%p, size:0x%08lx\n", __func__, | ||
217 | buf->area, buf->bytes); | ||
218 | |||
219 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
220 | sport_handle->tx_buf = buf->area; | ||
221 | else | ||
222 | sport_handle->rx_buf = buf->area; | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
228 | { | ||
229 | struct snd_pcm_substream *substream; | ||
230 | struct snd_dma_buffer *buf; | ||
231 | int stream; | ||
232 | |||
233 | for (stream = 0; stream < 2; stream++) { | ||
234 | substream = pcm->streams[stream].substream; | ||
235 | if (!substream) | ||
236 | continue; | ||
237 | |||
238 | buf = &substream->dma_buffer; | ||
239 | if (!buf->area) | ||
240 | continue; | ||
241 | dma_free_coherent(NULL, buf->bytes, buf->area, 0); | ||
242 | buf->area = NULL; | ||
243 | } | ||
244 | if (sport_handle) | ||
245 | sport_done(sport_handle); | ||
246 | } | ||
247 | |||
248 | static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK; | ||
249 | |||
250 | int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
251 | struct snd_pcm *pcm) | ||
252 | { | ||
253 | int ret = 0; | ||
254 | |||
255 | pr_debug("%s enter\n", __func__); | ||
256 | if (!card->dev->dma_mask) | ||
257 | card->dev->dma_mask = &bf5xx_pcm_dmamask; | ||
258 | if (!card->dev->coherent_dma_mask) | ||
259 | card->dev->coherent_dma_mask = DMA_32BIT_MASK; | ||
260 | |||
261 | if (dai->playback.channels_min) { | ||
262 | ret = bf5xx_pcm_preallocate_dma_buffer(pcm, | ||
263 | SNDRV_PCM_STREAM_PLAYBACK); | ||
264 | if (ret) | ||
265 | goto out; | ||
266 | } | ||
267 | |||
268 | if (dai->capture.channels_min) { | ||
269 | ret = bf5xx_pcm_preallocate_dma_buffer(pcm, | ||
270 | SNDRV_PCM_STREAM_CAPTURE); | ||
271 | if (ret) | ||
272 | goto out; | ||
273 | } | ||
274 | out: | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | struct snd_soc_platform bf5xx_i2s_soc_platform = { | ||
279 | .name = "bf5xx-audio", | ||
280 | .pcm_ops = &bf5xx_pcm_i2s_ops, | ||
281 | .pcm_new = bf5xx_pcm_i2s_new, | ||
282 | .pcm_free = bf5xx_pcm_free_dma_buffers, | ||
283 | }; | ||
284 | EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform); | ||
285 | |||
286 | MODULE_AUTHOR("Cliff Cai"); | ||
287 | MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module"); | ||
288 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.h b/sound/soc/blackfin/bf5xx-i2s-pcm.h new file mode 100644 index 00000000000..4d4609a97c5 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/bf5xx-i2s-pcm.h -- ALSA PCM interface for the Blackfin | ||
3 | * | ||
4 | * Copyright 2007 Analog Device Inc. | ||
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 version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef _BF5XX_I2S_PCM_H | ||
12 | #define _BF5XX_I2S_PCM_H | ||
13 | |||
14 | struct bf5xx_pcm_dma_params { | ||
15 | char *name; /* stream identifier */ | ||
16 | }; | ||
17 | |||
18 | struct bf5xx_gpio { | ||
19 | u32 sys; | ||
20 | u32 rx; | ||
21 | u32 tx; | ||
22 | u32 clk; | ||
23 | u32 frm; | ||
24 | }; | ||
25 | |||
26 | /* platform data */ | ||
27 | extern struct snd_soc_platform bf5xx_i2s_soc_platform; | ||
28 | |||
29 | #endif | ||
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c new file mode 100644 index 00000000000..43a4092eeb8 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-i2s.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* | ||
2 | * File: sound/soc/blackfin/bf5xx-i2s.c | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Tue June 06 2008 | ||
6 | * Description: Blackfin I2S CPU DAI driver | ||
7 | * | ||
8 | * Modified: | ||
9 | * Copyright 2008 Analog Devices Inc. | ||
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, see the file COPYING, or write | ||
25 | * to the Free Software Foundation, Inc., | ||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/init.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/pcm_params.h> | ||
36 | #include <sound/initval.h> | ||
37 | #include <sound/soc.h> | ||
38 | |||
39 | #include <asm/irq.h> | ||
40 | #include <asm/portmux.h> | ||
41 | #include <linux/mutex.h> | ||
42 | #include <linux/gpio.h> | ||
43 | |||
44 | #include "bf5xx-sport.h" | ||
45 | #include "bf5xx-i2s.h" | ||
46 | |||
47 | struct bf5xx_i2s_port { | ||
48 | u16 tcr1; | ||
49 | u16 rcr1; | ||
50 | u16 tcr2; | ||
51 | u16 rcr2; | ||
52 | int counter; | ||
53 | }; | ||
54 | |||
55 | static struct bf5xx_i2s_port bf5xx_i2s; | ||
56 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; | ||
57 | |||
58 | static struct sport_param sport_params[2] = { | ||
59 | { | ||
60 | .dma_rx_chan = CH_SPORT0_RX, | ||
61 | .dma_tx_chan = CH_SPORT0_TX, | ||
62 | .err_irq = IRQ_SPORT0_ERROR, | ||
63 | .regs = (struct sport_register *)SPORT0_TCR1, | ||
64 | }, | ||
65 | { | ||
66 | .dma_rx_chan = CH_SPORT1_RX, | ||
67 | .dma_tx_chan = CH_SPORT1_TX, | ||
68 | .err_irq = IRQ_SPORT1_ERROR, | ||
69 | .regs = (struct sport_register *)SPORT1_TCR1, | ||
70 | } | ||
71 | }; | ||
72 | |||
73 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | ||
74 | unsigned int fmt) | ||
75 | { | ||
76 | int ret = 0; | ||
77 | |||
78 | /* interface format:support I2S,slave mode */ | ||
79 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
80 | case SND_SOC_DAIFMT_I2S: | ||
81 | break; | ||
82 | case SND_SOC_DAIFMT_LEFT_J: | ||
83 | ret = -EINVAL; | ||
84 | break; | ||
85 | default: | ||
86 | ret = -EINVAL; | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
91 | case SND_SOC_DAIFMT_CBS_CFS: | ||
92 | ret = -EINVAL; | ||
93 | break; | ||
94 | case SND_SOC_DAIFMT_CBM_CFS: | ||
95 | ret = -EINVAL; | ||
96 | break; | ||
97 | case SND_SOC_DAIFMT_CBM_CFM: | ||
98 | break; | ||
99 | case SND_SOC_DAIFMT_CBS_CFM: | ||
100 | ret = -EINVAL; | ||
101 | break; | ||
102 | default: | ||
103 | ret = -EINVAL; | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | static int bf5xx_i2s_startup(struct snd_pcm_substream *substream) | ||
111 | { | ||
112 | pr_debug("%s enter\n", __func__); | ||
113 | |||
114 | /*this counter is used for counting how many pcm streams are opened*/ | ||
115 | bf5xx_i2s.counter++; | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | ||
120 | struct snd_pcm_hw_params *params) | ||
121 | { | ||
122 | int ret = 0; | ||
123 | |||
124 | bf5xx_i2s.tcr2 &= ~0x1f; | ||
125 | bf5xx_i2s.rcr2 &= ~0x1f; | ||
126 | switch (params_format(params)) { | ||
127 | case SNDRV_PCM_FORMAT_S16_LE: | ||
128 | bf5xx_i2s.tcr2 |= 15; | ||
129 | bf5xx_i2s.rcr2 |= 15; | ||
130 | break; | ||
131 | case SNDRV_PCM_FORMAT_S24_LE: | ||
132 | bf5xx_i2s.tcr2 |= 23; | ||
133 | bf5xx_i2s.rcr2 |= 23; | ||
134 | break; | ||
135 | case SNDRV_PCM_FORMAT_S32_LE: | ||
136 | bf5xx_i2s.tcr2 |= 31; | ||
137 | bf5xx_i2s.rcr2 |= 31; | ||
138 | break; | ||
139 | } | ||
140 | |||
141 | if (bf5xx_i2s.counter == 1) { | ||
142 | /* | ||
143 | * TX and RX are not independent,they are enabled at the | ||
144 | * same time, even if only one side is running. So, we | ||
145 | * need to configure both of them at the time when the first | ||
146 | * stream is opened. | ||
147 | * | ||
148 | * CPU DAI format:I2S, slave mode. | ||
149 | */ | ||
150 | ret = sport_config_rx(sport_handle, RFSR | RCKFE, | ||
151 | RSFSE|bf5xx_i2s.rcr2, 0, 0); | ||
152 | if (ret) { | ||
153 | pr_err("SPORT is busy!\n"); | ||
154 | return -EBUSY; | ||
155 | } | ||
156 | |||
157 | ret = sport_config_tx(sport_handle, TFSR | TCKFE, | ||
158 | TSFSE|bf5xx_i2s.tcr2, 0, 0); | ||
159 | if (ret) { | ||
160 | pr_err("SPORT is busy!\n"); | ||
161 | return -EBUSY; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream) | ||
169 | { | ||
170 | pr_debug("%s enter\n", __func__); | ||
171 | bf5xx_i2s.counter--; | ||
172 | } | ||
173 | |||
174 | static int bf5xx_i2s_probe(struct platform_device *pdev, | ||
175 | struct snd_soc_dai *dai) | ||
176 | { | ||
177 | u16 sport_req[][7] = { | ||
178 | { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, | ||
179 | P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}, | ||
180 | { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, | ||
181 | P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}, | ||
182 | }; | ||
183 | |||
184 | pr_debug("%s enter\n", __func__); | ||
185 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { | ||
186 | pr_err("Requesting Peripherals failed\n"); | ||
187 | return -EFAULT; | ||
188 | } | ||
189 | |||
190 | /* request DMA for SPORT */ | ||
191 | sport_handle = sport_init(&sport_params[sport_num], 4, \ | ||
192 | 2 * sizeof(u32), NULL); | ||
193 | if (!sport_handle) { | ||
194 | peripheral_free_list(&sport_req[sport_num][0]); | ||
195 | return -ENODEV; | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | #ifdef CONFIG_PM | ||
202 | static int bf5xx_i2s_suspend(struct platform_device *dev, | ||
203 | struct snd_soc_dai *dai) | ||
204 | { | ||
205 | struct sport_device *sport = | ||
206 | (struct sport_device *)dai->private_data; | ||
207 | |||
208 | pr_debug("%s : sport %d\n", __func__, dai->id); | ||
209 | if (!dai->active) | ||
210 | return 0; | ||
211 | if (dai->capture.active) | ||
212 | sport_rx_stop(sport); | ||
213 | if (dai->playback.active) | ||
214 | sport_tx_stop(sport); | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int bf5xx_i2s_resume(struct platform_device *pdev, | ||
219 | struct snd_soc_dai *dai) | ||
220 | { | ||
221 | int ret; | ||
222 | struct sport_device *sport = | ||
223 | (struct sport_device *)dai->private_data; | ||
224 | |||
225 | pr_debug("%s : sport %d\n", __func__, dai->id); | ||
226 | if (!dai->active) | ||
227 | return 0; | ||
228 | |||
229 | ret = sport_config_rx(sport_handle, RFSR | RCKFE, RSFSE|0x1f, 0, 0); | ||
230 | if (ret) { | ||
231 | pr_err("SPORT is busy!\n"); | ||
232 | return -EBUSY; | ||
233 | } | ||
234 | |||
235 | ret = sport_config_tx(sport_handle, TFSR | TCKFE, TSFSE|0x1f, 0, 0); | ||
236 | if (ret) { | ||
237 | pr_err("SPORT is busy!\n"); | ||
238 | return -EBUSY; | ||
239 | } | ||
240 | |||
241 | if (dai->capture.active) | ||
242 | sport_rx_start(sport); | ||
243 | if (dai->playback.active) | ||
244 | sport_tx_start(sport); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | #else | ||
249 | #define bf5xx_i2s_suspend NULL | ||
250 | #define bf5xx_i2s_resume NULL | ||
251 | #endif | ||
252 | |||
253 | #define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
254 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | ||
255 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ | ||
256 | SNDRV_PCM_RATE_96000) | ||
257 | |||
258 | #define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ | ||
259 | SNDRV_PCM_FMTBIT_S32_LE) | ||
260 | |||
261 | struct snd_soc_dai bf5xx_i2s_dai = { | ||
262 | .name = "bf5xx-i2s", | ||
263 | .id = 0, | ||
264 | .type = SND_SOC_DAI_I2S, | ||
265 | .probe = bf5xx_i2s_probe, | ||
266 | .suspend = bf5xx_i2s_suspend, | ||
267 | .resume = bf5xx_i2s_resume, | ||
268 | .playback = { | ||
269 | .channels_min = 2, | ||
270 | .channels_max = 2, | ||
271 | .rates = BF5XX_I2S_RATES, | ||
272 | .formats = BF5XX_I2S_FORMATS,}, | ||
273 | .capture = { | ||
274 | .channels_min = 2, | ||
275 | .channels_max = 2, | ||
276 | .rates = BF5XX_I2S_RATES, | ||
277 | .formats = BF5XX_I2S_FORMATS,}, | ||
278 | .ops = { | ||
279 | .startup = bf5xx_i2s_startup, | ||
280 | .shutdown = bf5xx_i2s_shutdown, | ||
281 | .hw_params = bf5xx_i2s_hw_params,}, | ||
282 | .dai_ops = { | ||
283 | .set_fmt = bf5xx_i2s_set_dai_fmt, | ||
284 | }, | ||
285 | }; | ||
286 | EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); | ||
287 | |||
288 | /* Module information */ | ||
289 | MODULE_AUTHOR("Cliff Cai"); | ||
290 | MODULE_DESCRIPTION("I2S driver for ADI Blackfin"); | ||
291 | MODULE_LICENSE("GPL"); | ||
292 | |||
diff --git a/sound/soc/blackfin/bf5xx-i2s.h b/sound/soc/blackfin/bf5xx-i2s.h new file mode 100644 index 00000000000..7107d1a0b06 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-i2s.h | |||
@@ -0,0 +1,14 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/bf5xx-i2s.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _BF5XX_I2S_H | ||
10 | #define _BF5XX_I2S_H | ||
11 | |||
12 | extern struct snd_soc_dai bf5xx_i2s_dai; | ||
13 | |||
14 | #endif | ||
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c new file mode 100644 index 00000000000..3b99e484d55 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-sport.c | |||
@@ -0,0 +1,1032 @@ | |||
1 | /* | ||
2 | * File: bf5xx_sport.c | ||
3 | * Based on: | ||
4 | * Author: Roy Huang <roy.huang@analog.com> | ||
5 | * | ||
6 | * Created: Tue Sep 21 10:52:42 CEST 2004 | ||
7 | * Description: | ||
8 | * Blackfin SPORT Driver | ||
9 | * | ||
10 | * Copyright 2004-2007 Analog Devices Inc. | ||
11 | * | ||
12 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, see the file COPYING, or write | ||
26 | * to the Free Software Foundation, Inc., | ||
27 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
28 | */ | ||
29 | |||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/dma-mapping.h> | ||
34 | #include <linux/gpio.h> | ||
35 | #include <linux/bug.h> | ||
36 | #include <asm/portmux.h> | ||
37 | #include <asm/dma.h> | ||
38 | #include <asm/blackfin.h> | ||
39 | #include <asm/cacheflush.h> | ||
40 | |||
41 | #include "bf5xx-sport.h" | ||
42 | /* delay between frame sync pulse and first data bit in multichannel mode */ | ||
43 | #define FRAME_DELAY (1<<12) | ||
44 | |||
45 | struct sport_device *sport_handle; | ||
46 | EXPORT_SYMBOL(sport_handle); | ||
47 | /* note: multichannel is in units of 8 channels, | ||
48 | * tdm_count is # channels NOT / 8 ! */ | ||
49 | int sport_set_multichannel(struct sport_device *sport, | ||
50 | int tdm_count, u32 mask, int packed) | ||
51 | { | ||
52 | pr_debug("%s tdm_count=%d mask:0x%08x packed=%d\n", __func__, | ||
53 | tdm_count, mask, packed); | ||
54 | |||
55 | if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN)) | ||
56 | return -EBUSY; | ||
57 | |||
58 | if (tdm_count & 0x7) | ||
59 | return -EINVAL; | ||
60 | |||
61 | if (tdm_count > 32) | ||
62 | return -EINVAL; /* Only support less than 32 channels now */ | ||
63 | |||
64 | if (tdm_count) { | ||
65 | sport->regs->mcmc1 = ((tdm_count>>3)-1) << 12; | ||
66 | sport->regs->mcmc2 = FRAME_DELAY | MCMEN | \ | ||
67 | (packed ? (MCDTXPE|MCDRXPE) : 0); | ||
68 | |||
69 | sport->regs->mtcs0 = mask; | ||
70 | sport->regs->mrcs0 = mask; | ||
71 | sport->regs->mtcs1 = 0; | ||
72 | sport->regs->mrcs1 = 0; | ||
73 | sport->regs->mtcs2 = 0; | ||
74 | sport->regs->mrcs2 = 0; | ||
75 | sport->regs->mtcs3 = 0; | ||
76 | sport->regs->mrcs3 = 0; | ||
77 | } else { | ||
78 | sport->regs->mcmc1 = 0; | ||
79 | sport->regs->mcmc2 = 0; | ||
80 | |||
81 | sport->regs->mtcs0 = 0; | ||
82 | sport->regs->mrcs0 = 0; | ||
83 | } | ||
84 | |||
85 | sport->regs->mtcs1 = 0; sport->regs->mtcs2 = 0; sport->regs->mtcs3 = 0; | ||
86 | sport->regs->mrcs1 = 0; sport->regs->mrcs2 = 0; sport->regs->mrcs3 = 0; | ||
87 | |||
88 | SSYNC(); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | EXPORT_SYMBOL(sport_set_multichannel); | ||
93 | |||
94 | int sport_config_rx(struct sport_device *sport, unsigned int rcr1, | ||
95 | unsigned int rcr2, unsigned int clkdiv, unsigned int fsdiv) | ||
96 | { | ||
97 | if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN)) | ||
98 | return -EBUSY; | ||
99 | |||
100 | sport->regs->rcr1 = rcr1; | ||
101 | sport->regs->rcr2 = rcr2; | ||
102 | sport->regs->rclkdiv = clkdiv; | ||
103 | sport->regs->rfsdiv = fsdiv; | ||
104 | |||
105 | SSYNC(); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | EXPORT_SYMBOL(sport_config_rx); | ||
110 | |||
111 | int sport_config_tx(struct sport_device *sport, unsigned int tcr1, | ||
112 | unsigned int tcr2, unsigned int clkdiv, unsigned int fsdiv) | ||
113 | { | ||
114 | if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN)) | ||
115 | return -EBUSY; | ||
116 | |||
117 | sport->regs->tcr1 = tcr1; | ||
118 | sport->regs->tcr2 = tcr2; | ||
119 | sport->regs->tclkdiv = clkdiv; | ||
120 | sport->regs->tfsdiv = fsdiv; | ||
121 | |||
122 | SSYNC(); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | EXPORT_SYMBOL(sport_config_tx); | ||
127 | |||
128 | static void setup_desc(struct dmasg *desc, void *buf, int fragcount, | ||
129 | size_t fragsize, unsigned int cfg, | ||
130 | unsigned int x_count, unsigned int ycount, size_t wdsize) | ||
131 | { | ||
132 | |||
133 | int i; | ||
134 | |||
135 | for (i = 0; i < fragcount; ++i) { | ||
136 | desc[i].next_desc_addr = (unsigned long)&(desc[i + 1]); | ||
137 | desc[i].start_addr = (unsigned long)buf + i*fragsize; | ||
138 | desc[i].cfg = cfg; | ||
139 | desc[i].x_count = x_count; | ||
140 | desc[i].x_modify = wdsize; | ||
141 | desc[i].y_count = ycount; | ||
142 | desc[i].y_modify = wdsize; | ||
143 | } | ||
144 | |||
145 | /* make circular */ | ||
146 | desc[fragcount-1].next_desc_addr = (unsigned long)desc; | ||
147 | |||
148 | pr_debug("setup desc: desc0=%p, next0=%lx, desc1=%p," | ||
149 | "next1=%lx\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n", | ||
150 | &(desc[0]), desc[0].next_desc_addr, | ||
151 | &(desc[1]), desc[1].next_desc_addr, | ||
152 | desc[0].x_count, desc[0].y_count, | ||
153 | desc[0].start_addr, desc[0].cfg); | ||
154 | } | ||
155 | |||
156 | static int sport_start(struct sport_device *sport) | ||
157 | { | ||
158 | enable_dma(sport->dma_rx_chan); | ||
159 | enable_dma(sport->dma_tx_chan); | ||
160 | sport->regs->rcr1 |= RSPEN; | ||
161 | sport->regs->tcr1 |= TSPEN; | ||
162 | SSYNC(); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int sport_stop(struct sport_device *sport) | ||
168 | { | ||
169 | sport->regs->tcr1 &= ~TSPEN; | ||
170 | sport->regs->rcr1 &= ~RSPEN; | ||
171 | SSYNC(); | ||
172 | |||
173 | disable_dma(sport->dma_rx_chan); | ||
174 | disable_dma(sport->dma_tx_chan); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static inline int sport_hook_rx_dummy(struct sport_device *sport) | ||
179 | { | ||
180 | struct dmasg *desc, temp_desc; | ||
181 | unsigned long flags; | ||
182 | |||
183 | BUG_ON(sport->dummy_rx_desc == NULL); | ||
184 | BUG_ON(sport->curr_rx_desc == sport->dummy_rx_desc); | ||
185 | |||
186 | /* Maybe the dummy buffer descriptor ring is damaged */ | ||
187 | sport->dummy_rx_desc->next_desc_addr = \ | ||
188 | (unsigned long)(sport->dummy_rx_desc+1); | ||
189 | |||
190 | local_irq_save(flags); | ||
191 | desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_rx_chan); | ||
192 | /* Copy the descriptor which will be damaged to backup */ | ||
193 | temp_desc = *desc; | ||
194 | desc->x_count = 0xa; | ||
195 | desc->y_count = 0; | ||
196 | desc->next_desc_addr = (unsigned long)(sport->dummy_rx_desc); | ||
197 | local_irq_restore(flags); | ||
198 | /* Waiting for dummy buffer descriptor is already hooked*/ | ||
199 | while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) - | ||
200 | sizeof(struct dmasg)) != | ||
201 | (unsigned long)sport->dummy_rx_desc) | ||
202 | ; | ||
203 | sport->curr_rx_desc = sport->dummy_rx_desc; | ||
204 | /* Restore the damaged descriptor */ | ||
205 | *desc = temp_desc; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static inline int sport_rx_dma_start(struct sport_device *sport, int dummy) | ||
211 | { | ||
212 | if (dummy) { | ||
213 | sport->dummy_rx_desc->next_desc_addr = \ | ||
214 | (unsigned long) sport->dummy_rx_desc; | ||
215 | sport->curr_rx_desc = sport->dummy_rx_desc; | ||
216 | } else | ||
217 | sport->curr_rx_desc = sport->dma_rx_desc; | ||
218 | |||
219 | set_dma_next_desc_addr(sport->dma_rx_chan, \ | ||
220 | (unsigned long)(sport->curr_rx_desc)); | ||
221 | set_dma_x_count(sport->dma_rx_chan, 0); | ||
222 | set_dma_x_modify(sport->dma_rx_chan, 0); | ||
223 | set_dma_config(sport->dma_rx_chan, (DMAFLOW_LARGE | NDSIZE_9 | \ | ||
224 | WDSIZE_32 | WNR)); | ||
225 | set_dma_curr_addr(sport->dma_rx_chan, sport->curr_rx_desc->start_addr); | ||
226 | SSYNC(); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static inline int sport_tx_dma_start(struct sport_device *sport, int dummy) | ||
232 | { | ||
233 | if (dummy) { | ||
234 | sport->dummy_tx_desc->next_desc_addr = \ | ||
235 | (unsigned long) sport->dummy_tx_desc; | ||
236 | sport->curr_tx_desc = sport->dummy_tx_desc; | ||
237 | } else | ||
238 | sport->curr_tx_desc = sport->dma_tx_desc; | ||
239 | |||
240 | set_dma_next_desc_addr(sport->dma_tx_chan, \ | ||
241 | (unsigned long)(sport->curr_tx_desc)); | ||
242 | set_dma_x_count(sport->dma_tx_chan, 0); | ||
243 | set_dma_x_modify(sport->dma_tx_chan, 0); | ||
244 | set_dma_config(sport->dma_tx_chan, | ||
245 | (DMAFLOW_LARGE | NDSIZE_9 | WDSIZE_32)); | ||
246 | set_dma_curr_addr(sport->dma_tx_chan, sport->curr_tx_desc->start_addr); | ||
247 | SSYNC(); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | int sport_rx_start(struct sport_device *sport) | ||
253 | { | ||
254 | unsigned long flags; | ||
255 | pr_debug("%s enter\n", __func__); | ||
256 | if (sport->rx_run) | ||
257 | return -EBUSY; | ||
258 | if (sport->tx_run) { | ||
259 | /* tx is running, rx is not running */ | ||
260 | BUG_ON(sport->dma_rx_desc == NULL); | ||
261 | BUG_ON(sport->curr_rx_desc != sport->dummy_rx_desc); | ||
262 | local_irq_save(flags); | ||
263 | while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) - | ||
264 | sizeof(struct dmasg)) != | ||
265 | (unsigned long)sport->dummy_rx_desc) | ||
266 | ; | ||
267 | sport->dummy_rx_desc->next_desc_addr = | ||
268 | (unsigned long)(sport->dma_rx_desc); | ||
269 | local_irq_restore(flags); | ||
270 | sport->curr_rx_desc = sport->dma_rx_desc; | ||
271 | } else { | ||
272 | sport_tx_dma_start(sport, 1); | ||
273 | sport_rx_dma_start(sport, 0); | ||
274 | sport_start(sport); | ||
275 | } | ||
276 | |||
277 | sport->rx_run = 1; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | EXPORT_SYMBOL(sport_rx_start); | ||
282 | |||
283 | int sport_rx_stop(struct sport_device *sport) | ||
284 | { | ||
285 | pr_debug("%s enter\n", __func__); | ||
286 | |||
287 | if (!sport->rx_run) | ||
288 | return 0; | ||
289 | if (sport->tx_run) { | ||
290 | /* TX dma is still running, hook the dummy buffer */ | ||
291 | sport_hook_rx_dummy(sport); | ||
292 | } else { | ||
293 | /* Both rx and tx dma will be stopped */ | ||
294 | sport_stop(sport); | ||
295 | sport->curr_rx_desc = NULL; | ||
296 | sport->curr_tx_desc = NULL; | ||
297 | } | ||
298 | |||
299 | sport->rx_run = 0; | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | EXPORT_SYMBOL(sport_rx_stop); | ||
304 | |||
305 | static inline int sport_hook_tx_dummy(struct sport_device *sport) | ||
306 | { | ||
307 | struct dmasg *desc, temp_desc; | ||
308 | unsigned long flags; | ||
309 | |||
310 | BUG_ON(sport->dummy_tx_desc == NULL); | ||
311 | BUG_ON(sport->curr_tx_desc == sport->dummy_tx_desc); | ||
312 | |||
313 | sport->dummy_tx_desc->next_desc_addr = \ | ||
314 | (unsigned long)(sport->dummy_tx_desc+1); | ||
315 | |||
316 | /* Shorten the time on last normal descriptor */ | ||
317 | local_irq_save(flags); | ||
318 | desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_tx_chan); | ||
319 | /* Store the descriptor which will be damaged */ | ||
320 | temp_desc = *desc; | ||
321 | desc->x_count = 0xa; | ||
322 | desc->y_count = 0; | ||
323 | desc->next_desc_addr = (unsigned long)(sport->dummy_tx_desc); | ||
324 | local_irq_restore(flags); | ||
325 | /* Waiting for dummy buffer descriptor is already hooked*/ | ||
326 | while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - \ | ||
327 | sizeof(struct dmasg)) != \ | ||
328 | (unsigned long)sport->dummy_tx_desc) | ||
329 | ; | ||
330 | sport->curr_tx_desc = sport->dummy_tx_desc; | ||
331 | /* Restore the damaged descriptor */ | ||
332 | *desc = temp_desc; | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | int sport_tx_start(struct sport_device *sport) | ||
338 | { | ||
339 | unsigned flags; | ||
340 | pr_debug("%s: tx_run:%d, rx_run:%d\n", __func__, | ||
341 | sport->tx_run, sport->rx_run); | ||
342 | if (sport->tx_run) | ||
343 | return -EBUSY; | ||
344 | if (sport->rx_run) { | ||
345 | BUG_ON(sport->dma_tx_desc == NULL); | ||
346 | BUG_ON(sport->curr_tx_desc != sport->dummy_tx_desc); | ||
347 | /* Hook the normal buffer descriptor */ | ||
348 | local_irq_save(flags); | ||
349 | while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - | ||
350 | sizeof(struct dmasg)) != | ||
351 | (unsigned long)sport->dummy_tx_desc) | ||
352 | ; | ||
353 | sport->dummy_tx_desc->next_desc_addr = | ||
354 | (unsigned long)(sport->dma_tx_desc); | ||
355 | local_irq_restore(flags); | ||
356 | sport->curr_tx_desc = sport->dma_tx_desc; | ||
357 | } else { | ||
358 | |||
359 | sport_tx_dma_start(sport, 0); | ||
360 | /* Let rx dma run the dummy buffer */ | ||
361 | sport_rx_dma_start(sport, 1); | ||
362 | sport_start(sport); | ||
363 | } | ||
364 | sport->tx_run = 1; | ||
365 | return 0; | ||
366 | } | ||
367 | EXPORT_SYMBOL(sport_tx_start); | ||
368 | |||
369 | int sport_tx_stop(struct sport_device *sport) | ||
370 | { | ||
371 | if (!sport->tx_run) | ||
372 | return 0; | ||
373 | if (sport->rx_run) { | ||
374 | /* RX is still running, hook the dummy buffer */ | ||
375 | sport_hook_tx_dummy(sport); | ||
376 | } else { | ||
377 | /* Both rx and tx dma stopped */ | ||
378 | sport_stop(sport); | ||
379 | sport->curr_rx_desc = NULL; | ||
380 | sport->curr_tx_desc = NULL; | ||
381 | } | ||
382 | |||
383 | sport->tx_run = 0; | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | EXPORT_SYMBOL(sport_tx_stop); | ||
388 | |||
389 | static inline int compute_wdsize(size_t wdsize) | ||
390 | { | ||
391 | switch (wdsize) { | ||
392 | case 1: | ||
393 | return WDSIZE_8; | ||
394 | case 2: | ||
395 | return WDSIZE_16; | ||
396 | case 4: | ||
397 | default: | ||
398 | return WDSIZE_32; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | int sport_config_rx_dma(struct sport_device *sport, void *buf, | ||
403 | int fragcount, size_t fragsize) | ||
404 | { | ||
405 | unsigned int x_count; | ||
406 | unsigned int y_count; | ||
407 | unsigned int cfg; | ||
408 | dma_addr_t addr; | ||
409 | |||
410 | pr_debug("%s buf:%p, frag:%d, fragsize:0x%lx\n", __func__, \ | ||
411 | buf, fragcount, fragsize); | ||
412 | |||
413 | x_count = fragsize / sport->wdsize; | ||
414 | y_count = 0; | ||
415 | |||
416 | /* for fragments larger than 64k words we use 2d dma, | ||
417 | * denote fragecount as two numbers' mutliply and both of them | ||
418 | * are less than 64k.*/ | ||
419 | if (x_count >= 0x10000) { | ||
420 | int i, count = x_count; | ||
421 | |||
422 | for (i = 16; i > 0; i--) { | ||
423 | x_count = 1 << i; | ||
424 | if ((count & (x_count - 1)) == 0) { | ||
425 | y_count = count >> i; | ||
426 | if (y_count < 0x10000) | ||
427 | break; | ||
428 | } | ||
429 | } | ||
430 | if (i == 0) | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | pr_debug("%s(x_count:0x%x, y_count:0x%x)\n", __func__, | ||
434 | x_count, y_count); | ||
435 | |||
436 | if (sport->dma_rx_desc) | ||
437 | dma_free_coherent(NULL, sport->rx_desc_bytes, | ||
438 | sport->dma_rx_desc, 0); | ||
439 | |||
440 | /* Allocate a new descritor ring as current one. */ | ||
441 | sport->dma_rx_desc = dma_alloc_coherent(NULL, \ | ||
442 | fragcount * sizeof(struct dmasg), &addr, 0); | ||
443 | sport->rx_desc_bytes = fragcount * sizeof(struct dmasg); | ||
444 | |||
445 | if (!sport->dma_rx_desc) { | ||
446 | pr_err("Failed to allocate memory for rx desc\n"); | ||
447 | return -ENOMEM; | ||
448 | } | ||
449 | |||
450 | sport->rx_buf = buf; | ||
451 | sport->rx_fragsize = fragsize; | ||
452 | sport->rx_frags = fragcount; | ||
453 | |||
454 | cfg = 0x7000 | DI_EN | compute_wdsize(sport->wdsize) | WNR | \ | ||
455 | (DESC_ELEMENT_COUNT << 8); /* large descriptor mode */ | ||
456 | |||
457 | if (y_count != 0) | ||
458 | cfg |= DMA2D; | ||
459 | |||
460 | setup_desc(sport->dma_rx_desc, buf, fragcount, fragsize, | ||
461 | cfg|DMAEN, x_count, y_count, sport->wdsize); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | EXPORT_SYMBOL(sport_config_rx_dma); | ||
466 | |||
467 | int sport_config_tx_dma(struct sport_device *sport, void *buf, \ | ||
468 | int fragcount, size_t fragsize) | ||
469 | { | ||
470 | unsigned int x_count; | ||
471 | unsigned int y_count; | ||
472 | unsigned int cfg; | ||
473 | dma_addr_t addr; | ||
474 | |||
475 | pr_debug("%s buf:%p, fragcount:%d, fragsize:0x%lx\n", | ||
476 | __func__, buf, fragcount, fragsize); | ||
477 | |||
478 | x_count = fragsize/sport->wdsize; | ||
479 | y_count = 0; | ||
480 | |||
481 | /* for fragments larger than 64k words we use 2d dma, | ||
482 | * denote fragecount as two numbers' mutliply and both of them | ||
483 | * are less than 64k.*/ | ||
484 | if (x_count >= 0x10000) { | ||
485 | int i, count = x_count; | ||
486 | |||
487 | for (i = 16; i > 0; i--) { | ||
488 | x_count = 1 << i; | ||
489 | if ((count & (x_count - 1)) == 0) { | ||
490 | y_count = count >> i; | ||
491 | if (y_count < 0x10000) | ||
492 | break; | ||
493 | } | ||
494 | } | ||
495 | if (i == 0) | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | pr_debug("%s x_count:0x%x, y_count:0x%x\n", __func__, | ||
499 | x_count, y_count); | ||
500 | |||
501 | |||
502 | if (sport->dma_tx_desc) { | ||
503 | dma_free_coherent(NULL, sport->tx_desc_bytes, \ | ||
504 | sport->dma_tx_desc, 0); | ||
505 | } | ||
506 | |||
507 | sport->dma_tx_desc = dma_alloc_coherent(NULL, \ | ||
508 | fragcount * sizeof(struct dmasg), &addr, 0); | ||
509 | sport->tx_desc_bytes = fragcount * sizeof(struct dmasg); | ||
510 | if (!sport->dma_tx_desc) { | ||
511 | pr_err("Failed to allocate memory for tx desc\n"); | ||
512 | return -ENOMEM; | ||
513 | } | ||
514 | |||
515 | sport->tx_buf = buf; | ||
516 | sport->tx_fragsize = fragsize; | ||
517 | sport->tx_frags = fragcount; | ||
518 | cfg = 0x7000 | DI_EN | compute_wdsize(sport->wdsize) | \ | ||
519 | (DESC_ELEMENT_COUNT << 8); /* large descriptor mode */ | ||
520 | |||
521 | if (y_count != 0) | ||
522 | cfg |= DMA2D; | ||
523 | |||
524 | setup_desc(sport->dma_tx_desc, buf, fragcount, fragsize, | ||
525 | cfg|DMAEN, x_count, y_count, sport->wdsize); | ||
526 | |||
527 | return 0; | ||
528 | } | ||
529 | EXPORT_SYMBOL(sport_config_tx_dma); | ||
530 | |||
531 | /* setup dummy dma descriptor ring, which don't generate interrupts, | ||
532 | * the x_modify is set to 0 */ | ||
533 | static int sport_config_rx_dummy(struct sport_device *sport) | ||
534 | { | ||
535 | struct dmasg *desc; | ||
536 | unsigned config; | ||
537 | |||
538 | pr_debug("%s entered\n", __func__); | ||
539 | #if L1_DATA_A_LENGTH != 0 | ||
540 | desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc)); | ||
541 | #else | ||
542 | { | ||
543 | dma_addr_t addr; | ||
544 | desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0); | ||
545 | } | ||
546 | #endif | ||
547 | if (desc == NULL) { | ||
548 | pr_err("Failed to allocate memory for dummy rx desc\n"); | ||
549 | return -ENOMEM; | ||
550 | } | ||
551 | memset(desc, 0, 2 * sizeof(*desc)); | ||
552 | sport->dummy_rx_desc = desc; | ||
553 | desc->start_addr = (unsigned long)sport->dummy_buf; | ||
554 | config = DMAFLOW_LARGE | NDSIZE_9 | compute_wdsize(sport->wdsize) | ||
555 | | WNR | DMAEN; | ||
556 | desc->cfg = config; | ||
557 | desc->x_count = sport->dummy_count/sport->wdsize; | ||
558 | desc->x_modify = sport->wdsize; | ||
559 | desc->y_count = 0; | ||
560 | desc->y_modify = 0; | ||
561 | memcpy(desc+1, desc, sizeof(*desc)); | ||
562 | desc->next_desc_addr = (unsigned long)(desc+1); | ||
563 | desc[1].next_desc_addr = (unsigned long)desc; | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static int sport_config_tx_dummy(struct sport_device *sport) | ||
568 | { | ||
569 | struct dmasg *desc; | ||
570 | unsigned int config; | ||
571 | |||
572 | pr_debug("%s entered\n", __func__); | ||
573 | |||
574 | #if L1_DATA_A_LENGTH != 0 | ||
575 | desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc)); | ||
576 | #else | ||
577 | { | ||
578 | dma_addr_t addr; | ||
579 | desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0); | ||
580 | } | ||
581 | #endif | ||
582 | if (!desc) { | ||
583 | pr_err("Failed to allocate memory for dummy tx desc\n"); | ||
584 | return -ENOMEM; | ||
585 | } | ||
586 | memset(desc, 0, 2 * sizeof(*desc)); | ||
587 | sport->dummy_tx_desc = desc; | ||
588 | desc->start_addr = (unsigned long)sport->dummy_buf + \ | ||
589 | sport->dummy_count; | ||
590 | config = DMAFLOW_LARGE | NDSIZE_9 | | ||
591 | compute_wdsize(sport->wdsize) | DMAEN; | ||
592 | desc->cfg = config; | ||
593 | desc->x_count = sport->dummy_count/sport->wdsize; | ||
594 | desc->x_modify = sport->wdsize; | ||
595 | desc->y_count = 0; | ||
596 | desc->y_modify = 0; | ||
597 | memcpy(desc+1, desc, sizeof(*desc)); | ||
598 | desc->next_desc_addr = (unsigned long)(desc+1); | ||
599 | desc[1].next_desc_addr = (unsigned long)desc; | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | unsigned long sport_curr_offset_rx(struct sport_device *sport) | ||
604 | { | ||
605 | unsigned long curr = get_dma_curr_addr(sport->dma_rx_chan); | ||
606 | |||
607 | return (unsigned char *)curr - sport->rx_buf; | ||
608 | } | ||
609 | EXPORT_SYMBOL(sport_curr_offset_rx); | ||
610 | |||
611 | unsigned long sport_curr_offset_tx(struct sport_device *sport) | ||
612 | { | ||
613 | unsigned long curr = get_dma_curr_addr(sport->dma_tx_chan); | ||
614 | |||
615 | return (unsigned char *)curr - sport->tx_buf; | ||
616 | } | ||
617 | EXPORT_SYMBOL(sport_curr_offset_tx); | ||
618 | |||
619 | void sport_incfrag(struct sport_device *sport, int *frag, int tx) | ||
620 | { | ||
621 | ++(*frag); | ||
622 | if (tx == 1 && *frag == sport->tx_frags) | ||
623 | *frag = 0; | ||
624 | |||
625 | if (tx == 0 && *frag == sport->rx_frags) | ||
626 | *frag = 0; | ||
627 | } | ||
628 | EXPORT_SYMBOL(sport_incfrag); | ||
629 | |||
630 | void sport_decfrag(struct sport_device *sport, int *frag, int tx) | ||
631 | { | ||
632 | --(*frag); | ||
633 | if (tx == 1 && *frag == 0) | ||
634 | *frag = sport->tx_frags; | ||
635 | |||
636 | if (tx == 0 && *frag == 0) | ||
637 | *frag = sport->rx_frags; | ||
638 | } | ||
639 | EXPORT_SYMBOL(sport_decfrag); | ||
640 | |||
641 | static int sport_check_status(struct sport_device *sport, | ||
642 | unsigned int *sport_stat, | ||
643 | unsigned int *rx_stat, | ||
644 | unsigned int *tx_stat) | ||
645 | { | ||
646 | int status = 0; | ||
647 | |||
648 | if (sport_stat) { | ||
649 | SSYNC(); | ||
650 | status = sport->regs->stat; | ||
651 | if (status & (TOVF|TUVF|ROVF|RUVF)) | ||
652 | sport->regs->stat = (status & (TOVF|TUVF|ROVF|RUVF)); | ||
653 | SSYNC(); | ||
654 | *sport_stat = status; | ||
655 | } | ||
656 | |||
657 | if (rx_stat) { | ||
658 | SSYNC(); | ||
659 | status = get_dma_curr_irqstat(sport->dma_rx_chan); | ||
660 | if (status & (DMA_DONE|DMA_ERR)) | ||
661 | clear_dma_irqstat(sport->dma_rx_chan); | ||
662 | SSYNC(); | ||
663 | *rx_stat = status; | ||
664 | } | ||
665 | |||
666 | if (tx_stat) { | ||
667 | SSYNC(); | ||
668 | status = get_dma_curr_irqstat(sport->dma_tx_chan); | ||
669 | if (status & (DMA_DONE|DMA_ERR)) | ||
670 | clear_dma_irqstat(sport->dma_tx_chan); | ||
671 | SSYNC(); | ||
672 | *tx_stat = status; | ||
673 | } | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | int sport_dump_stat(struct sport_device *sport, char *buf, size_t len) | ||
679 | { | ||
680 | int ret; | ||
681 | |||
682 | ret = snprintf(buf, len, | ||
683 | "sts: 0x%04x\n" | ||
684 | "rx dma %d sts: 0x%04x tx dma %d sts: 0x%04x\n", | ||
685 | sport->regs->stat, | ||
686 | sport->dma_rx_chan, | ||
687 | get_dma_curr_irqstat(sport->dma_rx_chan), | ||
688 | sport->dma_tx_chan, | ||
689 | get_dma_curr_irqstat(sport->dma_tx_chan)); | ||
690 | buf += ret; | ||
691 | len -= ret; | ||
692 | |||
693 | ret += snprintf(buf, len, | ||
694 | "curr_rx_desc:0x%p, curr_tx_desc:0x%p\n" | ||
695 | "dma_rx_desc:0x%p, dma_tx_desc:0x%p\n" | ||
696 | "dummy_rx_desc:0x%p, dummy_tx_desc:0x%p\n", | ||
697 | sport->curr_rx_desc, sport->curr_tx_desc, | ||
698 | sport->dma_rx_desc, sport->dma_tx_desc, | ||
699 | sport->dummy_rx_desc, sport->dummy_tx_desc); | ||
700 | |||
701 | return ret; | ||
702 | } | ||
703 | |||
704 | static irqreturn_t rx_handler(int irq, void *dev_id) | ||
705 | { | ||
706 | unsigned int rx_stat; | ||
707 | struct sport_device *sport = dev_id; | ||
708 | |||
709 | pr_debug("%s enter\n", __func__); | ||
710 | sport_check_status(sport, NULL, &rx_stat, NULL); | ||
711 | if (!(rx_stat & DMA_DONE)) | ||
712 | pr_err("rx dma is already stopped\n"); | ||
713 | |||
714 | if (sport->rx_callback) { | ||
715 | sport->rx_callback(sport->rx_data); | ||
716 | return IRQ_HANDLED; | ||
717 | } | ||
718 | |||
719 | return IRQ_NONE; | ||
720 | } | ||
721 | |||
722 | static irqreturn_t tx_handler(int irq, void *dev_id) | ||
723 | { | ||
724 | unsigned int tx_stat; | ||
725 | struct sport_device *sport = dev_id; | ||
726 | pr_debug("%s enter\n", __func__); | ||
727 | sport_check_status(sport, NULL, NULL, &tx_stat); | ||
728 | if (!(tx_stat & DMA_DONE)) { | ||
729 | pr_err("tx dma is already stopped\n"); | ||
730 | return IRQ_HANDLED; | ||
731 | } | ||
732 | if (sport->tx_callback) { | ||
733 | sport->tx_callback(sport->tx_data); | ||
734 | return IRQ_HANDLED; | ||
735 | } | ||
736 | |||
737 | return IRQ_NONE; | ||
738 | } | ||
739 | |||
740 | static irqreturn_t err_handler(int irq, void *dev_id) | ||
741 | { | ||
742 | unsigned int status = 0; | ||
743 | struct sport_device *sport = dev_id; | ||
744 | |||
745 | pr_debug("%s\n", __func__); | ||
746 | if (sport_check_status(sport, &status, NULL, NULL)) { | ||
747 | pr_err("error checking status ??"); | ||
748 | return IRQ_NONE; | ||
749 | } | ||
750 | |||
751 | if (status & (TOVF|TUVF|ROVF|RUVF)) { | ||
752 | pr_info("sport status error:%s%s%s%s\n", | ||
753 | status & TOVF ? " TOVF" : "", | ||
754 | status & TUVF ? " TUVF" : "", | ||
755 | status & ROVF ? " ROVF" : "", | ||
756 | status & RUVF ? " RUVF" : ""); | ||
757 | if (status & TOVF || status & TUVF) { | ||
758 | disable_dma(sport->dma_tx_chan); | ||
759 | if (sport->tx_run) | ||
760 | sport_tx_dma_start(sport, 0); | ||
761 | else | ||
762 | sport_tx_dma_start(sport, 1); | ||
763 | enable_dma(sport->dma_tx_chan); | ||
764 | } else { | ||
765 | disable_dma(sport->dma_rx_chan); | ||
766 | if (sport->rx_run) | ||
767 | sport_rx_dma_start(sport, 0); | ||
768 | else | ||
769 | sport_rx_dma_start(sport, 1); | ||
770 | enable_dma(sport->dma_rx_chan); | ||
771 | } | ||
772 | } | ||
773 | status = sport->regs->stat; | ||
774 | if (status & (TOVF|TUVF|ROVF|RUVF)) | ||
775 | sport->regs->stat = (status & (TOVF|TUVF|ROVF|RUVF)); | ||
776 | SSYNC(); | ||
777 | |||
778 | if (sport->err_callback) | ||
779 | sport->err_callback(sport->err_data); | ||
780 | |||
781 | return IRQ_HANDLED; | ||
782 | } | ||
783 | |||
784 | int sport_set_rx_callback(struct sport_device *sport, | ||
785 | void (*rx_callback)(void *), void *rx_data) | ||
786 | { | ||
787 | BUG_ON(rx_callback == NULL); | ||
788 | sport->rx_callback = rx_callback; | ||
789 | sport->rx_data = rx_data; | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | EXPORT_SYMBOL(sport_set_rx_callback); | ||
794 | |||
795 | int sport_set_tx_callback(struct sport_device *sport, | ||
796 | void (*tx_callback)(void *), void *tx_data) | ||
797 | { | ||
798 | BUG_ON(tx_callback == NULL); | ||
799 | sport->tx_callback = tx_callback; | ||
800 | sport->tx_data = tx_data; | ||
801 | |||
802 | return 0; | ||
803 | } | ||
804 | EXPORT_SYMBOL(sport_set_tx_callback); | ||
805 | |||
806 | int sport_set_err_callback(struct sport_device *sport, | ||
807 | void (*err_callback)(void *), void *err_data) | ||
808 | { | ||
809 | BUG_ON(err_callback == NULL); | ||
810 | sport->err_callback = err_callback; | ||
811 | sport->err_data = err_data; | ||
812 | |||
813 | return 0; | ||
814 | } | ||
815 | EXPORT_SYMBOL(sport_set_err_callback); | ||
816 | |||
817 | struct sport_device *sport_init(struct sport_param *param, unsigned wdsize, | ||
818 | unsigned dummy_count, void *private_data) | ||
819 | { | ||
820 | int ret; | ||
821 | struct sport_device *sport; | ||
822 | pr_debug("%s enter\n", __func__); | ||
823 | BUG_ON(param == NULL); | ||
824 | BUG_ON(wdsize == 0 || dummy_count == 0); | ||
825 | sport = kmalloc(sizeof(struct sport_device), GFP_KERNEL); | ||
826 | if (!sport) { | ||
827 | pr_err("Failed to allocate for sport device\n"); | ||
828 | return NULL; | ||
829 | } | ||
830 | |||
831 | memset(sport, 0, sizeof(struct sport_device)); | ||
832 | sport->dma_rx_chan = param->dma_rx_chan; | ||
833 | sport->dma_tx_chan = param->dma_tx_chan; | ||
834 | sport->err_irq = param->err_irq; | ||
835 | sport->regs = param->regs; | ||
836 | sport->private_data = private_data; | ||
837 | |||
838 | if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) { | ||
839 | pr_err("Failed to request RX dma %d\n", \ | ||
840 | sport->dma_rx_chan); | ||
841 | goto __init_err1; | ||
842 | } | ||
843 | if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) { | ||
844 | pr_err("Failed to request RX irq %d\n", \ | ||
845 | sport->dma_rx_chan); | ||
846 | goto __init_err2; | ||
847 | } | ||
848 | |||
849 | if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) { | ||
850 | pr_err("Failed to request TX dma %d\n", \ | ||
851 | sport->dma_tx_chan); | ||
852 | goto __init_err2; | ||
853 | } | ||
854 | |||
855 | if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) { | ||
856 | pr_err("Failed to request TX irq %d\n", \ | ||
857 | sport->dma_tx_chan); | ||
858 | goto __init_err3; | ||
859 | } | ||
860 | |||
861 | if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err", | ||
862 | sport) < 0) { | ||
863 | pr_err("Failed to request err irq:%d\n", \ | ||
864 | sport->err_irq); | ||
865 | goto __init_err3; | ||
866 | } | ||
867 | |||
868 | pr_err("dma rx:%d tx:%d, err irq:%d, regs:%p\n", | ||
869 | sport->dma_rx_chan, sport->dma_tx_chan, | ||
870 | sport->err_irq, sport->regs); | ||
871 | |||
872 | sport->wdsize = wdsize; | ||
873 | sport->dummy_count = dummy_count; | ||
874 | |||
875 | #if L1_DATA_A_LENGTH != 0 | ||
876 | sport->dummy_buf = l1_data_sram_alloc(dummy_count * 2); | ||
877 | #else | ||
878 | sport->dummy_buf = kmalloc(dummy_count * 2, GFP_KERNEL); | ||
879 | #endif | ||
880 | if (sport->dummy_buf == NULL) { | ||
881 | pr_err("Failed to allocate dummy buffer\n"); | ||
882 | goto __error; | ||
883 | } | ||
884 | |||
885 | memset(sport->dummy_buf, 0, dummy_count * 2); | ||
886 | ret = sport_config_rx_dummy(sport); | ||
887 | if (ret) { | ||
888 | pr_err("Failed to config rx dummy ring\n"); | ||
889 | goto __error; | ||
890 | } | ||
891 | ret = sport_config_tx_dummy(sport); | ||
892 | if (ret) { | ||
893 | pr_err("Failed to config tx dummy ring\n"); | ||
894 | goto __error; | ||
895 | } | ||
896 | |||
897 | return sport; | ||
898 | __error: | ||
899 | free_irq(sport->err_irq, sport); | ||
900 | __init_err3: | ||
901 | free_dma(sport->dma_tx_chan); | ||
902 | __init_err2: | ||
903 | free_dma(sport->dma_rx_chan); | ||
904 | __init_err1: | ||
905 | kfree(sport); | ||
906 | return NULL; | ||
907 | } | ||
908 | EXPORT_SYMBOL(sport_init); | ||
909 | |||
910 | void sport_done(struct sport_device *sport) | ||
911 | { | ||
912 | if (sport == NULL) | ||
913 | return; | ||
914 | |||
915 | sport_stop(sport); | ||
916 | if (sport->dma_rx_desc) | ||
917 | dma_free_coherent(NULL, sport->rx_desc_bytes, | ||
918 | sport->dma_rx_desc, 0); | ||
919 | if (sport->dma_tx_desc) | ||
920 | dma_free_coherent(NULL, sport->tx_desc_bytes, | ||
921 | sport->dma_tx_desc, 0); | ||
922 | |||
923 | #if L1_DATA_A_LENGTH != 0 | ||
924 | l1_data_sram_free(sport->dummy_rx_desc); | ||
925 | l1_data_sram_free(sport->dummy_tx_desc); | ||
926 | l1_data_sram_free(sport->dummy_buf); | ||
927 | #else | ||
928 | dma_free_coherent(NULL, 2*sizeof(struct dmasg), | ||
929 | sport->dummy_rx_desc, 0); | ||
930 | dma_free_coherent(NULL, 2*sizeof(struct dmasg), | ||
931 | sport->dummy_tx_desc, 0); | ||
932 | kfree(sport->dummy_buf); | ||
933 | #endif | ||
934 | free_dma(sport->dma_rx_chan); | ||
935 | free_dma(sport->dma_tx_chan); | ||
936 | free_irq(sport->err_irq, sport); | ||
937 | |||
938 | kfree(sport); | ||
939 | sport = NULL; | ||
940 | } | ||
941 | EXPORT_SYMBOL(sport_done); | ||
942 | /* | ||
943 | * It is only used to send several bytes when dma is not enabled | ||
944 | * sport controller is configured but not enabled. | ||
945 | * Multichannel cannot works with pio mode */ | ||
946 | /* Used by ac97 to write and read codec register */ | ||
947 | int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \ | ||
948 | u8 *in_data, int len) | ||
949 | { | ||
950 | unsigned short dma_config; | ||
951 | unsigned short status; | ||
952 | unsigned long flags; | ||
953 | unsigned long wait = 0; | ||
954 | |||
955 | pr_debug("%s enter, out_data:%p, in_data:%p len:%d\n", \ | ||
956 | __func__, out_data, in_data, len); | ||
957 | pr_debug("tcr1:0x%04x, tcr2:0x%04x, tclkdiv:0x%04x, tfsdiv:0x%04x\n" | ||
958 | "mcmc1:0x%04x, mcmc2:0x%04x\n", | ||
959 | sport->regs->tcr1, sport->regs->tcr2, | ||
960 | sport->regs->tclkdiv, sport->regs->tfsdiv, | ||
961 | sport->regs->mcmc1, sport->regs->mcmc2); | ||
962 | flush_dcache_range((unsigned)out_data, (unsigned)(out_data + len)); | ||
963 | |||
964 | /* Enable tx dma */ | ||
965 | dma_config = (RESTART | WDSIZE_16 | DI_EN); | ||
966 | set_dma_start_addr(sport->dma_tx_chan, (unsigned long)out_data); | ||
967 | set_dma_x_count(sport->dma_tx_chan, len/2); | ||
968 | set_dma_x_modify(sport->dma_tx_chan, 2); | ||
969 | set_dma_config(sport->dma_tx_chan, dma_config); | ||
970 | enable_dma(sport->dma_tx_chan); | ||
971 | |||
972 | if (in_data != NULL) { | ||
973 | invalidate_dcache_range((unsigned)in_data, \ | ||
974 | (unsigned)(in_data + len)); | ||
975 | /* Enable rx dma */ | ||
976 | dma_config = (RESTART | WDSIZE_16 | WNR | DI_EN); | ||
977 | set_dma_start_addr(sport->dma_rx_chan, (unsigned long)in_data); | ||
978 | set_dma_x_count(sport->dma_rx_chan, len/2); | ||
979 | set_dma_x_modify(sport->dma_rx_chan, 2); | ||
980 | set_dma_config(sport->dma_rx_chan, dma_config); | ||
981 | enable_dma(sport->dma_rx_chan); | ||
982 | } | ||
983 | |||
984 | local_irq_save(flags); | ||
985 | sport->regs->tcr1 |= TSPEN; | ||
986 | sport->regs->rcr1 |= RSPEN; | ||
987 | SSYNC(); | ||
988 | |||
989 | status = get_dma_curr_irqstat(sport->dma_tx_chan); | ||
990 | while (status & DMA_RUN) { | ||
991 | udelay(1); | ||
992 | status = get_dma_curr_irqstat(sport->dma_tx_chan); | ||
993 | pr_debug("DMA status:0x%04x\n", status); | ||
994 | if (wait++ > 100) | ||
995 | goto __over; | ||
996 | } | ||
997 | status = sport->regs->stat; | ||
998 | wait = 0; | ||
999 | |||
1000 | while (!(status & TXHRE)) { | ||
1001 | pr_debug("sport status:0x%04x\n", status); | ||
1002 | udelay(1); | ||
1003 | status = *(unsigned short *)&sport->regs->stat; | ||
1004 | if (wait++ > 1000) | ||
1005 | goto __over; | ||
1006 | } | ||
1007 | /* Wait for the last byte sent out */ | ||
1008 | udelay(20); | ||
1009 | pr_debug("sport status:0x%04x\n", status); | ||
1010 | |||
1011 | __over: | ||
1012 | sport->regs->tcr1 &= ~TSPEN; | ||
1013 | sport->regs->rcr1 &= ~RSPEN; | ||
1014 | SSYNC(); | ||
1015 | disable_dma(sport->dma_tx_chan); | ||
1016 | /* Clear the status */ | ||
1017 | clear_dma_irqstat(sport->dma_tx_chan); | ||
1018 | if (in_data != NULL) { | ||
1019 | disable_dma(sport->dma_rx_chan); | ||
1020 | clear_dma_irqstat(sport->dma_rx_chan); | ||
1021 | } | ||
1022 | SSYNC(); | ||
1023 | local_irq_restore(flags); | ||
1024 | |||
1025 | return 0; | ||
1026 | } | ||
1027 | EXPORT_SYMBOL(sport_send_and_recv); | ||
1028 | |||
1029 | MODULE_AUTHOR("Roy Huang"); | ||
1030 | MODULE_DESCRIPTION("SPORT driver for ADI Blackfin"); | ||
1031 | MODULE_LICENSE("GPL"); | ||
1032 | |||
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h new file mode 100644 index 00000000000..4c163454bbf --- /dev/null +++ b/sound/soc/blackfin/bf5xx-sport.h | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * File: bf5xx_ac97_sport.h | ||
3 | * Based on: | ||
4 | * Author: Roy Huang <roy.huang@analog.com> | ||
5 | * | ||
6 | * Created: | ||
7 | * Description: | ||
8 | * | ||
9 | * Copyright 2004-2007 Analog Devices Inc. | ||
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, see the file COPYING, or write | ||
25 | * to the Free Software Foundation, Inc., | ||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | |||
30 | #ifndef __BF5XX_SPORT_H__ | ||
31 | #define __BF5XX_SPORT_H__ | ||
32 | |||
33 | #include <linux/types.h> | ||
34 | #include <linux/wait.h> | ||
35 | #include <linux/workqueue.h> | ||
36 | #include <asm/dma.h> | ||
37 | |||
38 | struct sport_register { | ||
39 | u16 tcr1; u16 reserved0; | ||
40 | u16 tcr2; u16 reserved1; | ||
41 | u16 tclkdiv; u16 reserved2; | ||
42 | u16 tfsdiv; u16 reserved3; | ||
43 | u32 tx; | ||
44 | u32 reserved_l0; | ||
45 | u32 rx; | ||
46 | u32 reserved_l1; | ||
47 | u16 rcr1; u16 reserved4; | ||
48 | u16 rcr2; u16 reserved5; | ||
49 | u16 rclkdiv; u16 reserved6; | ||
50 | u16 rfsdiv; u16 reserved7; | ||
51 | u16 stat; u16 reserved8; | ||
52 | u16 chnl; u16 reserved9; | ||
53 | u16 mcmc1; u16 reserved10; | ||
54 | u16 mcmc2; u16 reserved11; | ||
55 | u32 mtcs0; | ||
56 | u32 mtcs1; | ||
57 | u32 mtcs2; | ||
58 | u32 mtcs3; | ||
59 | u32 mrcs0; | ||
60 | u32 mrcs1; | ||
61 | u32 mrcs2; | ||
62 | u32 mrcs3; | ||
63 | }; | ||
64 | |||
65 | #define DESC_ELEMENT_COUNT 9 | ||
66 | |||
67 | struct sport_device { | ||
68 | int dma_rx_chan; | ||
69 | int dma_tx_chan; | ||
70 | int err_irq; | ||
71 | struct sport_register *regs; | ||
72 | |||
73 | unsigned char *rx_buf; | ||
74 | unsigned char *tx_buf; | ||
75 | unsigned int rx_fragsize; | ||
76 | unsigned int tx_fragsize; | ||
77 | unsigned int rx_frags; | ||
78 | unsigned int tx_frags; | ||
79 | unsigned int wdsize; | ||
80 | |||
81 | /* for dummy dma transfer */ | ||
82 | void *dummy_buf; | ||
83 | unsigned int dummy_count; | ||
84 | |||
85 | /* DMA descriptor ring head of current audio stream*/ | ||
86 | struct dmasg *dma_rx_desc; | ||
87 | struct dmasg *dma_tx_desc; | ||
88 | unsigned int rx_desc_bytes; | ||
89 | unsigned int tx_desc_bytes; | ||
90 | |||
91 | unsigned int rx_run:1; /* rx is running */ | ||
92 | unsigned int tx_run:1; /* tx is running */ | ||
93 | |||
94 | struct dmasg *dummy_rx_desc; | ||
95 | struct dmasg *dummy_tx_desc; | ||
96 | |||
97 | struct dmasg *curr_rx_desc; | ||
98 | struct dmasg *curr_tx_desc; | ||
99 | |||
100 | int rx_curr_frag; | ||
101 | int tx_curr_frag; | ||
102 | |||
103 | unsigned int rcr1; | ||
104 | unsigned int rcr2; | ||
105 | int rx_tdm_count; | ||
106 | |||
107 | unsigned int tcr1; | ||
108 | unsigned int tcr2; | ||
109 | int tx_tdm_count; | ||
110 | |||
111 | void (*rx_callback)(void *data); | ||
112 | void *rx_data; | ||
113 | void (*tx_callback)(void *data); | ||
114 | void *tx_data; | ||
115 | void (*err_callback)(void *data); | ||
116 | void *err_data; | ||
117 | unsigned char *tx_dma_buf; | ||
118 | unsigned char *rx_dma_buf; | ||
119 | #ifdef CONFIG_SND_MMAP_SUPPORT | ||
120 | dma_addr_t tx_dma_phy; | ||
121 | dma_addr_t rx_dma_phy; | ||
122 | int tx_pos;/*pcm sample count*/ | ||
123 | int rx_pos; | ||
124 | unsigned int tx_buffer_size; | ||
125 | unsigned int rx_buffer_size; | ||
126 | #endif | ||
127 | void *private_data; | ||
128 | }; | ||
129 | |||
130 | extern struct sport_device *sport_handle; | ||
131 | |||
132 | struct sport_param { | ||
133 | int dma_rx_chan; | ||
134 | int dma_tx_chan; | ||
135 | int err_irq; | ||
136 | struct sport_register *regs; | ||
137 | }; | ||
138 | |||
139 | struct sport_device *sport_init(struct sport_param *param, unsigned wdsize, | ||
140 | unsigned dummy_count, void *private_data); | ||
141 | |||
142 | void sport_done(struct sport_device *sport); | ||
143 | |||
144 | /* first use these ...*/ | ||
145 | |||
146 | /* note: multichannel is in units of 8 channels, tdm_count is number of channels | ||
147 | * NOT / 8 ! all channels are enabled by default */ | ||
148 | int sport_set_multichannel(struct sport_device *sport, int tdm_count, | ||
149 | u32 mask, int packed); | ||
150 | |||
151 | int sport_config_rx(struct sport_device *sport, | ||
152 | unsigned int rcr1, unsigned int rcr2, | ||
153 | unsigned int clkdiv, unsigned int fsdiv); | ||
154 | |||
155 | int sport_config_tx(struct sport_device *sport, | ||
156 | unsigned int tcr1, unsigned int tcr2, | ||
157 | unsigned int clkdiv, unsigned int fsdiv); | ||
158 | |||
159 | /* ... then these: */ | ||
160 | |||
161 | /* buffer size (in bytes) == fragcount * fragsize_bytes */ | ||
162 | |||
163 | /* this is not a very general api, it sets the dma to 2d autobuffer mode */ | ||
164 | |||
165 | int sport_config_rx_dma(struct sport_device *sport, void *buf, | ||
166 | int fragcount, size_t fragsize_bytes); | ||
167 | |||
168 | int sport_config_tx_dma(struct sport_device *sport, void *buf, | ||
169 | int fragcount, size_t fragsize_bytes); | ||
170 | |||
171 | int sport_tx_start(struct sport_device *sport); | ||
172 | int sport_tx_stop(struct sport_device *sport); | ||
173 | int sport_rx_start(struct sport_device *sport); | ||
174 | int sport_rx_stop(struct sport_device *sport); | ||
175 | |||
176 | /* for use in interrupt handler */ | ||
177 | unsigned long sport_curr_offset_rx(struct sport_device *sport); | ||
178 | unsigned long sport_curr_offset_tx(struct sport_device *sport); | ||
179 | |||
180 | void sport_incfrag(struct sport_device *sport, int *frag, int tx); | ||
181 | void sport_decfrag(struct sport_device *sport, int *frag, int tx); | ||
182 | |||
183 | int sport_set_rx_callback(struct sport_device *sport, | ||
184 | void (*rx_callback)(void *), void *rx_data); | ||
185 | int sport_set_tx_callback(struct sport_device *sport, | ||
186 | void (*tx_callback)(void *), void *tx_data); | ||
187 | int sport_set_err_callback(struct sport_device *sport, | ||
188 | void (*err_callback)(void *), void *err_data); | ||
189 | |||
190 | int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \ | ||
191 | u8 *in_data, int len); | ||
192 | #endif /* BF53X_SPORT_H */ | ||
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c new file mode 100644 index 00000000000..e15f67fd776 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ssm2602.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * File: sound/soc/blackfin/bf5xx-ssm2602.c | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Tue June 06 2008 | ||
6 | * Description: board driver for SSM2602 sound chip | ||
7 | * | ||
8 | * Modified: | ||
9 | * Copyright 2008 Analog Devices Inc. | ||
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, see the file COPYING, or write | ||
25 | * to the Free Software Foundation, Inc., | ||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <linux/device.h> | ||
32 | |||
33 | #include <sound/core.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/soc.h> | ||
36 | #include <sound/soc-dapm.h> | ||
37 | #include <sound/pcm_params.h> | ||
38 | |||
39 | #include <asm/dma.h> | ||
40 | #include <asm/portmux.h> | ||
41 | #include <linux/gpio.h> | ||
42 | #include "../codecs/ssm2602.h" | ||
43 | #include "bf5xx-sport.h" | ||
44 | #include "bf5xx-i2s-pcm.h" | ||
45 | #include "bf5xx-i2s.h" | ||
46 | |||
47 | static struct snd_soc_machine bf5xx_ssm2602; | ||
48 | |||
49 | static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream) | ||
50 | { | ||
51 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
52 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
53 | |||
54 | pr_debug("%s enter\n", __func__); | ||
55 | cpu_dai->private_data = sport_handle; | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream, | ||
60 | struct snd_pcm_hw_params *params) | ||
61 | { | ||
62 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
63 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
64 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
65 | unsigned int clk = 0; | ||
66 | int ret = 0; | ||
67 | |||
68 | pr_debug("%s rate %d format %x\n", __func__, params_rate(params), | ||
69 | params_format(params)); | ||
70 | /* | ||
71 | * If you are using a crystal source which frequency is not 12MHz | ||
72 | * then modify the below case statement with frequency of the crystal. | ||
73 | * | ||
74 | * If you are using the SPORT to generate clocking then this is | ||
75 | * where to do it. | ||
76 | */ | ||
77 | |||
78 | switch (params_rate(params)) { | ||
79 | case 8000: | ||
80 | case 16000: | ||
81 | case 48000: | ||
82 | case 96000: | ||
83 | case 11025: | ||
84 | case 22050: | ||
85 | case 44100: | ||
86 | clk = 12000000; | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * CODEC is master for BCLK and LRC in this configuration. | ||
92 | */ | ||
93 | |||
94 | /* set codec DAI configuration */ | ||
95 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
96 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | /* set cpu DAI configuration */ | ||
100 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
101 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
102 | if (ret < 0) | ||
103 | return ret; | ||
104 | |||
105 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, SSM2602_SYSCLK, clk, | ||
106 | SND_SOC_CLOCK_IN); | ||
107 | if (ret < 0) | ||
108 | return ret; | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static struct snd_soc_ops bf5xx_ssm2602_ops = { | ||
114 | .startup = bf5xx_ssm2602_startup, | ||
115 | .hw_params = bf5xx_ssm2602_hw_params, | ||
116 | }; | ||
117 | |||
118 | static struct snd_soc_dai_link bf5xx_ssm2602_dai = { | ||
119 | .name = "ssm2602", | ||
120 | .stream_name = "SSM2602", | ||
121 | .cpu_dai = &bf5xx_i2s_dai, | ||
122 | .codec_dai = &ssm2602_dai, | ||
123 | .ops = &bf5xx_ssm2602_ops, | ||
124 | }; | ||
125 | |||
126 | /* | ||
127 | * SSM2602 2 wire address is determined by CSB | ||
128 | * state during powerup. | ||
129 | * low = 0x1a | ||
130 | * high = 0x1b | ||
131 | */ | ||
132 | |||
133 | static struct ssm2602_setup_data bf5xx_ssm2602_setup = { | ||
134 | .i2c_bus = 0, | ||
135 | .i2c_address = 0x1b, | ||
136 | }; | ||
137 | |||
138 | static struct snd_soc_machine bf5xx_ssm2602 = { | ||
139 | .name = "bf5xx_ssm2602", | ||
140 | .dai_link = &bf5xx_ssm2602_dai, | ||
141 | .num_links = 1, | ||
142 | }; | ||
143 | |||
144 | static struct snd_soc_device bf5xx_ssm2602_snd_devdata = { | ||
145 | .machine = &bf5xx_ssm2602, | ||
146 | .platform = &bf5xx_i2s_soc_platform, | ||
147 | .codec_dev = &soc_codec_dev_ssm2602, | ||
148 | .codec_data = &bf5xx_ssm2602_setup, | ||
149 | }; | ||
150 | |||
151 | static struct platform_device *bf52x_ssm2602_snd_device; | ||
152 | |||
153 | static int __init bf5xx_ssm2602_init(void) | ||
154 | { | ||
155 | int ret; | ||
156 | |||
157 | pr_debug("%s enter\n", __func__); | ||
158 | bf52x_ssm2602_snd_device = platform_device_alloc("soc-audio", -1); | ||
159 | if (!bf52x_ssm2602_snd_device) | ||
160 | return -ENOMEM; | ||
161 | |||
162 | platform_set_drvdata(bf52x_ssm2602_snd_device, | ||
163 | &bf5xx_ssm2602_snd_devdata); | ||
164 | bf5xx_ssm2602_snd_devdata.dev = &bf52x_ssm2602_snd_device->dev; | ||
165 | ret = platform_device_add(bf52x_ssm2602_snd_device); | ||
166 | |||
167 | if (ret) | ||
168 | platform_device_put(bf52x_ssm2602_snd_device); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static void __exit bf5xx_ssm2602_exit(void) | ||
174 | { | ||
175 | pr_debug("%s enter\n", __func__); | ||
176 | platform_device_unregister(bf52x_ssm2602_snd_device); | ||
177 | } | ||
178 | |||
179 | module_init(bf5xx_ssm2602_init); | ||
180 | module_exit(bf5xx_ssm2602_exit); | ||
181 | |||
182 | /* Module information */ | ||
183 | MODULE_AUTHOR("Cliff Cai"); | ||
184 | MODULE_DESCRIPTION("ALSA SoC SSM2602 BF527-EZKIT"); | ||
185 | MODULE_LICENSE("GPL"); | ||
186 | |||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1db04a28a53..e0b9869df0f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -1,16 +1,80 @@ | |||
1 | config SND_SOC_ALL_CODECS | ||
2 | tristate "Build all ASoC CODEC drivers" | ||
3 | depends on I2C | ||
4 | select SPI | ||
5 | select SPI_MASTER | ||
6 | select SND_SOC_AK4535 | ||
7 | select SND_SOC_CS4270 | ||
8 | select SND_SOC_SSM2602 | ||
9 | select SND_SOC_TLV320AIC26 | ||
10 | select SND_SOC_TLV320AIC3X | ||
11 | select SND_SOC_UDA1380 | ||
12 | select SND_SOC_WM8510 | ||
13 | select SND_SOC_WM8580 | ||
14 | select SND_SOC_WM8731 | ||
15 | select SND_SOC_WM8750 | ||
16 | select SND_SOC_WM8753 | ||
17 | select SND_SOC_WM8900 | ||
18 | select SND_SOC_WM8903 | ||
19 | select SND_SOC_WM8971 | ||
20 | select SND_SOC_WM8990 | ||
21 | help | ||
22 | Normally ASoC codec drivers are only built if a machine driver which | ||
23 | uses them is also built since they are only usable with a machine | ||
24 | driver. Selecting this option will allow these drivers to be built | ||
25 | without an explicit machine driver for test and development purposes. | ||
26 | |||
27 | If unsure select "N". | ||
28 | |||
29 | |||
1 | config SND_SOC_AC97_CODEC | 30 | config SND_SOC_AC97_CODEC |
2 | tristate | 31 | tristate |
3 | select SND_AC97_CODEC | 32 | select SND_AC97_CODEC |
4 | 33 | ||
34 | config SND_SOC_AD1980 | ||
35 | tristate | ||
36 | |||
5 | config SND_SOC_AK4535 | 37 | config SND_SOC_AK4535 |
6 | tristate | 38 | tristate |
7 | 39 | ||
40 | # Cirrus Logic CS4270 Codec | ||
41 | config SND_SOC_CS4270 | ||
42 | tristate | ||
43 | |||
44 | # Cirrus Logic CS4270 Codec Hardware Mute Support | ||
45 | # Select if you have external muting circuitry attached to your CS4270. | ||
46 | config SND_SOC_CS4270_HWMUTE | ||
47 | bool | ||
48 | depends on SND_SOC_CS4270 | ||
49 | |||
50 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | ||
51 | # Select if you are affected by the errata where the part will not function | ||
52 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will | ||
53 | # not select any sample rates that require MCLK to be divided by 1.5. | ||
54 | config SND_SOC_CS4270_VD33_ERRATA | ||
55 | bool | ||
56 | depends on SND_SOC_CS4270 | ||
57 | |||
58 | config SND_SOC_SSM2602 | ||
59 | tristate | ||
60 | |||
61 | config SND_SOC_TLV320AIC26 | ||
62 | tristate "TI TLV320AIC26 Codec support" | ||
63 | depends on SND_SOC && SPI | ||
64 | |||
65 | config SND_SOC_TLV320AIC3X | ||
66 | tristate | ||
67 | depends on I2C | ||
68 | |||
8 | config SND_SOC_UDA1380 | 69 | config SND_SOC_UDA1380 |
9 | tristate | 70 | tristate |
10 | 71 | ||
11 | config SND_SOC_WM8510 | 72 | config SND_SOC_WM8510 |
12 | tristate | 73 | tristate |
13 | 74 | ||
75 | config SND_SOC_WM8580 | ||
76 | tristate | ||
77 | |||
14 | config SND_SOC_WM8731 | 78 | config SND_SOC_WM8731 |
15 | tristate | 79 | tristate |
16 | 80 | ||
@@ -20,33 +84,20 @@ config SND_SOC_WM8750 | |||
20 | config SND_SOC_WM8753 | 84 | config SND_SOC_WM8753 |
21 | tristate | 85 | tristate |
22 | 86 | ||
23 | config SND_SOC_WM8990 | 87 | config SND_SOC_WM8900 |
24 | tristate | 88 | tristate |
25 | 89 | ||
26 | config SND_SOC_WM9712 | 90 | config SND_SOC_WM8903 |
27 | tristate | 91 | tristate |
28 | 92 | ||
29 | config SND_SOC_WM9713 | 93 | config SND_SOC_WM8971 |
30 | tristate | 94 | tristate |
31 | 95 | ||
32 | # Cirrus Logic CS4270 Codec | 96 | config SND_SOC_WM8990 |
33 | config SND_SOC_CS4270 | ||
34 | tristate | 97 | tristate |
35 | 98 | ||
36 | # Cirrus Logic CS4270 Codec Hardware Mute Support | 99 | config SND_SOC_WM9712 |
37 | # Select if you have external muting circuitry attached to your CS4270. | 100 | tristate |
38 | config SND_SOC_CS4270_HWMUTE | ||
39 | bool | ||
40 | depends on SND_SOC_CS4270 | ||
41 | |||
42 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | ||
43 | # Select if you are affected by the errata where the part will not function | ||
44 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will | ||
45 | # not select any sample rates that require MCLK to be divided by 1.5. | ||
46 | config SND_SOC_CS4270_VD33_ERRATA | ||
47 | bool | ||
48 | depends on SND_SOC_CS4270 | ||
49 | 101 | ||
50 | config SND_SOC_TLV320AIC3X | 102 | config SND_SOC_WM9713 |
51 | tristate | 103 | tristate |
52 | depends on I2C | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d7b97abcf72..f977978a340 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -1,25 +1,39 @@ | |||
1 | snd-soc-ac97-objs := ac97.o | 1 | snd-soc-ac97-objs := ac97.o |
2 | snd-soc-ad1980-objs := ad1980.o | ||
2 | snd-soc-ak4535-objs := ak4535.o | 3 | snd-soc-ak4535-objs := ak4535.o |
4 | snd-soc-cs4270-objs := cs4270.o | ||
5 | snd-soc-ssm2602-objs := ssm2602.o | ||
6 | snd-soc-tlv320aic26-objs := tlv320aic26.o | ||
7 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | ||
3 | snd-soc-uda1380-objs := uda1380.o | 8 | snd-soc-uda1380-objs := uda1380.o |
4 | snd-soc-wm8510-objs := wm8510.o | 9 | snd-soc-wm8510-objs := wm8510.o |
10 | snd-soc-wm8580-objs := wm8580.o | ||
5 | snd-soc-wm8731-objs := wm8731.o | 11 | snd-soc-wm8731-objs := wm8731.o |
6 | snd-soc-wm8750-objs := wm8750.o | 12 | snd-soc-wm8750-objs := wm8750.o |
7 | snd-soc-wm8753-objs := wm8753.o | 13 | snd-soc-wm8753-objs := wm8753.o |
14 | snd-soc-wm8900-objs := wm8900.o | ||
15 | snd-soc-wm8903-objs := wm8903.o | ||
16 | snd-soc-wm8971-objs := wm8971.o | ||
8 | snd-soc-wm8990-objs := wm8990.o | 17 | snd-soc-wm8990-objs := wm8990.o |
9 | snd-soc-wm9712-objs := wm9712.o | 18 | snd-soc-wm9712-objs := wm9712.o |
10 | snd-soc-wm9713-objs := wm9713.o | 19 | snd-soc-wm9713-objs := wm9713.o |
11 | snd-soc-cs4270-objs := cs4270.o | ||
12 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | ||
13 | 20 | ||
14 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 21 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
22 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | ||
15 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 23 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
24 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | ||
25 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | ||
26 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | ||
27 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | ||
16 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o | 28 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o |
17 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | 29 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o |
30 | obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o | ||
18 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 31 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
19 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 32 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
20 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 33 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
34 | obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o | ||
35 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o | ||
36 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o | ||
21 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | 37 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o |
22 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 38 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
23 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | 39 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o |
24 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | ||
25 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | ||
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c new file mode 100644 index 00000000000..4e09c1f2c06 --- /dev/null +++ b/sound/soc/codecs/ad1980.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * ad1980.c -- ALSA Soc AD1980 codec support | ||
3 | * | ||
4 | * Copyright: Analog Device Inc. | ||
5 | * Author: Roy Huang <roy.huang@analog.com> | ||
6 | * Cliff Cai <cliff.cai@analog.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 <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/version.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/ac97_codec.h> | ||
22 | #include <sound/initval.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/soc-dapm.h> | ||
25 | |||
26 | #include "ad1980.h" | ||
27 | |||
28 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
29 | unsigned int reg); | ||
30 | static int ac97_write(struct snd_soc_codec *codec, | ||
31 | unsigned int reg, unsigned int val); | ||
32 | |||
33 | /* | ||
34 | * AD1980 register cache | ||
35 | */ | ||
36 | static const u16 ad1980_reg[] = { | ||
37 | 0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */ | ||
38 | 0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */ | ||
39 | 0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */ | ||
40 | 0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */ | ||
41 | 0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */ | ||
42 | 0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */ | ||
43 | 0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */ | ||
44 | 0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */ | ||
45 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
46 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
47 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
48 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
49 | 0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */ | ||
50 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
51 | 0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */ | ||
52 | 0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */ | ||
53 | }; | ||
54 | |||
55 | static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", | ||
56 | "Stereo Mix", "Mono Mix", "Phone"}; | ||
57 | |||
58 | static const struct soc_enum ad1980_cap_src = | ||
59 | SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel); | ||
60 | |||
61 | static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = { | ||
62 | SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), | ||
63 | SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1), | ||
64 | |||
65 | SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), | ||
66 | SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1), | ||
67 | |||
68 | SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1), | ||
69 | SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1), | ||
70 | |||
71 | SOC_DOUBLE("PCM Capture Volume", AC97_REC_GAIN, 8, 0, 31, 0), | ||
72 | SOC_SINGLE("PCM Capture Switch", AC97_REC_GAIN, 15, 1, 1), | ||
73 | |||
74 | SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1), | ||
75 | SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), | ||
76 | |||
77 | SOC_SINGLE("Phone Capture Volume", AC97_PHONE, 0, 31, 1), | ||
78 | SOC_SINGLE("Phone Capture Switch", AC97_PHONE, 15, 1, 1), | ||
79 | |||
80 | SOC_SINGLE("Mic Volume", AC97_MIC, 0, 31, 1), | ||
81 | SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1), | ||
82 | |||
83 | SOC_SINGLE("Stereo Mic Switch", AC97_AD_MISC, 6, 1, 0), | ||
84 | SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0), | ||
85 | |||
86 | SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), | ||
87 | SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), | ||
88 | |||
89 | SOC_ENUM("Capture Source", ad1980_cap_src), | ||
90 | |||
91 | SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), | ||
92 | }; | ||
93 | |||
94 | /* add non dapm controls */ | ||
95 | static int ad1980_add_controls(struct snd_soc_codec *codec) | ||
96 | { | ||
97 | int err, i; | ||
98 | |||
99 | for (i = 0; i < ARRAY_SIZE(ad1980_snd_ac97_controls); i++) { | ||
100 | err = snd_ctl_add(codec->card, snd_soc_cnew( | ||
101 | &ad1980_snd_ac97_controls[i], codec, NULL)); | ||
102 | if (err < 0) | ||
103 | return err; | ||
104 | } | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
109 | unsigned int reg) | ||
110 | { | ||
111 | u16 *cache = codec->reg_cache; | ||
112 | |||
113 | switch (reg) { | ||
114 | case AC97_RESET: | ||
115 | case AC97_INT_PAGING: | ||
116 | case AC97_POWERDOWN: | ||
117 | case AC97_EXTENDED_STATUS: | ||
118 | case AC97_VENDOR_ID1: | ||
119 | case AC97_VENDOR_ID2: | ||
120 | return soc_ac97_ops.read(codec->ac97, reg); | ||
121 | default: | ||
122 | reg = reg >> 1; | ||
123 | |||
124 | if (reg >= (ARRAY_SIZE(ad1980_reg))) | ||
125 | return -EINVAL; | ||
126 | |||
127 | return cache[reg]; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
132 | unsigned int val) | ||
133 | { | ||
134 | u16 *cache = codec->reg_cache; | ||
135 | |||
136 | soc_ac97_ops.write(codec->ac97, reg, val); | ||
137 | reg = reg >> 1; | ||
138 | if (reg < (ARRAY_SIZE(ad1980_reg))) | ||
139 | cache[reg] = val; | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | struct snd_soc_dai ad1980_dai = { | ||
145 | .name = "AC97", | ||
146 | .playback = { | ||
147 | .stream_name = "Playback", | ||
148 | .channels_min = 2, | ||
149 | .channels_max = 2, | ||
150 | .rates = SNDRV_PCM_RATE_48000, | ||
151 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
152 | .capture = { | ||
153 | .stream_name = "Capture", | ||
154 | .channels_min = 2, | ||
155 | .channels_max = 2, | ||
156 | .rates = SNDRV_PCM_RATE_48000, | ||
157 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
158 | }; | ||
159 | EXPORT_SYMBOL_GPL(ad1980_dai); | ||
160 | |||
161 | static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) | ||
162 | { | ||
163 | u16 retry_cnt = 0; | ||
164 | |||
165 | retry: | ||
166 | if (try_warm && soc_ac97_ops.warm_reset) { | ||
167 | soc_ac97_ops.warm_reset(codec->ac97); | ||
168 | if (ac97_read(codec, AC97_RESET) == 0x0090) | ||
169 | return 1; | ||
170 | } | ||
171 | |||
172 | soc_ac97_ops.reset(codec->ac97); | ||
173 | /* Set bit 16slot in register 74h, then every slot will has only 16 | ||
174 | * bits. This command is sent out in 20bit mode, in which case the | ||
175 | * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ | ||
176 | ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); | ||
177 | |||
178 | if (ac97_read(codec, AC97_RESET) != 0x0090) | ||
179 | goto err; | ||
180 | return 0; | ||
181 | |||
182 | err: | ||
183 | while (retry_cnt++ < 10) | ||
184 | goto retry; | ||
185 | |||
186 | printk(KERN_ERR "AD1980 AC97 reset failed\n"); | ||
187 | return -EIO; | ||
188 | } | ||
189 | |||
190 | static int ad1980_soc_probe(struct platform_device *pdev) | ||
191 | { | ||
192 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
193 | struct snd_soc_codec *codec; | ||
194 | int ret = 0; | ||
195 | u16 vendor_id2; | ||
196 | |||
197 | printk(KERN_INFO "AD1980 SoC Audio Codec\n"); | ||
198 | |||
199 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
200 | if (socdev->codec == NULL) | ||
201 | return -ENOMEM; | ||
202 | codec = socdev->codec; | ||
203 | mutex_init(&codec->mutex); | ||
204 | |||
205 | codec->reg_cache = | ||
206 | kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL); | ||
207 | if (codec->reg_cache == NULL) { | ||
208 | ret = -ENOMEM; | ||
209 | goto cache_err; | ||
210 | } | ||
211 | memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \ | ||
212 | ARRAY_SIZE(ad1980_reg)); | ||
213 | codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg); | ||
214 | codec->reg_cache_step = 2; | ||
215 | codec->name = "AD1980"; | ||
216 | codec->owner = THIS_MODULE; | ||
217 | codec->dai = &ad1980_dai; | ||
218 | codec->num_dai = 1; | ||
219 | codec->write = ac97_write; | ||
220 | codec->read = ac97_read; | ||
221 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
222 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
223 | |||
224 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | ||
225 | if (ret < 0) { | ||
226 | printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); | ||
227 | goto codec_err; | ||
228 | } | ||
229 | |||
230 | /* register pcms */ | ||
231 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
232 | if (ret < 0) | ||
233 | goto pcm_err; | ||
234 | |||
235 | |||
236 | ret = ad1980_reset(codec, 0); | ||
237 | if (ret < 0) { | ||
238 | printk(KERN_ERR "AC97 link error\n"); | ||
239 | goto reset_err; | ||
240 | } | ||
241 | |||
242 | /* Read out vendor ID to make sure it is ad1980 */ | ||
243 | if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) | ||
244 | goto reset_err; | ||
245 | |||
246 | vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); | ||
247 | |||
248 | if (vendor_id2 != 0x5370) { | ||
249 | if (vendor_id2 != 0x5374) | ||
250 | goto reset_err; | ||
251 | else | ||
252 | printk(KERN_WARNING "ad1980: " | ||
253 | "Found AD1981 - only 2/2 IN/OUT Channels " | ||
254 | "supported\n"); | ||
255 | } | ||
256 | |||
257 | ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */ | ||
258 | ac97_write(codec, AC97_PCM, 0x0000); /* unmute PCM out volume */ | ||
259 | ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */ | ||
260 | |||
261 | ad1980_add_controls(codec); | ||
262 | ret = snd_soc_register_card(socdev); | ||
263 | if (ret < 0) { | ||
264 | printk(KERN_ERR "ad1980: failed to register card\n"); | ||
265 | goto reset_err; | ||
266 | } | ||
267 | |||
268 | return 0; | ||
269 | |||
270 | reset_err: | ||
271 | snd_soc_free_pcms(socdev); | ||
272 | |||
273 | pcm_err: | ||
274 | snd_soc_free_ac97_codec(codec); | ||
275 | |||
276 | codec_err: | ||
277 | kfree(codec->reg_cache); | ||
278 | |||
279 | cache_err: | ||
280 | kfree(socdev->codec); | ||
281 | socdev->codec = NULL; | ||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | static int ad1980_soc_remove(struct platform_device *pdev) | ||
286 | { | ||
287 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
288 | struct snd_soc_codec *codec = socdev->codec; | ||
289 | |||
290 | if (codec == NULL) | ||
291 | return 0; | ||
292 | |||
293 | snd_soc_dapm_free(socdev); | ||
294 | snd_soc_free_pcms(socdev); | ||
295 | snd_soc_free_ac97_codec(codec); | ||
296 | kfree(codec->reg_cache); | ||
297 | kfree(codec); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | struct snd_soc_codec_device soc_codec_dev_ad1980 = { | ||
302 | .probe = ad1980_soc_probe, | ||
303 | .remove = ad1980_soc_remove, | ||
304 | }; | ||
305 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980); | ||
306 | |||
307 | MODULE_DESCRIPTION("ASoC ad1980 driver"); | ||
308 | MODULE_AUTHOR("Roy Huang, Cliff Cai"); | ||
309 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h new file mode 100644 index 00000000000..db6c8500d66 --- /dev/null +++ b/sound/soc/codecs/ad1980.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * ad1980.h -- ad1980 Soc Audio driver | ||
3 | */ | ||
4 | |||
5 | #ifndef _AD1980_H | ||
6 | #define _AD1980_H | ||
7 | /* Bit definition of Power-Down Control/Status Register */ | ||
8 | #define ADC 0x0001 | ||
9 | #define DAC 0x0002 | ||
10 | #define ANL 0x0004 | ||
11 | #define REF 0x0008 | ||
12 | #define PR0 0x0100 | ||
13 | #define PR1 0x0200 | ||
14 | #define PR2 0x0400 | ||
15 | #define PR3 0x0800 | ||
16 | #define PR4 0x1000 | ||
17 | #define PR5 0x2000 | ||
18 | #define PR6 0x4000 | ||
19 | |||
20 | extern struct snd_soc_dai ad1980_dai; | ||
21 | extern struct snd_soc_codec_device soc_codec_dev_ad1980; | ||
22 | |||
23 | #endif | ||
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 7da9f467b7b..088cf992772 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -535,87 +535,85 @@ static struct snd_soc_device *ak4535_socdev; | |||
535 | 535 | ||
536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
537 | 537 | ||
538 | #define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */ | 538 | static int ak4535_i2c_probe(struct i2c_client *i2c, |
539 | 539 | const struct i2c_device_id *id) | |
540 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
541 | |||
542 | /* Magic definition of all other variables and things */ | ||
543 | I2C_CLIENT_INSMOD; | ||
544 | |||
545 | static struct i2c_driver ak4535_i2c_driver; | ||
546 | static struct i2c_client client_template; | ||
547 | |||
548 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
549 | around */ | ||
550 | static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
551 | { | 540 | { |
552 | struct snd_soc_device *socdev = ak4535_socdev; | 541 | struct snd_soc_device *socdev = ak4535_socdev; |
553 | struct ak4535_setup_data *setup = socdev->codec_data; | ||
554 | struct snd_soc_codec *codec = socdev->codec; | 542 | struct snd_soc_codec *codec = socdev->codec; |
555 | struct i2c_client *i2c; | ||
556 | int ret; | 543 | int ret; |
557 | 544 | ||
558 | if (addr != setup->i2c_address) | ||
559 | return -ENODEV; | ||
560 | |||
561 | client_template.adapter = adap; | ||
562 | client_template.addr = addr; | ||
563 | |||
564 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
565 | if (i2c == NULL) | ||
566 | return -ENOMEM; | ||
567 | |||
568 | i2c_set_clientdata(i2c, codec); | 545 | i2c_set_clientdata(i2c, codec); |
569 | codec->control_data = i2c; | 546 | codec->control_data = i2c; |
570 | 547 | ||
571 | ret = i2c_attach_client(i2c); | ||
572 | if (ret < 0) { | ||
573 | printk(KERN_ERR "failed to attach codec at addr %x\n", addr); | ||
574 | goto err; | ||
575 | } | ||
576 | |||
577 | ret = ak4535_init(socdev); | 548 | ret = ak4535_init(socdev); |
578 | if (ret < 0) { | 549 | if (ret < 0) |
579 | printk(KERN_ERR "failed to initialise AK4535\n"); | 550 | printk(KERN_ERR "failed to initialise AK4535\n"); |
580 | goto err; | ||
581 | } | ||
582 | return ret; | ||
583 | 551 | ||
584 | err: | ||
585 | kfree(i2c); | ||
586 | return ret; | 552 | return ret; |
587 | } | 553 | } |
588 | 554 | ||
589 | static int ak4535_i2c_detach(struct i2c_client *client) | 555 | static int ak4535_i2c_remove(struct i2c_client *client) |
590 | { | 556 | { |
591 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 557 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
592 | i2c_detach_client(client); | ||
593 | kfree(codec->reg_cache); | 558 | kfree(codec->reg_cache); |
594 | kfree(client); | ||
595 | return 0; | 559 | return 0; |
596 | } | 560 | } |
597 | 561 | ||
598 | static int ak4535_i2c_attach(struct i2c_adapter *adap) | 562 | static const struct i2c_device_id ak4535_i2c_id[] = { |
599 | { | 563 | { "ak4535", 0 }, |
600 | return i2c_probe(adap, &addr_data, ak4535_codec_probe); | 564 | { } |
601 | } | 565 | }; |
566 | MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id); | ||
602 | 567 | ||
603 | /* corgi i2c codec control layer */ | ||
604 | static struct i2c_driver ak4535_i2c_driver = { | 568 | static struct i2c_driver ak4535_i2c_driver = { |
605 | .driver = { | 569 | .driver = { |
606 | .name = "AK4535 I2C Codec", | 570 | .name = "AK4535 I2C Codec", |
607 | .owner = THIS_MODULE, | 571 | .owner = THIS_MODULE, |
608 | }, | 572 | }, |
609 | .id = I2C_DRIVERID_AK4535, | 573 | .probe = ak4535_i2c_probe, |
610 | .attach_adapter = ak4535_i2c_attach, | 574 | .remove = ak4535_i2c_remove, |
611 | .detach_client = ak4535_i2c_detach, | 575 | .id_table = ak4535_i2c_id, |
612 | .command = NULL, | ||
613 | }; | 576 | }; |
614 | 577 | ||
615 | static struct i2c_client client_template = { | 578 | static int ak4535_add_i2c_device(struct platform_device *pdev, |
616 | .name = "AK4535", | 579 | const struct ak4535_setup_data *setup) |
617 | .driver = &ak4535_i2c_driver, | 580 | { |
618 | }; | 581 | struct i2c_board_info info; |
582 | struct i2c_adapter *adapter; | ||
583 | struct i2c_client *client; | ||
584 | int ret; | ||
585 | |||
586 | ret = i2c_add_driver(&ak4535_i2c_driver); | ||
587 | if (ret != 0) { | ||
588 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
589 | return ret; | ||
590 | } | ||
591 | |||
592 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
593 | info.addr = setup->i2c_address; | ||
594 | strlcpy(info.type, "ak4535", I2C_NAME_SIZE); | ||
595 | |||
596 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
597 | if (!adapter) { | ||
598 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
599 | setup->i2c_bus); | ||
600 | goto err_driver; | ||
601 | } | ||
602 | |||
603 | client = i2c_new_device(adapter, &info); | ||
604 | i2c_put_adapter(adapter); | ||
605 | if (!client) { | ||
606 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
607 | (unsigned int)info.addr); | ||
608 | goto err_driver; | ||
609 | } | ||
610 | |||
611 | return 0; | ||
612 | |||
613 | err_driver: | ||
614 | i2c_del_driver(&ak4535_i2c_driver); | ||
615 | return -ENODEV; | ||
616 | } | ||
619 | #endif | 617 | #endif |
620 | 618 | ||
621 | static int ak4535_probe(struct platform_device *pdev) | 619 | static int ak4535_probe(struct platform_device *pdev) |
@@ -624,7 +622,7 @@ static int ak4535_probe(struct platform_device *pdev) | |||
624 | struct ak4535_setup_data *setup; | 622 | struct ak4535_setup_data *setup; |
625 | struct snd_soc_codec *codec; | 623 | struct snd_soc_codec *codec; |
626 | struct ak4535_priv *ak4535; | 624 | struct ak4535_priv *ak4535; |
627 | int ret = 0; | 625 | int ret; |
628 | 626 | ||
629 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); | 627 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); |
630 | 628 | ||
@@ -646,17 +644,14 @@ static int ak4535_probe(struct platform_device *pdev) | |||
646 | INIT_LIST_HEAD(&codec->dapm_paths); | 644 | INIT_LIST_HEAD(&codec->dapm_paths); |
647 | 645 | ||
648 | ak4535_socdev = socdev; | 646 | ak4535_socdev = socdev; |
647 | ret = -ENODEV; | ||
648 | |||
649 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 649 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
650 | if (setup->i2c_address) { | 650 | if (setup->i2c_address) { |
651 | normal_i2c[0] = setup->i2c_address; | ||
652 | codec->hw_write = (hw_write_t)i2c_master_send; | 651 | codec->hw_write = (hw_write_t)i2c_master_send; |
653 | codec->hw_read = (hw_read_t)i2c_master_recv; | 652 | codec->hw_read = (hw_read_t)i2c_master_recv; |
654 | ret = i2c_add_driver(&ak4535_i2c_driver); | 653 | ret = ak4535_add_i2c_device(pdev, setup); |
655 | if (ret != 0) | ||
656 | printk(KERN_ERR "can't add i2c driver"); | ||
657 | } | 654 | } |
658 | #else | ||
659 | /* Add other interfaces here */ | ||
660 | #endif | 655 | #endif |
661 | 656 | ||
662 | if (ret != 0) { | 657 | if (ret != 0) { |
@@ -678,6 +673,7 @@ static int ak4535_remove(struct platform_device *pdev) | |||
678 | snd_soc_free_pcms(socdev); | 673 | snd_soc_free_pcms(socdev); |
679 | snd_soc_dapm_free(socdev); | 674 | snd_soc_dapm_free(socdev); |
680 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 675 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
676 | i2c_unregister_device(codec->control_data); | ||
681 | i2c_del_driver(&ak4535_i2c_driver); | 677 | i2c_del_driver(&ak4535_i2c_driver); |
682 | #endif | 678 | #endif |
683 | kfree(codec->private_data); | 679 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h index e9fe30e2c05..c7a58703ea3 100644 --- a/sound/soc/codecs/ak4535.h +++ b/sound/soc/codecs/ak4535.h | |||
@@ -37,6 +37,7 @@ | |||
37 | #define AK4535_CACHEREGNUM 0x10 | 37 | #define AK4535_CACHEREGNUM 0x10 |
38 | 38 | ||
39 | struct ak4535_setup_data { | 39 | struct ak4535_setup_data { |
40 | int i2c_bus; | ||
40 | unsigned short i2c_address; | 41 | unsigned short i2c_address; |
41 | }; | 42 | }; |
42 | 43 | ||
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 9deb8c74fdf..0bbd94501d7 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -490,34 +490,7 @@ static int cs4270_mute(struct snd_soc_dai *dai, int mute) | |||
490 | 490 | ||
491 | #endif | 491 | #endif |
492 | 492 | ||
493 | static int cs4270_i2c_probe(struct i2c_adapter *adap, int addr, int kind); | 493 | static int cs4270_i2c_probe(struct i2c_client *, const struct i2c_device_id *); |
494 | |||
495 | /* | ||
496 | * Notify the driver that a new I2C bus has been found. | ||
497 | * | ||
498 | * This function is called for each I2C bus in the system. The function | ||
499 | * then asks the I2C subsystem to probe that bus at the addresses on which | ||
500 | * our device (the CS4270) could exist. If a device is found at one of | ||
501 | * those addresses, then our probe function (cs4270_i2c_probe) is called. | ||
502 | */ | ||
503 | static int cs4270_i2c_attach(struct i2c_adapter *adapter) | ||
504 | { | ||
505 | return i2c_probe(adapter, &addr_data, cs4270_i2c_probe); | ||
506 | } | ||
507 | |||
508 | static int cs4270_i2c_detach(struct i2c_client *client) | ||
509 | { | ||
510 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
511 | |||
512 | i2c_detach_client(client); | ||
513 | codec->control_data = NULL; | ||
514 | |||
515 | kfree(codec->reg_cache); | ||
516 | codec->reg_cache = NULL; | ||
517 | |||
518 | kfree(client); | ||
519 | return 0; | ||
520 | } | ||
521 | 494 | ||
522 | /* A list of non-DAPM controls that the CS4270 supports */ | 495 | /* A list of non-DAPM controls that the CS4270 supports */ |
523 | static const struct snd_kcontrol_new cs4270_snd_controls[] = { | 496 | static const struct snd_kcontrol_new cs4270_snd_controls[] = { |
@@ -525,14 +498,19 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = { | |||
525 | CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1) | 498 | CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1) |
526 | }; | 499 | }; |
527 | 500 | ||
501 | static const struct i2c_device_id cs4270_id[] = { | ||
502 | {"cs4270", 0}, | ||
503 | {} | ||
504 | }; | ||
505 | MODULE_DEVICE_TABLE(i2c, cs4270_id); | ||
506 | |||
528 | static struct i2c_driver cs4270_i2c_driver = { | 507 | static struct i2c_driver cs4270_i2c_driver = { |
529 | .driver = { | 508 | .driver = { |
530 | .name = "CS4270 I2C", | 509 | .name = "CS4270 I2C", |
531 | .owner = THIS_MODULE, | 510 | .owner = THIS_MODULE, |
532 | }, | 511 | }, |
533 | .id = I2C_DRIVERID_CS4270, | 512 | .id_table = cs4270_id, |
534 | .attach_adapter = cs4270_i2c_attach, | 513 | .probe = cs4270_i2c_probe, |
535 | .detach_client = cs4270_i2c_detach, | ||
536 | }; | 514 | }; |
537 | 515 | ||
538 | /* | 516 | /* |
@@ -561,11 +539,11 @@ static struct snd_soc_device *cs4270_socdev; | |||
561 | * Note: snd_soc_new_pcms() must be called before this function can be called, | 539 | * Note: snd_soc_new_pcms() must be called before this function can be called, |
562 | * because of snd_ctl_add(). | 540 | * because of snd_ctl_add(). |
563 | */ | 541 | */ |
564 | static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | 542 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, |
543 | const struct i2c_device_id *id) | ||
565 | { | 544 | { |
566 | struct snd_soc_device *socdev = cs4270_socdev; | 545 | struct snd_soc_device *socdev = cs4270_socdev; |
567 | struct snd_soc_codec *codec = socdev->codec; | 546 | struct snd_soc_codec *codec = socdev->codec; |
568 | struct i2c_client *i2c_client = NULL; | ||
569 | int i; | 547 | int i; |
570 | int ret = 0; | 548 | int ret = 0; |
571 | 549 | ||
@@ -578,12 +556,6 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | |||
578 | 556 | ||
579 | /* Note: codec_dai->codec is NULL here */ | 557 | /* Note: codec_dai->codec is NULL here */ |
580 | 558 | ||
581 | i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
582 | if (!i2c_client) { | ||
583 | printk(KERN_ERR "cs4270: could not allocate I2C client\n"); | ||
584 | return -ENOMEM; | ||
585 | } | ||
586 | |||
587 | codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL); | 559 | codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL); |
588 | if (!codec->reg_cache) { | 560 | if (!codec->reg_cache) { |
589 | printk(KERN_ERR "cs4270: could not allocate register cache\n"); | 561 | printk(KERN_ERR "cs4270: could not allocate register cache\n"); |
@@ -591,13 +563,6 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | |||
591 | goto error; | 563 | goto error; |
592 | } | 564 | } |
593 | 565 | ||
594 | i2c_set_clientdata(i2c_client, codec); | ||
595 | strcpy(i2c_client->name, "CS4270"); | ||
596 | |||
597 | i2c_client->driver = &cs4270_i2c_driver; | ||
598 | i2c_client->adapter = adapter; | ||
599 | i2c_client->addr = addr; | ||
600 | |||
601 | /* Verify that we have a CS4270 */ | 566 | /* Verify that we have a CS4270 */ |
602 | 567 | ||
603 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); | 568 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); |
@@ -612,18 +577,10 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | |||
612 | goto error; | 577 | goto error; |
613 | } | 578 | } |
614 | 579 | ||
615 | printk(KERN_INFO "cs4270: found device at I2C address %X\n", addr); | 580 | printk(KERN_INFO "cs4270: found device at I2C address %X\n", |
581 | i2c_client->addr); | ||
616 | printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); | 582 | printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); |
617 | 583 | ||
618 | /* Tell the I2C layer a new client has arrived */ | ||
619 | |||
620 | ret = i2c_attach_client(i2c_client); | ||
621 | if (ret) { | ||
622 | printk(KERN_ERR "cs4270: could not attach codec, " | ||
623 | "I2C address %x, error code %i\n", addr, ret); | ||
624 | goto error; | ||
625 | } | ||
626 | |||
627 | codec->control_data = i2c_client; | 584 | codec->control_data = i2c_client; |
628 | codec->read = cs4270_read_reg_cache; | 585 | codec->read = cs4270_read_reg_cache; |
629 | codec->write = cs4270_i2c_write; | 586 | codec->write = cs4270_i2c_write; |
@@ -648,20 +605,17 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | |||
648 | goto error; | 605 | goto error; |
649 | } | 606 | } |
650 | 607 | ||
608 | i2c_set_clientdata(i2c_client, codec); | ||
609 | |||
651 | return 0; | 610 | return 0; |
652 | 611 | ||
653 | error: | 612 | error: |
654 | if (codec->control_data) { | 613 | codec->control_data = NULL; |
655 | i2c_detach_client(i2c_client); | ||
656 | codec->control_data = NULL; | ||
657 | } | ||
658 | 614 | ||
659 | kfree(codec->reg_cache); | 615 | kfree(codec->reg_cache); |
660 | codec->reg_cache = NULL; | 616 | codec->reg_cache = NULL; |
661 | codec->reg_cache_size = 0; | 617 | codec->reg_cache_size = 0; |
662 | 618 | ||
663 | kfree(i2c_client); | ||
664 | |||
665 | return ret; | 619 | return ret; |
666 | } | 620 | } |
667 | 621 | ||
@@ -727,7 +681,7 @@ static int cs4270_probe(struct platform_device *pdev) | |||
727 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 681 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
728 | if (ret < 0) { | 682 | if (ret < 0) { |
729 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); | 683 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); |
730 | return ret; | 684 | goto error_free_codec; |
731 | } | 685 | } |
732 | 686 | ||
733 | #ifdef USE_I2C | 687 | #ifdef USE_I2C |
@@ -736,8 +690,7 @@ static int cs4270_probe(struct platform_device *pdev) | |||
736 | ret = i2c_add_driver(&cs4270_i2c_driver); | 690 | ret = i2c_add_driver(&cs4270_i2c_driver); |
737 | if (ret) { | 691 | if (ret) { |
738 | printk(KERN_ERR "cs4270: failed to attach driver"); | 692 | printk(KERN_ERR "cs4270: failed to attach driver"); |
739 | snd_soc_free_pcms(socdev); | 693 | goto error_free_pcms; |
740 | return ret; | ||
741 | } | 694 | } |
742 | 695 | ||
743 | /* Did we find a CS4270 on the I2C bus? */ | 696 | /* Did we find a CS4270 on the I2C bus? */ |
@@ -759,10 +712,23 @@ static int cs4270_probe(struct platform_device *pdev) | |||
759 | ret = snd_soc_register_card(socdev); | 712 | ret = snd_soc_register_card(socdev); |
760 | if (ret < 0) { | 713 | if (ret < 0) { |
761 | printk(KERN_ERR "cs4270: failed to register card\n"); | 714 | printk(KERN_ERR "cs4270: failed to register card\n"); |
762 | snd_soc_free_pcms(socdev); | 715 | goto error_del_driver; |
763 | return ret; | ||
764 | } | 716 | } |
765 | 717 | ||
718 | return 0; | ||
719 | |||
720 | error_del_driver: | ||
721 | #ifdef USE_I2C | ||
722 | i2c_del_driver(&cs4270_i2c_driver); | ||
723 | |||
724 | error_free_pcms: | ||
725 | #endif | ||
726 | snd_soc_free_pcms(socdev); | ||
727 | |||
728 | error_free_codec: | ||
729 | kfree(socdev->codec); | ||
730 | socdev->codec = NULL; | ||
731 | |||
766 | return ret; | 732 | return ret; |
767 | } | 733 | } |
768 | 734 | ||
@@ -773,8 +739,7 @@ static int cs4270_remove(struct platform_device *pdev) | |||
773 | snd_soc_free_pcms(socdev); | 739 | snd_soc_free_pcms(socdev); |
774 | 740 | ||
775 | #ifdef USE_I2C | 741 | #ifdef USE_I2C |
776 | if (socdev->codec->control_data) | 742 | i2c_del_driver(&cs4270_i2c_driver); |
777 | i2c_del_driver(&cs4270_i2c_driver); | ||
778 | #endif | 743 | #endif |
779 | 744 | ||
780 | kfree(socdev->codec); | 745 | kfree(socdev->codec); |
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c new file mode 100644 index 00000000000..940ce1c3522 --- /dev/null +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -0,0 +1,776 @@ | |||
1 | /* | ||
2 | * File: sound/soc/codecs/ssm2602.c | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Tue June 06 2008 | ||
6 | * Description: Driver for ssm2602 sound chip | ||
7 | * | ||
8 | * Modified: | ||
9 | * Copyright 2008 Analog Devices Inc. | ||
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, see the file COPYING, or write | ||
25 | * to the Free Software Foundation, Inc., | ||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/pm.h> | ||
34 | #include <linux/i2c.h> | ||
35 | #include <linux/platform_device.h> | ||
36 | #include <sound/core.h> | ||
37 | #include <sound/pcm.h> | ||
38 | #include <sound/pcm_params.h> | ||
39 | #include <sound/soc.h> | ||
40 | #include <sound/soc-dapm.h> | ||
41 | #include <sound/initval.h> | ||
42 | |||
43 | #include "ssm2602.h" | ||
44 | |||
45 | #define AUDIO_NAME "ssm2602" | ||
46 | #define SSM2602_VERSION "0.1" | ||
47 | |||
48 | struct snd_soc_codec_device soc_codec_dev_ssm2602; | ||
49 | |||
50 | /* codec private data */ | ||
51 | struct ssm2602_priv { | ||
52 | unsigned int sysclk; | ||
53 | struct snd_pcm_substream *master_substream; | ||
54 | struct snd_pcm_substream *slave_substream; | ||
55 | }; | ||
56 | |||
57 | /* | ||
58 | * ssm2602 register cache | ||
59 | * We can't read the ssm2602 register space when we are | ||
60 | * using 2 wire for device control, so we cache them instead. | ||
61 | * There is no point in caching the reset register | ||
62 | */ | ||
63 | static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { | ||
64 | 0x0017, 0x0017, 0x0079, 0x0079, | ||
65 | 0x0000, 0x0000, 0x0000, 0x000a, | ||
66 | 0x0000, 0x0000 | ||
67 | }; | ||
68 | |||
69 | /* | ||
70 | * read ssm2602 register cache | ||
71 | */ | ||
72 | static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec, | ||
73 | unsigned int reg) | ||
74 | { | ||
75 | u16 *cache = codec->reg_cache; | ||
76 | if (reg == SSM2602_RESET) | ||
77 | return 0; | ||
78 | if (reg >= SSM2602_CACHEREGNUM) | ||
79 | return -1; | ||
80 | return cache[reg]; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * write ssm2602 register cache | ||
85 | */ | ||
86 | static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec, | ||
87 | u16 reg, unsigned int value) | ||
88 | { | ||
89 | u16 *cache = codec->reg_cache; | ||
90 | if (reg >= SSM2602_CACHEREGNUM) | ||
91 | return; | ||
92 | cache[reg] = value; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * write to the ssm2602 register space | ||
97 | */ | ||
98 | static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg, | ||
99 | unsigned int value) | ||
100 | { | ||
101 | u8 data[2]; | ||
102 | |||
103 | /* data is | ||
104 | * D15..D9 ssm2602 register offset | ||
105 | * D8...D0 register data | ||
106 | */ | ||
107 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
108 | data[1] = value & 0x00ff; | ||
109 | |||
110 | ssm2602_write_reg_cache(codec, reg, value); | ||
111 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
112 | return 0; | ||
113 | else | ||
114 | return -EIO; | ||
115 | } | ||
116 | |||
117 | #define ssm2602_reset(c) ssm2602_write(c, SSM2602_RESET, 0) | ||
118 | |||
119 | /*Appending several "None"s just for OSS mixer use*/ | ||
120 | static const char *ssm2602_input_select[] = { | ||
121 | "Line", "Mic", "None", "None", "None", | ||
122 | "None", "None", "None", | ||
123 | }; | ||
124 | |||
125 | static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | ||
126 | |||
127 | static const struct soc_enum ssm2602_enum[] = { | ||
128 | SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select), | ||
129 | SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph), | ||
130 | }; | ||
131 | |||
132 | static const struct snd_kcontrol_new ssm2602_snd_controls[] = { | ||
133 | |||
134 | SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V, | ||
135 | 0, 127, 0), | ||
136 | SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V, | ||
137 | 7, 1, 0), | ||
138 | |||
139 | SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0), | ||
140 | SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1), | ||
141 | |||
142 | SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), | ||
143 | SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), | ||
144 | |||
145 | SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1), | ||
146 | |||
147 | SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1), | ||
148 | SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0), | ||
149 | |||
150 | SOC_ENUM("Capture Source", ssm2602_enum[0]), | ||
151 | |||
152 | SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), | ||
153 | }; | ||
154 | |||
155 | /* add non dapm controls */ | ||
156 | static int ssm2602_add_controls(struct snd_soc_codec *codec) | ||
157 | { | ||
158 | int err, i; | ||
159 | |||
160 | for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) { | ||
161 | err = snd_ctl_add(codec->card, | ||
162 | snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL)); | ||
163 | if (err < 0) | ||
164 | return err; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* Output Mixer */ | ||
171 | static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { | ||
172 | SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), | ||
173 | SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), | ||
174 | SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), | ||
175 | }; | ||
176 | |||
177 | /* Input mux */ | ||
178 | static const struct snd_kcontrol_new ssm2602_input_mux_controls = | ||
179 | SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); | ||
180 | |||
181 | static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = { | ||
182 | SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, | ||
183 | &ssm2602_output_mixer_controls[0], | ||
184 | ARRAY_SIZE(ssm2602_output_mixer_controls)), | ||
185 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), | ||
186 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
187 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | ||
188 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
189 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | ||
190 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), | ||
191 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), | ||
192 | SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0), | ||
193 | SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), | ||
194 | SND_SOC_DAPM_INPUT("MICIN"), | ||
195 | SND_SOC_DAPM_INPUT("RLINEIN"), | ||
196 | SND_SOC_DAPM_INPUT("LLINEIN"), | ||
197 | }; | ||
198 | |||
199 | static const struct snd_soc_dapm_route audio_conn[] = { | ||
200 | /* output mixer */ | ||
201 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | ||
202 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | ||
203 | {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, | ||
204 | |||
205 | /* outputs */ | ||
206 | {"RHPOUT", NULL, "Output Mixer"}, | ||
207 | {"ROUT", NULL, "Output Mixer"}, | ||
208 | {"LHPOUT", NULL, "Output Mixer"}, | ||
209 | {"LOUT", NULL, "Output Mixer"}, | ||
210 | |||
211 | /* input mux */ | ||
212 | {"Input Mux", "Line", "Line Input"}, | ||
213 | {"Input Mux", "Mic", "Mic Bias"}, | ||
214 | {"ADC", NULL, "Input Mux"}, | ||
215 | |||
216 | /* inputs */ | ||
217 | {"Line Input", NULL, "LLINEIN"}, | ||
218 | {"Line Input", NULL, "RLINEIN"}, | ||
219 | {"Mic Bias", NULL, "MICIN"}, | ||
220 | }; | ||
221 | |||
222 | static int ssm2602_add_widgets(struct snd_soc_codec *codec) | ||
223 | { | ||
224 | snd_soc_dapm_new_controls(codec, ssm2602_dapm_widgets, | ||
225 | ARRAY_SIZE(ssm2602_dapm_widgets)); | ||
226 | |||
227 | snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn)); | ||
228 | |||
229 | snd_soc_dapm_new_widgets(codec); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | struct _coeff_div { | ||
234 | u32 mclk; | ||
235 | u32 rate; | ||
236 | u16 fs; | ||
237 | u8 sr:4; | ||
238 | u8 bosr:1; | ||
239 | u8 usb:1; | ||
240 | }; | ||
241 | |||
242 | /* codec mclk clock divider coefficients */ | ||
243 | static const struct _coeff_div coeff_div[] = { | ||
244 | /* 48k */ | ||
245 | {12288000, 48000, 256, 0x0, 0x0, 0x0}, | ||
246 | {18432000, 48000, 384, 0x0, 0x1, 0x0}, | ||
247 | {12000000, 48000, 250, 0x0, 0x0, 0x1}, | ||
248 | |||
249 | /* 32k */ | ||
250 | {12288000, 32000, 384, 0x6, 0x0, 0x0}, | ||
251 | {18432000, 32000, 576, 0x6, 0x1, 0x0}, | ||
252 | {12000000, 32000, 375, 0x6, 0x0, 0x1}, | ||
253 | |||
254 | /* 8k */ | ||
255 | {12288000, 8000, 1536, 0x3, 0x0, 0x0}, | ||
256 | {18432000, 8000, 2304, 0x3, 0x1, 0x0}, | ||
257 | {11289600, 8000, 1408, 0xb, 0x0, 0x0}, | ||
258 | {16934400, 8000, 2112, 0xb, 0x1, 0x0}, | ||
259 | {12000000, 8000, 1500, 0x3, 0x0, 0x1}, | ||
260 | |||
261 | /* 96k */ | ||
262 | {12288000, 96000, 128, 0x7, 0x0, 0x0}, | ||
263 | {18432000, 96000, 192, 0x7, 0x1, 0x0}, | ||
264 | {12000000, 96000, 125, 0x7, 0x0, 0x1}, | ||
265 | |||
266 | /* 44.1k */ | ||
267 | {11289600, 44100, 256, 0x8, 0x0, 0x0}, | ||
268 | {16934400, 44100, 384, 0x8, 0x1, 0x0}, | ||
269 | {12000000, 44100, 272, 0x8, 0x1, 0x1}, | ||
270 | |||
271 | /* 88.2k */ | ||
272 | {11289600, 88200, 128, 0xf, 0x0, 0x0}, | ||
273 | {16934400, 88200, 192, 0xf, 0x1, 0x0}, | ||
274 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, | ||
275 | }; | ||
276 | |||
277 | static inline int get_coeff(int mclk, int rate) | ||
278 | { | ||
279 | int i; | ||
280 | |||
281 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | ||
282 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | ||
283 | return i; | ||
284 | } | ||
285 | return i; | ||
286 | } | ||
287 | |||
288 | static int ssm2602_hw_params(struct snd_pcm_substream *substream, | ||
289 | struct snd_pcm_hw_params *params) | ||
290 | { | ||
291 | u16 srate; | ||
292 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
293 | struct snd_soc_device *socdev = rtd->socdev; | ||
294 | struct snd_soc_codec *codec = socdev->codec; | ||
295 | struct ssm2602_priv *ssm2602 = codec->private_data; | ||
296 | u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; | ||
297 | int i = get_coeff(ssm2602->sysclk, params_rate(params)); | ||
298 | |||
299 | /*no match is found*/ | ||
300 | if (i == ARRAY_SIZE(coeff_div)) | ||
301 | return -EINVAL; | ||
302 | |||
303 | srate = (coeff_div[i].sr << 2) | | ||
304 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; | ||
305 | |||
306 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
307 | ssm2602_write(codec, SSM2602_SRATE, srate); | ||
308 | |||
309 | /* bit size */ | ||
310 | switch (params_format(params)) { | ||
311 | case SNDRV_PCM_FORMAT_S16_LE: | ||
312 | break; | ||
313 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
314 | iface |= 0x0004; | ||
315 | break; | ||
316 | case SNDRV_PCM_FORMAT_S24_LE: | ||
317 | iface |= 0x0008; | ||
318 | break; | ||
319 | case SNDRV_PCM_FORMAT_S32_LE: | ||
320 | iface |= 0x000c; | ||
321 | break; | ||
322 | } | ||
323 | ssm2602_write(codec, SSM2602_IFACE, iface); | ||
324 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int ssm2602_startup(struct snd_pcm_substream *substream) | ||
329 | { | ||
330 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
331 | struct snd_soc_device *socdev = rtd->socdev; | ||
332 | struct snd_soc_codec *codec = socdev->codec; | ||
333 | struct ssm2602_priv *ssm2602 = codec->private_data; | ||
334 | struct snd_pcm_runtime *master_runtime; | ||
335 | |||
336 | /* The DAI has shared clocks so if we already have a playback or | ||
337 | * capture going then constrain this substream to match it. | ||
338 | */ | ||
339 | if (ssm2602->master_substream) { | ||
340 | master_runtime = ssm2602->master_substream->runtime; | ||
341 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
342 | SNDRV_PCM_HW_PARAM_RATE, | ||
343 | master_runtime->rate, | ||
344 | master_runtime->rate); | ||
345 | |||
346 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
347 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
348 | master_runtime->sample_bits, | ||
349 | master_runtime->sample_bits); | ||
350 | |||
351 | ssm2602->slave_substream = substream; | ||
352 | } else | ||
353 | ssm2602->master_substream = substream; | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) | ||
359 | { | ||
360 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
361 | struct snd_soc_device *socdev = rtd->socdev; | ||
362 | struct snd_soc_codec *codec = socdev->codec; | ||
363 | /* set active */ | ||
364 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static void ssm2602_shutdown(struct snd_pcm_substream *substream) | ||
370 | { | ||
371 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
372 | struct snd_soc_device *socdev = rtd->socdev; | ||
373 | struct snd_soc_codec *codec = socdev->codec; | ||
374 | /* deactivate */ | ||
375 | if (!codec->active) | ||
376 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
377 | } | ||
378 | |||
379 | static int ssm2602_mute(struct snd_soc_dai *dai, int mute) | ||
380 | { | ||
381 | struct snd_soc_codec *codec = dai->codec; | ||
382 | u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE; | ||
383 | if (mute) | ||
384 | ssm2602_write(codec, SSM2602_APDIGI, | ||
385 | mute_reg | APDIGI_ENABLE_DAC_MUTE); | ||
386 | else | ||
387 | ssm2602_write(codec, SSM2602_APDIGI, mute_reg); | ||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
392 | int clk_id, unsigned int freq, int dir) | ||
393 | { | ||
394 | struct snd_soc_codec *codec = codec_dai->codec; | ||
395 | struct ssm2602_priv *ssm2602 = codec->private_data; | ||
396 | switch (freq) { | ||
397 | case 11289600: | ||
398 | case 12000000: | ||
399 | case 12288000: | ||
400 | case 16934400: | ||
401 | case 18432000: | ||
402 | ssm2602->sysclk = freq; | ||
403 | return 0; | ||
404 | } | ||
405 | return -EINVAL; | ||
406 | } | ||
407 | |||
408 | static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
409 | unsigned int fmt) | ||
410 | { | ||
411 | struct snd_soc_codec *codec = codec_dai->codec; | ||
412 | u16 iface = 0; | ||
413 | |||
414 | /* set master/slave audio interface */ | ||
415 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
416 | case SND_SOC_DAIFMT_CBM_CFM: | ||
417 | iface |= 0x0040; | ||
418 | break; | ||
419 | case SND_SOC_DAIFMT_CBS_CFS: | ||
420 | break; | ||
421 | default: | ||
422 | return -EINVAL; | ||
423 | } | ||
424 | |||
425 | /* interface format */ | ||
426 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
427 | case SND_SOC_DAIFMT_I2S: | ||
428 | iface |= 0x0002; | ||
429 | break; | ||
430 | case SND_SOC_DAIFMT_RIGHT_J: | ||
431 | break; | ||
432 | case SND_SOC_DAIFMT_LEFT_J: | ||
433 | iface |= 0x0001; | ||
434 | break; | ||
435 | case SND_SOC_DAIFMT_DSP_A: | ||
436 | iface |= 0x0003; | ||
437 | break; | ||
438 | case SND_SOC_DAIFMT_DSP_B: | ||
439 | iface |= 0x0013; | ||
440 | break; | ||
441 | default: | ||
442 | return -EINVAL; | ||
443 | } | ||
444 | |||
445 | /* clock inversion */ | ||
446 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
447 | case SND_SOC_DAIFMT_NB_NF: | ||
448 | break; | ||
449 | case SND_SOC_DAIFMT_IB_IF: | ||
450 | iface |= 0x0090; | ||
451 | break; | ||
452 | case SND_SOC_DAIFMT_IB_NF: | ||
453 | iface |= 0x0080; | ||
454 | break; | ||
455 | case SND_SOC_DAIFMT_NB_IF: | ||
456 | iface |= 0x0010; | ||
457 | break; | ||
458 | default: | ||
459 | return -EINVAL; | ||
460 | } | ||
461 | |||
462 | /* set iface */ | ||
463 | ssm2602_write(codec, SSM2602_IFACE, iface); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | ||
468 | enum snd_soc_bias_level level) | ||
469 | { | ||
470 | u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f; | ||
471 | |||
472 | switch (level) { | ||
473 | case SND_SOC_BIAS_ON: | ||
474 | /* vref/mid, osc on, dac unmute */ | ||
475 | ssm2602_write(codec, SSM2602_PWR, reg); | ||
476 | break; | ||
477 | case SND_SOC_BIAS_PREPARE: | ||
478 | break; | ||
479 | case SND_SOC_BIAS_STANDBY: | ||
480 | /* everything off except vref/vmid, */ | ||
481 | ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); | ||
482 | break; | ||
483 | case SND_SOC_BIAS_OFF: | ||
484 | /* everything off, dac mute, inactive */ | ||
485 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
486 | ssm2602_write(codec, SSM2602_PWR, 0xffff); | ||
487 | break; | ||
488 | |||
489 | } | ||
490 | codec->bias_level = level; | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | #define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
495 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
496 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
497 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ | ||
498 | SNDRV_PCM_RATE_96000) | ||
499 | |||
500 | struct snd_soc_dai ssm2602_dai = { | ||
501 | .name = "SSM2602", | ||
502 | .playback = { | ||
503 | .stream_name = "Playback", | ||
504 | .channels_min = 2, | ||
505 | .channels_max = 2, | ||
506 | .rates = SSM2602_RATES, | ||
507 | .formats = SNDRV_PCM_FMTBIT_S32_LE,}, | ||
508 | .capture = { | ||
509 | .stream_name = "Capture", | ||
510 | .channels_min = 2, | ||
511 | .channels_max = 2, | ||
512 | .rates = SSM2602_RATES, | ||
513 | .formats = SNDRV_PCM_FMTBIT_S32_LE,}, | ||
514 | .ops = { | ||
515 | .startup = ssm2602_startup, | ||
516 | .prepare = ssm2602_pcm_prepare, | ||
517 | .hw_params = ssm2602_hw_params, | ||
518 | .shutdown = ssm2602_shutdown, | ||
519 | }, | ||
520 | .dai_ops = { | ||
521 | .digital_mute = ssm2602_mute, | ||
522 | .set_sysclk = ssm2602_set_dai_sysclk, | ||
523 | .set_fmt = ssm2602_set_dai_fmt, | ||
524 | } | ||
525 | }; | ||
526 | EXPORT_SYMBOL_GPL(ssm2602_dai); | ||
527 | |||
528 | static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state) | ||
529 | { | ||
530 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
531 | struct snd_soc_codec *codec = socdev->codec; | ||
532 | |||
533 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int ssm2602_resume(struct platform_device *pdev) | ||
538 | { | ||
539 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
540 | struct snd_soc_codec *codec = socdev->codec; | ||
541 | int i; | ||
542 | u8 data[2]; | ||
543 | u16 *cache = codec->reg_cache; | ||
544 | |||
545 | /* Sync reg_cache with the hardware */ | ||
546 | for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) { | ||
547 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
548 | data[1] = cache[i] & 0x00ff; | ||
549 | codec->hw_write(codec->control_data, data, 2); | ||
550 | } | ||
551 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
552 | ssm2602_set_bias_level(codec, codec->suspend_bias_level); | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | /* | ||
557 | * initialise the ssm2602 driver | ||
558 | * register the mixer and dsp interfaces with the kernel | ||
559 | */ | ||
560 | static int ssm2602_init(struct snd_soc_device *socdev) | ||
561 | { | ||
562 | struct snd_soc_codec *codec = socdev->codec; | ||
563 | int reg, ret = 0; | ||
564 | |||
565 | codec->name = "SSM2602"; | ||
566 | codec->owner = THIS_MODULE; | ||
567 | codec->read = ssm2602_read_reg_cache; | ||
568 | codec->write = ssm2602_write; | ||
569 | codec->set_bias_level = ssm2602_set_bias_level; | ||
570 | codec->dai = &ssm2602_dai; | ||
571 | codec->num_dai = 1; | ||
572 | codec->reg_cache_size = sizeof(ssm2602_reg); | ||
573 | codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg), | ||
574 | GFP_KERNEL); | ||
575 | if (codec->reg_cache == NULL) | ||
576 | return -ENOMEM; | ||
577 | |||
578 | ssm2602_reset(codec); | ||
579 | |||
580 | /* register pcms */ | ||
581 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
582 | if (ret < 0) { | ||
583 | pr_err("ssm2602: failed to create pcms\n"); | ||
584 | goto pcm_err; | ||
585 | } | ||
586 | /*power on device*/ | ||
587 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
588 | /* set the update bits */ | ||
589 | reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL); | ||
590 | ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); | ||
591 | reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL); | ||
592 | ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); | ||
593 | reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V); | ||
594 | ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); | ||
595 | reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V); | ||
596 | ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); | ||
597 | /*select Line in as default input*/ | ||
598 | ssm2602_write(codec, SSM2602_APANA, | ||
599 | APANA_ENABLE_MIC_BOOST2 | APANA_SELECT_DAC | | ||
600 | APANA_ENABLE_MIC_BOOST); | ||
601 | ssm2602_write(codec, SSM2602_PWR, 0); | ||
602 | |||
603 | ssm2602_add_controls(codec); | ||
604 | ssm2602_add_widgets(codec); | ||
605 | ret = snd_soc_register_card(socdev); | ||
606 | if (ret < 0) { | ||
607 | pr_err("ssm2602: failed to register card\n"); | ||
608 | goto card_err; | ||
609 | } | ||
610 | |||
611 | return ret; | ||
612 | |||
613 | card_err: | ||
614 | snd_soc_free_pcms(socdev); | ||
615 | snd_soc_dapm_free(socdev); | ||
616 | pcm_err: | ||
617 | kfree(codec->reg_cache); | ||
618 | return ret; | ||
619 | } | ||
620 | |||
621 | static struct snd_soc_device *ssm2602_socdev; | ||
622 | |||
623 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
624 | /* | ||
625 | * ssm2602 2 wire address is determined by GPIO5 | ||
626 | * state during powerup. | ||
627 | * low = 0x1a | ||
628 | * high = 0x1b | ||
629 | */ | ||
630 | static int ssm2602_i2c_probe(struct i2c_client *i2c, | ||
631 | const struct i2c_device_id *id) | ||
632 | { | ||
633 | struct snd_soc_device *socdev = ssm2602_socdev; | ||
634 | struct snd_soc_codec *codec = socdev->codec; | ||
635 | int ret; | ||
636 | |||
637 | i2c_set_clientdata(i2c, codec); | ||
638 | codec->control_data = i2c; | ||
639 | |||
640 | ret = ssm2602_init(socdev); | ||
641 | if (ret < 0) | ||
642 | pr_err("failed to initialise SSM2602\n"); | ||
643 | |||
644 | return ret; | ||
645 | } | ||
646 | |||
647 | static int ssm2602_i2c_remove(struct i2c_client *client) | ||
648 | { | ||
649 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
650 | kfree(codec->reg_cache); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static const struct i2c_device_id ssm2602_i2c_id[] = { | ||
655 | { "ssm2602", 0 }, | ||
656 | { } | ||
657 | }; | ||
658 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); | ||
659 | /* corgi i2c codec control layer */ | ||
660 | static struct i2c_driver ssm2602_i2c_driver = { | ||
661 | .driver = { | ||
662 | .name = "SSM2602 I2C Codec", | ||
663 | .owner = THIS_MODULE, | ||
664 | }, | ||
665 | .probe = ssm2602_i2c_probe, | ||
666 | .remove = ssm2602_i2c_remove, | ||
667 | .id_table = ssm2602_i2c_id, | ||
668 | }; | ||
669 | |||
670 | static int ssm2602_add_i2c_device(struct platform_device *pdev, | ||
671 | const struct ssm2602_setup_data *setup) | ||
672 | { | ||
673 | struct i2c_board_info info; | ||
674 | struct i2c_adapter *adapter; | ||
675 | struct i2c_client *client; | ||
676 | int ret; | ||
677 | |||
678 | ret = i2c_add_driver(&ssm2602_i2c_driver); | ||
679 | if (ret != 0) { | ||
680 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
681 | return ret; | ||
682 | } | ||
683 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
684 | info.addr = setup->i2c_address; | ||
685 | strlcpy(info.type, "ssm2602", I2C_NAME_SIZE); | ||
686 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
687 | if (!adapter) { | ||
688 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
689 | setup->i2c_bus); | ||
690 | goto err_driver; | ||
691 | } | ||
692 | client = i2c_new_device(adapter, &info); | ||
693 | i2c_put_adapter(adapter); | ||
694 | if (!client) { | ||
695 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
696 | (unsigned int)info.addr); | ||
697 | goto err_driver; | ||
698 | } | ||
699 | return 0; | ||
700 | err_driver: | ||
701 | i2c_del_driver(&ssm2602_i2c_driver); | ||
702 | return -ENODEV; | ||
703 | } | ||
704 | #endif | ||
705 | |||
706 | static int ssm2602_probe(struct platform_device *pdev) | ||
707 | { | ||
708 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
709 | struct ssm2602_setup_data *setup; | ||
710 | struct snd_soc_codec *codec; | ||
711 | struct ssm2602_priv *ssm2602; | ||
712 | int ret = 0; | ||
713 | |||
714 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); | ||
715 | |||
716 | setup = socdev->codec_data; | ||
717 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
718 | if (codec == NULL) | ||
719 | return -ENOMEM; | ||
720 | |||
721 | ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL); | ||
722 | if (ssm2602 == NULL) { | ||
723 | kfree(codec); | ||
724 | return -ENOMEM; | ||
725 | } | ||
726 | |||
727 | codec->private_data = ssm2602; | ||
728 | socdev->codec = codec; | ||
729 | mutex_init(&codec->mutex); | ||
730 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
731 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
732 | |||
733 | ssm2602_socdev = socdev; | ||
734 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
735 | if (setup->i2c_address) { | ||
736 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
737 | ret = ssm2602_add_i2c_device(pdev, setup); | ||
738 | } | ||
739 | #else | ||
740 | /* other interfaces */ | ||
741 | #endif | ||
742 | return ret; | ||
743 | } | ||
744 | |||
745 | /* remove everything here */ | ||
746 | static int ssm2602_remove(struct platform_device *pdev) | ||
747 | { | ||
748 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
749 | struct snd_soc_codec *codec = socdev->codec; | ||
750 | |||
751 | if (codec->control_data) | ||
752 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
753 | |||
754 | snd_soc_free_pcms(socdev); | ||
755 | snd_soc_dapm_free(socdev); | ||
756 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
757 | i2c_unregister_device(codec->control_data); | ||
758 | i2c_del_driver(&ssm2602_i2c_driver); | ||
759 | #endif | ||
760 | kfree(codec->private_data); | ||
761 | kfree(codec); | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | struct snd_soc_codec_device soc_codec_dev_ssm2602 = { | ||
767 | .probe = ssm2602_probe, | ||
768 | .remove = ssm2602_remove, | ||
769 | .suspend = ssm2602_suspend, | ||
770 | .resume = ssm2602_resume, | ||
771 | }; | ||
772 | EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); | ||
773 | |||
774 | MODULE_DESCRIPTION("ASoC ssm2602 driver"); | ||
775 | MODULE_AUTHOR("Cliff Cai"); | ||
776 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h new file mode 100644 index 00000000000..f344e6d76e3 --- /dev/null +++ b/sound/soc/codecs/ssm2602.h | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * File: sound/soc/codecs/ssm2602.h | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Tue June 06 2008 | ||
6 | * | ||
7 | * Modified: | ||
8 | * Copyright 2008 Analog Devices Inc. | ||
9 | * | ||
10 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, see the file COPYING, or write | ||
24 | * to the Free Software Foundation, Inc., | ||
25 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
26 | */ | ||
27 | |||
28 | #ifndef _SSM2602_H | ||
29 | #define _SSM2602_H | ||
30 | |||
31 | /* SSM2602 Codec Register definitions */ | ||
32 | |||
33 | #define SSM2602_LINVOL 0x00 | ||
34 | #define SSM2602_RINVOL 0x01 | ||
35 | #define SSM2602_LOUT1V 0x02 | ||
36 | #define SSM2602_ROUT1V 0x03 | ||
37 | #define SSM2602_APANA 0x04 | ||
38 | #define SSM2602_APDIGI 0x05 | ||
39 | #define SSM2602_PWR 0x06 | ||
40 | #define SSM2602_IFACE 0x07 | ||
41 | #define SSM2602_SRATE 0x08 | ||
42 | #define SSM2602_ACTIVE 0x09 | ||
43 | #define SSM2602_RESET 0x0f | ||
44 | |||
45 | /*SSM2602 Codec Register Field definitions | ||
46 | *(Mask value to extract the corresponding Register field) | ||
47 | */ | ||
48 | |||
49 | /*Left ADC Volume Control (SSM2602_REG_LEFT_ADC_VOL)*/ | ||
50 | #define LINVOL_LIN_VOL 0x01F /* Left Channel PGA Volume control */ | ||
51 | #define LINVOL_LIN_ENABLE_MUTE 0x080 /* Left Channel Input Mute */ | ||
52 | #define LINVOL_LRIN_BOTH 0x100 /* Left Channel Line Input Volume update */ | ||
53 | |||
54 | /*Right ADC Volume Control (SSM2602_REG_RIGHT_ADC_VOL)*/ | ||
55 | #define RINVOL_RIN_VOL 0x01F /* Right Channel PGA Volume control */ | ||
56 | #define RINVOL_RIN_ENABLE_MUTE 0x080 /* Right Channel Input Mute */ | ||
57 | #define RINVOL_RLIN_BOTH 0x100 /* Right Channel Line Input Volume update */ | ||
58 | |||
59 | /*Left DAC Volume Control (SSM2602_REG_LEFT_DAC_VOL)*/ | ||
60 | #define LOUT1V_LHP_VOL 0x07F /* Left Channel Headphone volume control */ | ||
61 | #define LOUT1V_ENABLE_LZC 0x080 /* Left Channel Zero cross detect enable */ | ||
62 | #define LOUT1V_LRHP_BOTH 0x100 /* Left Channel Headphone volume update */ | ||
63 | |||
64 | /*Right DAC Volume Control (SSM2602_REG_RIGHT_DAC_VOL)*/ | ||
65 | #define ROUT1V_RHP_VOL 0x07F /* Right Channel Headphone volume control */ | ||
66 | #define ROUT1V_ENABLE_RZC 0x080 /* Right Channel Zero cross detect enable */ | ||
67 | #define ROUT1V_RLHP_BOTH 0x100 /* Right Channel Headphone volume update */ | ||
68 | |||
69 | /*Analogue Audio Path Control (SSM2602_REG_ANALOGUE_PATH)*/ | ||
70 | #define APANA_ENABLE_MIC_BOOST 0x001 /* Primary Microphone Amplifier gain booster control */ | ||
71 | #define APANA_ENABLE_MIC_MUTE 0x002 /* Microphone Mute Control */ | ||
72 | #define APANA_ADC_IN_SELECT 0x004 /* Microphone/Line IN select to ADC (1=MIC, 0=Line In) */ | ||
73 | #define APANA_ENABLE_BYPASS 0x008 /* Line input bypass to line output */ | ||
74 | #define APANA_SELECT_DAC 0x010 /* Select DAC (1=Select DAC, 0=Don't Select DAC) */ | ||
75 | #define APANA_ENABLE_SIDETONE 0x020 /* Enable/Disable Side Tone */ | ||
76 | #define APANA_SIDETONE_ATTN 0x0C0 /* Side Tone Attenuation */ | ||
77 | #define APANA_ENABLE_MIC_BOOST2 0x100 /* Secondary Microphone Amplifier gain booster control */ | ||
78 | |||
79 | /*Digital Audio Path Control (SSM2602_REG_DIGITAL_PATH)*/ | ||
80 | #define APDIGI_ENABLE_ADC_HPF 0x001 /* Enable/Disable ADC Highpass Filter */ | ||
81 | #define APDIGI_DE_EMPHASIS 0x006 /* De-Emphasis Control */ | ||
82 | #define APDIGI_ENABLE_DAC_MUTE 0x008 /* DAC Mute Control */ | ||
83 | #define APDIGI_STORE_OFFSET 0x010 /* Store/Clear DC offset when HPF is disabled */ | ||
84 | |||
85 | /*Power Down Control (SSM2602_REG_POWER) | ||
86 | *(1=Enable PowerDown, 0=Disable PowerDown) | ||
87 | */ | ||
88 | #define PWR_LINE_IN_PDN 0x001 /* Line Input Power Down */ | ||
89 | #define PWR_MIC_PDN 0x002 /* Microphone Input & Bias Power Down */ | ||
90 | #define PWR_ADC_PDN 0x004 /* ADC Power Down */ | ||
91 | #define PWR_DAC_PDN 0x008 /* DAC Power Down */ | ||
92 | #define PWR_OUT_PDN 0x010 /* Outputs Power Down */ | ||
93 | #define PWR_OSC_PDN 0x020 /* Oscillator Power Down */ | ||
94 | #define PWR_CLK_OUT_PDN 0x040 /* CLKOUT Power Down */ | ||
95 | #define PWR_POWER_OFF 0x080 /* POWEROFF Mode */ | ||
96 | |||
97 | /*Digital Audio Interface Format (SSM2602_REG_DIGITAL_IFACE)*/ | ||
98 | #define IFACE_IFACE_FORMAT 0x003 /* Digital Audio input format control */ | ||
99 | #define IFACE_AUDIO_DATA_LEN 0x00C /* Audio Data word length control */ | ||
100 | #define IFACE_DAC_LR_POLARITY 0x010 /* Polarity Control for clocks in RJ,LJ and I2S modes */ | ||
101 | #define IFACE_DAC_LR_SWAP 0x020 /* Swap DAC data control */ | ||
102 | #define IFACE_ENABLE_MASTER 0x040 /* Enable/Disable Master Mode */ | ||
103 | #define IFACE_BCLK_INVERT 0x080 /* Bit Clock Inversion control */ | ||
104 | |||
105 | /*Sampling Control (SSM2602_REG_SAMPLING_CTRL)*/ | ||
106 | #define SRATE_ENABLE_USB_MODE 0x001 /* Enable/Disable USB Mode */ | ||
107 | #define SRATE_BOS_RATE 0x002 /* Base Over-Sampling rate */ | ||
108 | #define SRATE_SAMPLE_RATE 0x03C /* Clock setting condition (Sampling rate control) */ | ||
109 | #define SRATE_CORECLK_DIV2 0x040 /* Core Clock divider select */ | ||
110 | #define SRATE_CLKOUT_DIV2 0x080 /* Clock Out divider select */ | ||
111 | |||
112 | /*Active Control (SSM2602_REG_ACTIVE_CTRL)*/ | ||
113 | #define ACTIVE_ACTIVATE_CODEC 0x001 /* Activate Codec Digital Audio Interface */ | ||
114 | |||
115 | /*********************************************************************/ | ||
116 | |||
117 | #define SSM2602_CACHEREGNUM 10 | ||
118 | |||
119 | #define SSM2602_SYSCLK 0 | ||
120 | #define SSM2602_DAI 0 | ||
121 | |||
122 | struct ssm2602_setup_data { | ||
123 | int i2c_bus; | ||
124 | unsigned short i2c_address; | ||
125 | }; | ||
126 | |||
127 | extern struct snd_soc_dai ssm2602_dai; | ||
128 | extern struct snd_soc_codec_device soc_codec_dev_ssm2602; | ||
129 | |||
130 | #endif | ||
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c new file mode 100644 index 00000000000..bed8a9e63dd --- /dev/null +++ b/sound/soc/codecs/tlv320aic26.c | |||
@@ -0,0 +1,520 @@ | |||
1 | /* | ||
2 | * Texas Instruments TLV320AIC26 low power audio CODEC | ||
3 | * ALSA SoC CODEC driver | ||
4 | * | ||
5 | * Copyright (C) 2008 Secret Lab Technologies Ltd. | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/moduleparam.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/pm.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/sysfs.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <sound/core.h> | ||
17 | #include <sound/pcm.h> | ||
18 | #include <sound/pcm_params.h> | ||
19 | #include <sound/soc.h> | ||
20 | #include <sound/soc-dapm.h> | ||
21 | #include <sound/soc-of-simple.h> | ||
22 | #include <sound/initval.h> | ||
23 | |||
24 | #include "tlv320aic26.h" | ||
25 | |||
26 | MODULE_DESCRIPTION("ASoC TLV320AIC26 codec driver"); | ||
27 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | /* AIC26 driver private data */ | ||
31 | struct aic26 { | ||
32 | struct spi_device *spi; | ||
33 | struct snd_soc_codec codec; | ||
34 | u16 reg_cache[AIC26_NUM_REGS]; /* shadow registers */ | ||
35 | int master; | ||
36 | int datfm; | ||
37 | int mclk; | ||
38 | |||
39 | /* Keyclick parameters */ | ||
40 | int keyclick_amplitude; | ||
41 | int keyclick_freq; | ||
42 | int keyclick_len; | ||
43 | }; | ||
44 | |||
45 | /* --------------------------------------------------------------------- | ||
46 | * Register access routines | ||
47 | */ | ||
48 | static unsigned int aic26_reg_read(struct snd_soc_codec *codec, | ||
49 | unsigned int reg) | ||
50 | { | ||
51 | struct aic26 *aic26 = codec->private_data; | ||
52 | u16 *cache = codec->reg_cache; | ||
53 | u16 cmd, value; | ||
54 | u8 buffer[2]; | ||
55 | int rc; | ||
56 | |||
57 | if (reg >= AIC26_NUM_REGS) { | ||
58 | WARN_ON_ONCE(1); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | /* Do SPI transfer; first 16bits are command; remaining is | ||
63 | * register contents */ | ||
64 | cmd = AIC26_READ_COMMAND_WORD(reg); | ||
65 | buffer[0] = (cmd >> 8) & 0xff; | ||
66 | buffer[1] = cmd & 0xff; | ||
67 | rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2); | ||
68 | if (rc) { | ||
69 | dev_err(&aic26->spi->dev, "AIC26 reg read error\n"); | ||
70 | return -EIO; | ||
71 | } | ||
72 | value = (buffer[0] << 8) | buffer[1]; | ||
73 | |||
74 | /* Update the cache before returning with the value */ | ||
75 | cache[reg] = value; | ||
76 | return value; | ||
77 | } | ||
78 | |||
79 | static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec, | ||
80 | unsigned int reg) | ||
81 | { | ||
82 | u16 *cache = codec->reg_cache; | ||
83 | |||
84 | if (reg >= AIC26_NUM_REGS) { | ||
85 | WARN_ON_ONCE(1); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | return cache[reg]; | ||
90 | } | ||
91 | |||
92 | static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, | ||
93 | unsigned int value) | ||
94 | { | ||
95 | struct aic26 *aic26 = codec->private_data; | ||
96 | u16 *cache = codec->reg_cache; | ||
97 | u16 cmd; | ||
98 | u8 buffer[4]; | ||
99 | int rc; | ||
100 | |||
101 | if (reg >= AIC26_NUM_REGS) { | ||
102 | WARN_ON_ONCE(1); | ||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | /* Do SPI transfer; first 16bits are command; remaining is data | ||
107 | * to write into register */ | ||
108 | cmd = AIC26_WRITE_COMMAND_WORD(reg); | ||
109 | buffer[0] = (cmd >> 8) & 0xff; | ||
110 | buffer[1] = cmd & 0xff; | ||
111 | buffer[2] = value >> 8; | ||
112 | buffer[3] = value; | ||
113 | rc = spi_write(aic26->spi, buffer, 4); | ||
114 | if (rc) { | ||
115 | dev_err(&aic26->spi->dev, "AIC26 reg read error\n"); | ||
116 | return -EIO; | ||
117 | } | ||
118 | |||
119 | /* update cache before returning */ | ||
120 | cache[reg] = value; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /* --------------------------------------------------------------------- | ||
125 | * Digital Audio Interface Operations | ||
126 | */ | ||
127 | static int aic26_hw_params(struct snd_pcm_substream *substream, | ||
128 | struct snd_pcm_hw_params *params) | ||
129 | { | ||
130 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
131 | struct snd_soc_device *socdev = rtd->socdev; | ||
132 | struct snd_soc_codec *codec = socdev->codec; | ||
133 | struct aic26 *aic26 = codec->private_data; | ||
134 | int fsref, divisor, wlen, pval, jval, dval, qval; | ||
135 | u16 reg; | ||
136 | |||
137 | dev_dbg(&aic26->spi->dev, "aic26_hw_params(substream=%p, params=%p)\n", | ||
138 | substream, params); | ||
139 | dev_dbg(&aic26->spi->dev, "rate=%i format=%i\n", params_rate(params), | ||
140 | params_format(params)); | ||
141 | |||
142 | switch (params_rate(params)) { | ||
143 | case 8000: fsref = 48000; divisor = AIC26_DIV_6; break; | ||
144 | case 11025: fsref = 44100; divisor = AIC26_DIV_4; break; | ||
145 | case 12000: fsref = 48000; divisor = AIC26_DIV_4; break; | ||
146 | case 16000: fsref = 48000; divisor = AIC26_DIV_3; break; | ||
147 | case 22050: fsref = 44100; divisor = AIC26_DIV_2; break; | ||
148 | case 24000: fsref = 48000; divisor = AIC26_DIV_2; break; | ||
149 | case 32000: fsref = 48000; divisor = AIC26_DIV_1_5; break; | ||
150 | case 44100: fsref = 44100; divisor = AIC26_DIV_1; break; | ||
151 | case 48000: fsref = 48000; divisor = AIC26_DIV_1; break; | ||
152 | default: | ||
153 | dev_dbg(&aic26->spi->dev, "bad rate\n"); return -EINVAL; | ||
154 | } | ||
155 | |||
156 | /* select data word length */ | ||
157 | switch (params_format(params)) { | ||
158 | case SNDRV_PCM_FORMAT_S8: wlen = AIC26_WLEN_16; break; | ||
159 | case SNDRV_PCM_FORMAT_S16_BE: wlen = AIC26_WLEN_16; break; | ||
160 | case SNDRV_PCM_FORMAT_S24_BE: wlen = AIC26_WLEN_24; break; | ||
161 | case SNDRV_PCM_FORMAT_S32_BE: wlen = AIC26_WLEN_32; break; | ||
162 | default: | ||
163 | dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL; | ||
164 | } | ||
165 | |||
166 | /* Configure PLL */ | ||
167 | pval = 1; | ||
168 | jval = (fsref == 44100) ? 7 : 8; | ||
169 | dval = (fsref == 44100) ? 5264 : 1920; | ||
170 | qval = 0; | ||
171 | reg = 0x8000 | qval << 11 | pval << 8 | jval << 2; | ||
172 | aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg); | ||
173 | reg = dval << 2; | ||
174 | aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg); | ||
175 | |||
176 | /* Audio Control 3 (master mode, fsref rate) */ | ||
177 | reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3); | ||
178 | reg &= ~0xf800; | ||
179 | if (aic26->master) | ||
180 | reg |= 0x0800; | ||
181 | if (fsref == 48000) | ||
182 | reg |= 0x2000; | ||
183 | aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg); | ||
184 | |||
185 | /* Audio Control 1 (FSref divisor) */ | ||
186 | reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1); | ||
187 | reg &= ~0x0fff; | ||
188 | reg |= wlen | aic26->datfm | (divisor << 3) | divisor; | ||
189 | aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL1, reg); | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * aic26_mute - Mute control to reduce noise when changing audio format | ||
196 | */ | ||
197 | static int aic26_mute(struct snd_soc_dai *dai, int mute) | ||
198 | { | ||
199 | struct snd_soc_codec *codec = dai->codec; | ||
200 | struct aic26 *aic26 = codec->private_data; | ||
201 | u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN); | ||
202 | |||
203 | dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n", | ||
204 | dai, mute); | ||
205 | |||
206 | if (mute) | ||
207 | reg |= 0x8080; | ||
208 | else | ||
209 | reg &= ~0x8080; | ||
210 | aic26_reg_write(codec, AIC26_REG_DAC_GAIN, reg); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int aic26_set_sysclk(struct snd_soc_dai *codec_dai, | ||
216 | int clk_id, unsigned int freq, int dir) | ||
217 | { | ||
218 | struct snd_soc_codec *codec = codec_dai->codec; | ||
219 | struct aic26 *aic26 = codec->private_data; | ||
220 | |||
221 | dev_dbg(&aic26->spi->dev, "aic26_set_sysclk(dai=%p, clk_id==%i," | ||
222 | " freq=%i, dir=%i)\n", | ||
223 | codec_dai, clk_id, freq, dir); | ||
224 | |||
225 | /* MCLK needs to fall between 2MHz and 50 MHz */ | ||
226 | if ((freq < 2000000) || (freq > 50000000)) | ||
227 | return -EINVAL; | ||
228 | |||
229 | aic26->mclk = freq; | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
234 | { | ||
235 | struct snd_soc_codec *codec = codec_dai->codec; | ||
236 | struct aic26 *aic26 = codec->private_data; | ||
237 | |||
238 | dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n", | ||
239 | codec_dai, fmt); | ||
240 | |||
241 | /* set master/slave audio interface */ | ||
242 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
243 | case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break; | ||
244 | case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break; | ||
245 | default: | ||
246 | dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL; | ||
247 | } | ||
248 | |||
249 | /* interface format */ | ||
250 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
251 | case SND_SOC_DAIFMT_I2S: aic26->datfm = AIC26_DATFM_I2S; break; | ||
252 | case SND_SOC_DAIFMT_DSP_A: aic26->datfm = AIC26_DATFM_DSP; break; | ||
253 | case SND_SOC_DAIFMT_RIGHT_J: aic26->datfm = AIC26_DATFM_RIGHTJ; break; | ||
254 | case SND_SOC_DAIFMT_LEFT_J: aic26->datfm = AIC26_DATFM_LEFTJ; break; | ||
255 | default: | ||
256 | dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL; | ||
257 | } | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /* --------------------------------------------------------------------- | ||
263 | * Digital Audio Interface Definition | ||
264 | */ | ||
265 | #define AIC26_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
266 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
267 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
268 | SNDRV_PCM_RATE_48000) | ||
269 | #define AIC26_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\ | ||
270 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE) | ||
271 | |||
272 | struct snd_soc_dai aic26_dai = { | ||
273 | .name = "tlv320aic26", | ||
274 | .playback = { | ||
275 | .stream_name = "Playback", | ||
276 | .channels_min = 2, | ||
277 | .channels_max = 2, | ||
278 | .rates = AIC26_RATES, | ||
279 | .formats = AIC26_FORMATS, | ||
280 | }, | ||
281 | .capture = { | ||
282 | .stream_name = "Capture", | ||
283 | .channels_min = 2, | ||
284 | .channels_max = 2, | ||
285 | .rates = AIC26_RATES, | ||
286 | .formats = AIC26_FORMATS, | ||
287 | }, | ||
288 | .ops = { | ||
289 | .hw_params = aic26_hw_params, | ||
290 | }, | ||
291 | .dai_ops = { | ||
292 | .digital_mute = aic26_mute, | ||
293 | .set_sysclk = aic26_set_sysclk, | ||
294 | .set_fmt = aic26_set_fmt, | ||
295 | }, | ||
296 | }; | ||
297 | EXPORT_SYMBOL_GPL(aic26_dai); | ||
298 | |||
299 | /* --------------------------------------------------------------------- | ||
300 | * ALSA controls | ||
301 | */ | ||
302 | static const char *aic26_capture_src_text[] = {"Mic", "Aux"}; | ||
303 | static const struct soc_enum aic26_capture_src_enum = | ||
304 | SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12, 2, aic26_capture_src_text); | ||
305 | |||
306 | static const struct snd_kcontrol_new aic26_snd_controls[] = { | ||
307 | /* Output */ | ||
308 | SOC_DOUBLE("PCM Playback Volume", AIC26_REG_DAC_GAIN, 8, 0, 0x7f, 1), | ||
309 | SOC_DOUBLE("PCM Playback Switch", AIC26_REG_DAC_GAIN, 15, 7, 1, 1), | ||
310 | SOC_SINGLE("PCM Capture Volume", AIC26_REG_ADC_GAIN, 8, 0x7f, 0), | ||
311 | SOC_SINGLE("PCM Capture Mute", AIC26_REG_ADC_GAIN, 15, 1, 1), | ||
312 | SOC_SINGLE("Keyclick activate", AIC26_REG_AUDIO_CTRL2, 15, 0x1, 0), | ||
313 | SOC_SINGLE("Keyclick amplitude", AIC26_REG_AUDIO_CTRL2, 12, 0x7, 0), | ||
314 | SOC_SINGLE("Keyclick frequency", AIC26_REG_AUDIO_CTRL2, 8, 0x7, 0), | ||
315 | SOC_SINGLE("Keyclick period", AIC26_REG_AUDIO_CTRL2, 4, 0xf, 0), | ||
316 | SOC_ENUM("Capture Source", aic26_capture_src_enum), | ||
317 | }; | ||
318 | |||
319 | /* --------------------------------------------------------------------- | ||
320 | * SoC CODEC portion of driver: probe and release routines | ||
321 | */ | ||
322 | static int aic26_probe(struct platform_device *pdev) | ||
323 | { | ||
324 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
325 | struct snd_soc_codec *codec; | ||
326 | struct snd_kcontrol *kcontrol; | ||
327 | struct aic26 *aic26; | ||
328 | int i, ret, err; | ||
329 | |||
330 | dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n"); | ||
331 | dev_dbg(&pdev->dev, "socdev=%p\n", socdev); | ||
332 | dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data); | ||
333 | |||
334 | /* Fetch the relevant aic26 private data here (it's already been | ||
335 | * stored in the .codec pointer) */ | ||
336 | aic26 = socdev->codec_data; | ||
337 | if (aic26 == NULL) { | ||
338 | dev_err(&pdev->dev, "aic26: missing codec pointer\n"); | ||
339 | return -ENODEV; | ||
340 | } | ||
341 | codec = &aic26->codec; | ||
342 | socdev->codec = codec; | ||
343 | |||
344 | dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n", | ||
345 | &pdev->dev, socdev->dev); | ||
346 | /* register pcms */ | ||
347 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
348 | if (ret < 0) { | ||
349 | dev_err(&pdev->dev, "aic26: failed to create pcms\n"); | ||
350 | return -ENODEV; | ||
351 | } | ||
352 | |||
353 | /* register controls */ | ||
354 | dev_dbg(&pdev->dev, "Registering controls\n"); | ||
355 | for (i = 0; i < ARRAY_SIZE(aic26_snd_controls); i++) { | ||
356 | kcontrol = snd_soc_cnew(&aic26_snd_controls[i], codec, NULL); | ||
357 | err = snd_ctl_add(codec->card, kcontrol); | ||
358 | WARN_ON(err < 0); | ||
359 | } | ||
360 | |||
361 | /* CODEC is setup, we can register the card now */ | ||
362 | dev_dbg(&pdev->dev, "Registering card\n"); | ||
363 | ret = snd_soc_register_card(socdev); | ||
364 | if (ret < 0) { | ||
365 | dev_err(&pdev->dev, "aic26: failed to register card\n"); | ||
366 | goto card_err; | ||
367 | } | ||
368 | return 0; | ||
369 | |||
370 | card_err: | ||
371 | snd_soc_free_pcms(socdev); | ||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | static int aic26_remove(struct platform_device *pdev) | ||
376 | { | ||
377 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
378 | snd_soc_free_pcms(socdev); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | struct snd_soc_codec_device aic26_soc_codec_dev = { | ||
383 | .probe = aic26_probe, | ||
384 | .remove = aic26_remove, | ||
385 | }; | ||
386 | EXPORT_SYMBOL_GPL(aic26_soc_codec_dev); | ||
387 | |||
388 | /* --------------------------------------------------------------------- | ||
389 | * SPI device portion of driver: sysfs files for debugging | ||
390 | */ | ||
391 | |||
392 | static ssize_t aic26_keyclick_show(struct device *dev, | ||
393 | struct device_attribute *attr, char *buf) | ||
394 | { | ||
395 | struct aic26 *aic26 = dev_get_drvdata(dev); | ||
396 | int val, amp, freq, len; | ||
397 | |||
398 | val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2); | ||
399 | amp = (val >> 12) & 0x7; | ||
400 | freq = (125 << ((val >> 8) & 0x7)) >> 1; | ||
401 | len = 2 * (1 + ((val >> 4) & 0xf)); | ||
402 | |||
403 | return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len); | ||
404 | } | ||
405 | |||
406 | /* Any write to the keyclick attribute will trigger the keyclick event */ | ||
407 | static ssize_t aic26_keyclick_set(struct device *dev, | ||
408 | struct device_attribute *attr, | ||
409 | const char *buf, size_t count) | ||
410 | { | ||
411 | struct aic26 *aic26 = dev_get_drvdata(dev); | ||
412 | int val; | ||
413 | |||
414 | val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2); | ||
415 | val |= 0x8000; | ||
416 | aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL2, val); | ||
417 | |||
418 | return count; | ||
419 | } | ||
420 | |||
421 | static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); | ||
422 | |||
423 | /* --------------------------------------------------------------------- | ||
424 | * SPI device portion of driver: probe and release routines and SPI | ||
425 | * driver registration. | ||
426 | */ | ||
427 | static int aic26_spi_probe(struct spi_device *spi) | ||
428 | { | ||
429 | struct aic26 *aic26; | ||
430 | int rc, i, reg; | ||
431 | |||
432 | dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n"); | ||
433 | |||
434 | /* Allocate driver data */ | ||
435 | aic26 = kzalloc(sizeof *aic26, GFP_KERNEL); | ||
436 | if (!aic26) | ||
437 | return -ENOMEM; | ||
438 | |||
439 | /* Initialize the driver data */ | ||
440 | aic26->spi = spi; | ||
441 | dev_set_drvdata(&spi->dev, aic26); | ||
442 | |||
443 | /* Setup what we can in the codec structure so that the register | ||
444 | * access functions will work as expected. More will be filled | ||
445 | * out when it is probed by the SoC CODEC part of this driver */ | ||
446 | aic26->codec.private_data = aic26; | ||
447 | aic26->codec.name = "aic26"; | ||
448 | aic26->codec.owner = THIS_MODULE; | ||
449 | aic26->codec.dai = &aic26_dai; | ||
450 | aic26->codec.num_dai = 1; | ||
451 | aic26->codec.read = aic26_reg_read; | ||
452 | aic26->codec.write = aic26_reg_write; | ||
453 | aic26->master = 1; | ||
454 | mutex_init(&aic26->codec.mutex); | ||
455 | INIT_LIST_HEAD(&aic26->codec.dapm_widgets); | ||
456 | INIT_LIST_HEAD(&aic26->codec.dapm_paths); | ||
457 | aic26->codec.reg_cache_size = AIC26_NUM_REGS; | ||
458 | aic26->codec.reg_cache = aic26->reg_cache; | ||
459 | |||
460 | /* Reset the codec to power on defaults */ | ||
461 | aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00); | ||
462 | |||
463 | /* Power up CODEC */ | ||
464 | aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0); | ||
465 | |||
466 | /* Audio Control 3 (master mode, fsref rate) */ | ||
467 | reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3); | ||
468 | reg &= ~0xf800; | ||
469 | reg |= 0x0800; /* set master mode */ | ||
470 | aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg); | ||
471 | |||
472 | /* Fill register cache */ | ||
473 | for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++) | ||
474 | aic26_reg_read(&aic26->codec, i); | ||
475 | |||
476 | /* Register the sysfs files for debugging */ | ||
477 | /* Create SysFS files */ | ||
478 | rc = device_create_file(&spi->dev, &dev_attr_keyclick); | ||
479 | if (rc) | ||
480 | dev_info(&spi->dev, "error creating sysfs files\n"); | ||
481 | |||
482 | #if defined(CONFIG_SND_SOC_OF_SIMPLE) | ||
483 | /* Tell the of_soc helper about this codec */ | ||
484 | of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai, | ||
485 | spi->dev.archdata.of_node); | ||
486 | #endif | ||
487 | |||
488 | dev_dbg(&spi->dev, "SPI device initialized\n"); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int aic26_spi_remove(struct spi_device *spi) | ||
493 | { | ||
494 | struct aic26 *aic26 = dev_get_drvdata(&spi->dev); | ||
495 | |||
496 | kfree(aic26); | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static struct spi_driver aic26_spi = { | ||
502 | .driver = { | ||
503 | .name = "tlv320aic26", | ||
504 | .owner = THIS_MODULE, | ||
505 | }, | ||
506 | .probe = aic26_spi_probe, | ||
507 | .remove = aic26_spi_remove, | ||
508 | }; | ||
509 | |||
510 | static int __init aic26_init(void) | ||
511 | { | ||
512 | return spi_register_driver(&aic26_spi); | ||
513 | } | ||
514 | module_init(aic26_init); | ||
515 | |||
516 | static void __exit aic26_exit(void) | ||
517 | { | ||
518 | spi_unregister_driver(&aic26_spi); | ||
519 | } | ||
520 | module_exit(aic26_exit); | ||
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h new file mode 100644 index 00000000000..786ba16c945 --- /dev/null +++ b/sound/soc/codecs/tlv320aic26.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Texas Instruments TLV320AIC26 low power audio CODEC | ||
3 | * register definitions | ||
4 | * | ||
5 | * Copyright (C) 2008 Secret Lab Technologies Ltd. | ||
6 | */ | ||
7 | |||
8 | #ifndef _TLV320AIC16_H_ | ||
9 | #define _TLV320AIC16_H_ | ||
10 | |||
11 | /* AIC26 Registers */ | ||
12 | #define AIC26_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5)) | ||
13 | #define AIC26_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5)) | ||
14 | #define AIC26_PAGE_ADDR(page, offset) ((page << 6) | offset) | ||
15 | #define AIC26_NUM_REGS AIC26_PAGE_ADDR(3, 0) | ||
16 | |||
17 | /* Page 0: Auxillary data registers */ | ||
18 | #define AIC26_REG_BAT1 AIC26_PAGE_ADDR(0, 0x05) | ||
19 | #define AIC26_REG_BAT2 AIC26_PAGE_ADDR(0, 0x06) | ||
20 | #define AIC26_REG_AUX AIC26_PAGE_ADDR(0, 0x07) | ||
21 | #define AIC26_REG_TEMP1 AIC26_PAGE_ADDR(0, 0x09) | ||
22 | #define AIC26_REG_TEMP2 AIC26_PAGE_ADDR(0, 0x0A) | ||
23 | |||
24 | /* Page 1: Auxillary control registers */ | ||
25 | #define AIC26_REG_AUX_ADC AIC26_PAGE_ADDR(1, 0x00) | ||
26 | #define AIC26_REG_STATUS AIC26_PAGE_ADDR(1, 0x01) | ||
27 | #define AIC26_REG_REFERENCE AIC26_PAGE_ADDR(1, 0x03) | ||
28 | #define AIC26_REG_RESET AIC26_PAGE_ADDR(1, 0x04) | ||
29 | |||
30 | /* Page 2: Audio control registers */ | ||
31 | #define AIC26_REG_AUDIO_CTRL1 AIC26_PAGE_ADDR(2, 0x00) | ||
32 | #define AIC26_REG_ADC_GAIN AIC26_PAGE_ADDR(2, 0x01) | ||
33 | #define AIC26_REG_DAC_GAIN AIC26_PAGE_ADDR(2, 0x02) | ||
34 | #define AIC26_REG_SIDETONE AIC26_PAGE_ADDR(2, 0x03) | ||
35 | #define AIC26_REG_AUDIO_CTRL2 AIC26_PAGE_ADDR(2, 0x04) | ||
36 | #define AIC26_REG_POWER_CTRL AIC26_PAGE_ADDR(2, 0x05) | ||
37 | #define AIC26_REG_AUDIO_CTRL3 AIC26_PAGE_ADDR(2, 0x06) | ||
38 | |||
39 | #define AIC26_REG_FILTER_COEFF_L_N0 AIC26_PAGE_ADDR(2, 0x07) | ||
40 | #define AIC26_REG_FILTER_COEFF_L_N1 AIC26_PAGE_ADDR(2, 0x08) | ||
41 | #define AIC26_REG_FILTER_COEFF_L_N2 AIC26_PAGE_ADDR(2, 0x09) | ||
42 | #define AIC26_REG_FILTER_COEFF_L_N3 AIC26_PAGE_ADDR(2, 0x0A) | ||
43 | #define AIC26_REG_FILTER_COEFF_L_N4 AIC26_PAGE_ADDR(2, 0x0B) | ||
44 | #define AIC26_REG_FILTER_COEFF_L_N5 AIC26_PAGE_ADDR(2, 0x0C) | ||
45 | #define AIC26_REG_FILTER_COEFF_L_D1 AIC26_PAGE_ADDR(2, 0x0D) | ||
46 | #define AIC26_REG_FILTER_COEFF_L_D2 AIC26_PAGE_ADDR(2, 0x0E) | ||
47 | #define AIC26_REG_FILTER_COEFF_L_D4 AIC26_PAGE_ADDR(2, 0x0F) | ||
48 | #define AIC26_REG_FILTER_COEFF_L_D5 AIC26_PAGE_ADDR(2, 0x10) | ||
49 | #define AIC26_REG_FILTER_COEFF_R_N0 AIC26_PAGE_ADDR(2, 0x11) | ||
50 | #define AIC26_REG_FILTER_COEFF_R_N1 AIC26_PAGE_ADDR(2, 0x12) | ||
51 | #define AIC26_REG_FILTER_COEFF_R_N2 AIC26_PAGE_ADDR(2, 0x13) | ||
52 | #define AIC26_REG_FILTER_COEFF_R_N3 AIC26_PAGE_ADDR(2, 0x14) | ||
53 | #define AIC26_REG_FILTER_COEFF_R_N4 AIC26_PAGE_ADDR(2, 0x15) | ||
54 | #define AIC26_REG_FILTER_COEFF_R_N5 AIC26_PAGE_ADDR(2, 0x16) | ||
55 | #define AIC26_REG_FILTER_COEFF_R_D1 AIC26_PAGE_ADDR(2, 0x17) | ||
56 | #define AIC26_REG_FILTER_COEFF_R_D2 AIC26_PAGE_ADDR(2, 0x18) | ||
57 | #define AIC26_REG_FILTER_COEFF_R_D4 AIC26_PAGE_ADDR(2, 0x19) | ||
58 | #define AIC26_REG_FILTER_COEFF_R_D5 AIC26_PAGE_ADDR(2, 0x1A) | ||
59 | |||
60 | #define AIC26_REG_PLL_PROG1 AIC26_PAGE_ADDR(2, 0x1B) | ||
61 | #define AIC26_REG_PLL_PROG2 AIC26_PAGE_ADDR(2, 0x1C) | ||
62 | #define AIC26_REG_AUDIO_CTRL4 AIC26_PAGE_ADDR(2, 0x1D) | ||
63 | #define AIC26_REG_AUDIO_CTRL5 AIC26_PAGE_ADDR(2, 0x1E) | ||
64 | |||
65 | /* fsref dividers; used in register 'Audio Control 1' */ | ||
66 | enum aic26_divisors { | ||
67 | AIC26_DIV_1 = 0, | ||
68 | AIC26_DIV_1_5 = 1, | ||
69 | AIC26_DIV_2 = 2, | ||
70 | AIC26_DIV_3 = 3, | ||
71 | AIC26_DIV_4 = 4, | ||
72 | AIC26_DIV_5 = 5, | ||
73 | AIC26_DIV_5_5 = 6, | ||
74 | AIC26_DIV_6 = 7, | ||
75 | }; | ||
76 | |||
77 | /* Digital data format */ | ||
78 | enum aic26_datfm { | ||
79 | AIC26_DATFM_I2S = 0 << 8, | ||
80 | AIC26_DATFM_DSP = 1 << 8, | ||
81 | AIC26_DATFM_RIGHTJ = 2 << 8, /* right justified */ | ||
82 | AIC26_DATFM_LEFTJ = 3 << 8, /* left justified */ | ||
83 | }; | ||
84 | |||
85 | /* Sample word length in bits; used in register 'Audio Control 1' */ | ||
86 | enum aic26_wlen { | ||
87 | AIC26_WLEN_16 = 0 << 10, | ||
88 | AIC26_WLEN_20 = 1 << 10, | ||
89 | AIC26_WLEN_24 = 2 << 10, | ||
90 | AIC26_WLEN_32 = 3 << 10, | ||
91 | }; | ||
92 | |||
93 | extern struct snd_soc_dai aic26_dai; | ||
94 | extern struct snd_soc_codec_device aic26_soc_codec_dev; | ||
95 | |||
96 | #endif /* _TLV320AIC16_H_ */ | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5f9abb19943..566a427c928 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ALSA SoC TLV320AIC3X codec driver | 2 | * ALSA SoC TLV320AIC3X codec driver |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * Based on sound/soc/codecs/wm8753.c by Liam Girdwood | 7 | * Based on sound/soc/codecs/wm8753.c by Liam Girdwood |
@@ -1172,71 +1172,39 @@ static struct snd_soc_device *aic3x_socdev; | |||
1172 | * AIC3X 2 wire address can be up to 4 devices with device addresses | 1172 | * AIC3X 2 wire address can be up to 4 devices with device addresses |
1173 | * 0x18, 0x19, 0x1A, 0x1B | 1173 | * 0x18, 0x19, 0x1A, 0x1B |
1174 | */ | 1174 | */ |
1175 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1176 | |||
1177 | /* Magic definition of all other variables and things */ | ||
1178 | I2C_CLIENT_INSMOD; | ||
1179 | |||
1180 | static struct i2c_driver aic3x_i2c_driver; | ||
1181 | static struct i2c_client client_template; | ||
1182 | 1175 | ||
1183 | /* | 1176 | /* |
1184 | * If the i2c layer weren't so broken, we could pass this kind of data | 1177 | * If the i2c layer weren't so broken, we could pass this kind of data |
1185 | * around | 1178 | * around |
1186 | */ | 1179 | */ |
1187 | static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 1180 | static int aic3x_i2c_probe(struct i2c_client *i2c, |
1181 | const struct i2c_device_id *id) | ||
1188 | { | 1182 | { |
1189 | struct snd_soc_device *socdev = aic3x_socdev; | 1183 | struct snd_soc_device *socdev = aic3x_socdev; |
1190 | struct aic3x_setup_data *setup = socdev->codec_data; | ||
1191 | struct snd_soc_codec *codec = socdev->codec; | 1184 | struct snd_soc_codec *codec = socdev->codec; |
1192 | struct i2c_client *i2c; | ||
1193 | int ret; | 1185 | int ret; |
1194 | 1186 | ||
1195 | if (addr != setup->i2c_address) | ||
1196 | return -ENODEV; | ||
1197 | |||
1198 | client_template.adapter = adap; | ||
1199 | client_template.addr = addr; | ||
1200 | |||
1201 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1202 | if (i2c == NULL) | ||
1203 | return -ENOMEM; | ||
1204 | |||
1205 | i2c_set_clientdata(i2c, codec); | 1187 | i2c_set_clientdata(i2c, codec); |
1206 | codec->control_data = i2c; | 1188 | codec->control_data = i2c; |
1207 | 1189 | ||
1208 | ret = i2c_attach_client(i2c); | ||
1209 | if (ret < 0) { | ||
1210 | printk(KERN_ERR "aic3x: failed to attach codec at addr %x\n", | ||
1211 | addr); | ||
1212 | goto err; | ||
1213 | } | ||
1214 | |||
1215 | ret = aic3x_init(socdev); | 1190 | ret = aic3x_init(socdev); |
1216 | if (ret < 0) { | 1191 | if (ret < 0) |
1217 | printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); | 1192 | printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); |
1218 | goto err; | ||
1219 | } | ||
1220 | return ret; | ||
1221 | |||
1222 | err: | ||
1223 | kfree(i2c); | ||
1224 | return ret; | 1193 | return ret; |
1225 | } | 1194 | } |
1226 | 1195 | ||
1227 | static int aic3x_i2c_detach(struct i2c_client *client) | 1196 | static int aic3x_i2c_remove(struct i2c_client *client) |
1228 | { | 1197 | { |
1229 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1198 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1230 | i2c_detach_client(client); | ||
1231 | kfree(codec->reg_cache); | 1199 | kfree(codec->reg_cache); |
1232 | kfree(client); | ||
1233 | return 0; | 1200 | return 0; |
1234 | } | 1201 | } |
1235 | 1202 | ||
1236 | static int aic3x_i2c_attach(struct i2c_adapter *adap) | 1203 | static const struct i2c_device_id aic3x_i2c_id[] = { |
1237 | { | 1204 | { "tlv320aic3x", 0 }, |
1238 | return i2c_probe(adap, &addr_data, aic3x_codec_probe); | 1205 | { } |
1239 | } | 1206 | }; |
1207 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); | ||
1240 | 1208 | ||
1241 | /* machine i2c codec control layer */ | 1209 | /* machine i2c codec control layer */ |
1242 | static struct i2c_driver aic3x_i2c_driver = { | 1210 | static struct i2c_driver aic3x_i2c_driver = { |
@@ -1244,13 +1212,9 @@ static struct i2c_driver aic3x_i2c_driver = { | |||
1244 | .name = "aic3x I2C Codec", | 1212 | .name = "aic3x I2C Codec", |
1245 | .owner = THIS_MODULE, | 1213 | .owner = THIS_MODULE, |
1246 | }, | 1214 | }, |
1247 | .attach_adapter = aic3x_i2c_attach, | 1215 | .probe = aic3x_i2c_probe, |
1248 | .detach_client = aic3x_i2c_detach, | 1216 | .remove = aic3x_i2c_remove, |
1249 | }; | 1217 | .id_table = aic3x_i2c_id, |
1250 | |||
1251 | static struct i2c_client client_template = { | ||
1252 | .name = "AIC3X", | ||
1253 | .driver = &aic3x_i2c_driver, | ||
1254 | }; | 1218 | }; |
1255 | 1219 | ||
1256 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) | 1220 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) |
@@ -1258,6 +1222,46 @@ static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) | |||
1258 | value[0] = i2c_smbus_read_byte_data(client, value[0]); | 1222 | value[0] = i2c_smbus_read_byte_data(client, value[0]); |
1259 | return (len == 1); | 1223 | return (len == 1); |
1260 | } | 1224 | } |
1225 | |||
1226 | static int aic3x_add_i2c_device(struct platform_device *pdev, | ||
1227 | const struct aic3x_setup_data *setup) | ||
1228 | { | ||
1229 | struct i2c_board_info info; | ||
1230 | struct i2c_adapter *adapter; | ||
1231 | struct i2c_client *client; | ||
1232 | int ret; | ||
1233 | |||
1234 | ret = i2c_add_driver(&aic3x_i2c_driver); | ||
1235 | if (ret != 0) { | ||
1236 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1237 | return ret; | ||
1238 | } | ||
1239 | |||
1240 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1241 | info.addr = setup->i2c_address; | ||
1242 | strlcpy(info.type, "tlv320aic3x", I2C_NAME_SIZE); | ||
1243 | |||
1244 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1245 | if (!adapter) { | ||
1246 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1247 | setup->i2c_bus); | ||
1248 | goto err_driver; | ||
1249 | } | ||
1250 | |||
1251 | client = i2c_new_device(adapter, &info); | ||
1252 | i2c_put_adapter(adapter); | ||
1253 | if (!client) { | ||
1254 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1255 | (unsigned int)info.addr); | ||
1256 | goto err_driver; | ||
1257 | } | ||
1258 | |||
1259 | return 0; | ||
1260 | |||
1261 | err_driver: | ||
1262 | i2c_del_driver(&aic3x_i2c_driver); | ||
1263 | return -ENODEV; | ||
1264 | } | ||
1261 | #endif | 1265 | #endif |
1262 | 1266 | ||
1263 | static int aic3x_probe(struct platform_device *pdev) | 1267 | static int aic3x_probe(struct platform_device *pdev) |
@@ -1290,12 +1294,9 @@ static int aic3x_probe(struct platform_device *pdev) | |||
1290 | aic3x_socdev = socdev; | 1294 | aic3x_socdev = socdev; |
1291 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1295 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1292 | if (setup->i2c_address) { | 1296 | if (setup->i2c_address) { |
1293 | normal_i2c[0] = setup->i2c_address; | ||
1294 | codec->hw_write = (hw_write_t) i2c_master_send; | 1297 | codec->hw_write = (hw_write_t) i2c_master_send; |
1295 | codec->hw_read = (hw_read_t) aic3x_i2c_read; | 1298 | codec->hw_read = (hw_read_t) aic3x_i2c_read; |
1296 | ret = i2c_add_driver(&aic3x_i2c_driver); | 1299 | ret = aic3x_add_i2c_device(pdev, setup); |
1297 | if (ret != 0) | ||
1298 | printk(KERN_ERR "can't add i2c driver"); | ||
1299 | } | 1300 | } |
1300 | #else | 1301 | #else |
1301 | /* Add other interfaces here */ | 1302 | /* Add other interfaces here */ |
@@ -1320,6 +1321,7 @@ static int aic3x_remove(struct platform_device *pdev) | |||
1320 | snd_soc_free_pcms(socdev); | 1321 | snd_soc_free_pcms(socdev); |
1321 | snd_soc_dapm_free(socdev); | 1322 | snd_soc_dapm_free(socdev); |
1322 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1323 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1324 | i2c_unregister_device(codec->control_data); | ||
1323 | i2c_del_driver(&aic3x_i2c_driver); | 1325 | i2c_del_driver(&aic3x_i2c_driver); |
1324 | #endif | 1326 | #endif |
1325 | kfree(codec->private_data); | 1327 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index d76c079b86e..00a195aa02e 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ALSA SoC TLV320AIC3X codec driver | 2 | * ALSA SoC TLV320AIC3X codec driver |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -224,6 +224,7 @@ int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); | |||
224 | int aic3x_headset_detected(struct snd_soc_codec *codec); | 224 | int aic3x_headset_detected(struct snd_soc_codec *codec); |
225 | 225 | ||
226 | struct aic3x_setup_data { | 226 | struct aic3x_setup_data { |
227 | int i2c_bus; | ||
227 | unsigned short i2c_address; | 228 | unsigned short i2c_address; |
228 | unsigned int gpio_func[2]; | 229 | unsigned int gpio_func[2]; |
229 | }; | 230 | }; |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 807318fbdc8..d206d7f892b 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -701,87 +701,86 @@ static struct snd_soc_device *uda1380_socdev; | |||
701 | 701 | ||
702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
703 | 703 | ||
704 | #define I2C_DRIVERID_UDA1380 0xfefe /* liam - need a proper id */ | 704 | static int uda1380_i2c_probe(struct i2c_client *i2c, |
705 | 705 | const struct i2c_device_id *id) | |
706 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
707 | |||
708 | /* Magic definition of all other variables and things */ | ||
709 | I2C_CLIENT_INSMOD; | ||
710 | |||
711 | static struct i2c_driver uda1380_i2c_driver; | ||
712 | static struct i2c_client client_template; | ||
713 | |||
714 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
715 | around */ | ||
716 | |||
717 | static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
718 | { | 706 | { |
719 | struct snd_soc_device *socdev = uda1380_socdev; | 707 | struct snd_soc_device *socdev = uda1380_socdev; |
720 | struct uda1380_setup_data *setup = socdev->codec_data; | 708 | struct uda1380_setup_data *setup = socdev->codec_data; |
721 | struct snd_soc_codec *codec = socdev->codec; | 709 | struct snd_soc_codec *codec = socdev->codec; |
722 | struct i2c_client *i2c; | ||
723 | int ret; | 710 | int ret; |
724 | 711 | ||
725 | if (addr != setup->i2c_address) | ||
726 | return -ENODEV; | ||
727 | |||
728 | client_template.adapter = adap; | ||
729 | client_template.addr = addr; | ||
730 | |||
731 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
732 | if (i2c == NULL) | ||
733 | return -ENOMEM; | ||
734 | |||
735 | i2c_set_clientdata(i2c, codec); | 712 | i2c_set_clientdata(i2c, codec); |
736 | codec->control_data = i2c; | 713 | codec->control_data = i2c; |
737 | 714 | ||
738 | ret = i2c_attach_client(i2c); | ||
739 | if (ret < 0) { | ||
740 | pr_err("uda1380: failed to attach codec at addr %x\n", addr); | ||
741 | goto err; | ||
742 | } | ||
743 | |||
744 | ret = uda1380_init(socdev, setup->dac_clk); | 715 | ret = uda1380_init(socdev, setup->dac_clk); |
745 | if (ret < 0) { | 716 | if (ret < 0) |
746 | pr_err("uda1380: failed to initialise UDA1380\n"); | 717 | pr_err("uda1380: failed to initialise UDA1380\n"); |
747 | goto err; | ||
748 | } | ||
749 | return ret; | ||
750 | 718 | ||
751 | err: | ||
752 | kfree(i2c); | ||
753 | return ret; | 719 | return ret; |
754 | } | 720 | } |
755 | 721 | ||
756 | static int uda1380_i2c_detach(struct i2c_client *client) | 722 | static int uda1380_i2c_remove(struct i2c_client *client) |
757 | { | 723 | { |
758 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 724 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
759 | i2c_detach_client(client); | ||
760 | kfree(codec->reg_cache); | 725 | kfree(codec->reg_cache); |
761 | kfree(client); | ||
762 | return 0; | 726 | return 0; |
763 | } | 727 | } |
764 | 728 | ||
765 | static int uda1380_i2c_attach(struct i2c_adapter *adap) | 729 | static const struct i2c_device_id uda1380_i2c_id[] = { |
766 | { | 730 | { "uda1380", 0 }, |
767 | return i2c_probe(adap, &addr_data, uda1380_codec_probe); | 731 | { } |
768 | } | 732 | }; |
733 | MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); | ||
769 | 734 | ||
770 | static struct i2c_driver uda1380_i2c_driver = { | 735 | static struct i2c_driver uda1380_i2c_driver = { |
771 | .driver = { | 736 | .driver = { |
772 | .name = "UDA1380 I2C Codec", | 737 | .name = "UDA1380 I2C Codec", |
773 | .owner = THIS_MODULE, | 738 | .owner = THIS_MODULE, |
774 | }, | 739 | }, |
775 | .id = I2C_DRIVERID_UDA1380, | 740 | .probe = uda1380_i2c_probe, |
776 | .attach_adapter = uda1380_i2c_attach, | 741 | .remove = uda1380_i2c_remove, |
777 | .detach_client = uda1380_i2c_detach, | 742 | .id_table = uda1380_i2c_id, |
778 | .command = NULL, | ||
779 | }; | 743 | }; |
780 | 744 | ||
781 | static struct i2c_client client_template = { | 745 | static int uda1380_add_i2c_device(struct platform_device *pdev, |
782 | .name = "UDA1380", | 746 | const struct uda1380_setup_data *setup) |
783 | .driver = &uda1380_i2c_driver, | 747 | { |
784 | }; | 748 | struct i2c_board_info info; |
749 | struct i2c_adapter *adapter; | ||
750 | struct i2c_client *client; | ||
751 | int ret; | ||
752 | |||
753 | ret = i2c_add_driver(&uda1380_i2c_driver); | ||
754 | if (ret != 0) { | ||
755 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
756 | return ret; | ||
757 | } | ||
758 | |||
759 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
760 | info.addr = setup->i2c_address; | ||
761 | strlcpy(info.type, "uda1380", I2C_NAME_SIZE); | ||
762 | |||
763 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
764 | if (!adapter) { | ||
765 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
766 | setup->i2c_bus); | ||
767 | goto err_driver; | ||
768 | } | ||
769 | |||
770 | client = i2c_new_device(adapter, &info); | ||
771 | i2c_put_adapter(adapter); | ||
772 | if (!client) { | ||
773 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
774 | (unsigned int)info.addr); | ||
775 | goto err_driver; | ||
776 | } | ||
777 | |||
778 | return 0; | ||
779 | |||
780 | err_driver: | ||
781 | i2c_del_driver(&uda1380_i2c_driver); | ||
782 | return -ENODEV; | ||
783 | } | ||
785 | #endif | 784 | #endif |
786 | 785 | ||
787 | static int uda1380_probe(struct platform_device *pdev) | 786 | static int uda1380_probe(struct platform_device *pdev) |
@@ -789,7 +788,7 @@ static int uda1380_probe(struct platform_device *pdev) | |||
789 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 788 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
790 | struct uda1380_setup_data *setup; | 789 | struct uda1380_setup_data *setup; |
791 | struct snd_soc_codec *codec; | 790 | struct snd_soc_codec *codec; |
792 | int ret = 0; | 791 | int ret; |
793 | 792 | ||
794 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); | 793 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); |
795 | 794 | ||
@@ -804,16 +803,13 @@ static int uda1380_probe(struct platform_device *pdev) | |||
804 | INIT_LIST_HEAD(&codec->dapm_paths); | 803 | INIT_LIST_HEAD(&codec->dapm_paths); |
805 | 804 | ||
806 | uda1380_socdev = socdev; | 805 | uda1380_socdev = socdev; |
806 | ret = -ENODEV; | ||
807 | |||
807 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 808 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
808 | if (setup->i2c_address) { | 809 | if (setup->i2c_address) { |
809 | normal_i2c[0] = setup->i2c_address; | ||
810 | codec->hw_write = (hw_write_t)i2c_master_send; | 810 | codec->hw_write = (hw_write_t)i2c_master_send; |
811 | ret = i2c_add_driver(&uda1380_i2c_driver); | 811 | ret = uda1380_add_i2c_device(pdev, setup); |
812 | if (ret != 0) | ||
813 | printk(KERN_ERR "can't add i2c driver"); | ||
814 | } | 812 | } |
815 | #else | ||
816 | /* Add other interfaces here */ | ||
817 | #endif | 813 | #endif |
818 | 814 | ||
819 | if (ret != 0) | 815 | if (ret != 0) |
@@ -833,6 +829,7 @@ static int uda1380_remove(struct platform_device *pdev) | |||
833 | snd_soc_free_pcms(socdev); | 829 | snd_soc_free_pcms(socdev); |
834 | snd_soc_dapm_free(socdev); | 830 | snd_soc_dapm_free(socdev); |
835 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 831 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
832 | i2c_unregister_device(codec->control_data); | ||
836 | i2c_del_driver(&uda1380_i2c_driver); | 833 | i2c_del_driver(&uda1380_i2c_driver); |
837 | #endif | 834 | #endif |
838 | kfree(codec); | 835 | kfree(codec); |
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h index 50c603e2c9f..c55c17a52a1 100644 --- a/sound/soc/codecs/uda1380.h +++ b/sound/soc/codecs/uda1380.h | |||
@@ -73,6 +73,7 @@ | |||
73 | #define R23_AGC_EN 0x0001 | 73 | #define R23_AGC_EN 0x0001 |
74 | 74 | ||
75 | struct uda1380_setup_data { | 75 | struct uda1380_setup_data { |
76 | int i2c_bus; | ||
76 | unsigned short i2c_address; | 77 | unsigned short i2c_address; |
77 | int dac_clk; | 78 | int dac_clk; |
78 | #define UDA1380_DAC_CLK_SYSCLK 0 | 79 | #define UDA1380_DAC_CLK_SYSCLK 0 |
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 3d998e6a997..9a37c8d95ed 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -199,7 +199,7 @@ SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0), | |||
199 | }; | 199 | }; |
200 | 200 | ||
201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { | 201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { |
202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 0), | 202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 1), |
203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), | 203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), |
204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), | 204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), |
205 | }; | 205 | }; |
@@ -665,88 +665,86 @@ static struct snd_soc_device *wm8510_socdev; | |||
665 | /* | 665 | /* |
666 | * WM8510 2 wire address is 0x1a | 666 | * WM8510 2 wire address is 0x1a |
667 | */ | 667 | */ |
668 | #define I2C_DRIVERID_WM8510 0xfefe /* liam - need a proper id */ | ||
669 | 668 | ||
670 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 669 | static int wm8510_i2c_probe(struct i2c_client *i2c, |
671 | 670 | const struct i2c_device_id *id) | |
672 | /* Magic definition of all other variables and things */ | ||
673 | I2C_CLIENT_INSMOD; | ||
674 | |||
675 | static struct i2c_driver wm8510_i2c_driver; | ||
676 | static struct i2c_client client_template; | ||
677 | |||
678 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
679 | around */ | ||
680 | |||
681 | static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
682 | { | 671 | { |
683 | struct snd_soc_device *socdev = wm8510_socdev; | 672 | struct snd_soc_device *socdev = wm8510_socdev; |
684 | struct wm8510_setup_data *setup = socdev->codec_data; | ||
685 | struct snd_soc_codec *codec = socdev->codec; | 673 | struct snd_soc_codec *codec = socdev->codec; |
686 | struct i2c_client *i2c; | ||
687 | int ret; | 674 | int ret; |
688 | 675 | ||
689 | if (addr != setup->i2c_address) | ||
690 | return -ENODEV; | ||
691 | |||
692 | client_template.adapter = adap; | ||
693 | client_template.addr = addr; | ||
694 | |||
695 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
696 | if (i2c == NULL) | ||
697 | return -ENOMEM; | ||
698 | |||
699 | i2c_set_clientdata(i2c, codec); | 676 | i2c_set_clientdata(i2c, codec); |
700 | codec->control_data = i2c; | 677 | codec->control_data = i2c; |
701 | 678 | ||
702 | ret = i2c_attach_client(i2c); | ||
703 | if (ret < 0) { | ||
704 | pr_err("failed to attach codec at addr %x\n", addr); | ||
705 | goto err; | ||
706 | } | ||
707 | |||
708 | ret = wm8510_init(socdev); | 679 | ret = wm8510_init(socdev); |
709 | if (ret < 0) { | 680 | if (ret < 0) |
710 | pr_err("failed to initialise WM8510\n"); | 681 | pr_err("failed to initialise WM8510\n"); |
711 | goto err; | ||
712 | } | ||
713 | return ret; | ||
714 | 682 | ||
715 | err: | ||
716 | kfree(i2c); | ||
717 | return ret; | 683 | return ret; |
718 | } | 684 | } |
719 | 685 | ||
720 | static int wm8510_i2c_detach(struct i2c_client *client) | 686 | static int wm8510_i2c_remove(struct i2c_client *client) |
721 | { | 687 | { |
722 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 688 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
723 | i2c_detach_client(client); | ||
724 | kfree(codec->reg_cache); | 689 | kfree(codec->reg_cache); |
725 | kfree(client); | ||
726 | return 0; | 690 | return 0; |
727 | } | 691 | } |
728 | 692 | ||
729 | static int wm8510_i2c_attach(struct i2c_adapter *adap) | 693 | static const struct i2c_device_id wm8510_i2c_id[] = { |
730 | { | 694 | { "wm8510", 0 }, |
731 | return i2c_probe(adap, &addr_data, wm8510_codec_probe); | 695 | { } |
732 | } | 696 | }; |
697 | MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id); | ||
733 | 698 | ||
734 | /* corgi i2c codec control layer */ | ||
735 | static struct i2c_driver wm8510_i2c_driver = { | 699 | static struct i2c_driver wm8510_i2c_driver = { |
736 | .driver = { | 700 | .driver = { |
737 | .name = "WM8510 I2C Codec", | 701 | .name = "WM8510 I2C Codec", |
738 | .owner = THIS_MODULE, | 702 | .owner = THIS_MODULE, |
739 | }, | 703 | }, |
740 | .id = I2C_DRIVERID_WM8510, | 704 | .probe = wm8510_i2c_probe, |
741 | .attach_adapter = wm8510_i2c_attach, | 705 | .remove = wm8510_i2c_remove, |
742 | .detach_client = wm8510_i2c_detach, | 706 | .id_table = wm8510_i2c_id, |
743 | .command = NULL, | ||
744 | }; | 707 | }; |
745 | 708 | ||
746 | static struct i2c_client client_template = { | 709 | static int wm8510_add_i2c_device(struct platform_device *pdev, |
747 | .name = "WM8510", | 710 | const struct wm8510_setup_data *setup) |
748 | .driver = &wm8510_i2c_driver, | 711 | { |
749 | }; | 712 | struct i2c_board_info info; |
713 | struct i2c_adapter *adapter; | ||
714 | struct i2c_client *client; | ||
715 | int ret; | ||
716 | |||
717 | ret = i2c_add_driver(&wm8510_i2c_driver); | ||
718 | if (ret != 0) { | ||
719 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
724 | info.addr = setup->i2c_address; | ||
725 | strlcpy(info.type, "wm8510", I2C_NAME_SIZE); | ||
726 | |||
727 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
728 | if (!adapter) { | ||
729 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
730 | setup->i2c_bus); | ||
731 | goto err_driver; | ||
732 | } | ||
733 | |||
734 | client = i2c_new_device(adapter, &info); | ||
735 | i2c_put_adapter(adapter); | ||
736 | if (!client) { | ||
737 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
738 | (unsigned int)info.addr); | ||
739 | goto err_driver; | ||
740 | } | ||
741 | |||
742 | return 0; | ||
743 | |||
744 | err_driver: | ||
745 | i2c_del_driver(&wm8510_i2c_driver); | ||
746 | return -ENODEV; | ||
747 | } | ||
750 | #endif | 748 | #endif |
751 | 749 | ||
752 | static int wm8510_probe(struct platform_device *pdev) | 750 | static int wm8510_probe(struct platform_device *pdev) |
@@ -771,11 +769,8 @@ static int wm8510_probe(struct platform_device *pdev) | |||
771 | wm8510_socdev = socdev; | 769 | wm8510_socdev = socdev; |
772 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 770 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
773 | if (setup->i2c_address) { | 771 | if (setup->i2c_address) { |
774 | normal_i2c[0] = setup->i2c_address; | ||
775 | codec->hw_write = (hw_write_t)i2c_master_send; | 772 | codec->hw_write = (hw_write_t)i2c_master_send; |
776 | ret = i2c_add_driver(&wm8510_i2c_driver); | 773 | ret = wm8510_add_i2c_device(pdev, setup); |
777 | if (ret != 0) | ||
778 | printk(KERN_ERR "can't add i2c driver"); | ||
779 | } | 774 | } |
780 | #else | 775 | #else |
781 | /* Add other interfaces here */ | 776 | /* Add other interfaces here */ |
@@ -798,6 +793,7 @@ static int wm8510_remove(struct platform_device *pdev) | |||
798 | snd_soc_free_pcms(socdev); | 793 | snd_soc_free_pcms(socdev); |
799 | snd_soc_dapm_free(socdev); | 794 | snd_soc_dapm_free(socdev); |
800 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 795 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
796 | i2c_unregister_device(codec->control_data); | ||
801 | i2c_del_driver(&wm8510_i2c_driver); | 797 | i2c_del_driver(&wm8510_i2c_driver); |
802 | #endif | 798 | #endif |
803 | kfree(codec); | 799 | kfree(codec); |
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h index f5d2e42eb3f..c5368396045 100644 --- a/sound/soc/codecs/wm8510.h +++ b/sound/soc/codecs/wm8510.h | |||
@@ -94,6 +94,7 @@ | |||
94 | #define WM8510_MCLKDIV_12 (7 << 5) | 94 | #define WM8510_MCLKDIV_12 (7 << 5) |
95 | 95 | ||
96 | struct wm8510_setup_data { | 96 | struct wm8510_setup_data { |
97 | int i2c_bus; | ||
97 | unsigned short i2c_address; | 98 | unsigned short i2c_address; |
98 | }; | 99 | }; |
99 | 100 | ||
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c new file mode 100644 index 00000000000..df1ffbe305b --- /dev/null +++ b/sound/soc/codecs/wm8580.c | |||
@@ -0,0 +1,1055 @@ | |||
1 | /* | ||
2 | * wm8580.c -- WM8580 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
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 | * Notes: | ||
12 | * The WM8580 is a multichannel codec with S/PDIF support, featuring six | ||
13 | * DAC channels and two ADC channels. | ||
14 | * | ||
15 | * Currently only the primary audio interface is supported - S/PDIF and | ||
16 | * the secondary audio interfaces are not. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/version.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/pm.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dapm.h> | ||
33 | #include <sound/tlv.h> | ||
34 | #include <sound/initval.h> | ||
35 | #include <asm/div64.h> | ||
36 | |||
37 | #include "wm8580.h" | ||
38 | |||
39 | #define AUDIO_NAME "wm8580" | ||
40 | #define WM8580_VERSION "0.1" | ||
41 | |||
42 | struct pll_state { | ||
43 | unsigned int in; | ||
44 | unsigned int out; | ||
45 | }; | ||
46 | |||
47 | /* codec private data */ | ||
48 | struct wm8580_priv { | ||
49 | struct pll_state a; | ||
50 | struct pll_state b; | ||
51 | }; | ||
52 | |||
53 | /* WM8580 register space */ | ||
54 | #define WM8580_PLLA1 0x00 | ||
55 | #define WM8580_PLLA2 0x01 | ||
56 | #define WM8580_PLLA3 0x02 | ||
57 | #define WM8580_PLLA4 0x03 | ||
58 | #define WM8580_PLLB1 0x04 | ||
59 | #define WM8580_PLLB2 0x05 | ||
60 | #define WM8580_PLLB3 0x06 | ||
61 | #define WM8580_PLLB4 0x07 | ||
62 | #define WM8580_CLKSEL 0x08 | ||
63 | #define WM8580_PAIF1 0x09 | ||
64 | #define WM8580_PAIF2 0x0A | ||
65 | #define WM8580_SAIF1 0x0B | ||
66 | #define WM8580_PAIF3 0x0C | ||
67 | #define WM8580_PAIF4 0x0D | ||
68 | #define WM8580_SAIF2 0x0E | ||
69 | #define WM8580_DAC_CONTROL1 0x0F | ||
70 | #define WM8580_DAC_CONTROL2 0x10 | ||
71 | #define WM8580_DAC_CONTROL3 0x11 | ||
72 | #define WM8580_DAC_CONTROL4 0x12 | ||
73 | #define WM8580_DAC_CONTROL5 0x13 | ||
74 | #define WM8580_DIGITAL_ATTENUATION_DACL1 0x14 | ||
75 | #define WM8580_DIGITAL_ATTENUATION_DACR1 0x15 | ||
76 | #define WM8580_DIGITAL_ATTENUATION_DACL2 0x16 | ||
77 | #define WM8580_DIGITAL_ATTENUATION_DACR2 0x17 | ||
78 | #define WM8580_DIGITAL_ATTENUATION_DACL3 0x18 | ||
79 | #define WM8580_DIGITAL_ATTENUATION_DACR3 0x19 | ||
80 | #define WM8580_MASTER_DIGITAL_ATTENUATION 0x1C | ||
81 | #define WM8580_ADC_CONTROL1 0x1D | ||
82 | #define WM8580_SPDTXCHAN0 0x1E | ||
83 | #define WM8580_SPDTXCHAN1 0x1F | ||
84 | #define WM8580_SPDTXCHAN2 0x20 | ||
85 | #define WM8580_SPDTXCHAN3 0x21 | ||
86 | #define WM8580_SPDTXCHAN4 0x22 | ||
87 | #define WM8580_SPDTXCHAN5 0x23 | ||
88 | #define WM8580_SPDMODE 0x24 | ||
89 | #define WM8580_INTMASK 0x25 | ||
90 | #define WM8580_GPO1 0x26 | ||
91 | #define WM8580_GPO2 0x27 | ||
92 | #define WM8580_GPO3 0x28 | ||
93 | #define WM8580_GPO4 0x29 | ||
94 | #define WM8580_GPO5 0x2A | ||
95 | #define WM8580_INTSTAT 0x2B | ||
96 | #define WM8580_SPDRXCHAN1 0x2C | ||
97 | #define WM8580_SPDRXCHAN2 0x2D | ||
98 | #define WM8580_SPDRXCHAN3 0x2E | ||
99 | #define WM8580_SPDRXCHAN4 0x2F | ||
100 | #define WM8580_SPDRXCHAN5 0x30 | ||
101 | #define WM8580_SPDSTAT 0x31 | ||
102 | #define WM8580_PWRDN1 0x32 | ||
103 | #define WM8580_PWRDN2 0x33 | ||
104 | #define WM8580_READBACK 0x34 | ||
105 | #define WM8580_RESET 0x35 | ||
106 | |||
107 | /* PLLB4 (register 7h) */ | ||
108 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 | ||
109 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 | ||
110 | #define WM8580_PLLB4_MCLKOUTSRC_PLLB 0x40 | ||
111 | #define WM8580_PLLB4_MCLKOUTSRC_OSC 0x60 | ||
112 | |||
113 | #define WM8580_PLLB4_CLKOUTSRC_MASK 0x180 | ||
114 | #define WM8580_PLLB4_CLKOUTSRC_PLLACLK 0x080 | ||
115 | #define WM8580_PLLB4_CLKOUTSRC_PLLBCLK 0x100 | ||
116 | #define WM8580_PLLB4_CLKOUTSRC_OSCCLK 0x180 | ||
117 | |||
118 | /* CLKSEL (register 8h) */ | ||
119 | #define WM8580_CLKSEL_DAC_CLKSEL_MASK 0x03 | ||
120 | #define WM8580_CLKSEL_DAC_CLKSEL_PLLA 0x01 | ||
121 | #define WM8580_CLKSEL_DAC_CLKSEL_PLLB 0x02 | ||
122 | |||
123 | /* AIF control 1 (registers 9h-bh) */ | ||
124 | #define WM8580_AIF_RATE_MASK 0x7 | ||
125 | #define WM8580_AIF_RATE_128 0x0 | ||
126 | #define WM8580_AIF_RATE_192 0x1 | ||
127 | #define WM8580_AIF_RATE_256 0x2 | ||
128 | #define WM8580_AIF_RATE_384 0x3 | ||
129 | #define WM8580_AIF_RATE_512 0x4 | ||
130 | #define WM8580_AIF_RATE_768 0x5 | ||
131 | #define WM8580_AIF_RATE_1152 0x6 | ||
132 | |||
133 | #define WM8580_AIF_BCLKSEL_MASK 0x18 | ||
134 | #define WM8580_AIF_BCLKSEL_64 0x00 | ||
135 | #define WM8580_AIF_BCLKSEL_128 0x08 | ||
136 | #define WM8580_AIF_BCLKSEL_256 0x10 | ||
137 | #define WM8580_AIF_BCLKSEL_SYSCLK 0x18 | ||
138 | |||
139 | #define WM8580_AIF_MS 0x20 | ||
140 | |||
141 | #define WM8580_AIF_CLKSRC_MASK 0xc0 | ||
142 | #define WM8580_AIF_CLKSRC_PLLA 0x40 | ||
143 | #define WM8580_AIF_CLKSRC_PLLB 0x40 | ||
144 | #define WM8580_AIF_CLKSRC_MCLK 0xc0 | ||
145 | |||
146 | /* AIF control 2 (registers ch-eh) */ | ||
147 | #define WM8580_AIF_FMT_MASK 0x03 | ||
148 | #define WM8580_AIF_FMT_RIGHTJ 0x00 | ||
149 | #define WM8580_AIF_FMT_LEFTJ 0x01 | ||
150 | #define WM8580_AIF_FMT_I2S 0x02 | ||
151 | #define WM8580_AIF_FMT_DSP 0x03 | ||
152 | |||
153 | #define WM8580_AIF_LENGTH_MASK 0x0c | ||
154 | #define WM8580_AIF_LENGTH_16 0x00 | ||
155 | #define WM8580_AIF_LENGTH_20 0x04 | ||
156 | #define WM8580_AIF_LENGTH_24 0x08 | ||
157 | #define WM8580_AIF_LENGTH_32 0x0c | ||
158 | |||
159 | #define WM8580_AIF_LRP 0x10 | ||
160 | #define WM8580_AIF_BCP 0x20 | ||
161 | |||
162 | /* Powerdown Register 1 (register 32h) */ | ||
163 | #define WM8580_PWRDN1_PWDN 0x001 | ||
164 | #define WM8580_PWRDN1_ALLDACPD 0x040 | ||
165 | |||
166 | /* Powerdown Register 2 (register 33h) */ | ||
167 | #define WM8580_PWRDN2_OSSCPD 0x001 | ||
168 | #define WM8580_PWRDN2_PLLAPD 0x002 | ||
169 | #define WM8580_PWRDN2_PLLBPD 0x004 | ||
170 | #define WM8580_PWRDN2_SPDIFPD 0x008 | ||
171 | #define WM8580_PWRDN2_SPDIFTXD 0x010 | ||
172 | #define WM8580_PWRDN2_SPDIFRXD 0x020 | ||
173 | |||
174 | #define WM8580_DAC_CONTROL5_MUTEALL 0x10 | ||
175 | |||
176 | /* | ||
177 | * wm8580 register cache | ||
178 | * We can't read the WM8580 register space when we | ||
179 | * are using 2 wire for device control, so we cache them instead. | ||
180 | */ | ||
181 | static const u16 wm8580_reg[] = { | ||
182 | 0x0121, 0x017e, 0x007d, 0x0014, /*R3*/ | ||
183 | 0x0121, 0x017e, 0x007d, 0x0194, /*R7*/ | ||
184 | 0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/ | ||
185 | 0x0182, 0x0082, 0x000a, 0x0024, /*R15*/ | ||
186 | 0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/ | ||
187 | 0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/ | ||
188 | 0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R27*/ | ||
189 | 0x01f0, 0x0040, 0x0000, 0x0000, /*R31(0x1F)*/ | ||
190 | 0x0000, 0x0000, 0x0031, 0x000b, /*R35*/ | ||
191 | 0x0039, 0x0000, 0x0010, 0x0032, /*R39*/ | ||
192 | 0x0054, 0x0076, 0x0098, 0x0000, /*R43(0x2B)*/ | ||
193 | 0x0000, 0x0000, 0x0000, 0x0000, /*R47*/ | ||
194 | 0x0000, 0x0000, 0x005e, 0x003e, /*R51(0x33)*/ | ||
195 | 0x0000, 0x0000 /*R53*/ | ||
196 | }; | ||
197 | |||
198 | /* | ||
199 | * read wm8580 register cache | ||
200 | */ | ||
201 | static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec, | ||
202 | unsigned int reg) | ||
203 | { | ||
204 | u16 *cache = codec->reg_cache; | ||
205 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | ||
206 | return cache[reg]; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * write wm8580 register cache | ||
211 | */ | ||
212 | static inline void wm8580_write_reg_cache(struct snd_soc_codec *codec, | ||
213 | unsigned int reg, unsigned int value) | ||
214 | { | ||
215 | u16 *cache = codec->reg_cache; | ||
216 | |||
217 | cache[reg] = value; | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * write to the WM8580 register space | ||
222 | */ | ||
223 | static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg, | ||
224 | unsigned int value) | ||
225 | { | ||
226 | u8 data[2]; | ||
227 | |||
228 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | ||
229 | |||
230 | /* Registers are 9 bits wide */ | ||
231 | value &= 0x1ff; | ||
232 | |||
233 | switch (reg) { | ||
234 | case WM8580_RESET: | ||
235 | /* Uncached */ | ||
236 | break; | ||
237 | default: | ||
238 | if (value == wm8580_read_reg_cache(codec, reg)) | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | /* data is | ||
243 | * D15..D9 WM8580 register offset | ||
244 | * D8...D0 register data | ||
245 | */ | ||
246 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
247 | data[1] = value & 0x00ff; | ||
248 | |||
249 | wm8580_write_reg_cache(codec, reg, value); | ||
250 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
251 | return 0; | ||
252 | else | ||
253 | return -EIO; | ||
254 | } | ||
255 | |||
256 | static inline unsigned int wm8580_read(struct snd_soc_codec *codec, | ||
257 | unsigned int reg) | ||
258 | { | ||
259 | switch (reg) { | ||
260 | default: | ||
261 | return wm8580_read_reg_cache(codec, reg); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | ||
266 | |||
267 | static int wm8580_out_vu(struct snd_kcontrol *kcontrol, | ||
268 | struct snd_ctl_elem_value *ucontrol) | ||
269 | { | ||
270 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
271 | int reg = kcontrol->private_value & 0xff; | ||
272 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | ||
273 | int ret; | ||
274 | u16 val; | ||
275 | |||
276 | /* Clear the register cache so we write without VU set */ | ||
277 | wm8580_write_reg_cache(codec, reg, 0); | ||
278 | wm8580_write_reg_cache(codec, reg2, 0); | ||
279 | |||
280 | ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); | ||
281 | if (ret < 0) | ||
282 | return ret; | ||
283 | |||
284 | /* Now write again with the volume update bit set */ | ||
285 | val = wm8580_read_reg_cache(codec, reg); | ||
286 | wm8580_write(codec, reg, val | 0x0100); | ||
287 | |||
288 | val = wm8580_read_reg_cache(codec, reg2); | ||
289 | wm8580_write(codec, reg2, val | 0x0100); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | #define SOC_WM8580_OUT_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \ | ||
295 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
296 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
297 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
298 | .tlv.p = (tlv_array), \ | ||
299 | .info = snd_soc_info_volsw_2r, \ | ||
300 | .get = snd_soc_get_volsw_2r, .put = wm8580_out_vu, \ | ||
301 | .private_value = (reg_left) | ((shift) << 8) | \ | ||
302 | ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) } | ||
303 | |||
304 | static const struct snd_kcontrol_new wm8580_snd_controls[] = { | ||
305 | SOC_WM8580_OUT_DOUBLE_R_TLV("DAC1 Playback Volume", | ||
306 | WM8580_DIGITAL_ATTENUATION_DACL1, | ||
307 | WM8580_DIGITAL_ATTENUATION_DACR1, | ||
308 | 0, 0xff, 0, dac_tlv), | ||
309 | SOC_WM8580_OUT_DOUBLE_R_TLV("DAC2 Playback Volume", | ||
310 | WM8580_DIGITAL_ATTENUATION_DACL2, | ||
311 | WM8580_DIGITAL_ATTENUATION_DACR2, | ||
312 | 0, 0xff, 0, dac_tlv), | ||
313 | SOC_WM8580_OUT_DOUBLE_R_TLV("DAC3 Playback Volume", | ||
314 | WM8580_DIGITAL_ATTENUATION_DACL3, | ||
315 | WM8580_DIGITAL_ATTENUATION_DACR3, | ||
316 | 0, 0xff, 0, dac_tlv), | ||
317 | |||
318 | SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0), | ||
319 | SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0), | ||
320 | SOC_SINGLE("DAC3 Deemphasis Switch", WM8580_DAC_CONTROL3, 2, 1, 0), | ||
321 | |||
322 | SOC_DOUBLE("DAC1 Invert Switch", WM8580_DAC_CONTROL4, 0, 1, 1, 0), | ||
323 | SOC_DOUBLE("DAC2 Invert Switch", WM8580_DAC_CONTROL4, 2, 3, 1, 0), | ||
324 | SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4, 4, 5, 1, 0), | ||
325 | |||
326 | SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0), | ||
327 | SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0), | ||
328 | SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0), | ||
329 | SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0), | ||
330 | |||
331 | SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), | ||
332 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), | ||
333 | }; | ||
334 | |||
335 | /* Add non-DAPM controls */ | ||
336 | static int wm8580_add_controls(struct snd_soc_codec *codec) | ||
337 | { | ||
338 | int err, i; | ||
339 | |||
340 | for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) { | ||
341 | err = snd_ctl_add(codec->card, | ||
342 | snd_soc_cnew(&wm8580_snd_controls[i], | ||
343 | codec, NULL)); | ||
344 | if (err < 0) | ||
345 | return err; | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { | ||
350 | SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), | ||
351 | SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), | ||
352 | SND_SOC_DAPM_DAC("DAC3", "Playback", WM8580_PWRDN1, 4, 1), | ||
353 | |||
354 | SND_SOC_DAPM_OUTPUT("VOUT1L"), | ||
355 | SND_SOC_DAPM_OUTPUT("VOUT1R"), | ||
356 | SND_SOC_DAPM_OUTPUT("VOUT2L"), | ||
357 | SND_SOC_DAPM_OUTPUT("VOUT2R"), | ||
358 | SND_SOC_DAPM_OUTPUT("VOUT3L"), | ||
359 | SND_SOC_DAPM_OUTPUT("VOUT3R"), | ||
360 | |||
361 | SND_SOC_DAPM_ADC("ADC", "Capture", WM8580_PWRDN1, 1, 1), | ||
362 | |||
363 | SND_SOC_DAPM_INPUT("AINL"), | ||
364 | SND_SOC_DAPM_INPUT("AINR"), | ||
365 | }; | ||
366 | |||
367 | static const struct snd_soc_dapm_route audio_map[] = { | ||
368 | { "VOUT1L", NULL, "DAC1" }, | ||
369 | { "VOUT1R", NULL, "DAC1" }, | ||
370 | |||
371 | { "VOUT2L", NULL, "DAC2" }, | ||
372 | { "VOUT2R", NULL, "DAC2" }, | ||
373 | |||
374 | { "VOUT3L", NULL, "DAC3" }, | ||
375 | { "VOUT3R", NULL, "DAC3" }, | ||
376 | |||
377 | { "ADC", NULL, "AINL" }, | ||
378 | { "ADC", NULL, "AINR" }, | ||
379 | }; | ||
380 | |||
381 | static int wm8580_add_widgets(struct snd_soc_codec *codec) | ||
382 | { | ||
383 | snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets, | ||
384 | ARRAY_SIZE(wm8580_dapm_widgets)); | ||
385 | |||
386 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
387 | |||
388 | snd_soc_dapm_new_widgets(codec); | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | /* PLL divisors */ | ||
393 | struct _pll_div { | ||
394 | u32 prescale:1; | ||
395 | u32 postscale:1; | ||
396 | u32 freqmode:2; | ||
397 | u32 n:4; | ||
398 | u32 k:24; | ||
399 | }; | ||
400 | |||
401 | /* The size in bits of the pll divide */ | ||
402 | #define FIXED_PLL_SIZE (1 << 22) | ||
403 | |||
404 | /* PLL rate to output rate divisions */ | ||
405 | static struct { | ||
406 | unsigned int div; | ||
407 | unsigned int freqmode; | ||
408 | unsigned int postscale; | ||
409 | } post_table[] = { | ||
410 | { 2, 0, 0 }, | ||
411 | { 4, 0, 1 }, | ||
412 | { 4, 1, 0 }, | ||
413 | { 8, 1, 1 }, | ||
414 | { 8, 2, 0 }, | ||
415 | { 16, 2, 1 }, | ||
416 | { 12, 3, 0 }, | ||
417 | { 24, 3, 1 } | ||
418 | }; | ||
419 | |||
420 | static int pll_factors(struct _pll_div *pll_div, unsigned int target, | ||
421 | unsigned int source) | ||
422 | { | ||
423 | u64 Kpart; | ||
424 | unsigned int K, Ndiv, Nmod; | ||
425 | int i; | ||
426 | |||
427 | pr_debug("wm8580: PLL %dHz->%dHz\n", source, target); | ||
428 | |||
429 | /* Scale the output frequency up; the PLL should run in the | ||
430 | * region of 90-100MHz. | ||
431 | */ | ||
432 | for (i = 0; i < ARRAY_SIZE(post_table); i++) { | ||
433 | if (target * post_table[i].div >= 90000000 && | ||
434 | target * post_table[i].div <= 100000000) { | ||
435 | pll_div->freqmode = post_table[i].freqmode; | ||
436 | pll_div->postscale = post_table[i].postscale; | ||
437 | target *= post_table[i].div; | ||
438 | break; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | if (i == ARRAY_SIZE(post_table)) { | ||
443 | printk(KERN_ERR "wm8580: Unable to scale output frequency " | ||
444 | "%u\n", target); | ||
445 | return -EINVAL; | ||
446 | } | ||
447 | |||
448 | Ndiv = target / source; | ||
449 | |||
450 | if (Ndiv < 5) { | ||
451 | source /= 2; | ||
452 | pll_div->prescale = 1; | ||
453 | Ndiv = target / source; | ||
454 | } else | ||
455 | pll_div->prescale = 0; | ||
456 | |||
457 | if ((Ndiv < 5) || (Ndiv > 13)) { | ||
458 | printk(KERN_ERR | ||
459 | "WM8580 N=%d outside supported range\n", Ndiv); | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | |||
463 | pll_div->n = Ndiv; | ||
464 | Nmod = target % source; | ||
465 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
466 | |||
467 | do_div(Kpart, source); | ||
468 | |||
469 | K = Kpart & 0xFFFFFFFF; | ||
470 | |||
471 | pll_div->k = K; | ||
472 | |||
473 | pr_debug("PLL %x.%x prescale %d freqmode %d postscale %d\n", | ||
474 | pll_div->n, pll_div->k, pll_div->prescale, pll_div->freqmode, | ||
475 | pll_div->postscale); | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
481 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
482 | { | ||
483 | int offset; | ||
484 | struct snd_soc_codec *codec = codec_dai->codec; | ||
485 | struct wm8580_priv *wm8580 = codec->private_data; | ||
486 | struct pll_state *state; | ||
487 | struct _pll_div pll_div; | ||
488 | unsigned int reg; | ||
489 | unsigned int pwr_mask; | ||
490 | int ret; | ||
491 | |||
492 | /* GCC isn't able to work out the ifs below for initialising/using | ||
493 | * pll_div so suppress warnings. | ||
494 | */ | ||
495 | memset(&pll_div, 0, sizeof(pll_div)); | ||
496 | |||
497 | switch (pll_id) { | ||
498 | case WM8580_PLLA: | ||
499 | state = &wm8580->a; | ||
500 | offset = 0; | ||
501 | pwr_mask = WM8580_PWRDN2_PLLAPD; | ||
502 | break; | ||
503 | case WM8580_PLLB: | ||
504 | state = &wm8580->b; | ||
505 | offset = 4; | ||
506 | pwr_mask = WM8580_PWRDN2_PLLBPD; | ||
507 | break; | ||
508 | default: | ||
509 | return -ENODEV; | ||
510 | } | ||
511 | |||
512 | if (freq_in && freq_out) { | ||
513 | ret = pll_factors(&pll_div, freq_out, freq_in); | ||
514 | if (ret != 0) | ||
515 | return ret; | ||
516 | } | ||
517 | |||
518 | state->in = freq_in; | ||
519 | state->out = freq_out; | ||
520 | |||
521 | /* Always disable the PLL - it is not safe to leave it running | ||
522 | * while reprogramming it. | ||
523 | */ | ||
524 | reg = wm8580_read(codec, WM8580_PWRDN2); | ||
525 | wm8580_write(codec, WM8580_PWRDN2, reg | pwr_mask); | ||
526 | |||
527 | if (!freq_in || !freq_out) | ||
528 | return 0; | ||
529 | |||
530 | wm8580_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); | ||
531 | wm8580_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); | ||
532 | wm8580_write(codec, WM8580_PLLA3 + offset, | ||
533 | (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); | ||
534 | |||
535 | reg = wm8580_read(codec, WM8580_PLLA4 + offset); | ||
536 | reg &= ~0x3f; | ||
537 | reg |= pll_div.prescale | pll_div.postscale << 1 | | ||
538 | pll_div.freqmode << 4; | ||
539 | |||
540 | wm8580_write(codec, WM8580_PLLA4 + offset, reg); | ||
541 | |||
542 | /* All done, turn it on */ | ||
543 | reg = wm8580_read(codec, WM8580_PWRDN2); | ||
544 | wm8580_write(codec, WM8580_PWRDN2, reg & ~pwr_mask); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | /* | ||
550 | * Set PCM DAI bit size and sample rate. | ||
551 | */ | ||
552 | static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, | ||
553 | struct snd_pcm_hw_params *params) | ||
554 | { | ||
555 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
556 | struct snd_soc_dai_link *dai = rtd->dai; | ||
557 | struct snd_soc_device *socdev = rtd->socdev; | ||
558 | struct snd_soc_codec *codec = socdev->codec; | ||
559 | u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id); | ||
560 | |||
561 | paifb &= ~WM8580_AIF_LENGTH_MASK; | ||
562 | /* bit size */ | ||
563 | switch (params_format(params)) { | ||
564 | case SNDRV_PCM_FORMAT_S16_LE: | ||
565 | break; | ||
566 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
567 | paifb |= WM8580_AIF_LENGTH_20; | ||
568 | break; | ||
569 | case SNDRV_PCM_FORMAT_S24_LE: | ||
570 | paifb |= WM8580_AIF_LENGTH_24; | ||
571 | break; | ||
572 | case SNDRV_PCM_FORMAT_S32_LE: | ||
573 | paifb |= WM8580_AIF_LENGTH_24; | ||
574 | break; | ||
575 | default: | ||
576 | return -EINVAL; | ||
577 | } | ||
578 | |||
579 | wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, | ||
584 | unsigned int fmt) | ||
585 | { | ||
586 | struct snd_soc_codec *codec = codec_dai->codec; | ||
587 | unsigned int aifa; | ||
588 | unsigned int aifb; | ||
589 | int can_invert_lrclk; | ||
590 | |||
591 | aifa = wm8580_read(codec, WM8580_PAIF1 + codec_dai->id); | ||
592 | aifb = wm8580_read(codec, WM8580_PAIF3 + codec_dai->id); | ||
593 | |||
594 | aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); | ||
595 | |||
596 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
597 | case SND_SOC_DAIFMT_CBS_CFS: | ||
598 | aifa &= ~WM8580_AIF_MS; | ||
599 | break; | ||
600 | case SND_SOC_DAIFMT_CBM_CFM: | ||
601 | aifa |= WM8580_AIF_MS; | ||
602 | break; | ||
603 | default: | ||
604 | return -EINVAL; | ||
605 | } | ||
606 | |||
607 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
608 | case SND_SOC_DAIFMT_I2S: | ||
609 | can_invert_lrclk = 1; | ||
610 | aifb |= WM8580_AIF_FMT_I2S; | ||
611 | break; | ||
612 | case SND_SOC_DAIFMT_RIGHT_J: | ||
613 | can_invert_lrclk = 1; | ||
614 | aifb |= WM8580_AIF_FMT_RIGHTJ; | ||
615 | break; | ||
616 | case SND_SOC_DAIFMT_LEFT_J: | ||
617 | can_invert_lrclk = 1; | ||
618 | aifb |= WM8580_AIF_FMT_LEFTJ; | ||
619 | break; | ||
620 | case SND_SOC_DAIFMT_DSP_A: | ||
621 | can_invert_lrclk = 0; | ||
622 | aifb |= WM8580_AIF_FMT_DSP; | ||
623 | break; | ||
624 | case SND_SOC_DAIFMT_DSP_B: | ||
625 | can_invert_lrclk = 0; | ||
626 | aifb |= WM8580_AIF_FMT_DSP; | ||
627 | aifb |= WM8580_AIF_LRP; | ||
628 | break; | ||
629 | default: | ||
630 | return -EINVAL; | ||
631 | } | ||
632 | |||
633 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
634 | case SND_SOC_DAIFMT_NB_NF: | ||
635 | break; | ||
636 | |||
637 | case SND_SOC_DAIFMT_IB_IF: | ||
638 | if (!can_invert_lrclk) | ||
639 | return -EINVAL; | ||
640 | aifb |= WM8580_AIF_BCP; | ||
641 | aifb |= WM8580_AIF_LRP; | ||
642 | break; | ||
643 | |||
644 | case SND_SOC_DAIFMT_IB_NF: | ||
645 | aifb |= WM8580_AIF_BCP; | ||
646 | break; | ||
647 | |||
648 | case SND_SOC_DAIFMT_NB_IF: | ||
649 | if (!can_invert_lrclk) | ||
650 | return -EINVAL; | ||
651 | aifb |= WM8580_AIF_LRP; | ||
652 | break; | ||
653 | |||
654 | default: | ||
655 | return -EINVAL; | ||
656 | } | ||
657 | |||
658 | wm8580_write(codec, WM8580_PAIF1 + codec_dai->id, aifa); | ||
659 | wm8580_write(codec, WM8580_PAIF3 + codec_dai->id, aifb); | ||
660 | |||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
665 | int div_id, int div) | ||
666 | { | ||
667 | struct snd_soc_codec *codec = codec_dai->codec; | ||
668 | unsigned int reg; | ||
669 | |||
670 | switch (div_id) { | ||
671 | case WM8580_MCLK: | ||
672 | reg = wm8580_read(codec, WM8580_PLLB4); | ||
673 | reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK; | ||
674 | |||
675 | switch (div) { | ||
676 | case WM8580_CLKSRC_MCLK: | ||
677 | /* Input */ | ||
678 | break; | ||
679 | |||
680 | case WM8580_CLKSRC_PLLA: | ||
681 | reg |= WM8580_PLLB4_MCLKOUTSRC_PLLA; | ||
682 | break; | ||
683 | case WM8580_CLKSRC_PLLB: | ||
684 | reg |= WM8580_PLLB4_MCLKOUTSRC_PLLB; | ||
685 | break; | ||
686 | |||
687 | case WM8580_CLKSRC_OSC: | ||
688 | reg |= WM8580_PLLB4_MCLKOUTSRC_OSC; | ||
689 | break; | ||
690 | |||
691 | default: | ||
692 | return -EINVAL; | ||
693 | } | ||
694 | wm8580_write(codec, WM8580_PLLB4, reg); | ||
695 | break; | ||
696 | |||
697 | case WM8580_DAC_CLKSEL: | ||
698 | reg = wm8580_read(codec, WM8580_CLKSEL); | ||
699 | reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK; | ||
700 | |||
701 | switch (div) { | ||
702 | case WM8580_CLKSRC_MCLK: | ||
703 | break; | ||
704 | |||
705 | case WM8580_CLKSRC_PLLA: | ||
706 | reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA; | ||
707 | break; | ||
708 | |||
709 | case WM8580_CLKSRC_PLLB: | ||
710 | reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB; | ||
711 | break; | ||
712 | |||
713 | default: | ||
714 | return -EINVAL; | ||
715 | } | ||
716 | wm8580_write(codec, WM8580_CLKSEL, reg); | ||
717 | break; | ||
718 | |||
719 | case WM8580_CLKOUTSRC: | ||
720 | reg = wm8580_read(codec, WM8580_PLLB4); | ||
721 | reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK; | ||
722 | |||
723 | switch (div) { | ||
724 | case WM8580_CLKSRC_NONE: | ||
725 | break; | ||
726 | |||
727 | case WM8580_CLKSRC_PLLA: | ||
728 | reg |= WM8580_PLLB4_CLKOUTSRC_PLLACLK; | ||
729 | break; | ||
730 | |||
731 | case WM8580_CLKSRC_PLLB: | ||
732 | reg |= WM8580_PLLB4_CLKOUTSRC_PLLBCLK; | ||
733 | break; | ||
734 | |||
735 | case WM8580_CLKSRC_OSC: | ||
736 | reg |= WM8580_PLLB4_CLKOUTSRC_OSCCLK; | ||
737 | break; | ||
738 | |||
739 | default: | ||
740 | return -EINVAL; | ||
741 | } | ||
742 | wm8580_write(codec, WM8580_PLLB4, reg); | ||
743 | break; | ||
744 | |||
745 | default: | ||
746 | return -EINVAL; | ||
747 | } | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
753 | { | ||
754 | struct snd_soc_codec *codec = codec_dai->codec; | ||
755 | unsigned int reg; | ||
756 | |||
757 | reg = wm8580_read(codec, WM8580_DAC_CONTROL5); | ||
758 | |||
759 | if (mute) | ||
760 | reg |= WM8580_DAC_CONTROL5_MUTEALL; | ||
761 | else | ||
762 | reg &= ~WM8580_DAC_CONTROL5_MUTEALL; | ||
763 | |||
764 | wm8580_write(codec, WM8580_DAC_CONTROL5, reg); | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static int wm8580_set_bias_level(struct snd_soc_codec *codec, | ||
770 | enum snd_soc_bias_level level) | ||
771 | { | ||
772 | u16 reg; | ||
773 | switch (level) { | ||
774 | case SND_SOC_BIAS_ON: | ||
775 | case SND_SOC_BIAS_PREPARE: | ||
776 | case SND_SOC_BIAS_STANDBY: | ||
777 | break; | ||
778 | case SND_SOC_BIAS_OFF: | ||
779 | reg = wm8580_read(codec, WM8580_PWRDN1); | ||
780 | wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); | ||
781 | break; | ||
782 | } | ||
783 | codec->bias_level = level; | ||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
788 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
789 | |||
790 | struct snd_soc_dai wm8580_dai[] = { | ||
791 | { | ||
792 | .name = "WM8580 PAIFRX", | ||
793 | .id = 0, | ||
794 | .playback = { | ||
795 | .stream_name = "Playback", | ||
796 | .channels_min = 1, | ||
797 | .channels_max = 6, | ||
798 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
799 | .formats = WM8580_FORMATS, | ||
800 | }, | ||
801 | .ops = { | ||
802 | .hw_params = wm8580_paif_hw_params, | ||
803 | }, | ||
804 | .dai_ops = { | ||
805 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
806 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
807 | .set_pll = wm8580_set_dai_pll, | ||
808 | .digital_mute = wm8580_digital_mute, | ||
809 | }, | ||
810 | }, | ||
811 | { | ||
812 | .name = "WM8580 PAIFTX", | ||
813 | .id = 1, | ||
814 | .capture = { | ||
815 | .stream_name = "Capture", | ||
816 | .channels_min = 2, | ||
817 | .channels_max = 2, | ||
818 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
819 | .formats = WM8580_FORMATS, | ||
820 | }, | ||
821 | .ops = { | ||
822 | .hw_params = wm8580_paif_hw_params, | ||
823 | }, | ||
824 | .dai_ops = { | ||
825 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
826 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
827 | .set_pll = wm8580_set_dai_pll, | ||
828 | }, | ||
829 | }, | ||
830 | }; | ||
831 | EXPORT_SYMBOL_GPL(wm8580_dai); | ||
832 | |||
833 | /* | ||
834 | * initialise the WM8580 driver | ||
835 | * register the mixer and dsp interfaces with the kernel | ||
836 | */ | ||
837 | static int wm8580_init(struct snd_soc_device *socdev) | ||
838 | { | ||
839 | struct snd_soc_codec *codec = socdev->codec; | ||
840 | int ret = 0; | ||
841 | |||
842 | codec->name = "WM8580"; | ||
843 | codec->owner = THIS_MODULE; | ||
844 | codec->read = wm8580_read_reg_cache; | ||
845 | codec->write = wm8580_write; | ||
846 | codec->set_bias_level = wm8580_set_bias_level; | ||
847 | codec->dai = wm8580_dai; | ||
848 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
849 | codec->reg_cache_size = ARRAY_SIZE(wm8580_reg); | ||
850 | codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg), | ||
851 | GFP_KERNEL); | ||
852 | |||
853 | if (codec->reg_cache == NULL) | ||
854 | return -ENOMEM; | ||
855 | |||
856 | /* Get the codec into a known state */ | ||
857 | wm8580_write(codec, WM8580_RESET, 0); | ||
858 | |||
859 | /* Power up and get individual control of the DACs */ | ||
860 | wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) & | ||
861 | ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD)); | ||
862 | |||
863 | /* Make VMID high impedence */ | ||
864 | wm8580_write(codec, WM8580_ADC_CONTROL1, | ||
865 | wm8580_read(codec, WM8580_ADC_CONTROL1) & ~0x100); | ||
866 | |||
867 | /* register pcms */ | ||
868 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, | ||
869 | SNDRV_DEFAULT_STR1); | ||
870 | if (ret < 0) { | ||
871 | printk(KERN_ERR "wm8580: failed to create pcms\n"); | ||
872 | goto pcm_err; | ||
873 | } | ||
874 | |||
875 | wm8580_add_controls(codec); | ||
876 | wm8580_add_widgets(codec); | ||
877 | |||
878 | ret = snd_soc_register_card(socdev); | ||
879 | if (ret < 0) { | ||
880 | printk(KERN_ERR "wm8580: failed to register card\n"); | ||
881 | goto card_err; | ||
882 | } | ||
883 | return ret; | ||
884 | |||
885 | card_err: | ||
886 | snd_soc_free_pcms(socdev); | ||
887 | snd_soc_dapm_free(socdev); | ||
888 | pcm_err: | ||
889 | kfree(codec->reg_cache); | ||
890 | return ret; | ||
891 | } | ||
892 | |||
893 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
894 | around */ | ||
895 | static struct snd_soc_device *wm8580_socdev; | ||
896 | |||
897 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
898 | |||
899 | /* | ||
900 | * WM8580 2 wire address is determined by GPIO5 | ||
901 | * state during powerup. | ||
902 | * low = 0x1a | ||
903 | * high = 0x1b | ||
904 | */ | ||
905 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
906 | |||
907 | /* Magic definition of all other variables and things */ | ||
908 | I2C_CLIENT_INSMOD; | ||
909 | |||
910 | static struct i2c_driver wm8580_i2c_driver; | ||
911 | static struct i2c_client client_template; | ||
912 | |||
913 | static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
914 | { | ||
915 | struct snd_soc_device *socdev = wm8580_socdev; | ||
916 | struct wm8580_setup_data *setup = socdev->codec_data; | ||
917 | struct snd_soc_codec *codec = socdev->codec; | ||
918 | struct i2c_client *i2c; | ||
919 | int ret; | ||
920 | |||
921 | if (addr != setup->i2c_address) | ||
922 | return -ENODEV; | ||
923 | |||
924 | client_template.adapter = adap; | ||
925 | client_template.addr = addr; | ||
926 | |||
927 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
928 | if (i2c == NULL) { | ||
929 | kfree(codec); | ||
930 | return -ENOMEM; | ||
931 | } | ||
932 | i2c_set_clientdata(i2c, codec); | ||
933 | codec->control_data = i2c; | ||
934 | |||
935 | ret = i2c_attach_client(i2c); | ||
936 | if (ret < 0) { | ||
937 | dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr); | ||
938 | goto err; | ||
939 | } | ||
940 | |||
941 | ret = wm8580_init(socdev); | ||
942 | if (ret < 0) { | ||
943 | dev_err(&i2c->dev, "failed to initialise WM8580\n"); | ||
944 | goto err; | ||
945 | } | ||
946 | |||
947 | return ret; | ||
948 | |||
949 | err: | ||
950 | kfree(codec); | ||
951 | kfree(i2c); | ||
952 | return ret; | ||
953 | } | ||
954 | |||
955 | static int wm8580_i2c_detach(struct i2c_client *client) | ||
956 | { | ||
957 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
958 | i2c_detach_client(client); | ||
959 | kfree(codec->reg_cache); | ||
960 | kfree(client); | ||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | static int wm8580_i2c_attach(struct i2c_adapter *adap) | ||
965 | { | ||
966 | return i2c_probe(adap, &addr_data, wm8580_codec_probe); | ||
967 | } | ||
968 | |||
969 | /* corgi i2c codec control layer */ | ||
970 | static struct i2c_driver wm8580_i2c_driver = { | ||
971 | .driver = { | ||
972 | .name = "WM8580 I2C Codec", | ||
973 | .owner = THIS_MODULE, | ||
974 | }, | ||
975 | .attach_adapter = wm8580_i2c_attach, | ||
976 | .detach_client = wm8580_i2c_detach, | ||
977 | .command = NULL, | ||
978 | }; | ||
979 | |||
980 | static struct i2c_client client_template = { | ||
981 | .name = "WM8580", | ||
982 | .driver = &wm8580_i2c_driver, | ||
983 | }; | ||
984 | #endif | ||
985 | |||
986 | static int wm8580_probe(struct platform_device *pdev) | ||
987 | { | ||
988 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
989 | struct wm8580_setup_data *setup; | ||
990 | struct snd_soc_codec *codec; | ||
991 | struct wm8580_priv *wm8580; | ||
992 | int ret = 0; | ||
993 | |||
994 | pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION); | ||
995 | |||
996 | setup = socdev->codec_data; | ||
997 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
998 | if (codec == NULL) | ||
999 | return -ENOMEM; | ||
1000 | |||
1001 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); | ||
1002 | if (wm8580 == NULL) { | ||
1003 | kfree(codec); | ||
1004 | return -ENOMEM; | ||
1005 | } | ||
1006 | |||
1007 | codec->private_data = wm8580; | ||
1008 | socdev->codec = codec; | ||
1009 | mutex_init(&codec->mutex); | ||
1010 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1011 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1012 | wm8580_socdev = socdev; | ||
1013 | |||
1014 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1015 | if (setup->i2c_address) { | ||
1016 | normal_i2c[0] = setup->i2c_address; | ||
1017 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1018 | ret = i2c_add_driver(&wm8580_i2c_driver); | ||
1019 | if (ret != 0) | ||
1020 | printk(KERN_ERR "can't add i2c driver"); | ||
1021 | } | ||
1022 | #else | ||
1023 | /* Add other interfaces here */ | ||
1024 | #endif | ||
1025 | return ret; | ||
1026 | } | ||
1027 | |||
1028 | /* power down chip */ | ||
1029 | static int wm8580_remove(struct platform_device *pdev) | ||
1030 | { | ||
1031 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1032 | struct snd_soc_codec *codec = socdev->codec; | ||
1033 | |||
1034 | if (codec->control_data) | ||
1035 | wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1036 | snd_soc_free_pcms(socdev); | ||
1037 | snd_soc_dapm_free(socdev); | ||
1038 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1039 | i2c_del_driver(&wm8580_i2c_driver); | ||
1040 | #endif | ||
1041 | kfree(codec->private_data); | ||
1042 | kfree(codec); | ||
1043 | |||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { | ||
1048 | .probe = wm8580_probe, | ||
1049 | .remove = wm8580_remove, | ||
1050 | }; | ||
1051 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); | ||
1052 | |||
1053 | MODULE_DESCRIPTION("ASoC WM8580 driver"); | ||
1054 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
1055 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h new file mode 100644 index 00000000000..589ddaba21d --- /dev/null +++ b/sound/soc/codecs/wm8580.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * wm8580.h -- audio driver for WM8580 | ||
3 | * | ||
4 | * Copyright 2008 Samsung Electronics. | ||
5 | * Author: Ryu Euiyoul | ||
6 | * ryu.real@gmail.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 | |||
15 | #ifndef _WM8580_H | ||
16 | #define _WM8580_H | ||
17 | |||
18 | #define WM8580_PLLA 1 | ||
19 | #define WM8580_PLLB 2 | ||
20 | |||
21 | #define WM8580_MCLK 1 | ||
22 | #define WM8580_DAC_CLKSEL 2 | ||
23 | #define WM8580_CLKOUTSRC 3 | ||
24 | |||
25 | #define WM8580_CLKSRC_MCLK 1 | ||
26 | #define WM8580_CLKSRC_PLLA 2 | ||
27 | #define WM8580_CLKSRC_PLLB 3 | ||
28 | #define WM8580_CLKSRC_OSC 4 | ||
29 | #define WM8580_CLKSRC_NONE 5 | ||
30 | |||
31 | struct wm8580_setup_data { | ||
32 | unsigned short i2c_address; | ||
33 | }; | ||
34 | |||
35 | #define WM8580_DAI_PAIFRX 0 | ||
36 | #define WM8580_DAI_PAIFTX 1 | ||
37 | |||
38 | extern struct snd_soc_dai wm8580_dai[]; | ||
39 | extern struct snd_soc_codec_device soc_codec_dev_wm8580; | ||
40 | |||
41 | #endif | ||
42 | |||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 9402fcaf04f..7b64d9a7ff7 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/spi/spi.h> | ||
22 | #include <sound/core.h> | 23 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
@@ -570,88 +571,144 @@ static struct snd_soc_device *wm8731_socdev; | |||
570 | * low = 0x1a | 571 | * low = 0x1a |
571 | * high = 0x1b | 572 | * high = 0x1b |
572 | */ | 573 | */ |
573 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
574 | 574 | ||
575 | /* Magic definition of all other variables and things */ | 575 | static int wm8731_i2c_probe(struct i2c_client *i2c, |
576 | I2C_CLIENT_INSMOD; | 576 | const struct i2c_device_id *id) |
577 | |||
578 | static struct i2c_driver wm8731_i2c_driver; | ||
579 | static struct i2c_client client_template; | ||
580 | |||
581 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
582 | around */ | ||
583 | |||
584 | static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
585 | { | 577 | { |
586 | struct snd_soc_device *socdev = wm8731_socdev; | 578 | struct snd_soc_device *socdev = wm8731_socdev; |
587 | struct wm8731_setup_data *setup = socdev->codec_data; | ||
588 | struct snd_soc_codec *codec = socdev->codec; | 579 | struct snd_soc_codec *codec = socdev->codec; |
589 | struct i2c_client *i2c; | ||
590 | int ret; | 580 | int ret; |
591 | 581 | ||
592 | if (addr != setup->i2c_address) | ||
593 | return -ENODEV; | ||
594 | |||
595 | client_template.adapter = adap; | ||
596 | client_template.addr = addr; | ||
597 | |||
598 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
599 | if (i2c == NULL) | ||
600 | return -ENOMEM; | ||
601 | |||
602 | i2c_set_clientdata(i2c, codec); | 582 | i2c_set_clientdata(i2c, codec); |
603 | codec->control_data = i2c; | 583 | codec->control_data = i2c; |
604 | 584 | ||
605 | ret = i2c_attach_client(i2c); | ||
606 | if (ret < 0) { | ||
607 | pr_err("failed to attach codec at addr %x\n", addr); | ||
608 | goto err; | ||
609 | } | ||
610 | |||
611 | ret = wm8731_init(socdev); | 585 | ret = wm8731_init(socdev); |
612 | if (ret < 0) { | 586 | if (ret < 0) |
613 | pr_err("failed to initialise WM8731\n"); | 587 | pr_err("failed to initialise WM8731\n"); |
614 | goto err; | ||
615 | } | ||
616 | return ret; | ||
617 | 588 | ||
618 | err: | ||
619 | kfree(i2c); | ||
620 | return ret; | 589 | return ret; |
621 | } | 590 | } |
622 | 591 | ||
623 | static int wm8731_i2c_detach(struct i2c_client *client) | 592 | static int wm8731_i2c_remove(struct i2c_client *client) |
624 | { | 593 | { |
625 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 594 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
626 | i2c_detach_client(client); | ||
627 | kfree(codec->reg_cache); | 595 | kfree(codec->reg_cache); |
628 | kfree(client); | ||
629 | return 0; | 596 | return 0; |
630 | } | 597 | } |
631 | 598 | ||
632 | static int wm8731_i2c_attach(struct i2c_adapter *adap) | 599 | static const struct i2c_device_id wm8731_i2c_id[] = { |
633 | { | 600 | { "wm8731", 0 }, |
634 | return i2c_probe(adap, &addr_data, wm8731_codec_probe); | 601 | { } |
635 | } | 602 | }; |
603 | MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); | ||
636 | 604 | ||
637 | /* corgi i2c codec control layer */ | ||
638 | static struct i2c_driver wm8731_i2c_driver = { | 605 | static struct i2c_driver wm8731_i2c_driver = { |
639 | .driver = { | 606 | .driver = { |
640 | .name = "WM8731 I2C Codec", | 607 | .name = "WM8731 I2C Codec", |
641 | .owner = THIS_MODULE, | 608 | .owner = THIS_MODULE, |
642 | }, | 609 | }, |
643 | .id = I2C_DRIVERID_WM8731, | 610 | .probe = wm8731_i2c_probe, |
644 | .attach_adapter = wm8731_i2c_attach, | 611 | .remove = wm8731_i2c_remove, |
645 | .detach_client = wm8731_i2c_detach, | 612 | .id_table = wm8731_i2c_id, |
646 | .command = NULL, | ||
647 | }; | 613 | }; |
648 | 614 | ||
649 | static struct i2c_client client_template = { | 615 | static int wm8731_add_i2c_device(struct platform_device *pdev, |
650 | .name = "WM8731", | 616 | const struct wm8731_setup_data *setup) |
651 | .driver = &wm8731_i2c_driver, | 617 | { |
652 | }; | 618 | struct i2c_board_info info; |
619 | struct i2c_adapter *adapter; | ||
620 | struct i2c_client *client; | ||
621 | int ret; | ||
622 | |||
623 | ret = i2c_add_driver(&wm8731_i2c_driver); | ||
624 | if (ret != 0) { | ||
625 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
630 | info.addr = setup->i2c_address; | ||
631 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
632 | |||
633 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
634 | if (!adapter) { | ||
635 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
636 | setup->i2c_bus); | ||
637 | goto err_driver; | ||
638 | } | ||
639 | |||
640 | client = i2c_new_device(adapter, &info); | ||
641 | i2c_put_adapter(adapter); | ||
642 | if (!client) { | ||
643 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
644 | (unsigned int)info.addr); | ||
645 | goto err_driver; | ||
646 | } | ||
647 | |||
648 | return 0; | ||
649 | |||
650 | err_driver: | ||
651 | i2c_del_driver(&wm8731_i2c_driver); | ||
652 | return -ENODEV; | ||
653 | } | ||
653 | #endif | 654 | #endif |
654 | 655 | ||
656 | #if defined(CONFIG_SPI_MASTER) | ||
657 | static int __devinit wm8731_spi_probe(struct spi_device *spi) | ||
658 | { | ||
659 | struct snd_soc_device *socdev = wm8731_socdev; | ||
660 | struct snd_soc_codec *codec = socdev->codec; | ||
661 | int ret; | ||
662 | |||
663 | codec->control_data = spi; | ||
664 | |||
665 | ret = wm8731_init(socdev); | ||
666 | if (ret < 0) | ||
667 | dev_err(&spi->dev, "failed to initialise WM8731\n"); | ||
668 | |||
669 | return ret; | ||
670 | } | ||
671 | |||
672 | static int __devexit wm8731_spi_remove(struct spi_device *spi) | ||
673 | { | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static struct spi_driver wm8731_spi_driver = { | ||
678 | .driver = { | ||
679 | .name = "wm8731", | ||
680 | .bus = &spi_bus_type, | ||
681 | .owner = THIS_MODULE, | ||
682 | }, | ||
683 | .probe = wm8731_spi_probe, | ||
684 | .remove = __devexit_p(wm8731_spi_remove), | ||
685 | }; | ||
686 | |||
687 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) | ||
688 | { | ||
689 | struct spi_transfer t; | ||
690 | struct spi_message m; | ||
691 | u8 msg[2]; | ||
692 | |||
693 | if (len <= 0) | ||
694 | return 0; | ||
695 | |||
696 | msg[0] = data[0]; | ||
697 | msg[1] = data[1]; | ||
698 | |||
699 | spi_message_init(&m); | ||
700 | memset(&t, 0, (sizeof t)); | ||
701 | |||
702 | t.tx_buf = &msg[0]; | ||
703 | t.len = len; | ||
704 | |||
705 | spi_message_add_tail(&t, &m); | ||
706 | spi_sync(spi, &m); | ||
707 | |||
708 | return len; | ||
709 | } | ||
710 | #endif /* CONFIG_SPI_MASTER */ | ||
711 | |||
655 | static int wm8731_probe(struct platform_device *pdev) | 712 | static int wm8731_probe(struct platform_device *pdev) |
656 | { | 713 | { |
657 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 714 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -680,16 +737,21 @@ static int wm8731_probe(struct platform_device *pdev) | |||
680 | INIT_LIST_HEAD(&codec->dapm_paths); | 737 | INIT_LIST_HEAD(&codec->dapm_paths); |
681 | 738 | ||
682 | wm8731_socdev = socdev; | 739 | wm8731_socdev = socdev; |
740 | ret = -ENODEV; | ||
741 | |||
683 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 742 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
684 | if (setup->i2c_address) { | 743 | if (setup->i2c_address) { |
685 | normal_i2c[0] = setup->i2c_address; | ||
686 | codec->hw_write = (hw_write_t)i2c_master_send; | 744 | codec->hw_write = (hw_write_t)i2c_master_send; |
687 | ret = i2c_add_driver(&wm8731_i2c_driver); | 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); | ||
688 | if (ret != 0) | 752 | if (ret != 0) |
689 | printk(KERN_ERR "can't add i2c driver"); | 753 | printk(KERN_ERR "can't add spi driver"); |
690 | } | 754 | } |
691 | #else | ||
692 | /* Add other interfaces here */ | ||
693 | #endif | 755 | #endif |
694 | 756 | ||
695 | if (ret != 0) { | 757 | if (ret != 0) { |
@@ -711,8 +773,12 @@ static int wm8731_remove(struct platform_device *pdev) | |||
711 | snd_soc_free_pcms(socdev); | 773 | snd_soc_free_pcms(socdev); |
712 | snd_soc_dapm_free(socdev); | 774 | snd_soc_dapm_free(socdev); |
713 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 775 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
776 | i2c_unregister_device(codec->control_data); | ||
714 | i2c_del_driver(&wm8731_i2c_driver); | 777 | i2c_del_driver(&wm8731_i2c_driver); |
715 | #endif | 778 | #endif |
779 | #if defined(CONFIG_SPI_MASTER) | ||
780 | spi_unregister_driver(&wm8731_spi_driver); | ||
781 | #endif | ||
716 | kfree(codec->private_data); | 782 | kfree(codec->private_data); |
717 | kfree(codec); | 783 | kfree(codec); |
718 | 784 | ||
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 99f2e3c60e3..95190e9c0c1 100644 --- a/sound/soc/codecs/wm8731.h +++ b/sound/soc/codecs/wm8731.h | |||
@@ -35,6 +35,8 @@ | |||
35 | #define WM8731_DAI 0 | 35 | #define WM8731_DAI 0 |
36 | 36 | ||
37 | struct wm8731_setup_data { | 37 | struct wm8731_setup_data { |
38 | int spi; | ||
39 | int i2c_bus; | ||
38 | unsigned short i2c_address; | 40 | unsigned short i2c_address; |
39 | }; | 41 | }; |
40 | 42 | ||
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index dd1f55404b2..4892e398a59 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/spi/spi.h> | ||
22 | #include <sound/core.h> | 23 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
@@ -841,88 +842,147 @@ static struct snd_soc_device *wm8750_socdev; | |||
841 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 842 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
842 | 843 | ||
843 | /* | 844 | /* |
844 | * WM8731 2 wire address is determined by GPIO5 | 845 | * WM8750 2 wire address is determined by GPIO5 |
845 | * state during powerup. | 846 | * state during powerup. |
846 | * low = 0x1a | 847 | * low = 0x1a |
847 | * high = 0x1b | 848 | * high = 0x1b |
848 | */ | 849 | */ |
849 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
850 | 850 | ||
851 | /* Magic definition of all other variables and things */ | 851 | static int wm8750_i2c_probe(struct i2c_client *i2c, |
852 | I2C_CLIENT_INSMOD; | 852 | const struct i2c_device_id *id) |
853 | |||
854 | static struct i2c_driver wm8750_i2c_driver; | ||
855 | static struct i2c_client client_template; | ||
856 | |||
857 | static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
858 | { | 853 | { |
859 | struct snd_soc_device *socdev = wm8750_socdev; | 854 | struct snd_soc_device *socdev = wm8750_socdev; |
860 | struct wm8750_setup_data *setup = socdev->codec_data; | ||
861 | struct snd_soc_codec *codec = socdev->codec; | 855 | struct snd_soc_codec *codec = socdev->codec; |
862 | struct i2c_client *i2c; | ||
863 | int ret; | 856 | int ret; |
864 | 857 | ||
865 | if (addr != setup->i2c_address) | ||
866 | return -ENODEV; | ||
867 | |||
868 | client_template.adapter = adap; | ||
869 | client_template.addr = addr; | ||
870 | |||
871 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
872 | if (i2c == NULL) | ||
873 | return -ENOMEM; | ||
874 | |||
875 | i2c_set_clientdata(i2c, codec); | 858 | i2c_set_clientdata(i2c, codec); |
876 | codec->control_data = i2c; | 859 | codec->control_data = i2c; |
877 | 860 | ||
878 | ret = i2c_attach_client(i2c); | ||
879 | if (ret < 0) { | ||
880 | pr_err("failed to attach codec at addr %x\n", addr); | ||
881 | goto err; | ||
882 | } | ||
883 | |||
884 | ret = wm8750_init(socdev); | 861 | ret = wm8750_init(socdev); |
885 | if (ret < 0) { | 862 | if (ret < 0) |
886 | pr_err("failed to initialise WM8750\n"); | 863 | pr_err("failed to initialise WM8750\n"); |
887 | goto err; | ||
888 | } | ||
889 | return ret; | ||
890 | 864 | ||
891 | err: | ||
892 | kfree(i2c); | ||
893 | return ret; | 865 | return ret; |
894 | } | 866 | } |
895 | 867 | ||
896 | static int wm8750_i2c_detach(struct i2c_client *client) | 868 | static int wm8750_i2c_remove(struct i2c_client *client) |
897 | { | 869 | { |
898 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 870 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
899 | i2c_detach_client(client); | ||
900 | kfree(codec->reg_cache); | 871 | kfree(codec->reg_cache); |
901 | kfree(client); | ||
902 | return 0; | 872 | return 0; |
903 | } | 873 | } |
904 | 874 | ||
905 | static int wm8750_i2c_attach(struct i2c_adapter *adap) | 875 | static const struct i2c_device_id wm8750_i2c_id[] = { |
906 | { | 876 | { "wm8750", 0 }, |
907 | return i2c_probe(adap, &addr_data, wm8750_codec_probe); | 877 | { } |
908 | } | 878 | }; |
879 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); | ||
909 | 880 | ||
910 | /* corgi i2c codec control layer */ | ||
911 | static struct i2c_driver wm8750_i2c_driver = { | 881 | static struct i2c_driver wm8750_i2c_driver = { |
912 | .driver = { | 882 | .driver = { |
913 | .name = "WM8750 I2C Codec", | 883 | .name = "WM8750 I2C Codec", |
914 | .owner = THIS_MODULE, | 884 | .owner = THIS_MODULE, |
915 | }, | 885 | }, |
916 | .id = I2C_DRIVERID_WM8750, | 886 | .probe = wm8750_i2c_probe, |
917 | .attach_adapter = wm8750_i2c_attach, | 887 | .remove = wm8750_i2c_remove, |
918 | .detach_client = wm8750_i2c_detach, | 888 | .id_table = wm8750_i2c_id, |
919 | .command = NULL, | ||
920 | }; | 889 | }; |
921 | 890 | ||
922 | static struct i2c_client client_template = { | 891 | static int wm8750_add_i2c_device(struct platform_device *pdev, |
923 | .name = "WM8750", | 892 | const struct wm8750_setup_data *setup) |
924 | .driver = &wm8750_i2c_driver, | 893 | { |
894 | struct i2c_board_info info; | ||
895 | struct i2c_adapter *adapter; | ||
896 | struct i2c_client *client; | ||
897 | int ret; | ||
898 | |||
899 | ret = i2c_add_driver(&wm8750_i2c_driver); | ||
900 | if (ret != 0) { | ||
901 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
906 | info.addr = setup->i2c_address; | ||
907 | strlcpy(info.type, "wm8750", I2C_NAME_SIZE); | ||
908 | |||
909 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
910 | if (!adapter) { | ||
911 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
912 | setup->i2c_bus); | ||
913 | goto err_driver; | ||
914 | } | ||
915 | |||
916 | client = i2c_new_device(adapter, &info); | ||
917 | i2c_put_adapter(adapter); | ||
918 | if (!client) { | ||
919 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
920 | (unsigned int)info.addr); | ||
921 | goto err_driver; | ||
922 | } | ||
923 | |||
924 | return 0; | ||
925 | |||
926 | err_driver: | ||
927 | i2c_del_driver(&wm8750_i2c_driver); | ||
928 | return -ENODEV; | ||
929 | } | ||
930 | #endif | ||
931 | |||
932 | #if defined(CONFIG_SPI_MASTER) | ||
933 | static int __devinit wm8750_spi_probe(struct spi_device *spi) | ||
934 | { | ||
935 | struct snd_soc_device *socdev = wm8750_socdev; | ||
936 | struct snd_soc_codec *codec = socdev->codec; | ||
937 | int ret; | ||
938 | |||
939 | codec->control_data = spi; | ||
940 | |||
941 | ret = wm8750_init(socdev); | ||
942 | if (ret < 0) | ||
943 | dev_err(&spi->dev, "failed to initialise WM8750\n"); | ||
944 | |||
945 | return ret; | ||
946 | } | ||
947 | |||
948 | static int __devexit wm8750_spi_remove(struct spi_device *spi) | ||
949 | { | ||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | static struct spi_driver wm8750_spi_driver = { | ||
954 | .driver = { | ||
955 | .name = "wm8750", | ||
956 | .bus = &spi_bus_type, | ||
957 | .owner = THIS_MODULE, | ||
958 | }, | ||
959 | .probe = wm8750_spi_probe, | ||
960 | .remove = __devexit_p(wm8750_spi_remove), | ||
925 | }; | 961 | }; |
962 | |||
963 | static int wm8750_spi_write(struct spi_device *spi, const char *data, int len) | ||
964 | { | ||
965 | struct spi_transfer t; | ||
966 | struct spi_message m; | ||
967 | u8 msg[2]; | ||
968 | |||
969 | if (len <= 0) | ||
970 | return 0; | ||
971 | |||
972 | msg[0] = data[0]; | ||
973 | msg[1] = data[1]; | ||
974 | |||
975 | spi_message_init(&m); | ||
976 | memset(&t, 0, (sizeof t)); | ||
977 | |||
978 | t.tx_buf = &msg[0]; | ||
979 | t.len = len; | ||
980 | |||
981 | spi_message_add_tail(&t, &m); | ||
982 | spi_sync(spi, &m); | ||
983 | |||
984 | return len; | ||
985 | } | ||
926 | #endif | 986 | #endif |
927 | 987 | ||
928 | static int wm8750_probe(struct platform_device *pdev) | 988 | static int wm8750_probe(struct platform_device *pdev) |
@@ -931,7 +991,7 @@ static int wm8750_probe(struct platform_device *pdev) | |||
931 | struct wm8750_setup_data *setup = socdev->codec_data; | 991 | struct wm8750_setup_data *setup = socdev->codec_data; |
932 | struct snd_soc_codec *codec; | 992 | struct snd_soc_codec *codec; |
933 | struct wm8750_priv *wm8750; | 993 | struct wm8750_priv *wm8750; |
934 | int ret = 0; | 994 | int ret; |
935 | 995 | ||
936 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); | 996 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); |
937 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 997 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
@@ -952,16 +1012,21 @@ static int wm8750_probe(struct platform_device *pdev) | |||
952 | wm8750_socdev = socdev; | 1012 | wm8750_socdev = socdev; |
953 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); | 1013 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); |
954 | 1014 | ||
1015 | ret = -ENODEV; | ||
1016 | |||
955 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1017 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
956 | if (setup->i2c_address) { | 1018 | if (setup->i2c_address) { |
957 | normal_i2c[0] = setup->i2c_address; | ||
958 | codec->hw_write = (hw_write_t)i2c_master_send; | 1019 | codec->hw_write = (hw_write_t)i2c_master_send; |
959 | ret = i2c_add_driver(&wm8750_i2c_driver); | 1020 | ret = wm8750_add_i2c_device(pdev, setup); |
1021 | } | ||
1022 | #endif | ||
1023 | #if defined(CONFIG_SPI_MASTER) | ||
1024 | if (setup->spi) { | ||
1025 | codec->hw_write = (hw_write_t)wm8750_spi_write; | ||
1026 | ret = spi_register_driver(&wm8750_spi_driver); | ||
960 | if (ret != 0) | 1027 | if (ret != 0) |
961 | printk(KERN_ERR "can't add i2c driver"); | 1028 | printk(KERN_ERR "can't add spi driver"); |
962 | } | 1029 | } |
963 | #else | ||
964 | /* Add other interfaces here */ | ||
965 | #endif | 1030 | #endif |
966 | 1031 | ||
967 | if (ret != 0) { | 1032 | if (ret != 0) { |
@@ -1002,8 +1067,12 @@ static int wm8750_remove(struct platform_device *pdev) | |||
1002 | snd_soc_free_pcms(socdev); | 1067 | snd_soc_free_pcms(socdev); |
1003 | snd_soc_dapm_free(socdev); | 1068 | snd_soc_dapm_free(socdev); |
1004 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1069 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1070 | i2c_unregister_device(codec->control_data); | ||
1005 | i2c_del_driver(&wm8750_i2c_driver); | 1071 | i2c_del_driver(&wm8750_i2c_driver); |
1006 | #endif | 1072 | #endif |
1073 | #if defined(CONFIG_SPI_MASTER) | ||
1074 | spi_unregister_driver(&wm8750_spi_driver); | ||
1075 | #endif | ||
1007 | kfree(codec->private_data); | 1076 | kfree(codec->private_data); |
1008 | kfree(codec); | 1077 | kfree(codec); |
1009 | 1078 | ||
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h index 8ef30e628b2..1dc100e19cf 100644 --- a/sound/soc/codecs/wm8750.h +++ b/sound/soc/codecs/wm8750.h | |||
@@ -58,6 +58,8 @@ | |||
58 | #define WM8750_SYSCLK 0 | 58 | #define WM8750_SYSCLK 0 |
59 | 59 | ||
60 | struct wm8750_setup_data { | 60 | struct wm8750_setup_data { |
61 | int spi; | ||
62 | int i2c_bus; | ||
61 | unsigned short i2c_address; | 63 | unsigned short i2c_address; |
62 | }; | 64 | }; |
63 | 65 | ||
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 5761164fe16..8c4df44f334 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -583,7 +583,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
583 | 583 | ||
584 | /* out 4 */ | 584 | /* out 4 */ |
585 | {"Out4 Mux", "VREF", "VREF"}, | 585 | {"Out4 Mux", "VREF", "VREF"}, |
586 | {"Out4 Mux", "Capture ST", "Capture ST Mixer"}, | 586 | {"Out4 Mux", "Capture ST", "Playback Mixer"}, |
587 | {"Out4 Mux", "LOUT2", "LOUT2"}, | 587 | {"Out4 Mux", "LOUT2", "LOUT2"}, |
588 | {"Out 4", NULL, "Out4 Mux"}, | 588 | {"Out 4", NULL, "Out4 Mux"}, |
589 | {"OUT4", NULL, "Out 4"}, | 589 | {"OUT4", NULL, "Out 4"}, |
@@ -607,7 +607,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
607 | /* Capture Right Mux */ | 607 | /* Capture Right Mux */ |
608 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, | 608 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, |
609 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, | 609 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, |
610 | {"Capture Right Mux", "Sidetone", "Capture ST Mixer"}, | 610 | {"Capture Right Mux", "Sidetone", "Playback Mixer"}, |
611 | 611 | ||
612 | /* Mono Capture mixer-mux */ | 612 | /* Mono Capture mixer-mux */ |
613 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, | 613 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, |
@@ -1637,84 +1637,86 @@ static struct snd_soc_device *wm8753_socdev; | |||
1637 | * low = 0x1a | 1637 | * low = 0x1a |
1638 | * high = 0x1b | 1638 | * high = 0x1b |
1639 | */ | 1639 | */ |
1640 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1641 | 1640 | ||
1642 | /* Magic definition of all other variables and things */ | 1641 | static int wm8753_i2c_probe(struct i2c_client *i2c, |
1643 | I2C_CLIENT_INSMOD; | 1642 | const struct i2c_device_id *id) |
1644 | |||
1645 | static struct i2c_driver wm8753_i2c_driver; | ||
1646 | static struct i2c_client client_template; | ||
1647 | |||
1648 | static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1649 | { | 1643 | { |
1650 | struct snd_soc_device *socdev = wm8753_socdev; | 1644 | struct snd_soc_device *socdev = wm8753_socdev; |
1651 | struct wm8753_setup_data *setup = socdev->codec_data; | ||
1652 | struct snd_soc_codec *codec = socdev->codec; | 1645 | struct snd_soc_codec *codec = socdev->codec; |
1653 | struct i2c_client *i2c; | ||
1654 | int ret; | 1646 | int ret; |
1655 | 1647 | ||
1656 | if (addr != setup->i2c_address) | ||
1657 | return -ENODEV; | ||
1658 | |||
1659 | client_template.adapter = adap; | ||
1660 | client_template.addr = addr; | ||
1661 | |||
1662 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1663 | if (!i2c) | ||
1664 | return -ENOMEM; | ||
1665 | |||
1666 | i2c_set_clientdata(i2c, codec); | 1648 | i2c_set_clientdata(i2c, codec); |
1667 | codec->control_data = i2c; | 1649 | codec->control_data = i2c; |
1668 | 1650 | ||
1669 | ret = i2c_attach_client(i2c); | ||
1670 | if (ret < 0) { | ||
1671 | pr_err("failed to attach codec at addr %x\n", addr); | ||
1672 | goto err; | ||
1673 | } | ||
1674 | |||
1675 | ret = wm8753_init(socdev); | 1651 | ret = wm8753_init(socdev); |
1676 | if (ret < 0) { | 1652 | if (ret < 0) |
1677 | pr_err("failed to initialise WM8753\n"); | 1653 | pr_err("failed to initialise WM8753\n"); |
1678 | goto err; | ||
1679 | } | ||
1680 | |||
1681 | return ret; | ||
1682 | 1654 | ||
1683 | err: | ||
1684 | kfree(i2c); | ||
1685 | return ret; | 1655 | return ret; |
1686 | } | 1656 | } |
1687 | 1657 | ||
1688 | static int wm8753_i2c_detach(struct i2c_client *client) | 1658 | static int wm8753_i2c_remove(struct i2c_client *client) |
1689 | { | 1659 | { |
1690 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1660 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1691 | i2c_detach_client(client); | ||
1692 | kfree(codec->reg_cache); | 1661 | kfree(codec->reg_cache); |
1693 | kfree(client); | ||
1694 | return 0; | 1662 | return 0; |
1695 | } | 1663 | } |
1696 | 1664 | ||
1697 | static int wm8753_i2c_attach(struct i2c_adapter *adap) | 1665 | static const struct i2c_device_id wm8753_i2c_id[] = { |
1698 | { | 1666 | { "wm8753", 0 }, |
1699 | return i2c_probe(adap, &addr_data, wm8753_codec_probe); | 1667 | { } |
1700 | } | 1668 | }; |
1669 | MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); | ||
1701 | 1670 | ||
1702 | /* corgi i2c codec control layer */ | ||
1703 | static struct i2c_driver wm8753_i2c_driver = { | 1671 | static struct i2c_driver wm8753_i2c_driver = { |
1704 | .driver = { | 1672 | .driver = { |
1705 | .name = "WM8753 I2C Codec", | 1673 | .name = "WM8753 I2C Codec", |
1706 | .owner = THIS_MODULE, | 1674 | .owner = THIS_MODULE, |
1707 | }, | 1675 | }, |
1708 | .id = I2C_DRIVERID_WM8753, | 1676 | .probe = wm8753_i2c_probe, |
1709 | .attach_adapter = wm8753_i2c_attach, | 1677 | .remove = wm8753_i2c_remove, |
1710 | .detach_client = wm8753_i2c_detach, | 1678 | .id_table = wm8753_i2c_id, |
1711 | .command = NULL, | ||
1712 | }; | 1679 | }; |
1713 | 1680 | ||
1714 | static struct i2c_client client_template = { | 1681 | static int wm8753_add_i2c_device(struct platform_device *pdev, |
1715 | .name = "WM8753", | 1682 | const struct wm8753_setup_data *setup) |
1716 | .driver = &wm8753_i2c_driver, | 1683 | { |
1717 | }; | 1684 | struct i2c_board_info info; |
1685 | struct i2c_adapter *adapter; | ||
1686 | struct i2c_client *client; | ||
1687 | int ret; | ||
1688 | |||
1689 | ret = i2c_add_driver(&wm8753_i2c_driver); | ||
1690 | if (ret != 0) { | ||
1691 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1692 | return ret; | ||
1693 | } | ||
1694 | |||
1695 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1696 | info.addr = setup->i2c_address; | ||
1697 | strlcpy(info.type, "wm8753", I2C_NAME_SIZE); | ||
1698 | |||
1699 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1700 | if (!adapter) { | ||
1701 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1702 | setup->i2c_bus); | ||
1703 | goto err_driver; | ||
1704 | } | ||
1705 | |||
1706 | client = i2c_new_device(adapter, &info); | ||
1707 | i2c_put_adapter(adapter); | ||
1708 | if (!client) { | ||
1709 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1710 | (unsigned int)info.addr); | ||
1711 | goto err_driver; | ||
1712 | } | ||
1713 | |||
1714 | return 0; | ||
1715 | |||
1716 | err_driver: | ||
1717 | i2c_del_driver(&wm8753_i2c_driver); | ||
1718 | return -ENODEV; | ||
1719 | } | ||
1718 | #endif | 1720 | #endif |
1719 | 1721 | ||
1720 | static int wm8753_probe(struct platform_device *pdev) | 1722 | static int wm8753_probe(struct platform_device *pdev) |
@@ -1748,11 +1750,8 @@ static int wm8753_probe(struct platform_device *pdev) | |||
1748 | 1750 | ||
1749 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1751 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1750 | if (setup->i2c_address) { | 1752 | if (setup->i2c_address) { |
1751 | normal_i2c[0] = setup->i2c_address; | ||
1752 | codec->hw_write = (hw_write_t)i2c_master_send; | 1753 | codec->hw_write = (hw_write_t)i2c_master_send; |
1753 | ret = i2c_add_driver(&wm8753_i2c_driver); | 1754 | ret = wm8753_add_i2c_device(pdev, setup); |
1754 | if (ret != 0) | ||
1755 | printk(KERN_ERR "can't add i2c driver"); | ||
1756 | } | 1755 | } |
1757 | #else | 1756 | #else |
1758 | /* Add other interfaces here */ | 1757 | /* Add other interfaces here */ |
@@ -1796,6 +1795,7 @@ static int wm8753_remove(struct platform_device *pdev) | |||
1796 | snd_soc_free_pcms(socdev); | 1795 | snd_soc_free_pcms(socdev); |
1797 | snd_soc_dapm_free(socdev); | 1796 | snd_soc_dapm_free(socdev); |
1798 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1797 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1798 | i2c_unregister_device(codec->control_data); | ||
1799 | i2c_del_driver(&wm8753_i2c_driver); | 1799 | i2c_del_driver(&wm8753_i2c_driver); |
1800 | #endif | 1800 | #endif |
1801 | kfree(codec->private_data); | 1801 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 44f5f1ff0cc..7defde069f1 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h | |||
@@ -79,6 +79,7 @@ | |||
79 | #define WM8753_ADCTL2 0x3f | 79 | #define WM8753_ADCTL2 0x3f |
80 | 80 | ||
81 | struct wm8753_setup_data { | 81 | struct wm8753_setup_data { |
82 | int i2c_bus; | ||
82 | unsigned short i2c_address; | 83 | unsigned short i2c_address; |
83 | }; | 84 | }; |
84 | 85 | ||
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c new file mode 100644 index 00000000000..0b8c6d38b48 --- /dev/null +++ b/sound/soc/codecs/wm8900.c | |||
@@ -0,0 +1,1542 @@ | |||
1 | /* | ||
2 | * wm8900.c -- WM8900 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2007, 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 | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * TODO: | ||
13 | * - Tristating. | ||
14 | * - TDM. | ||
15 | * - Jack detect. | ||
16 | * - FLL source configuration, currently only MCLK is supported. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/version.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/pm.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dapm.h> | ||
33 | #include <sound/initval.h> | ||
34 | #include <sound/tlv.h> | ||
35 | |||
36 | #include "wm8900.h" | ||
37 | |||
38 | /* WM8900 register space */ | ||
39 | #define WM8900_REG_RESET 0x0 | ||
40 | #define WM8900_REG_ID 0x0 | ||
41 | #define WM8900_REG_POWER1 0x1 | ||
42 | #define WM8900_REG_POWER2 0x2 | ||
43 | #define WM8900_REG_POWER3 0x3 | ||
44 | #define WM8900_REG_AUDIO1 0x4 | ||
45 | #define WM8900_REG_AUDIO2 0x5 | ||
46 | #define WM8900_REG_CLOCKING1 0x6 | ||
47 | #define WM8900_REG_CLOCKING2 0x7 | ||
48 | #define WM8900_REG_AUDIO3 0x8 | ||
49 | #define WM8900_REG_AUDIO4 0x9 | ||
50 | #define WM8900_REG_DACCTRL 0xa | ||
51 | #define WM8900_REG_LDAC_DV 0xb | ||
52 | #define WM8900_REG_RDAC_DV 0xc | ||
53 | #define WM8900_REG_SIDETONE 0xd | ||
54 | #define WM8900_REG_ADCCTRL 0xe | ||
55 | #define WM8900_REG_LADC_DV 0xf | ||
56 | #define WM8900_REG_RADC_DV 0x10 | ||
57 | #define WM8900_REG_GPIO 0x12 | ||
58 | #define WM8900_REG_INCTL 0x15 | ||
59 | #define WM8900_REG_LINVOL 0x16 | ||
60 | #define WM8900_REG_RINVOL 0x17 | ||
61 | #define WM8900_REG_INBOOSTMIX1 0x18 | ||
62 | #define WM8900_REG_INBOOSTMIX2 0x19 | ||
63 | #define WM8900_REG_ADCPATH 0x1a | ||
64 | #define WM8900_REG_AUXBOOST 0x1b | ||
65 | #define WM8900_REG_ADDCTL 0x1e | ||
66 | #define WM8900_REG_FLLCTL1 0x24 | ||
67 | #define WM8900_REG_FLLCTL2 0x25 | ||
68 | #define WM8900_REG_FLLCTL3 0x26 | ||
69 | #define WM8900_REG_FLLCTL4 0x27 | ||
70 | #define WM8900_REG_FLLCTL5 0x28 | ||
71 | #define WM8900_REG_FLLCTL6 0x29 | ||
72 | #define WM8900_REG_LOUTMIXCTL1 0x2c | ||
73 | #define WM8900_REG_ROUTMIXCTL1 0x2d | ||
74 | #define WM8900_REG_BYPASS1 0x2e | ||
75 | #define WM8900_REG_BYPASS2 0x2f | ||
76 | #define WM8900_REG_AUXOUT_CTL 0x30 | ||
77 | #define WM8900_REG_LOUT1CTL 0x33 | ||
78 | #define WM8900_REG_ROUT1CTL 0x34 | ||
79 | #define WM8900_REG_LOUT2CTL 0x35 | ||
80 | #define WM8900_REG_ROUT2CTL 0x36 | ||
81 | #define WM8900_REG_HPCTL1 0x3a | ||
82 | #define WM8900_REG_OUTBIASCTL 0x73 | ||
83 | |||
84 | #define WM8900_MAXREG 0x80 | ||
85 | |||
86 | #define WM8900_REG_ADDCTL_OUT1_DIS 0x80 | ||
87 | #define WM8900_REG_ADDCTL_OUT2_DIS 0x40 | ||
88 | #define WM8900_REG_ADDCTL_VMID_DIS 0x20 | ||
89 | #define WM8900_REG_ADDCTL_BIAS_SRC 0x10 | ||
90 | #define WM8900_REG_ADDCTL_VMID_SOFTST 0x04 | ||
91 | #define WM8900_REG_ADDCTL_TEMP_SD 0x02 | ||
92 | |||
93 | #define WM8900_REG_GPIO_TEMP_ENA 0x2 | ||
94 | |||
95 | #define WM8900_REG_POWER1_STARTUP_BIAS_ENA 0x0100 | ||
96 | #define WM8900_REG_POWER1_BIAS_ENA 0x0008 | ||
97 | #define WM8900_REG_POWER1_VMID_BUF_ENA 0x0004 | ||
98 | #define WM8900_REG_POWER1_FLL_ENA 0x0040 | ||
99 | |||
100 | #define WM8900_REG_POWER2_SYSCLK_ENA 0x8000 | ||
101 | #define WM8900_REG_POWER2_ADCL_ENA 0x0002 | ||
102 | #define WM8900_REG_POWER2_ADCR_ENA 0x0001 | ||
103 | |||
104 | #define WM8900_REG_POWER3_DACL_ENA 0x0002 | ||
105 | #define WM8900_REG_POWER3_DACR_ENA 0x0001 | ||
106 | |||
107 | #define WM8900_REG_AUDIO1_AIF_FMT_MASK 0x0018 | ||
108 | #define WM8900_REG_AUDIO1_LRCLK_INV 0x0080 | ||
109 | #define WM8900_REG_AUDIO1_BCLK_INV 0x0100 | ||
110 | |||
111 | #define WM8900_REG_CLOCKING1_BCLK_DIR 0x1 | ||
112 | #define WM8900_REG_CLOCKING1_MCLK_SRC 0x100 | ||
113 | #define WM8900_REG_CLOCKING1_BCLK_MASK (~0x01e) | ||
114 | #define WM8900_REG_CLOCKING1_OPCLK_MASK (~0x7000) | ||
115 | |||
116 | #define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0 | ||
117 | #define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c | ||
118 | |||
119 | #define WM8900_REG_DACCTRL_MUTE 0x004 | ||
120 | #define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400 | ||
121 | |||
122 | #define WM8900_REG_AUDIO3_ADCLRC_DIR 0x0800 | ||
123 | |||
124 | #define WM8900_REG_AUDIO4_DACLRC_DIR 0x0800 | ||
125 | |||
126 | #define WM8900_REG_FLLCTL1_OSC_ENA 0x100 | ||
127 | |||
128 | #define WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF 0x100 | ||
129 | |||
130 | #define WM8900_REG_HPCTL1_HP_IPSTAGE_ENA 0x80 | ||
131 | #define WM8900_REG_HPCTL1_HP_OPSTAGE_ENA 0x40 | ||
132 | #define WM8900_REG_HPCTL1_HP_CLAMP_IP 0x20 | ||
133 | #define WM8900_REG_HPCTL1_HP_CLAMP_OP 0x10 | ||
134 | #define WM8900_REG_HPCTL1_HP_SHORT 0x08 | ||
135 | #define WM8900_REG_HPCTL1_HP_SHORT2 0x04 | ||
136 | |||
137 | #define WM8900_LRC_MASK 0xfc00 | ||
138 | |||
139 | struct snd_soc_codec_device soc_codec_dev_wm8900; | ||
140 | |||
141 | struct wm8900_priv { | ||
142 | u32 fll_in; /* FLL input frequency */ | ||
143 | u32 fll_out; /* FLL output frequency */ | ||
144 | }; | ||
145 | |||
146 | /* | ||
147 | * wm8900 register cache. We can't read the entire register space and we | ||
148 | * have slow control buses so we cache the registers. | ||
149 | */ | ||
150 | static const u16 wm8900_reg_defaults[WM8900_MAXREG] = { | ||
151 | 0x8900, 0x0000, | ||
152 | 0xc000, 0x0000, | ||
153 | 0x4050, 0x4000, | ||
154 | 0x0008, 0x0000, | ||
155 | 0x0040, 0x0040, | ||
156 | 0x1004, 0x00c0, | ||
157 | 0x00c0, 0x0000, | ||
158 | 0x0100, 0x00c0, | ||
159 | 0x00c0, 0x0000, | ||
160 | 0xb001, 0x0000, | ||
161 | 0x0000, 0x0044, | ||
162 | 0x004c, 0x004c, | ||
163 | 0x0044, 0x0044, | ||
164 | 0x0000, 0x0044, | ||
165 | 0x0000, 0x0000, | ||
166 | 0x0002, 0x0000, | ||
167 | 0x0000, 0x0000, | ||
168 | 0x0000, 0x0000, | ||
169 | 0x0008, 0x0000, | ||
170 | 0x0000, 0x0008, | ||
171 | 0x0097, 0x0100, | ||
172 | 0x0000, 0x0000, | ||
173 | 0x0050, 0x0050, | ||
174 | 0x0055, 0x0055, | ||
175 | 0x0055, 0x0000, | ||
176 | 0x0000, 0x0079, | ||
177 | 0x0079, 0x0079, | ||
178 | 0x0079, 0x0000, | ||
179 | /* Remaining registers all zero */ | ||
180 | }; | ||
181 | |||
182 | /* | ||
183 | * read wm8900 register cache | ||
184 | */ | ||
185 | static inline unsigned int wm8900_read_reg_cache(struct snd_soc_codec *codec, | ||
186 | unsigned int reg) | ||
187 | { | ||
188 | u16 *cache = codec->reg_cache; | ||
189 | |||
190 | BUG_ON(reg >= WM8900_MAXREG); | ||
191 | |||
192 | if (reg == WM8900_REG_ID) | ||
193 | return 0; | ||
194 | |||
195 | return cache[reg]; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * write wm8900 register cache | ||
200 | */ | ||
201 | static inline void wm8900_write_reg_cache(struct snd_soc_codec *codec, | ||
202 | u16 reg, unsigned int value) | ||
203 | { | ||
204 | u16 *cache = codec->reg_cache; | ||
205 | |||
206 | BUG_ON(reg >= WM8900_MAXREG); | ||
207 | |||
208 | cache[reg] = value; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * write to the WM8900 register space | ||
213 | */ | ||
214 | static int wm8900_write(struct snd_soc_codec *codec, unsigned int reg, | ||
215 | unsigned int value) | ||
216 | { | ||
217 | u8 data[3]; | ||
218 | |||
219 | if (value == wm8900_read_reg_cache(codec, reg)) | ||
220 | return 0; | ||
221 | |||
222 | /* data is | ||
223 | * D15..D9 WM8900 register offset | ||
224 | * D8...D0 register data | ||
225 | */ | ||
226 | data[0] = reg; | ||
227 | data[1] = value >> 8; | ||
228 | data[2] = value & 0x00ff; | ||
229 | |||
230 | wm8900_write_reg_cache(codec, reg, value); | ||
231 | if (codec->hw_write(codec->control_data, data, 3) == 3) | ||
232 | return 0; | ||
233 | else | ||
234 | return -EIO; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Read from the wm8900. | ||
239 | */ | ||
240 | static unsigned int wm8900_chip_read(struct snd_soc_codec *codec, u8 reg) | ||
241 | { | ||
242 | struct i2c_msg xfer[2]; | ||
243 | u16 data; | ||
244 | int ret; | ||
245 | struct i2c_client *client = codec->control_data; | ||
246 | |||
247 | BUG_ON(reg != WM8900_REG_ID && reg != WM8900_REG_POWER1); | ||
248 | |||
249 | /* Write register */ | ||
250 | xfer[0].addr = client->addr; | ||
251 | xfer[0].flags = 0; | ||
252 | xfer[0].len = 1; | ||
253 | xfer[0].buf = ® | ||
254 | |||
255 | /* Read data */ | ||
256 | xfer[1].addr = client->addr; | ||
257 | xfer[1].flags = I2C_M_RD; | ||
258 | xfer[1].len = 2; | ||
259 | xfer[1].buf = (u8 *)&data; | ||
260 | |||
261 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
262 | if (ret != 2) { | ||
263 | printk(KERN_CRIT "i2c_transfer returned %d\n", ret); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | return (data >> 8) | ((data & 0xff) << 8); | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Read from the WM8900 register space. Most registers can't be read | ||
272 | * and are therefore supplied from cache. | ||
273 | */ | ||
274 | static unsigned int wm8900_read(struct snd_soc_codec *codec, unsigned int reg) | ||
275 | { | ||
276 | switch (reg) { | ||
277 | case WM8900_REG_ID: | ||
278 | return wm8900_chip_read(codec, reg); | ||
279 | default: | ||
280 | return wm8900_read_reg_cache(codec, reg); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static void wm8900_reset(struct snd_soc_codec *codec) | ||
285 | { | ||
286 | wm8900_write(codec, WM8900_REG_RESET, 0); | ||
287 | |||
288 | memcpy(codec->reg_cache, wm8900_reg_defaults, | ||
289 | sizeof(codec->reg_cache)); | ||
290 | } | ||
291 | |||
292 | static int wm8900_hp_event(struct snd_soc_dapm_widget *w, | ||
293 | struct snd_kcontrol *kcontrol, int event) | ||
294 | { | ||
295 | struct snd_soc_codec *codec = w->codec; | ||
296 | u16 hpctl1 = wm8900_read(codec, WM8900_REG_HPCTL1); | ||
297 | |||
298 | switch (event) { | ||
299 | case SND_SOC_DAPM_PRE_PMU: | ||
300 | /* Clamp headphone outputs */ | ||
301 | hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP | | ||
302 | WM8900_REG_HPCTL1_HP_CLAMP_OP; | ||
303 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
304 | break; | ||
305 | |||
306 | case SND_SOC_DAPM_POST_PMU: | ||
307 | /* Enable the input stage */ | ||
308 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP; | ||
309 | hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT | | ||
310 | WM8900_REG_HPCTL1_HP_SHORT2 | | ||
311 | WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; | ||
312 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
313 | |||
314 | msleep(400); | ||
315 | |||
316 | /* Enable the output stage */ | ||
317 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP; | ||
318 | hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; | ||
319 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
320 | |||
321 | /* Remove the shorts */ | ||
322 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2; | ||
323 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
324 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT; | ||
325 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
326 | break; | ||
327 | |||
328 | case SND_SOC_DAPM_PRE_PMD: | ||
329 | /* Short the output */ | ||
330 | hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT; | ||
331 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
332 | |||
333 | /* Disable the output stage */ | ||
334 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; | ||
335 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
336 | |||
337 | /* Clamp the outputs and power down input */ | ||
338 | hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP | | ||
339 | WM8900_REG_HPCTL1_HP_CLAMP_OP; | ||
340 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; | ||
341 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
342 | break; | ||
343 | |||
344 | case SND_SOC_DAPM_POST_PMD: | ||
345 | /* Disable everything */ | ||
346 | wm8900_write(codec, WM8900_REG_HPCTL1, 0); | ||
347 | break; | ||
348 | |||
349 | default: | ||
350 | BUG(); | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 100, 0); | ||
357 | |||
358 | static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 0); | ||
359 | |||
360 | static const DECLARE_TLV_DB_SCALE(in_boost_tlv, -1200, 600, 0); | ||
361 | |||
362 | static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1200, 100, 0); | ||
363 | |||
364 | static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); | ||
365 | |||
366 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1); | ||
367 | |||
368 | static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3600, 300, 0); | ||
369 | |||
370 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); | ||
371 | |||
372 | static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; | ||
373 | |||
374 | static const struct soc_enum mic_bias_level = | ||
375 | SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt); | ||
376 | |||
377 | static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; | ||
378 | |||
379 | static const struct soc_enum dac_mute_rate = | ||
380 | SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt); | ||
381 | |||
382 | static const char *dac_deemphasis_txt[] = { | ||
383 | "Disabled", "32kHz", "44.1kHz", "48kHz" | ||
384 | }; | ||
385 | |||
386 | static const struct soc_enum dac_deemphasis = | ||
387 | SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt); | ||
388 | |||
389 | static const char *adc_hpf_cut_txt[] = { | ||
390 | "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3" | ||
391 | }; | ||
392 | |||
393 | static const struct soc_enum adc_hpf_cut = | ||
394 | SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt); | ||
395 | |||
396 | static const char *lr_txt[] = { | ||
397 | "Left", "Right" | ||
398 | }; | ||
399 | |||
400 | static const struct soc_enum aifl_src = | ||
401 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt); | ||
402 | |||
403 | static const struct soc_enum aifr_src = | ||
404 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt); | ||
405 | |||
406 | static const struct soc_enum dacl_src = | ||
407 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt); | ||
408 | |||
409 | static const struct soc_enum dacr_src = | ||
410 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt); | ||
411 | |||
412 | static const char *sidetone_txt[] = { | ||
413 | "Disabled", "Left ADC", "Right ADC" | ||
414 | }; | ||
415 | |||
416 | static const struct soc_enum dacl_sidetone = | ||
417 | SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt); | ||
418 | |||
419 | static const struct soc_enum dacr_sidetone = | ||
420 | SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt); | ||
421 | |||
422 | static const struct snd_kcontrol_new wm8900_snd_controls[] = { | ||
423 | SOC_ENUM("Mic Bias Level", mic_bias_level), | ||
424 | |||
425 | SOC_SINGLE_TLV("Left Input PGA Volume", WM8900_REG_LINVOL, 0, 31, 0, | ||
426 | in_pga_tlv), | ||
427 | SOC_SINGLE("Left Input PGA Switch", WM8900_REG_LINVOL, 6, 1, 1), | ||
428 | SOC_SINGLE("Left Input PGA ZC Switch", WM8900_REG_LINVOL, 7, 1, 0), | ||
429 | |||
430 | SOC_SINGLE_TLV("Right Input PGA Volume", WM8900_REG_RINVOL, 0, 31, 0, | ||
431 | in_pga_tlv), | ||
432 | SOC_SINGLE("Right Input PGA Switch", WM8900_REG_RINVOL, 6, 1, 1), | ||
433 | SOC_SINGLE("Right Input PGA ZC Switch", WM8900_REG_RINVOL, 7, 1, 0), | ||
434 | |||
435 | SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1), | ||
436 | SOC_ENUM("DAC Mute Rate", dac_mute_rate), | ||
437 | SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0), | ||
438 | SOC_ENUM("DAC Deemphasis", dac_deemphasis), | ||
439 | SOC_SINGLE("DAC Sloping Stopband Filter Switch", WM8900_REG_DACCTRL, 8, 1, 0), | ||
440 | SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL, | ||
441 | 12, 1, 0), | ||
442 | |||
443 | SOC_SINGLE("ADC HPF Switch", WM8900_REG_ADCCTRL, 8, 1, 0), | ||
444 | SOC_ENUM("ADC HPF Cut-Off", adc_hpf_cut), | ||
445 | SOC_DOUBLE("ADC Invert Switch", WM8900_REG_ADCCTRL, 1, 0, 1, 0), | ||
446 | SOC_SINGLE_TLV("Left ADC Sidetone Volume", WM8900_REG_SIDETONE, 9, 12, 0, | ||
447 | adc_svol_tlv), | ||
448 | SOC_SINGLE_TLV("Right ADC Sidetone Volume", WM8900_REG_SIDETONE, 5, 12, 0, | ||
449 | adc_svol_tlv), | ||
450 | SOC_ENUM("Left Digital Audio Source", aifl_src), | ||
451 | SOC_ENUM("Right Digital Audio Source", aifr_src), | ||
452 | |||
453 | SOC_SINGLE_TLV("DAC Input Boost Volume", WM8900_REG_AUDIO2, 10, 4, 0, | ||
454 | dac_boost_tlv), | ||
455 | SOC_ENUM("Left DAC Source", dacl_src), | ||
456 | SOC_ENUM("Right DAC Source", dacr_src), | ||
457 | SOC_ENUM("Left DAC Sidetone", dacl_sidetone), | ||
458 | SOC_ENUM("Right DAC Sidetone", dacr_sidetone), | ||
459 | SOC_DOUBLE("DAC Invert Switch", WM8900_REG_DACCTRL, 1, 0, 1, 0), | ||
460 | |||
461 | SOC_DOUBLE_R_TLV("Digital Playback Volume", | ||
462 | WM8900_REG_LDAC_DV, WM8900_REG_RDAC_DV, | ||
463 | 1, 96, 0, dac_tlv), | ||
464 | SOC_DOUBLE_R_TLV("Digital Capture Volume", | ||
465 | WM8900_REG_LADC_DV, WM8900_REG_RADC_DV, 1, 119, 0, adc_tlv), | ||
466 | |||
467 | SOC_SINGLE_TLV("LINPUT3 Bypass Volume", WM8900_REG_LOUTMIXCTL1, 4, 7, 0, | ||
468 | out_mix_tlv), | ||
469 | SOC_SINGLE_TLV("RINPUT3 Bypass Volume", WM8900_REG_ROUTMIXCTL1, 4, 7, 0, | ||
470 | out_mix_tlv), | ||
471 | SOC_SINGLE_TLV("Left AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 4, 7, 0, | ||
472 | out_mix_tlv), | ||
473 | SOC_SINGLE_TLV("Right AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 0, 7, 0, | ||
474 | out_mix_tlv), | ||
475 | |||
476 | SOC_SINGLE_TLV("LeftIn to RightOut Mixer Volume", WM8900_REG_BYPASS1, 0, 7, 0, | ||
477 | out_mix_tlv), | ||
478 | SOC_SINGLE_TLV("LeftIn to LeftOut Mixer Volume", WM8900_REG_BYPASS1, 4, 7, 0, | ||
479 | out_mix_tlv), | ||
480 | SOC_SINGLE_TLV("RightIn to LeftOut Mixer Volume", WM8900_REG_BYPASS2, 0, 7, 0, | ||
481 | out_mix_tlv), | ||
482 | SOC_SINGLE_TLV("RightIn to RightOut Mixer Volume", WM8900_REG_BYPASS2, 4, 7, 0, | ||
483 | out_mix_tlv), | ||
484 | |||
485 | SOC_SINGLE_TLV("IN2L Boost Volume", WM8900_REG_INBOOSTMIX1, 0, 3, 0, | ||
486 | in_boost_tlv), | ||
487 | SOC_SINGLE_TLV("IN3L Boost Volume", WM8900_REG_INBOOSTMIX1, 4, 3, 0, | ||
488 | in_boost_tlv), | ||
489 | SOC_SINGLE_TLV("IN2R Boost Volume", WM8900_REG_INBOOSTMIX2, 0, 3, 0, | ||
490 | in_boost_tlv), | ||
491 | SOC_SINGLE_TLV("IN3R Boost Volume", WM8900_REG_INBOOSTMIX2, 4, 3, 0, | ||
492 | in_boost_tlv), | ||
493 | SOC_SINGLE_TLV("Left AUX Boost Volume", WM8900_REG_AUXBOOST, 4, 3, 0, | ||
494 | in_boost_tlv), | ||
495 | SOC_SINGLE_TLV("Right AUX Boost Volume", WM8900_REG_AUXBOOST, 0, 3, 0, | ||
496 | in_boost_tlv), | ||
497 | |||
498 | SOC_DOUBLE_R_TLV("LINEOUT1 Volume", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, | ||
499 | 0, 63, 0, out_pga_tlv), | ||
500 | SOC_DOUBLE_R("LINEOUT1 Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, | ||
501 | 6, 1, 1), | ||
502 | SOC_DOUBLE_R("LINEOUT1 ZC Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, | ||
503 | 7, 1, 0), | ||
504 | |||
505 | SOC_DOUBLE_R_TLV("LINEOUT2 Volume", | ||
506 | WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, | ||
507 | 0, 63, 0, out_pga_tlv), | ||
508 | SOC_DOUBLE_R("LINEOUT2 Switch", | ||
509 | WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 6, 1, 1), | ||
510 | SOC_DOUBLE_R("LINEOUT2 ZC Switch", | ||
511 | WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 7, 1, 0), | ||
512 | SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1, | ||
513 | 0, 1, 1), | ||
514 | |||
515 | }; | ||
516 | |||
517 | /* add non dapm controls */ | ||
518 | static int wm8900_add_controls(struct snd_soc_codec *codec) | ||
519 | { | ||
520 | int err, i; | ||
521 | |||
522 | for (i = 0; i < ARRAY_SIZE(wm8900_snd_controls); i++) { | ||
523 | err = snd_ctl_add(codec->card, | ||
524 | snd_soc_cnew(&wm8900_snd_controls[i], | ||
525 | codec, NULL)); | ||
526 | if (err < 0) | ||
527 | return err; | ||
528 | } | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static const struct snd_kcontrol_new wm8900_dapm_loutput2_control = | ||
534 | SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0); | ||
535 | |||
536 | static const struct snd_kcontrol_new wm8900_dapm_routput2_control = | ||
537 | SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0); | ||
538 | |||
539 | static const struct snd_kcontrol_new wm8900_loutmix_controls[] = { | ||
540 | SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0), | ||
541 | SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0), | ||
542 | SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 7, 1, 0), | ||
543 | SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 3, 1, 0), | ||
544 | SOC_DAPM_SINGLE("DACL Switch", WM8900_REG_LOUTMIXCTL1, 8, 1, 0), | ||
545 | }; | ||
546 | |||
547 | static const struct snd_kcontrol_new wm8900_routmix_controls[] = { | ||
548 | SOC_DAPM_SINGLE("RINPUT3 Bypass Switch", WM8900_REG_ROUTMIXCTL1, 7, 1, 0), | ||
549 | SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 3, 1, 0), | ||
550 | SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 3, 1, 0), | ||
551 | SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 7, 1, 0), | ||
552 | SOC_DAPM_SINGLE("DACR Switch", WM8900_REG_ROUTMIXCTL1, 8, 1, 0), | ||
553 | }; | ||
554 | |||
555 | static const struct snd_kcontrol_new wm8900_linmix_controls[] = { | ||
556 | SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INBOOSTMIX1, 2, 1, 1), | ||
557 | SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INBOOSTMIX1, 6, 1, 1), | ||
558 | SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 6, 1, 1), | ||
559 | SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0), | ||
560 | }; | ||
561 | |||
562 | static const struct snd_kcontrol_new wm8900_rinmix_controls[] = { | ||
563 | SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INBOOSTMIX2, 2, 1, 1), | ||
564 | SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INBOOSTMIX2, 6, 1, 1), | ||
565 | SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 2, 1, 1), | ||
566 | SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0), | ||
567 | }; | ||
568 | |||
569 | static const struct snd_kcontrol_new wm8900_linpga_controls[] = { | ||
570 | SOC_DAPM_SINGLE("LINPUT1 Switch", WM8900_REG_INCTL, 6, 1, 0), | ||
571 | SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INCTL, 5, 1, 0), | ||
572 | SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INCTL, 4, 1, 0), | ||
573 | }; | ||
574 | |||
575 | static const struct snd_kcontrol_new wm8900_rinpga_controls[] = { | ||
576 | SOC_DAPM_SINGLE("RINPUT1 Switch", WM8900_REG_INCTL, 2, 1, 0), | ||
577 | SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0), | ||
578 | SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0), | ||
579 | }; | ||
580 | |||
581 | static const char *wm9700_lp_mux[] = { "Disabled", "Enabled" }; | ||
582 | |||
583 | static const struct soc_enum wm8900_lineout2_lp_mux = | ||
584 | SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm9700_lp_mux); | ||
585 | |||
586 | static const struct snd_kcontrol_new wm8900_lineout2_lp = | ||
587 | SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); | ||
588 | |||
589 | static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = { | ||
590 | |||
591 | /* Externally visible pins */ | ||
592 | SND_SOC_DAPM_OUTPUT("LINEOUT1L"), | ||
593 | SND_SOC_DAPM_OUTPUT("LINEOUT1R"), | ||
594 | SND_SOC_DAPM_OUTPUT("LINEOUT2L"), | ||
595 | SND_SOC_DAPM_OUTPUT("LINEOUT2R"), | ||
596 | SND_SOC_DAPM_OUTPUT("HP_L"), | ||
597 | SND_SOC_DAPM_OUTPUT("HP_R"), | ||
598 | |||
599 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
600 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
601 | SND_SOC_DAPM_INPUT("RINPUT2"), | ||
602 | SND_SOC_DAPM_INPUT("LINPUT2"), | ||
603 | SND_SOC_DAPM_INPUT("RINPUT3"), | ||
604 | SND_SOC_DAPM_INPUT("LINPUT3"), | ||
605 | SND_SOC_DAPM_INPUT("AUX"), | ||
606 | |||
607 | SND_SOC_DAPM_VMID("VMID"), | ||
608 | |||
609 | /* Input */ | ||
610 | SND_SOC_DAPM_MIXER("Left Input PGA", WM8900_REG_POWER2, 3, 0, | ||
611 | wm8900_linpga_controls, | ||
612 | ARRAY_SIZE(wm8900_linpga_controls)), | ||
613 | SND_SOC_DAPM_MIXER("Right Input PGA", WM8900_REG_POWER2, 2, 0, | ||
614 | wm8900_rinpga_controls, | ||
615 | ARRAY_SIZE(wm8900_rinpga_controls)), | ||
616 | |||
617 | SND_SOC_DAPM_MIXER("Left Input Mixer", WM8900_REG_POWER2, 5, 0, | ||
618 | wm8900_linmix_controls, | ||
619 | ARRAY_SIZE(wm8900_linmix_controls)), | ||
620 | SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0, | ||
621 | wm8900_rinmix_controls, | ||
622 | ARRAY_SIZE(wm8900_rinmix_controls)), | ||
623 | |||
624 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8900_REG_POWER1, 4, 0), | ||
625 | |||
626 | SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0), | ||
627 | SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0), | ||
628 | |||
629 | /* Output */ | ||
630 | SND_SOC_DAPM_DAC("DACL", "Left HiFi Playback", WM8900_REG_POWER3, 1, 0), | ||
631 | SND_SOC_DAPM_DAC("DACR", "Right HiFi Playback", WM8900_REG_POWER3, 0, 0), | ||
632 | |||
633 | SND_SOC_DAPM_PGA_E("Headphone Amplifier", WM8900_REG_POWER3, 7, 0, NULL, 0, | ||
634 | wm8900_hp_event, | ||
635 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
636 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
637 | |||
638 | SND_SOC_DAPM_PGA("LINEOUT1L PGA", WM8900_REG_POWER2, 8, 0, NULL, 0), | ||
639 | SND_SOC_DAPM_PGA("LINEOUT1R PGA", WM8900_REG_POWER2, 7, 0, NULL, 0), | ||
640 | |||
641 | SND_SOC_DAPM_MUX("LINEOUT2 LP", SND_SOC_NOPM, 0, 0, &wm8900_lineout2_lp), | ||
642 | SND_SOC_DAPM_PGA("LINEOUT2L PGA", WM8900_REG_POWER3, 6, 0, NULL, 0), | ||
643 | SND_SOC_DAPM_PGA("LINEOUT2R PGA", WM8900_REG_POWER3, 5, 0, NULL, 0), | ||
644 | |||
645 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8900_REG_POWER3, 3, 0, | ||
646 | wm8900_loutmix_controls, | ||
647 | ARRAY_SIZE(wm8900_loutmix_controls)), | ||
648 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0, | ||
649 | wm8900_routmix_controls, | ||
650 | ARRAY_SIZE(wm8900_routmix_controls)), | ||
651 | }; | ||
652 | |||
653 | /* Target, Path, Source */ | ||
654 | static const struct snd_soc_dapm_route audio_map[] = { | ||
655 | /* Inputs */ | ||
656 | {"Left Input PGA", "LINPUT1 Switch", "LINPUT1"}, | ||
657 | {"Left Input PGA", "LINPUT2 Switch", "LINPUT2"}, | ||
658 | {"Left Input PGA", "LINPUT3 Switch", "LINPUT3"}, | ||
659 | |||
660 | {"Right Input PGA", "RINPUT1 Switch", "RINPUT1"}, | ||
661 | {"Right Input PGA", "RINPUT2 Switch", "RINPUT2"}, | ||
662 | {"Right Input PGA", "RINPUT3 Switch", "RINPUT3"}, | ||
663 | |||
664 | {"Left Input Mixer", "LINPUT2 Switch", "LINPUT2"}, | ||
665 | {"Left Input Mixer", "LINPUT3 Switch", "LINPUT3"}, | ||
666 | {"Left Input Mixer", "AUX Switch", "AUX"}, | ||
667 | {"Left Input Mixer", "Input PGA Switch", "Left Input PGA"}, | ||
668 | |||
669 | {"Right Input Mixer", "RINPUT2 Switch", "RINPUT2"}, | ||
670 | {"Right Input Mixer", "RINPUT3 Switch", "RINPUT3"}, | ||
671 | {"Right Input Mixer", "AUX Switch", "AUX"}, | ||
672 | {"Right Input Mixer", "Input PGA Switch", "Right Input PGA"}, | ||
673 | |||
674 | {"ADCL", NULL, "Left Input Mixer"}, | ||
675 | {"ADCR", NULL, "Right Input Mixer"}, | ||
676 | |||
677 | /* Outputs */ | ||
678 | {"LINEOUT1L", NULL, "LINEOUT1L PGA"}, | ||
679 | {"LINEOUT1L PGA", NULL, "Left Output Mixer"}, | ||
680 | {"LINEOUT1R", NULL, "LINEOUT1R PGA"}, | ||
681 | {"LINEOUT1R PGA", NULL, "Right Output Mixer"}, | ||
682 | |||
683 | {"LINEOUT2L PGA", NULL, "Left Output Mixer"}, | ||
684 | {"LINEOUT2 LP", "Disabled", "LINEOUT2L PGA"}, | ||
685 | {"LINEOUT2 LP", "Enabled", "Left Output Mixer"}, | ||
686 | {"LINEOUT2L", NULL, "LINEOUT2 LP"}, | ||
687 | |||
688 | {"LINEOUT2R PGA", NULL, "Right Output Mixer"}, | ||
689 | {"LINEOUT2 LP", "Disabled", "LINEOUT2R PGA"}, | ||
690 | {"LINEOUT2 LP", "Enabled", "Right Output Mixer"}, | ||
691 | {"LINEOUT2R", NULL, "LINEOUT2 LP"}, | ||
692 | |||
693 | {"Left Output Mixer", "LINPUT3 Bypass Switch", "LINPUT3"}, | ||
694 | {"Left Output Mixer", "AUX Bypass Switch", "AUX"}, | ||
695 | {"Left Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, | ||
696 | {"Left Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, | ||
697 | {"Left Output Mixer", "DACL Switch", "DACL"}, | ||
698 | |||
699 | {"Right Output Mixer", "RINPUT3 Bypass Switch", "RINPUT3"}, | ||
700 | {"Right Output Mixer", "AUX Bypass Switch", "AUX"}, | ||
701 | {"Right Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, | ||
702 | {"Right Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, | ||
703 | {"Right Output Mixer", "DACR Switch", "DACR"}, | ||
704 | |||
705 | /* Note that the headphone output stage needs to be connected | ||
706 | * externally to LINEOUT2 via DC blocking capacitors. Other | ||
707 | * configurations are not supported. | ||
708 | * | ||
709 | * Note also that left and right headphone paths are treated as a | ||
710 | * mono path. | ||
711 | */ | ||
712 | {"Headphone Amplifier", NULL, "LINEOUT2 LP"}, | ||
713 | {"Headphone Amplifier", NULL, "LINEOUT2 LP"}, | ||
714 | {"HP_L", NULL, "Headphone Amplifier"}, | ||
715 | {"HP_R", NULL, "Headphone Amplifier"}, | ||
716 | }; | ||
717 | |||
718 | static int wm8900_add_widgets(struct snd_soc_codec *codec) | ||
719 | { | ||
720 | snd_soc_dapm_new_controls(codec, wm8900_dapm_widgets, | ||
721 | ARRAY_SIZE(wm8900_dapm_widgets)); | ||
722 | |||
723 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
724 | |||
725 | snd_soc_dapm_new_widgets(codec); | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static int wm8900_hw_params(struct snd_pcm_substream *substream, | ||
731 | struct snd_pcm_hw_params *params) | ||
732 | { | ||
733 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
734 | struct snd_soc_device *socdev = rtd->socdev; | ||
735 | struct snd_soc_codec *codec = socdev->codec; | ||
736 | u16 reg; | ||
737 | |||
738 | reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60; | ||
739 | |||
740 | switch (params_format(params)) { | ||
741 | case SNDRV_PCM_FORMAT_S16_LE: | ||
742 | break; | ||
743 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
744 | reg |= 0x20; | ||
745 | break; | ||
746 | case SNDRV_PCM_FORMAT_S24_LE: | ||
747 | reg |= 0x40; | ||
748 | break; | ||
749 | case SNDRV_PCM_FORMAT_S32_LE: | ||
750 | reg |= 0x60; | ||
751 | break; | ||
752 | default: | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | |||
756 | wm8900_write(codec, WM8900_REG_AUDIO1, reg); | ||
757 | |||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | /* FLL divisors */ | ||
762 | struct _fll_div { | ||
763 | u16 fll_ratio; | ||
764 | u16 fllclk_div; | ||
765 | u16 fll_slow_lock_ref; | ||
766 | u16 n; | ||
767 | u16 k; | ||
768 | }; | ||
769 | |||
770 | /* The size in bits of the FLL divide multiplied by 10 | ||
771 | * to allow rounding later */ | ||
772 | #define FIXED_FLL_SIZE ((1 << 16) * 10) | ||
773 | |||
774 | static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, | ||
775 | unsigned int Fout) | ||
776 | { | ||
777 | u64 Kpart; | ||
778 | unsigned int K, Ndiv, Nmod, target; | ||
779 | unsigned int div; | ||
780 | |||
781 | BUG_ON(!Fout); | ||
782 | |||
783 | /* The FLL must run at 90-100MHz which is then scaled down to | ||
784 | * the output value by FLLCLK_DIV. */ | ||
785 | target = Fout; | ||
786 | div = 1; | ||
787 | while (target < 90000000) { | ||
788 | div *= 2; | ||
789 | target *= 2; | ||
790 | } | ||
791 | |||
792 | if (target > 100000000) | ||
793 | printk(KERN_WARNING "wm8900: FLL rate %d out of range, Fref=%d" | ||
794 | " Fout=%d\n", target, Fref, Fout); | ||
795 | if (div > 32) { | ||
796 | printk(KERN_ERR "wm8900: Invalid FLL division rate %u, " | ||
797 | "Fref=%d, Fout=%d, target=%d\n", | ||
798 | div, Fref, Fout, target); | ||
799 | return -EINVAL; | ||
800 | } | ||
801 | |||
802 | fll_div->fllclk_div = div >> 2; | ||
803 | |||
804 | if (Fref < 48000) | ||
805 | fll_div->fll_slow_lock_ref = 1; | ||
806 | else | ||
807 | fll_div->fll_slow_lock_ref = 0; | ||
808 | |||
809 | Ndiv = target / Fref; | ||
810 | |||
811 | if (Fref < 1000000) | ||
812 | fll_div->fll_ratio = 8; | ||
813 | else | ||
814 | fll_div->fll_ratio = 1; | ||
815 | |||
816 | fll_div->n = Ndiv / fll_div->fll_ratio; | ||
817 | Nmod = (target / fll_div->fll_ratio) % Fref; | ||
818 | |||
819 | /* Calculate fractional part - scale up so we can round. */ | ||
820 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | ||
821 | |||
822 | do_div(Kpart, Fref); | ||
823 | |||
824 | K = Kpart & 0xFFFFFFFF; | ||
825 | |||
826 | if ((K % 10) >= 5) | ||
827 | K += 5; | ||
828 | |||
829 | /* Move down to proper range now rounding is done */ | ||
830 | fll_div->k = K / 10; | ||
831 | |||
832 | BUG_ON(target != Fout * (fll_div->fllclk_div << 2)); | ||
833 | BUG_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n); | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | static int wm8900_set_fll(struct snd_soc_codec *codec, | ||
839 | int fll_id, unsigned int freq_in, unsigned int freq_out) | ||
840 | { | ||
841 | struct wm8900_priv *wm8900 = codec->private_data; | ||
842 | struct _fll_div fll_div; | ||
843 | unsigned int reg; | ||
844 | |||
845 | if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out) | ||
846 | return 0; | ||
847 | |||
848 | /* The digital side should be disabled during any change. */ | ||
849 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
850 | wm8900_write(codec, WM8900_REG_POWER1, | ||
851 | reg & (~WM8900_REG_POWER1_FLL_ENA)); | ||
852 | |||
853 | /* Disable the FLL? */ | ||
854 | if (!freq_in || !freq_out) { | ||
855 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
856 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
857 | reg & (~WM8900_REG_CLOCKING1_MCLK_SRC)); | ||
858 | |||
859 | reg = wm8900_read(codec, WM8900_REG_FLLCTL1); | ||
860 | wm8900_write(codec, WM8900_REG_FLLCTL1, | ||
861 | reg & (~WM8900_REG_FLLCTL1_OSC_ENA)); | ||
862 | |||
863 | wm8900->fll_in = freq_in; | ||
864 | wm8900->fll_out = freq_out; | ||
865 | |||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | if (fll_factors(&fll_div, freq_in, freq_out) != 0) | ||
870 | goto reenable; | ||
871 | |||
872 | wm8900->fll_in = freq_in; | ||
873 | wm8900->fll_out = freq_out; | ||
874 | |||
875 | /* The osclilator *MUST* be enabled before we enable the | ||
876 | * digital circuit. */ | ||
877 | wm8900_write(codec, WM8900_REG_FLLCTL1, | ||
878 | fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA); | ||
879 | |||
880 | wm8900_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5); | ||
881 | wm8900_write(codec, WM8900_REG_FLLCTL5, | ||
882 | (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f)); | ||
883 | |||
884 | if (fll_div.k) { | ||
885 | wm8900_write(codec, WM8900_REG_FLLCTL2, | ||
886 | (fll_div.k >> 8) | 0x100); | ||
887 | wm8900_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff); | ||
888 | } else | ||
889 | wm8900_write(codec, WM8900_REG_FLLCTL2, 0); | ||
890 | |||
891 | if (fll_div.fll_slow_lock_ref) | ||
892 | wm8900_write(codec, WM8900_REG_FLLCTL6, | ||
893 | WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF); | ||
894 | else | ||
895 | wm8900_write(codec, WM8900_REG_FLLCTL6, 0); | ||
896 | |||
897 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
898 | wm8900_write(codec, WM8900_REG_POWER1, | ||
899 | reg | WM8900_REG_POWER1_FLL_ENA); | ||
900 | |||
901 | reenable: | ||
902 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
903 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
904 | reg | WM8900_REG_CLOCKING1_MCLK_SRC); | ||
905 | |||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
910 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
911 | { | ||
912 | return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); | ||
913 | } | ||
914 | |||
915 | static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
916 | int div_id, int div) | ||
917 | { | ||
918 | struct snd_soc_codec *codec = codec_dai->codec; | ||
919 | unsigned int reg; | ||
920 | |||
921 | switch (div_id) { | ||
922 | case WM8900_BCLK_DIV: | ||
923 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
924 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
925 | div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK)); | ||
926 | break; | ||
927 | case WM8900_OPCLK_DIV: | ||
928 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
929 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
930 | div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK)); | ||
931 | break; | ||
932 | case WM8900_DAC_LRCLK: | ||
933 | reg = wm8900_read(codec, WM8900_REG_AUDIO4); | ||
934 | wm8900_write(codec, WM8900_REG_AUDIO4, | ||
935 | div | (reg & WM8900_LRC_MASK)); | ||
936 | break; | ||
937 | case WM8900_ADC_LRCLK: | ||
938 | reg = wm8900_read(codec, WM8900_REG_AUDIO3); | ||
939 | wm8900_write(codec, WM8900_REG_AUDIO3, | ||
940 | div | (reg & WM8900_LRC_MASK)); | ||
941 | break; | ||
942 | case WM8900_DAC_CLKDIV: | ||
943 | reg = wm8900_read(codec, WM8900_REG_CLOCKING2); | ||
944 | wm8900_write(codec, WM8900_REG_CLOCKING2, | ||
945 | div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV)); | ||
946 | break; | ||
947 | case WM8900_ADC_CLKDIV: | ||
948 | reg = wm8900_read(codec, WM8900_REG_CLOCKING2); | ||
949 | wm8900_write(codec, WM8900_REG_CLOCKING2, | ||
950 | div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV)); | ||
951 | break; | ||
952 | case WM8900_LRCLK_MODE: | ||
953 | reg = wm8900_read(codec, WM8900_REG_DACCTRL); | ||
954 | wm8900_write(codec, WM8900_REG_DACCTRL, | ||
955 | div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE)); | ||
956 | break; | ||
957 | default: | ||
958 | return -EINVAL; | ||
959 | } | ||
960 | |||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | |||
965 | static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
966 | unsigned int fmt) | ||
967 | { | ||
968 | struct snd_soc_codec *codec = codec_dai->codec; | ||
969 | unsigned int clocking1, aif1, aif3, aif4; | ||
970 | |||
971 | clocking1 = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
972 | aif1 = wm8900_read(codec, WM8900_REG_AUDIO1); | ||
973 | aif3 = wm8900_read(codec, WM8900_REG_AUDIO3); | ||
974 | aif4 = wm8900_read(codec, WM8900_REG_AUDIO4); | ||
975 | |||
976 | /* set master/slave audio interface */ | ||
977 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
978 | case SND_SOC_DAIFMT_CBS_CFS: | ||
979 | clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR; | ||
980 | aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
981 | aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR; | ||
982 | break; | ||
983 | case SND_SOC_DAIFMT_CBS_CFM: | ||
984 | clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR; | ||
985 | aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
986 | aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR; | ||
987 | break; | ||
988 | case SND_SOC_DAIFMT_CBM_CFM: | ||
989 | clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR; | ||
990 | aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
991 | aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR; | ||
992 | break; | ||
993 | case SND_SOC_DAIFMT_CBM_CFS: | ||
994 | clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR; | ||
995 | aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
996 | aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR; | ||
997 | break; | ||
998 | default: | ||
999 | return -EINVAL; | ||
1000 | } | ||
1001 | |||
1002 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1003 | case SND_SOC_DAIFMT_DSP_A: | ||
1004 | aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1005 | aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV; | ||
1006 | break; | ||
1007 | case SND_SOC_DAIFMT_DSP_B: | ||
1008 | aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1009 | aif1 |= WM8900_REG_AUDIO1_LRCLK_INV; | ||
1010 | break; | ||
1011 | case SND_SOC_DAIFMT_I2S: | ||
1012 | aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1013 | aif1 |= 0x10; | ||
1014 | break; | ||
1015 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1016 | aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1017 | break; | ||
1018 | case SND_SOC_DAIFMT_LEFT_J: | ||
1019 | aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1020 | aif1 |= 0x8; | ||
1021 | break; | ||
1022 | default: | ||
1023 | return -EINVAL; | ||
1024 | } | ||
1025 | |||
1026 | /* Clock inversion */ | ||
1027 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1028 | case SND_SOC_DAIFMT_DSP_A: | ||
1029 | case SND_SOC_DAIFMT_DSP_B: | ||
1030 | /* frame inversion not valid for DSP modes */ | ||
1031 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1032 | case SND_SOC_DAIFMT_NB_NF: | ||
1033 | aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV; | ||
1034 | break; | ||
1035 | case SND_SOC_DAIFMT_IB_NF: | ||
1036 | aif1 |= WM8900_REG_AUDIO1_BCLK_INV; | ||
1037 | break; | ||
1038 | default: | ||
1039 | return -EINVAL; | ||
1040 | } | ||
1041 | break; | ||
1042 | case SND_SOC_DAIFMT_I2S: | ||
1043 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1044 | case SND_SOC_DAIFMT_LEFT_J: | ||
1045 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1046 | case SND_SOC_DAIFMT_NB_NF: | ||
1047 | aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV; | ||
1048 | aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV; | ||
1049 | break; | ||
1050 | case SND_SOC_DAIFMT_IB_IF: | ||
1051 | aif1 |= WM8900_REG_AUDIO1_BCLK_INV; | ||
1052 | aif1 |= WM8900_REG_AUDIO1_LRCLK_INV; | ||
1053 | break; | ||
1054 | case SND_SOC_DAIFMT_IB_NF: | ||
1055 | aif1 |= WM8900_REG_AUDIO1_BCLK_INV; | ||
1056 | aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV; | ||
1057 | break; | ||
1058 | case SND_SOC_DAIFMT_NB_IF: | ||
1059 | aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV; | ||
1060 | aif1 |= WM8900_REG_AUDIO1_LRCLK_INV; | ||
1061 | break; | ||
1062 | default: | ||
1063 | return -EINVAL; | ||
1064 | } | ||
1065 | break; | ||
1066 | default: | ||
1067 | return -EINVAL; | ||
1068 | } | ||
1069 | |||
1070 | wm8900_write(codec, WM8900_REG_CLOCKING1, clocking1); | ||
1071 | wm8900_write(codec, WM8900_REG_AUDIO1, aif1); | ||
1072 | wm8900_write(codec, WM8900_REG_AUDIO3, aif3); | ||
1073 | wm8900_write(codec, WM8900_REG_AUDIO4, aif4); | ||
1074 | |||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
1079 | { | ||
1080 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1081 | u16 reg; | ||
1082 | |||
1083 | reg = wm8900_read(codec, WM8900_REG_DACCTRL); | ||
1084 | |||
1085 | if (mute) | ||
1086 | reg |= WM8900_REG_DACCTRL_MUTE; | ||
1087 | else | ||
1088 | reg &= ~WM8900_REG_DACCTRL_MUTE; | ||
1089 | |||
1090 | wm8900_write(codec, WM8900_REG_DACCTRL, reg); | ||
1091 | |||
1092 | return 0; | ||
1093 | } | ||
1094 | |||
1095 | #define WM8900_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
1096 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
1097 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
1098 | |||
1099 | #define WM8900_PCM_FORMATS \ | ||
1100 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | ||
1101 | SNDRV_PCM_FORMAT_S24_LE) | ||
1102 | |||
1103 | struct snd_soc_dai wm8900_dai = { | ||
1104 | .name = "WM8900 HiFi", | ||
1105 | .playback = { | ||
1106 | .stream_name = "HiFi Playback", | ||
1107 | .channels_min = 1, | ||
1108 | .channels_max = 2, | ||
1109 | .rates = WM8900_RATES, | ||
1110 | .formats = WM8900_PCM_FORMATS, | ||
1111 | }, | ||
1112 | .capture = { | ||
1113 | .stream_name = "HiFi Capture", | ||
1114 | .channels_min = 1, | ||
1115 | .channels_max = 2, | ||
1116 | .rates = WM8900_RATES, | ||
1117 | .formats = WM8900_PCM_FORMATS, | ||
1118 | }, | ||
1119 | .ops = { | ||
1120 | .hw_params = wm8900_hw_params, | ||
1121 | }, | ||
1122 | .dai_ops = { | ||
1123 | .set_clkdiv = wm8900_set_dai_clkdiv, | ||
1124 | .set_pll = wm8900_set_dai_pll, | ||
1125 | .set_fmt = wm8900_set_dai_fmt, | ||
1126 | .digital_mute = wm8900_digital_mute, | ||
1127 | }, | ||
1128 | }; | ||
1129 | EXPORT_SYMBOL_GPL(wm8900_dai); | ||
1130 | |||
1131 | static int wm8900_set_bias_level(struct snd_soc_codec *codec, | ||
1132 | enum snd_soc_bias_level level) | ||
1133 | { | ||
1134 | u16 reg; | ||
1135 | |||
1136 | switch (level) { | ||
1137 | case SND_SOC_BIAS_ON: | ||
1138 | /* Enable thermal shutdown */ | ||
1139 | reg = wm8900_read(codec, WM8900_REG_GPIO); | ||
1140 | wm8900_write(codec, WM8900_REG_GPIO, | ||
1141 | reg | WM8900_REG_GPIO_TEMP_ENA); | ||
1142 | reg = wm8900_read(codec, WM8900_REG_ADDCTL); | ||
1143 | wm8900_write(codec, WM8900_REG_ADDCTL, | ||
1144 | reg | WM8900_REG_ADDCTL_TEMP_SD); | ||
1145 | break; | ||
1146 | |||
1147 | case SND_SOC_BIAS_PREPARE: | ||
1148 | break; | ||
1149 | |||
1150 | case SND_SOC_BIAS_STANDBY: | ||
1151 | /* Charge capacitors if initial power up */ | ||
1152 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
1153 | /* STARTUP_BIAS_ENA on */ | ||
1154 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1155 | WM8900_REG_POWER1_STARTUP_BIAS_ENA); | ||
1156 | |||
1157 | /* Startup bias mode */ | ||
1158 | wm8900_write(codec, WM8900_REG_ADDCTL, | ||
1159 | WM8900_REG_ADDCTL_BIAS_SRC | | ||
1160 | WM8900_REG_ADDCTL_VMID_SOFTST); | ||
1161 | |||
1162 | /* VMID 2x50k */ | ||
1163 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1164 | WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1); | ||
1165 | |||
1166 | /* Allow capacitors to charge */ | ||
1167 | schedule_timeout_interruptible(msecs_to_jiffies(400)); | ||
1168 | |||
1169 | /* Enable bias */ | ||
1170 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1171 | WM8900_REG_POWER1_STARTUP_BIAS_ENA | | ||
1172 | WM8900_REG_POWER1_BIAS_ENA | 0x1); | ||
1173 | |||
1174 | wm8900_write(codec, WM8900_REG_ADDCTL, 0); | ||
1175 | |||
1176 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1177 | WM8900_REG_POWER1_BIAS_ENA | 0x1); | ||
1178 | } | ||
1179 | |||
1180 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
1181 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1182 | (reg & WM8900_REG_POWER1_FLL_ENA) | | ||
1183 | WM8900_REG_POWER1_BIAS_ENA | 0x1); | ||
1184 | wm8900_write(codec, WM8900_REG_POWER2, | ||
1185 | WM8900_REG_POWER2_SYSCLK_ENA); | ||
1186 | wm8900_write(codec, WM8900_REG_POWER3, 0); | ||
1187 | break; | ||
1188 | |||
1189 | case SND_SOC_BIAS_OFF: | ||
1190 | /* Startup bias enable */ | ||
1191 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
1192 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1193 | reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA); | ||
1194 | wm8900_write(codec, WM8900_REG_ADDCTL, | ||
1195 | WM8900_REG_ADDCTL_BIAS_SRC | | ||
1196 | WM8900_REG_ADDCTL_VMID_SOFTST); | ||
1197 | |||
1198 | /* Discharge caps */ | ||
1199 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1200 | WM8900_REG_POWER1_STARTUP_BIAS_ENA); | ||
1201 | schedule_timeout_interruptible(msecs_to_jiffies(500)); | ||
1202 | |||
1203 | /* Remove clamp */ | ||
1204 | wm8900_write(codec, WM8900_REG_HPCTL1, 0); | ||
1205 | |||
1206 | /* Power down */ | ||
1207 | wm8900_write(codec, WM8900_REG_ADDCTL, 0); | ||
1208 | wm8900_write(codec, WM8900_REG_POWER1, 0); | ||
1209 | wm8900_write(codec, WM8900_REG_POWER2, 0); | ||
1210 | wm8900_write(codec, WM8900_REG_POWER3, 0); | ||
1211 | |||
1212 | /* Need to let things settle before stopping the clock | ||
1213 | * to ensure that restart works, see "Stopping the | ||
1214 | * master clock" in the datasheet. */ | ||
1215 | schedule_timeout_interruptible(msecs_to_jiffies(1)); | ||
1216 | wm8900_write(codec, WM8900_REG_POWER2, | ||
1217 | WM8900_REG_POWER2_SYSCLK_ENA); | ||
1218 | break; | ||
1219 | } | ||
1220 | codec->bias_level = level; | ||
1221 | return 0; | ||
1222 | } | ||
1223 | |||
1224 | static int wm8900_suspend(struct platform_device *pdev, pm_message_t state) | ||
1225 | { | ||
1226 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1227 | struct snd_soc_codec *codec = socdev->codec; | ||
1228 | struct wm8900_priv *wm8900 = codec->private_data; | ||
1229 | int fll_out = wm8900->fll_out; | ||
1230 | int fll_in = wm8900->fll_in; | ||
1231 | int ret; | ||
1232 | |||
1233 | /* Stop the FLL in an orderly fashion */ | ||
1234 | ret = wm8900_set_fll(codec, 0, 0, 0); | ||
1235 | if (ret != 0) { | ||
1236 | dev_err(&pdev->dev, "Failed to stop FLL\n"); | ||
1237 | return ret; | ||
1238 | } | ||
1239 | |||
1240 | wm8900->fll_out = fll_out; | ||
1241 | wm8900->fll_in = fll_in; | ||
1242 | |||
1243 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1244 | |||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | static int wm8900_resume(struct platform_device *pdev) | ||
1249 | { | ||
1250 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1251 | struct snd_soc_codec *codec = socdev->codec; | ||
1252 | struct wm8900_priv *wm8900 = codec->private_data; | ||
1253 | u16 *cache; | ||
1254 | int i, ret; | ||
1255 | |||
1256 | cache = kmemdup(codec->reg_cache, sizeof(wm8900_reg_defaults), | ||
1257 | GFP_KERNEL); | ||
1258 | |||
1259 | wm8900_reset(codec); | ||
1260 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1261 | |||
1262 | /* Restart the FLL? */ | ||
1263 | if (wm8900->fll_out) { | ||
1264 | int fll_out = wm8900->fll_out; | ||
1265 | int fll_in = wm8900->fll_in; | ||
1266 | |||
1267 | wm8900->fll_in = 0; | ||
1268 | wm8900->fll_out = 0; | ||
1269 | |||
1270 | ret = wm8900_set_fll(codec, 0, fll_in, fll_out); | ||
1271 | if (ret != 0) { | ||
1272 | dev_err(&pdev->dev, "Failed to restart FLL\n"); | ||
1273 | return ret; | ||
1274 | } | ||
1275 | } | ||
1276 | |||
1277 | if (cache) { | ||
1278 | for (i = 0; i < WM8900_MAXREG; i++) | ||
1279 | wm8900_write(codec, i, cache[i]); | ||
1280 | kfree(cache); | ||
1281 | } else | ||
1282 | dev_err(&pdev->dev, "Unable to allocate register cache\n"); | ||
1283 | |||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1287 | /* | ||
1288 | * initialise the WM8900 driver | ||
1289 | * register the mixer and dsp interfaces with the kernel | ||
1290 | */ | ||
1291 | static int wm8900_init(struct snd_soc_device *socdev) | ||
1292 | { | ||
1293 | struct snd_soc_codec *codec = socdev->codec; | ||
1294 | int ret = 0; | ||
1295 | unsigned int reg; | ||
1296 | struct i2c_client *i2c_client = socdev->codec->control_data; | ||
1297 | |||
1298 | codec->name = "WM8900"; | ||
1299 | codec->owner = THIS_MODULE; | ||
1300 | codec->read = wm8900_read; | ||
1301 | codec->write = wm8900_write; | ||
1302 | codec->dai = &wm8900_dai; | ||
1303 | codec->num_dai = 1; | ||
1304 | codec->reg_cache_size = WM8900_MAXREG; | ||
1305 | codec->reg_cache = kmemdup(wm8900_reg_defaults, | ||
1306 | sizeof(wm8900_reg_defaults), GFP_KERNEL); | ||
1307 | |||
1308 | if (codec->reg_cache == NULL) | ||
1309 | return -ENOMEM; | ||
1310 | |||
1311 | reg = wm8900_read(codec, WM8900_REG_ID); | ||
1312 | if (reg != 0x8900) { | ||
1313 | dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n", | ||
1314 | reg); | ||
1315 | return -ENODEV; | ||
1316 | } | ||
1317 | |||
1318 | codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); | ||
1319 | if (codec->private_data == NULL) { | ||
1320 | ret = -ENOMEM; | ||
1321 | goto priv_err; | ||
1322 | } | ||
1323 | |||
1324 | /* Read back from the chip */ | ||
1325 | reg = wm8900_chip_read(codec, WM8900_REG_POWER1); | ||
1326 | reg = (reg >> 12) & 0xf; | ||
1327 | dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg); | ||
1328 | |||
1329 | wm8900_reset(codec); | ||
1330 | |||
1331 | /* Latch the volume update bits */ | ||
1332 | wm8900_write(codec, WM8900_REG_LINVOL, | ||
1333 | wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); | ||
1334 | wm8900_write(codec, WM8900_REG_RINVOL, | ||
1335 | wm8900_read(codec, WM8900_REG_RINVOL) | 0x100); | ||
1336 | wm8900_write(codec, WM8900_REG_LOUT1CTL, | ||
1337 | wm8900_read(codec, WM8900_REG_LOUT1CTL) | 0x100); | ||
1338 | wm8900_write(codec, WM8900_REG_ROUT1CTL, | ||
1339 | wm8900_read(codec, WM8900_REG_ROUT1CTL) | 0x100); | ||
1340 | wm8900_write(codec, WM8900_REG_LOUT2CTL, | ||
1341 | wm8900_read(codec, WM8900_REG_LOUT2CTL) | 0x100); | ||
1342 | wm8900_write(codec, WM8900_REG_ROUT2CTL, | ||
1343 | wm8900_read(codec, WM8900_REG_ROUT2CTL) | 0x100); | ||
1344 | wm8900_write(codec, WM8900_REG_LDAC_DV, | ||
1345 | wm8900_read(codec, WM8900_REG_LDAC_DV) | 0x100); | ||
1346 | wm8900_write(codec, WM8900_REG_RDAC_DV, | ||
1347 | wm8900_read(codec, WM8900_REG_RDAC_DV) | 0x100); | ||
1348 | wm8900_write(codec, WM8900_REG_LADC_DV, | ||
1349 | wm8900_read(codec, WM8900_REG_LADC_DV) | 0x100); | ||
1350 | wm8900_write(codec, WM8900_REG_RADC_DV, | ||
1351 | wm8900_read(codec, WM8900_REG_RADC_DV) | 0x100); | ||
1352 | |||
1353 | /* Set the DAC and mixer output bias */ | ||
1354 | wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); | ||
1355 | |||
1356 | /* Register pcms */ | ||
1357 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1358 | if (ret < 0) { | ||
1359 | dev_err(&i2c_client->dev, "Failed to register new PCMs\n"); | ||
1360 | goto pcm_err; | ||
1361 | } | ||
1362 | |||
1363 | /* Turn the chip on */ | ||
1364 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1365 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1366 | |||
1367 | wm8900_add_controls(codec); | ||
1368 | wm8900_add_widgets(codec); | ||
1369 | |||
1370 | ret = snd_soc_register_card(socdev); | ||
1371 | if (ret < 0) { | ||
1372 | dev_err(&i2c_client->dev, "Failed to register card\n"); | ||
1373 | goto card_err; | ||
1374 | } | ||
1375 | return ret; | ||
1376 | |||
1377 | card_err: | ||
1378 | snd_soc_free_pcms(socdev); | ||
1379 | snd_soc_dapm_free(socdev); | ||
1380 | pcm_err: | ||
1381 | kfree(codec->reg_cache); | ||
1382 | priv_err: | ||
1383 | kfree(codec->private_data); | ||
1384 | return ret; | ||
1385 | } | ||
1386 | |||
1387 | static struct snd_soc_device *wm8900_socdev; | ||
1388 | |||
1389 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1390 | |||
1391 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1392 | |||
1393 | /* Magic definition of all other variables and things */ | ||
1394 | I2C_CLIENT_INSMOD; | ||
1395 | |||
1396 | static struct i2c_driver wm8900_i2c_driver; | ||
1397 | static struct i2c_client client_template; | ||
1398 | |||
1399 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
1400 | around */ | ||
1401 | static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1402 | { | ||
1403 | struct snd_soc_device *socdev = wm8900_socdev; | ||
1404 | struct wm8900_setup_data *setup = socdev->codec_data; | ||
1405 | struct snd_soc_codec *codec = socdev->codec; | ||
1406 | struct i2c_client *i2c; | ||
1407 | int ret; | ||
1408 | |||
1409 | if (addr != setup->i2c_address) | ||
1410 | return -ENODEV; | ||
1411 | |||
1412 | dev_err(&adap->dev, "Probe on %x\n", addr); | ||
1413 | |||
1414 | client_template.adapter = adap; | ||
1415 | client_template.addr = addr; | ||
1416 | |||
1417 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1418 | if (i2c == NULL) { | ||
1419 | kfree(codec); | ||
1420 | return -ENOMEM; | ||
1421 | } | ||
1422 | i2c_set_clientdata(i2c, codec); | ||
1423 | codec->control_data = i2c; | ||
1424 | |||
1425 | ret = i2c_attach_client(i2c); | ||
1426 | if (ret < 0) { | ||
1427 | dev_err(&adap->dev, | ||
1428 | "failed to attach codec at addr %x\n", addr); | ||
1429 | goto err; | ||
1430 | } | ||
1431 | |||
1432 | ret = wm8900_init(socdev); | ||
1433 | if (ret < 0) { | ||
1434 | dev_err(&adap->dev, "failed to initialise WM8900\n"); | ||
1435 | goto err; | ||
1436 | } | ||
1437 | return ret; | ||
1438 | |||
1439 | err: | ||
1440 | kfree(codec); | ||
1441 | kfree(i2c); | ||
1442 | return ret; | ||
1443 | } | ||
1444 | |||
1445 | static int wm8900_i2c_detach(struct i2c_client *client) | ||
1446 | { | ||
1447 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
1448 | i2c_detach_client(client); | ||
1449 | kfree(codec->reg_cache); | ||
1450 | kfree(client); | ||
1451 | return 0; | ||
1452 | } | ||
1453 | |||
1454 | static int wm8900_i2c_attach(struct i2c_adapter *adap) | ||
1455 | { | ||
1456 | return i2c_probe(adap, &addr_data, wm8900_codec_probe); | ||
1457 | } | ||
1458 | |||
1459 | /* corgi i2c codec control layer */ | ||
1460 | static struct i2c_driver wm8900_i2c_driver = { | ||
1461 | .driver = { | ||
1462 | .name = "WM8900 I2C codec", | ||
1463 | .owner = THIS_MODULE, | ||
1464 | }, | ||
1465 | .attach_adapter = wm8900_i2c_attach, | ||
1466 | .detach_client = wm8900_i2c_detach, | ||
1467 | .command = NULL, | ||
1468 | }; | ||
1469 | |||
1470 | static struct i2c_client client_template = { | ||
1471 | .name = "WM8900", | ||
1472 | .driver = &wm8900_i2c_driver, | ||
1473 | }; | ||
1474 | #endif | ||
1475 | |||
1476 | static int wm8900_probe(struct platform_device *pdev) | ||
1477 | { | ||
1478 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1479 | struct wm8900_setup_data *setup; | ||
1480 | struct snd_soc_codec *codec; | ||
1481 | int ret = 0; | ||
1482 | |||
1483 | dev_info(&pdev->dev, "WM8900 Audio Codec\n"); | ||
1484 | |||
1485 | setup = socdev->codec_data; | ||
1486 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1487 | if (codec == NULL) | ||
1488 | return -ENOMEM; | ||
1489 | |||
1490 | mutex_init(&codec->mutex); | ||
1491 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1492 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1493 | |||
1494 | socdev->codec = codec; | ||
1495 | |||
1496 | codec->set_bias_level = wm8900_set_bias_level; | ||
1497 | |||
1498 | wm8900_socdev = socdev; | ||
1499 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1500 | if (setup->i2c_address) { | ||
1501 | normal_i2c[0] = setup->i2c_address; | ||
1502 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1503 | ret = i2c_add_driver(&wm8900_i2c_driver); | ||
1504 | if (ret != 0) | ||
1505 | printk(KERN_ERR "can't add i2c driver"); | ||
1506 | } | ||
1507 | #else | ||
1508 | #error Non-I2C interfaces not yet supported | ||
1509 | #endif | ||
1510 | return ret; | ||
1511 | } | ||
1512 | |||
1513 | /* power down chip */ | ||
1514 | static int wm8900_remove(struct platform_device *pdev) | ||
1515 | { | ||
1516 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1517 | struct snd_soc_codec *codec = socdev->codec; | ||
1518 | |||
1519 | if (codec->control_data) | ||
1520 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1521 | |||
1522 | snd_soc_free_pcms(socdev); | ||
1523 | snd_soc_dapm_free(socdev); | ||
1524 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1525 | i2c_del_driver(&wm8900_i2c_driver); | ||
1526 | #endif | ||
1527 | kfree(codec); | ||
1528 | |||
1529 | return 0; | ||
1530 | } | ||
1531 | |||
1532 | struct snd_soc_codec_device soc_codec_dev_wm8900 = { | ||
1533 | .probe = wm8900_probe, | ||
1534 | .remove = wm8900_remove, | ||
1535 | .suspend = wm8900_suspend, | ||
1536 | .resume = wm8900_resume, | ||
1537 | }; | ||
1538 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); | ||
1539 | |||
1540 | MODULE_DESCRIPTION("ASoC WM8900 driver"); | ||
1541 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); | ||
1542 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h new file mode 100644 index 00000000000..ba450d99e90 --- /dev/null +++ b/sound/soc/codecs/wm8900.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * wm8900.h -- WM890 Soc Audio driver | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _WM8900_H | ||
10 | #define _WM8900_H | ||
11 | |||
12 | #define WM8900_FLL 1 | ||
13 | |||
14 | #define WM8900_BCLK_DIV 1 | ||
15 | #define WM8900_ADC_CLKDIV 2 | ||
16 | #define WM8900_DAC_CLKDIV 3 | ||
17 | #define WM8900_ADC_LRCLK 4 | ||
18 | #define WM8900_DAC_LRCLK 5 | ||
19 | #define WM8900_OPCLK_DIV 6 | ||
20 | #define WM8900_LRCLK_MODE 7 | ||
21 | |||
22 | #define WM8900_BCLK_DIV_1 0x00 | ||
23 | #define WM8900_BCLK_DIV_1_5 0x02 | ||
24 | #define WM8900_BCLK_DIV_2 0x04 | ||
25 | #define WM8900_BCLK_DIV_3 0x06 | ||
26 | #define WM8900_BCLK_DIV_4 0x08 | ||
27 | #define WM8900_BCLK_DIV_5_5 0x0a | ||
28 | #define WM8900_BCLK_DIV_6 0x0c | ||
29 | #define WM8900_BCLK_DIV_8 0x0e | ||
30 | #define WM8900_BCLK_DIV_11 0x10 | ||
31 | #define WM8900_BCLK_DIV_12 0x12 | ||
32 | #define WM8900_BCLK_DIV_16 0x14 | ||
33 | #define WM8900_BCLK_DIV_22 0x16 | ||
34 | #define WM8900_BCLK_DIV_24 0x18 | ||
35 | #define WM8900_BCLK_DIV_32 0x1a | ||
36 | #define WM8900_BCLK_DIV_44 0x1c | ||
37 | #define WM8900_BCLK_DIV_48 0x1e | ||
38 | |||
39 | #define WM8900_ADC_CLKDIV_1 0x00 | ||
40 | #define WM8900_ADC_CLKDIV_1_5 0x20 | ||
41 | #define WM8900_ADC_CLKDIV_2 0x40 | ||
42 | #define WM8900_ADC_CLKDIV_3 0x60 | ||
43 | #define WM8900_ADC_CLKDIV_4 0x80 | ||
44 | #define WM8900_ADC_CLKDIV_5_5 0xa0 | ||
45 | #define WM8900_ADC_CLKDIV_6 0xc0 | ||
46 | |||
47 | #define WM8900_DAC_CLKDIV_1 0x00 | ||
48 | #define WM8900_DAC_CLKDIV_1_5 0x04 | ||
49 | #define WM8900_DAC_CLKDIV_2 0x08 | ||
50 | #define WM8900_DAC_CLKDIV_3 0x0c | ||
51 | #define WM8900_DAC_CLKDIV_4 0x10 | ||
52 | #define WM8900_DAC_CLKDIV_5_5 0x14 | ||
53 | #define WM8900_DAC_CLKDIV_6 0x18 | ||
54 | |||
55 | #define WM8900_ | ||
56 | |||
57 | struct wm8900_setup_data { | ||
58 | unsigned short i2c_address; | ||
59 | }; | ||
60 | |||
61 | extern struct snd_soc_dai wm8900_dai; | ||
62 | extern struct snd_soc_codec_device soc_codec_dev_wm8900; | ||
63 | |||
64 | #endif | ||
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c new file mode 100644 index 00000000000..a3f54ec4226 --- /dev/null +++ b/sound/soc/codecs/wm8903.c | |||
@@ -0,0 +1,1813 @@ | |||
1 | /* | ||
2 | * wm8903.c -- WM8903 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * TODO: | ||
13 | * - TDM mode configuration. | ||
14 | * - Mic detect. | ||
15 | * - Digital microphone support. | ||
16 | * - Interrupt support (mic detect and sequencer). | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/pm.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/pcm_params.h> | ||
29 | #include <sound/tlv.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | ||
32 | #include <sound/initval.h> | ||
33 | |||
34 | #include "wm8903.h" | ||
35 | |||
36 | struct wm8903_priv { | ||
37 | int sysclk; | ||
38 | |||
39 | /* Reference counts */ | ||
40 | int charge_pump_users; | ||
41 | int class_w_users; | ||
42 | int playback_active; | ||
43 | int capture_active; | ||
44 | |||
45 | struct snd_pcm_substream *master_substream; | ||
46 | struct snd_pcm_substream *slave_substream; | ||
47 | }; | ||
48 | |||
49 | /* Register defaults at reset */ | ||
50 | static u16 wm8903_reg_defaults[] = { | ||
51 | 0x8903, /* R0 - SW Reset and ID */ | ||
52 | 0x0000, /* R1 - Revision Number */ | ||
53 | 0x0000, /* R2 */ | ||
54 | 0x0000, /* R3 */ | ||
55 | 0x0018, /* R4 - Bias Control 0 */ | ||
56 | 0x0000, /* R5 - VMID Control 0 */ | ||
57 | 0x0000, /* R6 - Mic Bias Control 0 */ | ||
58 | 0x0000, /* R7 */ | ||
59 | 0x0001, /* R8 - Analogue DAC 0 */ | ||
60 | 0x0000, /* R9 */ | ||
61 | 0x0001, /* R10 - Analogue ADC 0 */ | ||
62 | 0x0000, /* R11 */ | ||
63 | 0x0000, /* R12 - Power Management 0 */ | ||
64 | 0x0000, /* R13 - Power Management 1 */ | ||
65 | 0x0000, /* R14 - Power Management 2 */ | ||
66 | 0x0000, /* R15 - Power Management 3 */ | ||
67 | 0x0000, /* R16 - Power Management 4 */ | ||
68 | 0x0000, /* R17 - Power Management 5 */ | ||
69 | 0x0000, /* R18 - Power Management 6 */ | ||
70 | 0x0000, /* R19 */ | ||
71 | 0x0400, /* R20 - Clock Rates 0 */ | ||
72 | 0x0D07, /* R21 - Clock Rates 1 */ | ||
73 | 0x0000, /* R22 - Clock Rates 2 */ | ||
74 | 0x0000, /* R23 */ | ||
75 | 0x0050, /* R24 - Audio Interface 0 */ | ||
76 | 0x0242, /* R25 - Audio Interface 1 */ | ||
77 | 0x0008, /* R26 - Audio Interface 2 */ | ||
78 | 0x0022, /* R27 - Audio Interface 3 */ | ||
79 | 0x0000, /* R28 */ | ||
80 | 0x0000, /* R29 */ | ||
81 | 0x00C0, /* R30 - DAC Digital Volume Left */ | ||
82 | 0x00C0, /* R31 - DAC Digital Volume Right */ | ||
83 | 0x0000, /* R32 - DAC Digital 0 */ | ||
84 | 0x0000, /* R33 - DAC Digital 1 */ | ||
85 | 0x0000, /* R34 */ | ||
86 | 0x0000, /* R35 */ | ||
87 | 0x00C0, /* R36 - ADC Digital Volume Left */ | ||
88 | 0x00C0, /* R37 - ADC Digital Volume Right */ | ||
89 | 0x0000, /* R38 - ADC Digital 0 */ | ||
90 | 0x0073, /* R39 - Digital Microphone 0 */ | ||
91 | 0x09BF, /* R40 - DRC 0 */ | ||
92 | 0x3241, /* R41 - DRC 1 */ | ||
93 | 0x0020, /* R42 - DRC 2 */ | ||
94 | 0x0000, /* R43 - DRC 3 */ | ||
95 | 0x0085, /* R44 - Analogue Left Input 0 */ | ||
96 | 0x0085, /* R45 - Analogue Right Input 0 */ | ||
97 | 0x0044, /* R46 - Analogue Left Input 1 */ | ||
98 | 0x0044, /* R47 - Analogue Right Input 1 */ | ||
99 | 0x0000, /* R48 */ | ||
100 | 0x0000, /* R49 */ | ||
101 | 0x0008, /* R50 - Analogue Left Mix 0 */ | ||
102 | 0x0004, /* R51 - Analogue Right Mix 0 */ | ||
103 | 0x0000, /* R52 - Analogue Spk Mix Left 0 */ | ||
104 | 0x0000, /* R53 - Analogue Spk Mix Left 1 */ | ||
105 | 0x0000, /* R54 - Analogue Spk Mix Right 0 */ | ||
106 | 0x0000, /* R55 - Analogue Spk Mix Right 1 */ | ||
107 | 0x0000, /* R56 */ | ||
108 | 0x002D, /* R57 - Analogue OUT1 Left */ | ||
109 | 0x002D, /* R58 - Analogue OUT1 Right */ | ||
110 | 0x0039, /* R59 - Analogue OUT2 Left */ | ||
111 | 0x0039, /* R60 - Analogue OUT2 Right */ | ||
112 | 0x0100, /* R61 */ | ||
113 | 0x0139, /* R62 - Analogue OUT3 Left */ | ||
114 | 0x0139, /* R63 - Analogue OUT3 Right */ | ||
115 | 0x0000, /* R64 */ | ||
116 | 0x0000, /* R65 - Analogue SPK Output Control 0 */ | ||
117 | 0x0000, /* R66 */ | ||
118 | 0x0010, /* R67 - DC Servo 0 */ | ||
119 | 0x0100, /* R68 */ | ||
120 | 0x00A4, /* R69 - DC Servo 2 */ | ||
121 | 0x0807, /* R70 */ | ||
122 | 0x0000, /* R71 */ | ||
123 | 0x0000, /* R72 */ | ||
124 | 0x0000, /* R73 */ | ||
125 | 0x0000, /* R74 */ | ||
126 | 0x0000, /* R75 */ | ||
127 | 0x0000, /* R76 */ | ||
128 | 0x0000, /* R77 */ | ||
129 | 0x0000, /* R78 */ | ||
130 | 0x000E, /* R79 */ | ||
131 | 0x0000, /* R80 */ | ||
132 | 0x0000, /* R81 */ | ||
133 | 0x0000, /* R82 */ | ||
134 | 0x0000, /* R83 */ | ||
135 | 0x0000, /* R84 */ | ||
136 | 0x0000, /* R85 */ | ||
137 | 0x0000, /* R86 */ | ||
138 | 0x0006, /* R87 */ | ||
139 | 0x0000, /* R88 */ | ||
140 | 0x0000, /* R89 */ | ||
141 | 0x0000, /* R90 - Analogue HP 0 */ | ||
142 | 0x0060, /* R91 */ | ||
143 | 0x0000, /* R92 */ | ||
144 | 0x0000, /* R93 */ | ||
145 | 0x0000, /* R94 - Analogue Lineout 0 */ | ||
146 | 0x0060, /* R95 */ | ||
147 | 0x0000, /* R96 */ | ||
148 | 0x0000, /* R97 */ | ||
149 | 0x0000, /* R98 - Charge Pump 0 */ | ||
150 | 0x1F25, /* R99 */ | ||
151 | 0x2B19, /* R100 */ | ||
152 | 0x01C0, /* R101 */ | ||
153 | 0x01EF, /* R102 */ | ||
154 | 0x2B00, /* R103 */ | ||
155 | 0x0000, /* R104 - Class W 0 */ | ||
156 | 0x01C0, /* R105 */ | ||
157 | 0x1C10, /* R106 */ | ||
158 | 0x0000, /* R107 */ | ||
159 | 0x0000, /* R108 - Write Sequencer 0 */ | ||
160 | 0x0000, /* R109 - Write Sequencer 1 */ | ||
161 | 0x0000, /* R110 - Write Sequencer 2 */ | ||
162 | 0x0000, /* R111 - Write Sequencer 3 */ | ||
163 | 0x0000, /* R112 - Write Sequencer 4 */ | ||
164 | 0x0000, /* R113 */ | ||
165 | 0x0000, /* R114 - Control Interface */ | ||
166 | 0x0000, /* R115 */ | ||
167 | 0x00A8, /* R116 - GPIO Control 1 */ | ||
168 | 0x00A8, /* R117 - GPIO Control 2 */ | ||
169 | 0x00A8, /* R118 - GPIO Control 3 */ | ||
170 | 0x0220, /* R119 - GPIO Control 4 */ | ||
171 | 0x01A0, /* R120 - GPIO Control 5 */ | ||
172 | 0x0000, /* R121 - Interrupt Status 1 */ | ||
173 | 0xFFFF, /* R122 - Interrupt Status 1 Mask */ | ||
174 | 0x0000, /* R123 - Interrupt Polarity 1 */ | ||
175 | 0x0000, /* R124 */ | ||
176 | 0x0003, /* R125 */ | ||
177 | 0x0000, /* R126 - Interrupt Control */ | ||
178 | 0x0000, /* R127 */ | ||
179 | 0x0005, /* R128 */ | ||
180 | 0x0000, /* R129 - Control Interface Test 1 */ | ||
181 | 0x0000, /* R130 */ | ||
182 | 0x0000, /* R131 */ | ||
183 | 0x0000, /* R132 */ | ||
184 | 0x0000, /* R133 */ | ||
185 | 0x0000, /* R134 */ | ||
186 | 0x03FF, /* R135 */ | ||
187 | 0x0007, /* R136 */ | ||
188 | 0x0040, /* R137 */ | ||
189 | 0x0000, /* R138 */ | ||
190 | 0x0000, /* R139 */ | ||
191 | 0x0000, /* R140 */ | ||
192 | 0x0000, /* R141 */ | ||
193 | 0x0000, /* R142 */ | ||
194 | 0x0000, /* R143 */ | ||
195 | 0x0000, /* R144 */ | ||
196 | 0x0000, /* R145 */ | ||
197 | 0x0000, /* R146 */ | ||
198 | 0x0000, /* R147 */ | ||
199 | 0x4000, /* R148 */ | ||
200 | 0x6810, /* R149 - Charge Pump Test 1 */ | ||
201 | 0x0004, /* R150 */ | ||
202 | 0x0000, /* R151 */ | ||
203 | 0x0000, /* R152 */ | ||
204 | 0x0000, /* R153 */ | ||
205 | 0x0000, /* R154 */ | ||
206 | 0x0000, /* R155 */ | ||
207 | 0x0000, /* R156 */ | ||
208 | 0x0000, /* R157 */ | ||
209 | 0x0000, /* R158 */ | ||
210 | 0x0000, /* R159 */ | ||
211 | 0x0000, /* R160 */ | ||
212 | 0x0000, /* R161 */ | ||
213 | 0x0000, /* R162 */ | ||
214 | 0x0000, /* R163 */ | ||
215 | 0x0028, /* R164 - Clock Rate Test 4 */ | ||
216 | 0x0004, /* R165 */ | ||
217 | 0x0000, /* R166 */ | ||
218 | 0x0060, /* R167 */ | ||
219 | 0x0000, /* R168 */ | ||
220 | 0x0000, /* R169 */ | ||
221 | 0x0000, /* R170 */ | ||
222 | 0x0000, /* R171 */ | ||
223 | 0x0000, /* R172 - Analogue Output Bias 0 */ | ||
224 | }; | ||
225 | |||
226 | static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec, | ||
227 | unsigned int reg) | ||
228 | { | ||
229 | u16 *cache = codec->reg_cache; | ||
230 | |||
231 | BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults)); | ||
232 | |||
233 | return cache[reg]; | ||
234 | } | ||
235 | |||
236 | static unsigned int wm8903_hw_read(struct snd_soc_codec *codec, u8 reg) | ||
237 | { | ||
238 | struct i2c_msg xfer[2]; | ||
239 | u16 data; | ||
240 | int ret; | ||
241 | struct i2c_client *client = codec->control_data; | ||
242 | |||
243 | /* Write register */ | ||
244 | xfer[0].addr = client->addr; | ||
245 | xfer[0].flags = 0; | ||
246 | xfer[0].len = 1; | ||
247 | xfer[0].buf = ® | ||
248 | |||
249 | /* Read data */ | ||
250 | xfer[1].addr = client->addr; | ||
251 | xfer[1].flags = I2C_M_RD; | ||
252 | xfer[1].len = 2; | ||
253 | xfer[1].buf = (u8 *)&data; | ||
254 | |||
255 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
256 | if (ret != 2) { | ||
257 | pr_err("i2c_transfer returned %d\n", ret); | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | return (data >> 8) | ((data & 0xff) << 8); | ||
262 | } | ||
263 | |||
264 | static unsigned int wm8903_read(struct snd_soc_codec *codec, | ||
265 | unsigned int reg) | ||
266 | { | ||
267 | switch (reg) { | ||
268 | case WM8903_SW_RESET_AND_ID: | ||
269 | case WM8903_REVISION_NUMBER: | ||
270 | case WM8903_INTERRUPT_STATUS_1: | ||
271 | case WM8903_WRITE_SEQUENCER_4: | ||
272 | return wm8903_hw_read(codec, reg); | ||
273 | |||
274 | default: | ||
275 | return wm8903_read_reg_cache(codec, reg); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | static void wm8903_write_reg_cache(struct snd_soc_codec *codec, | ||
280 | u16 reg, unsigned int value) | ||
281 | { | ||
282 | u16 *cache = codec->reg_cache; | ||
283 | |||
284 | BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults)); | ||
285 | |||
286 | switch (reg) { | ||
287 | case WM8903_SW_RESET_AND_ID: | ||
288 | case WM8903_REVISION_NUMBER: | ||
289 | break; | ||
290 | |||
291 | default: | ||
292 | cache[reg] = value; | ||
293 | break; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | static int wm8903_write(struct snd_soc_codec *codec, unsigned int reg, | ||
298 | unsigned int value) | ||
299 | { | ||
300 | u8 data[3]; | ||
301 | |||
302 | wm8903_write_reg_cache(codec, reg, value); | ||
303 | |||
304 | /* Data format is 1 byte of address followed by 2 bytes of data */ | ||
305 | data[0] = reg; | ||
306 | data[1] = (value >> 8) & 0xff; | ||
307 | data[2] = value & 0xff; | ||
308 | |||
309 | if (codec->hw_write(codec->control_data, data, 3) == 2) | ||
310 | return 0; | ||
311 | else | ||
312 | return -EIO; | ||
313 | } | ||
314 | |||
315 | static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) | ||
316 | { | ||
317 | u16 reg[5]; | ||
318 | struct i2c_client *i2c = codec->control_data; | ||
319 | |||
320 | BUG_ON(start > 48); | ||
321 | |||
322 | /* Enable the sequencer */ | ||
323 | reg[0] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_0); | ||
324 | reg[0] |= WM8903_WSEQ_ENA; | ||
325 | wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]); | ||
326 | |||
327 | dev_dbg(&i2c->dev, "Starting sequence at %d\n", start); | ||
328 | |||
329 | wm8903_write(codec, WM8903_WRITE_SEQUENCER_3, | ||
330 | start | WM8903_WSEQ_START); | ||
331 | |||
332 | /* Wait for it to complete. If we have the interrupt wired up then | ||
333 | * we could block waiting for an interrupt, though polling may still | ||
334 | * be desirable for diagnostic purposes. | ||
335 | */ | ||
336 | do { | ||
337 | msleep(10); | ||
338 | |||
339 | reg[4] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_4); | ||
340 | } while (reg[4] & WM8903_WSEQ_BUSY); | ||
341 | |||
342 | dev_dbg(&i2c->dev, "Sequence complete\n"); | ||
343 | |||
344 | /* Disable the sequencer again */ | ||
345 | wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, | ||
346 | reg[0] & ~WM8903_WSEQ_ENA); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache) | ||
352 | { | ||
353 | int i; | ||
354 | |||
355 | /* There really ought to be something better we can do here :/ */ | ||
356 | for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++) | ||
357 | cache[i] = wm8903_hw_read(codec, i); | ||
358 | } | ||
359 | |||
360 | static void wm8903_reset(struct snd_soc_codec *codec) | ||
361 | { | ||
362 | wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); | ||
363 | } | ||
364 | |||
365 | #define WM8903_OUTPUT_SHORT 0x8 | ||
366 | #define WM8903_OUTPUT_OUT 0x4 | ||
367 | #define WM8903_OUTPUT_INT 0x2 | ||
368 | #define WM8903_OUTPUT_IN 0x1 | ||
369 | |||
370 | /* | ||
371 | * Event for headphone and line out amplifier power changes. Special | ||
372 | * power up/down sequences are required in order to maximise pop/click | ||
373 | * performance. | ||
374 | */ | ||
375 | static int wm8903_output_event(struct snd_soc_dapm_widget *w, | ||
376 | struct snd_kcontrol *kcontrol, int event) | ||
377 | { | ||
378 | struct snd_soc_codec *codec = w->codec; | ||
379 | struct wm8903_priv *wm8903 = codec->private_data; | ||
380 | struct i2c_client *i2c = codec->control_data; | ||
381 | u16 val; | ||
382 | u16 reg; | ||
383 | int shift; | ||
384 | u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0); | ||
385 | |||
386 | switch (w->reg) { | ||
387 | case WM8903_POWER_MANAGEMENT_2: | ||
388 | reg = WM8903_ANALOGUE_HP_0; | ||
389 | break; | ||
390 | case WM8903_POWER_MANAGEMENT_3: | ||
391 | reg = WM8903_ANALOGUE_LINEOUT_0; | ||
392 | break; | ||
393 | default: | ||
394 | BUG(); | ||
395 | } | ||
396 | |||
397 | switch (w->shift) { | ||
398 | case 0: | ||
399 | shift = 0; | ||
400 | break; | ||
401 | case 1: | ||
402 | shift = 4; | ||
403 | break; | ||
404 | default: | ||
405 | BUG(); | ||
406 | } | ||
407 | |||
408 | if (event & SND_SOC_DAPM_PRE_PMU) { | ||
409 | val = wm8903_read(codec, reg); | ||
410 | |||
411 | /* Short the output */ | ||
412 | val &= ~(WM8903_OUTPUT_SHORT << shift); | ||
413 | wm8903_write(codec, reg, val); | ||
414 | |||
415 | wm8903->charge_pump_users++; | ||
416 | |||
417 | dev_dbg(&i2c->dev, "Charge pump use count now %d\n", | ||
418 | wm8903->charge_pump_users); | ||
419 | |||
420 | if (wm8903->charge_pump_users == 1) { | ||
421 | dev_dbg(&i2c->dev, "Enabling charge pump\n"); | ||
422 | wm8903_write(codec, WM8903_CHARGE_PUMP_0, | ||
423 | cp_reg | WM8903_CP_ENA); | ||
424 | mdelay(4); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | if (event & SND_SOC_DAPM_POST_PMU) { | ||
429 | val = wm8903_read(codec, reg); | ||
430 | |||
431 | val |= (WM8903_OUTPUT_IN << shift); | ||
432 | wm8903_write(codec, reg, val); | ||
433 | |||
434 | val |= (WM8903_OUTPUT_INT << shift); | ||
435 | wm8903_write(codec, reg, val); | ||
436 | |||
437 | /* Turn on the output ENA_OUTP */ | ||
438 | val |= (WM8903_OUTPUT_OUT << shift); | ||
439 | wm8903_write(codec, reg, val); | ||
440 | |||
441 | /* Remove the short */ | ||
442 | val |= (WM8903_OUTPUT_SHORT << shift); | ||
443 | wm8903_write(codec, reg, val); | ||
444 | } | ||
445 | |||
446 | if (event & SND_SOC_DAPM_PRE_PMD) { | ||
447 | val = wm8903_read(codec, reg); | ||
448 | |||
449 | /* Short the output */ | ||
450 | val &= ~(WM8903_OUTPUT_SHORT << shift); | ||
451 | wm8903_write(codec, reg, val); | ||
452 | |||
453 | /* Then disable the intermediate and output stages */ | ||
454 | val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT | | ||
455 | WM8903_OUTPUT_IN) << shift); | ||
456 | wm8903_write(codec, reg, val); | ||
457 | } | ||
458 | |||
459 | if (event & SND_SOC_DAPM_POST_PMD) { | ||
460 | wm8903->charge_pump_users--; | ||
461 | |||
462 | dev_dbg(&i2c->dev, "Charge pump use count now %d\n", | ||
463 | wm8903->charge_pump_users); | ||
464 | |||
465 | if (wm8903->charge_pump_users == 0) { | ||
466 | dev_dbg(&i2c->dev, "Disabling charge pump\n"); | ||
467 | wm8903_write(codec, WM8903_CHARGE_PUMP_0, | ||
468 | cp_reg & ~WM8903_CP_ENA); | ||
469 | } | ||
470 | } | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * When used with DAC outputs only the WM8903 charge pump supports | ||
477 | * operation in class W mode, providing very low power consumption | ||
478 | * when used with digital sources. Enable and disable this mode | ||
479 | * automatically depending on the mixer configuration. | ||
480 | * | ||
481 | * All the relevant controls are simple switches. | ||
482 | */ | ||
483 | static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, | ||
484 | struct snd_ctl_elem_value *ucontrol) | ||
485 | { | ||
486 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
487 | struct snd_soc_codec *codec = widget->codec; | ||
488 | struct wm8903_priv *wm8903 = codec->private_data; | ||
489 | struct i2c_client *i2c = codec->control_data; | ||
490 | u16 reg; | ||
491 | int ret; | ||
492 | |||
493 | reg = wm8903_read(codec, WM8903_CLASS_W_0); | ||
494 | |||
495 | /* Turn it off if we're about to enable bypass */ | ||
496 | if (ucontrol->value.integer.value[0]) { | ||
497 | if (wm8903->class_w_users == 0) { | ||
498 | dev_dbg(&i2c->dev, "Disabling Class W\n"); | ||
499 | wm8903_write(codec, WM8903_CLASS_W_0, reg & | ||
500 | ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V)); | ||
501 | } | ||
502 | wm8903->class_w_users++; | ||
503 | } | ||
504 | |||
505 | /* Implement the change */ | ||
506 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); | ||
507 | |||
508 | /* If we've just disabled the last bypass path turn Class W on */ | ||
509 | if (!ucontrol->value.integer.value[0]) { | ||
510 | if (wm8903->class_w_users == 1) { | ||
511 | dev_dbg(&i2c->dev, "Enabling Class W\n"); | ||
512 | wm8903_write(codec, WM8903_CLASS_W_0, reg | | ||
513 | WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); | ||
514 | } | ||
515 | wm8903->class_w_users--; | ||
516 | } | ||
517 | |||
518 | dev_dbg(&i2c->dev, "Bypass use count now %d\n", | ||
519 | wm8903->class_w_users); | ||
520 | |||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | #define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \ | ||
525 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
526 | .info = snd_soc_info_volsw, \ | ||
527 | .get = snd_soc_dapm_get_volsw, .put = wm8903_class_w_put, \ | ||
528 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
529 | |||
530 | |||
531 | /* ALSA can only do steps of .01dB */ | ||
532 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); | ||
533 | |||
534 | static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); | ||
535 | |||
536 | static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0); | ||
537 | static const DECLARE_TLV_DB_SCALE(drc_tlv_amp, -2250, 75, 0); | ||
538 | static const DECLARE_TLV_DB_SCALE(drc_tlv_min, 0, 600, 0); | ||
539 | static const DECLARE_TLV_DB_SCALE(drc_tlv_max, 1200, 600, 0); | ||
540 | static const DECLARE_TLV_DB_SCALE(drc_tlv_startup, -300, 50, 0); | ||
541 | |||
542 | static const char *drc_slope_text[] = { | ||
543 | "1", "1/2", "1/4", "1/8", "1/16", "0" | ||
544 | }; | ||
545 | |||
546 | static const struct soc_enum drc_slope_r0 = | ||
547 | SOC_ENUM_SINGLE(WM8903_DRC_2, 3, 6, drc_slope_text); | ||
548 | |||
549 | static const struct soc_enum drc_slope_r1 = | ||
550 | SOC_ENUM_SINGLE(WM8903_DRC_2, 0, 6, drc_slope_text); | ||
551 | |||
552 | static const char *drc_attack_text[] = { | ||
553 | "instantaneous", | ||
554 | "363us", "762us", "1.45ms", "2.9ms", "5.8ms", "11.6ms", "23.2ms", | ||
555 | "46.4ms", "92.8ms", "185.6ms" | ||
556 | }; | ||
557 | |||
558 | static const struct soc_enum drc_attack = | ||
559 | SOC_ENUM_SINGLE(WM8903_DRC_1, 12, 11, drc_attack_text); | ||
560 | |||
561 | static const char *drc_decay_text[] = { | ||
562 | "186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s", | ||
563 | "23.87s", "47.56s" | ||
564 | }; | ||
565 | |||
566 | static const struct soc_enum drc_decay = | ||
567 | SOC_ENUM_SINGLE(WM8903_DRC_1, 8, 9, drc_decay_text); | ||
568 | |||
569 | static const char *drc_ff_delay_text[] = { | ||
570 | "5 samples", "9 samples" | ||
571 | }; | ||
572 | |||
573 | static const struct soc_enum drc_ff_delay = | ||
574 | SOC_ENUM_SINGLE(WM8903_DRC_0, 5, 2, drc_ff_delay_text); | ||
575 | |||
576 | static const char *drc_qr_decay_text[] = { | ||
577 | "0.725ms", "1.45ms", "5.8ms" | ||
578 | }; | ||
579 | |||
580 | static const struct soc_enum drc_qr_decay = | ||
581 | SOC_ENUM_SINGLE(WM8903_DRC_1, 4, 3, drc_qr_decay_text); | ||
582 | |||
583 | static const char *drc_smoothing_text[] = { | ||
584 | "Low", "Medium", "High" | ||
585 | }; | ||
586 | |||
587 | static const struct soc_enum drc_smoothing = | ||
588 | SOC_ENUM_SINGLE(WM8903_DRC_0, 11, 3, drc_smoothing_text); | ||
589 | |||
590 | static const char *soft_mute_text[] = { | ||
591 | "Fast (fs/2)", "Slow (fs/32)" | ||
592 | }; | ||
593 | |||
594 | static const struct soc_enum soft_mute = | ||
595 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 10, 2, soft_mute_text); | ||
596 | |||
597 | static const char *mute_mode_text[] = { | ||
598 | "Hard", "Soft" | ||
599 | }; | ||
600 | |||
601 | static const struct soc_enum mute_mode = | ||
602 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text); | ||
603 | |||
604 | static const char *dac_deemphasis_text[] = { | ||
605 | "Disabled", "32kHz", "44.1kHz", "48kHz" | ||
606 | }; | ||
607 | |||
608 | static const struct soc_enum dac_deemphasis = | ||
609 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 1, 4, dac_deemphasis_text); | ||
610 | |||
611 | static const char *companding_text[] = { | ||
612 | "ulaw", "alaw" | ||
613 | }; | ||
614 | |||
615 | static const struct soc_enum dac_companding = | ||
616 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 0, 2, companding_text); | ||
617 | |||
618 | static const struct soc_enum adc_companding = | ||
619 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 2, 2, companding_text); | ||
620 | |||
621 | static const char *input_mode_text[] = { | ||
622 | "Single-Ended", "Differential Line", "Differential Mic" | ||
623 | }; | ||
624 | |||
625 | static const struct soc_enum linput_mode_enum = | ||
626 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); | ||
627 | |||
628 | static const struct soc_enum rinput_mode_enum = | ||
629 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); | ||
630 | |||
631 | static const char *linput_mux_text[] = { | ||
632 | "IN1L", "IN2L", "IN3L" | ||
633 | }; | ||
634 | |||
635 | static const struct soc_enum linput_enum = | ||
636 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 2, 3, linput_mux_text); | ||
637 | |||
638 | static const struct soc_enum linput_inv_enum = | ||
639 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 4, 3, linput_mux_text); | ||
640 | |||
641 | static const char *rinput_mux_text[] = { | ||
642 | "IN1R", "IN2R", "IN3R" | ||
643 | }; | ||
644 | |||
645 | static const struct soc_enum rinput_enum = | ||
646 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 2, 3, rinput_mux_text); | ||
647 | |||
648 | static const struct soc_enum rinput_inv_enum = | ||
649 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text); | ||
650 | |||
651 | |||
652 | static const struct snd_kcontrol_new wm8903_snd_controls[] = { | ||
653 | |||
654 | /* Input PGAs - No TLV since the scale depends on PGA mode */ | ||
655 | SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0, | ||
656 | 7, 1, 0), | ||
657 | SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0, | ||
658 | 0, 31, 0), | ||
659 | SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1, | ||
660 | 6, 1, 0), | ||
661 | |||
662 | SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0, | ||
663 | 7, 1, 0), | ||
664 | SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0, | ||
665 | 0, 31, 0), | ||
666 | SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1, | ||
667 | 6, 1, 0), | ||
668 | |||
669 | /* ADCs */ | ||
670 | SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0), | ||
671 | SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0), | ||
672 | SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1), | ||
673 | SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8903_DRC_3, 5, 124, 1, | ||
674 | drc_tlv_thresh), | ||
675 | SOC_SINGLE_TLV("DRC Volume", WM8903_DRC_3, 0, 30, 1, drc_tlv_amp), | ||
676 | SOC_SINGLE_TLV("DRC Minimum Gain Volume", WM8903_DRC_1, 2, 3, 1, drc_tlv_min), | ||
677 | SOC_SINGLE_TLV("DRC Maximum Gain Volume", WM8903_DRC_1, 0, 3, 0, drc_tlv_max), | ||
678 | SOC_ENUM("DRC Attack Rate", drc_attack), | ||
679 | SOC_ENUM("DRC Decay Rate", drc_decay), | ||
680 | SOC_ENUM("DRC FF Delay", drc_ff_delay), | ||
681 | SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0), | ||
682 | SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0), | ||
683 | SOC_SINGLE_TLV("DRC QR Threashold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max), | ||
684 | SOC_ENUM("DRC QR Decay Rate", drc_qr_decay), | ||
685 | SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0), | ||
686 | SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0), | ||
687 | SOC_ENUM("DRC Smoothing Threashold", drc_smoothing), | ||
688 | SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup), | ||
689 | |||
690 | SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT, | ||
691 | WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv), | ||
692 | SOC_ENUM("ADC Companding Mode", adc_companding), | ||
693 | SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0), | ||
694 | |||
695 | /* DAC */ | ||
696 | SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT, | ||
697 | WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv), | ||
698 | SOC_ENUM("DAC Soft Mute Rate", soft_mute), | ||
699 | SOC_ENUM("DAC Mute Mode", mute_mode), | ||
700 | SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0), | ||
701 | SOC_ENUM("DAC De-emphasis", dac_deemphasis), | ||
702 | SOC_SINGLE("DAC Sloping Stopband Filter Switch", | ||
703 | WM8903_DAC_DIGITAL_1, 11, 1, 0), | ||
704 | SOC_ENUM("DAC Companding Mode", dac_companding), | ||
705 | SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0), | ||
706 | |||
707 | /* Headphones */ | ||
708 | SOC_DOUBLE_R("Headphone Switch", | ||
709 | WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT, | ||
710 | 8, 1, 1), | ||
711 | SOC_DOUBLE_R("Headphone ZC Switch", | ||
712 | WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT, | ||
713 | 6, 1, 0), | ||
714 | SOC_DOUBLE_R_TLV("Headphone Volume", | ||
715 | WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT, | ||
716 | 0, 63, 0, out_tlv), | ||
717 | |||
718 | /* Line out */ | ||
719 | SOC_DOUBLE_R("Line Out Switch", | ||
720 | WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT, | ||
721 | 8, 1, 1), | ||
722 | SOC_DOUBLE_R("Line Out ZC Switch", | ||
723 | WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT, | ||
724 | 6, 1, 0), | ||
725 | SOC_DOUBLE_R_TLV("Line Out Volume", | ||
726 | WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT, | ||
727 | 0, 63, 0, out_tlv), | ||
728 | |||
729 | /* Speaker */ | ||
730 | SOC_DOUBLE_R("Speaker Switch", | ||
731 | WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 8, 1, 1), | ||
732 | SOC_DOUBLE_R("Speaker ZC Switch", | ||
733 | WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 6, 1, 0), | ||
734 | SOC_DOUBLE_R_TLV("Speaker Volume", | ||
735 | WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, | ||
736 | 0, 63, 0, out_tlv), | ||
737 | }; | ||
738 | |||
739 | static int wm8903_add_controls(struct snd_soc_codec *codec) | ||
740 | { | ||
741 | int err, i; | ||
742 | |||
743 | for (i = 0; i < ARRAY_SIZE(wm8903_snd_controls); i++) { | ||
744 | err = snd_ctl_add(codec->card, | ||
745 | snd_soc_cnew(&wm8903_snd_controls[i], | ||
746 | codec, NULL)); | ||
747 | if (err < 0) | ||
748 | return err; | ||
749 | } | ||
750 | |||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | static const struct snd_kcontrol_new linput_mode_mux = | ||
755 | SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum); | ||
756 | |||
757 | static const struct snd_kcontrol_new rinput_mode_mux = | ||
758 | SOC_DAPM_ENUM("Right Input Mode Mux", rinput_mode_enum); | ||
759 | |||
760 | static const struct snd_kcontrol_new linput_mux = | ||
761 | SOC_DAPM_ENUM("Left Input Mux", linput_enum); | ||
762 | |||
763 | static const struct snd_kcontrol_new linput_inv_mux = | ||
764 | SOC_DAPM_ENUM("Left Inverting Input Mux", linput_inv_enum); | ||
765 | |||
766 | static const struct snd_kcontrol_new rinput_mux = | ||
767 | SOC_DAPM_ENUM("Right Input Mux", rinput_enum); | ||
768 | |||
769 | static const struct snd_kcontrol_new rinput_inv_mux = | ||
770 | SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum); | ||
771 | |||
772 | static const struct snd_kcontrol_new left_output_mixer[] = { | ||
773 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), | ||
774 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), | ||
775 | SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), | ||
776 | SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), | ||
777 | }; | ||
778 | |||
779 | static const struct snd_kcontrol_new right_output_mixer[] = { | ||
780 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0), | ||
781 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0), | ||
782 | SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), | ||
783 | SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), | ||
784 | }; | ||
785 | |||
786 | static const struct snd_kcontrol_new left_speaker_mixer[] = { | ||
787 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0), | ||
788 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0), | ||
789 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0), | ||
790 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, | ||
791 | 1, 1, 0), | ||
792 | }; | ||
793 | |||
794 | static const struct snd_kcontrol_new right_speaker_mixer[] = { | ||
795 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 3, 1, 0), | ||
796 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0), | ||
797 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, | ||
798 | 1, 1, 0), | ||
799 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, | ||
800 | 1, 1, 0), | ||
801 | }; | ||
802 | |||
803 | static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = { | ||
804 | SND_SOC_DAPM_INPUT("IN1L"), | ||
805 | SND_SOC_DAPM_INPUT("IN1R"), | ||
806 | SND_SOC_DAPM_INPUT("IN2L"), | ||
807 | SND_SOC_DAPM_INPUT("IN2R"), | ||
808 | SND_SOC_DAPM_INPUT("IN3L"), | ||
809 | SND_SOC_DAPM_INPUT("IN3R"), | ||
810 | |||
811 | SND_SOC_DAPM_OUTPUT("HPOUTL"), | ||
812 | SND_SOC_DAPM_OUTPUT("HPOUTR"), | ||
813 | SND_SOC_DAPM_OUTPUT("LINEOUTL"), | ||
814 | SND_SOC_DAPM_OUTPUT("LINEOUTR"), | ||
815 | SND_SOC_DAPM_OUTPUT("LOP"), | ||
816 | SND_SOC_DAPM_OUTPUT("LON"), | ||
817 | SND_SOC_DAPM_OUTPUT("ROP"), | ||
818 | SND_SOC_DAPM_OUTPUT("RON"), | ||
819 | |||
820 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8903_MIC_BIAS_CONTROL_0, 0, 0), | ||
821 | |||
822 | SND_SOC_DAPM_MUX("Left Input Mux", SND_SOC_NOPM, 0, 0, &linput_mux), | ||
823 | SND_SOC_DAPM_MUX("Left Input Inverting Mux", SND_SOC_NOPM, 0, 0, | ||
824 | &linput_inv_mux), | ||
825 | SND_SOC_DAPM_MUX("Left Input Mode Mux", SND_SOC_NOPM, 0, 0, &linput_mode_mux), | ||
826 | |||
827 | SND_SOC_DAPM_MUX("Right Input Mux", SND_SOC_NOPM, 0, 0, &rinput_mux), | ||
828 | SND_SOC_DAPM_MUX("Right Input Inverting Mux", SND_SOC_NOPM, 0, 0, | ||
829 | &rinput_inv_mux), | ||
830 | SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux), | ||
831 | |||
832 | SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0), | ||
833 | SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0), | ||
834 | |||
835 | SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0), | ||
836 | SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0), | ||
837 | |||
838 | SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0), | ||
839 | SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0), | ||
840 | |||
841 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8903_POWER_MANAGEMENT_1, 1, 0, | ||
842 | left_output_mixer, ARRAY_SIZE(left_output_mixer)), | ||
843 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8903_POWER_MANAGEMENT_1, 0, 0, | ||
844 | right_output_mixer, ARRAY_SIZE(right_output_mixer)), | ||
845 | |||
846 | SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0, | ||
847 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), | ||
848 | SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0, | ||
849 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), | ||
850 | |||
851 | SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, | ||
852 | 1, 0, NULL, 0, wm8903_output_event, | ||
853 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
854 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
855 | SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, | ||
856 | 0, 0, NULL, 0, wm8903_output_event, | ||
857 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
858 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
859 | |||
860 | SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0, | ||
861 | NULL, 0, wm8903_output_event, | ||
862 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
863 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
864 | SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0, | ||
865 | NULL, 0, wm8903_output_event, | ||
866 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
867 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
868 | |||
869 | SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0, | ||
870 | NULL, 0), | ||
871 | SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0, | ||
872 | NULL, 0), | ||
873 | |||
874 | }; | ||
875 | |||
876 | static const struct snd_soc_dapm_route intercon[] = { | ||
877 | |||
878 | { "Left Input Mux", "IN1L", "IN1L" }, | ||
879 | { "Left Input Mux", "IN2L", "IN2L" }, | ||
880 | { "Left Input Mux", "IN3L", "IN3L" }, | ||
881 | |||
882 | { "Left Input Inverting Mux", "IN1L", "IN1L" }, | ||
883 | { "Left Input Inverting Mux", "IN2L", "IN2L" }, | ||
884 | { "Left Input Inverting Mux", "IN3L", "IN3L" }, | ||
885 | |||
886 | { "Right Input Mux", "IN1R", "IN1R" }, | ||
887 | { "Right Input Mux", "IN2R", "IN2R" }, | ||
888 | { "Right Input Mux", "IN3R", "IN3R" }, | ||
889 | |||
890 | { "Right Input Inverting Mux", "IN1R", "IN1R" }, | ||
891 | { "Right Input Inverting Mux", "IN2R", "IN2R" }, | ||
892 | { "Right Input Inverting Mux", "IN3R", "IN3R" }, | ||
893 | |||
894 | { "Left Input Mode Mux", "Single-Ended", "Left Input Inverting Mux" }, | ||
895 | { "Left Input Mode Mux", "Differential Line", | ||
896 | "Left Input Mux" }, | ||
897 | { "Left Input Mode Mux", "Differential Line", | ||
898 | "Left Input Inverting Mux" }, | ||
899 | { "Left Input Mode Mux", "Differential Mic", | ||
900 | "Left Input Mux" }, | ||
901 | { "Left Input Mode Mux", "Differential Mic", | ||
902 | "Left Input Inverting Mux" }, | ||
903 | |||
904 | { "Right Input Mode Mux", "Single-Ended", | ||
905 | "Right Input Inverting Mux" }, | ||
906 | { "Right Input Mode Mux", "Differential Line", | ||
907 | "Right Input Mux" }, | ||
908 | { "Right Input Mode Mux", "Differential Line", | ||
909 | "Right Input Inverting Mux" }, | ||
910 | { "Right Input Mode Mux", "Differential Mic", | ||
911 | "Right Input Mux" }, | ||
912 | { "Right Input Mode Mux", "Differential Mic", | ||
913 | "Right Input Inverting Mux" }, | ||
914 | |||
915 | { "Left Input PGA", NULL, "Left Input Mode Mux" }, | ||
916 | { "Right Input PGA", NULL, "Right Input Mode Mux" }, | ||
917 | |||
918 | { "ADCL", NULL, "Left Input PGA" }, | ||
919 | { "ADCR", NULL, "Right Input PGA" }, | ||
920 | |||
921 | { "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" }, | ||
922 | { "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" }, | ||
923 | { "Left Output Mixer", "DACL Switch", "DACL" }, | ||
924 | { "Left Output Mixer", "DACR Switch", "DACR" }, | ||
925 | |||
926 | { "Right Output Mixer", "Left Bypass Switch", "Left Input PGA" }, | ||
927 | { "Right Output Mixer", "Right Bypass Switch", "Right Input PGA" }, | ||
928 | { "Right Output Mixer", "DACL Switch", "DACL" }, | ||
929 | { "Right Output Mixer", "DACR Switch", "DACR" }, | ||
930 | |||
931 | { "Left Speaker Mixer", "Left Bypass Switch", "Left Input PGA" }, | ||
932 | { "Left Speaker Mixer", "Right Bypass Switch", "Right Input PGA" }, | ||
933 | { "Left Speaker Mixer", "DACL Switch", "DACL" }, | ||
934 | { "Left Speaker Mixer", "DACR Switch", "DACR" }, | ||
935 | |||
936 | { "Right Speaker Mixer", "Left Bypass Switch", "Left Input PGA" }, | ||
937 | { "Right Speaker Mixer", "Right Bypass Switch", "Right Input PGA" }, | ||
938 | { "Right Speaker Mixer", "DACL Switch", "DACL" }, | ||
939 | { "Right Speaker Mixer", "DACR Switch", "DACR" }, | ||
940 | |||
941 | { "Left Line Output PGA", NULL, "Left Output Mixer" }, | ||
942 | { "Right Line Output PGA", NULL, "Right Output Mixer" }, | ||
943 | |||
944 | { "Left Headphone Output PGA", NULL, "Left Output Mixer" }, | ||
945 | { "Right Headphone Output PGA", NULL, "Right Output Mixer" }, | ||
946 | |||
947 | { "Left Speaker PGA", NULL, "Left Speaker Mixer" }, | ||
948 | { "Right Speaker PGA", NULL, "Right Speaker Mixer" }, | ||
949 | |||
950 | { "HPOUTL", NULL, "Left Headphone Output PGA" }, | ||
951 | { "HPOUTR", NULL, "Right Headphone Output PGA" }, | ||
952 | |||
953 | { "LINEOUTL", NULL, "Left Line Output PGA" }, | ||
954 | { "LINEOUTR", NULL, "Right Line Output PGA" }, | ||
955 | |||
956 | { "LOP", NULL, "Left Speaker PGA" }, | ||
957 | { "LON", NULL, "Left Speaker PGA" }, | ||
958 | |||
959 | { "ROP", NULL, "Right Speaker PGA" }, | ||
960 | { "RON", NULL, "Right Speaker PGA" }, | ||
961 | }; | ||
962 | |||
963 | static int wm8903_add_widgets(struct snd_soc_codec *codec) | ||
964 | { | ||
965 | snd_soc_dapm_new_controls(codec, wm8903_dapm_widgets, | ||
966 | ARRAY_SIZE(wm8903_dapm_widgets)); | ||
967 | |||
968 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
969 | |||
970 | snd_soc_dapm_new_widgets(codec); | ||
971 | |||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | static int wm8903_set_bias_level(struct snd_soc_codec *codec, | ||
976 | enum snd_soc_bias_level level) | ||
977 | { | ||
978 | struct i2c_client *i2c = codec->control_data; | ||
979 | u16 reg, reg2; | ||
980 | |||
981 | switch (level) { | ||
982 | case SND_SOC_BIAS_ON: | ||
983 | case SND_SOC_BIAS_PREPARE: | ||
984 | reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); | ||
985 | reg &= ~(WM8903_VMID_RES_MASK); | ||
986 | reg |= WM8903_VMID_RES_50K; | ||
987 | wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); | ||
988 | break; | ||
989 | |||
990 | case SND_SOC_BIAS_STANDBY: | ||
991 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
992 | wm8903_run_sequence(codec, 0); | ||
993 | wm8903_sync_reg_cache(codec, codec->reg_cache); | ||
994 | |||
995 | /* Enable low impedence charge pump output */ | ||
996 | reg = wm8903_read(codec, | ||
997 | WM8903_CONTROL_INTERFACE_TEST_1); | ||
998 | wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, | ||
999 | reg | WM8903_TEST_KEY); | ||
1000 | reg2 = wm8903_read(codec, WM8903_CHARGE_PUMP_TEST_1); | ||
1001 | wm8903_write(codec, WM8903_CHARGE_PUMP_TEST_1, | ||
1002 | reg2 | WM8903_CP_SW_KELVIN_MODE_MASK); | ||
1003 | wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, | ||
1004 | reg); | ||
1005 | |||
1006 | /* By default no bypass paths are enabled so | ||
1007 | * enable Class W support. | ||
1008 | */ | ||
1009 | dev_dbg(&i2c->dev, "Enabling Class W\n"); | ||
1010 | wm8903_write(codec, WM8903_CLASS_W_0, reg | | ||
1011 | WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); | ||
1012 | } | ||
1013 | |||
1014 | reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); | ||
1015 | reg &= ~(WM8903_VMID_RES_MASK); | ||
1016 | reg |= WM8903_VMID_RES_250K; | ||
1017 | wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); | ||
1018 | break; | ||
1019 | |||
1020 | case SND_SOC_BIAS_OFF: | ||
1021 | wm8903_run_sequence(codec, 32); | ||
1022 | break; | ||
1023 | } | ||
1024 | |||
1025 | codec->bias_level = level; | ||
1026 | |||
1027 | return 0; | ||
1028 | } | ||
1029 | |||
1030 | static int wm8903_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
1031 | int clk_id, unsigned int freq, int dir) | ||
1032 | { | ||
1033 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1034 | struct wm8903_priv *wm8903 = codec->private_data; | ||
1035 | |||
1036 | wm8903->sysclk = freq; | ||
1037 | |||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
1042 | unsigned int fmt) | ||
1043 | { | ||
1044 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1045 | u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); | ||
1046 | |||
1047 | aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK | | ||
1048 | WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV); | ||
1049 | |||
1050 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1051 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1052 | break; | ||
1053 | case SND_SOC_DAIFMT_CBS_CFM: | ||
1054 | aif1 |= WM8903_LRCLK_DIR; | ||
1055 | break; | ||
1056 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1057 | aif1 |= WM8903_LRCLK_DIR | WM8903_BCLK_DIR; | ||
1058 | break; | ||
1059 | case SND_SOC_DAIFMT_CBM_CFS: | ||
1060 | aif1 |= WM8903_BCLK_DIR; | ||
1061 | break; | ||
1062 | default: | ||
1063 | return -EINVAL; | ||
1064 | } | ||
1065 | |||
1066 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1067 | case SND_SOC_DAIFMT_DSP_A: | ||
1068 | aif1 |= 0x3; | ||
1069 | break; | ||
1070 | case SND_SOC_DAIFMT_DSP_B: | ||
1071 | aif1 |= 0x3 | WM8903_AIF_LRCLK_INV; | ||
1072 | break; | ||
1073 | case SND_SOC_DAIFMT_I2S: | ||
1074 | aif1 |= 0x2; | ||
1075 | break; | ||
1076 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1077 | aif1 |= 0x1; | ||
1078 | break; | ||
1079 | case SND_SOC_DAIFMT_LEFT_J: | ||
1080 | break; | ||
1081 | default: | ||
1082 | return -EINVAL; | ||
1083 | } | ||
1084 | |||
1085 | /* Clock inversion */ | ||
1086 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1087 | case SND_SOC_DAIFMT_DSP_A: | ||
1088 | case SND_SOC_DAIFMT_DSP_B: | ||
1089 | /* frame inversion not valid for DSP modes */ | ||
1090 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1091 | case SND_SOC_DAIFMT_NB_NF: | ||
1092 | break; | ||
1093 | case SND_SOC_DAIFMT_IB_NF: | ||
1094 | aif1 |= WM8903_AIF_BCLK_INV; | ||
1095 | break; | ||
1096 | default: | ||
1097 | return -EINVAL; | ||
1098 | } | ||
1099 | break; | ||
1100 | case SND_SOC_DAIFMT_I2S: | ||
1101 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1102 | case SND_SOC_DAIFMT_LEFT_J: | ||
1103 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1104 | case SND_SOC_DAIFMT_NB_NF: | ||
1105 | break; | ||
1106 | case SND_SOC_DAIFMT_IB_IF: | ||
1107 | aif1 |= WM8903_AIF_BCLK_INV | WM8903_AIF_LRCLK_INV; | ||
1108 | break; | ||
1109 | case SND_SOC_DAIFMT_IB_NF: | ||
1110 | aif1 |= WM8903_AIF_BCLK_INV; | ||
1111 | break; | ||
1112 | case SND_SOC_DAIFMT_NB_IF: | ||
1113 | aif1 |= WM8903_AIF_LRCLK_INV; | ||
1114 | break; | ||
1115 | default: | ||
1116 | return -EINVAL; | ||
1117 | } | ||
1118 | break; | ||
1119 | default: | ||
1120 | return -EINVAL; | ||
1121 | } | ||
1122 | |||
1123 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | static int wm8903_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
1129 | { | ||
1130 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1131 | u16 reg; | ||
1132 | |||
1133 | reg = wm8903_read(codec, WM8903_DAC_DIGITAL_1); | ||
1134 | |||
1135 | if (mute) | ||
1136 | reg |= WM8903_DAC_MUTE; | ||
1137 | else | ||
1138 | reg &= ~WM8903_DAC_MUTE; | ||
1139 | |||
1140 | wm8903_write(codec, WM8903_DAC_DIGITAL_1, reg); | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | /* Lookup table for CLK_SYS/fs ratio. 256fs or more is recommended | ||
1146 | * for optimal performance so we list the lower rates first and match | ||
1147 | * on the last match we find. */ | ||
1148 | static struct { | ||
1149 | int div; | ||
1150 | int rate; | ||
1151 | int mode; | ||
1152 | int mclk_div; | ||
1153 | } clk_sys_ratios[] = { | ||
1154 | { 64, 0x0, 0x0, 1 }, | ||
1155 | { 68, 0x0, 0x1, 1 }, | ||
1156 | { 125, 0x0, 0x2, 1 }, | ||
1157 | { 128, 0x1, 0x0, 1 }, | ||
1158 | { 136, 0x1, 0x1, 1 }, | ||
1159 | { 192, 0x2, 0x0, 1 }, | ||
1160 | { 204, 0x2, 0x1, 1 }, | ||
1161 | |||
1162 | { 64, 0x0, 0x0, 2 }, | ||
1163 | { 68, 0x0, 0x1, 2 }, | ||
1164 | { 125, 0x0, 0x2, 2 }, | ||
1165 | { 128, 0x1, 0x0, 2 }, | ||
1166 | { 136, 0x1, 0x1, 2 }, | ||
1167 | { 192, 0x2, 0x0, 2 }, | ||
1168 | { 204, 0x2, 0x1, 2 }, | ||
1169 | |||
1170 | { 250, 0x2, 0x2, 1 }, | ||
1171 | { 256, 0x3, 0x0, 1 }, | ||
1172 | { 272, 0x3, 0x1, 1 }, | ||
1173 | { 384, 0x4, 0x0, 1 }, | ||
1174 | { 408, 0x4, 0x1, 1 }, | ||
1175 | { 375, 0x4, 0x2, 1 }, | ||
1176 | { 512, 0x5, 0x0, 1 }, | ||
1177 | { 544, 0x5, 0x1, 1 }, | ||
1178 | { 500, 0x5, 0x2, 1 }, | ||
1179 | { 768, 0x6, 0x0, 1 }, | ||
1180 | { 816, 0x6, 0x1, 1 }, | ||
1181 | { 750, 0x6, 0x2, 1 }, | ||
1182 | { 1024, 0x7, 0x0, 1 }, | ||
1183 | { 1088, 0x7, 0x1, 1 }, | ||
1184 | { 1000, 0x7, 0x2, 1 }, | ||
1185 | { 1408, 0x8, 0x0, 1 }, | ||
1186 | { 1496, 0x8, 0x1, 1 }, | ||
1187 | { 1536, 0x9, 0x0, 1 }, | ||
1188 | { 1632, 0x9, 0x1, 1 }, | ||
1189 | { 1500, 0x9, 0x2, 1 }, | ||
1190 | |||
1191 | { 250, 0x2, 0x2, 2 }, | ||
1192 | { 256, 0x3, 0x0, 2 }, | ||
1193 | { 272, 0x3, 0x1, 2 }, | ||
1194 | { 384, 0x4, 0x0, 2 }, | ||
1195 | { 408, 0x4, 0x1, 2 }, | ||
1196 | { 375, 0x4, 0x2, 2 }, | ||
1197 | { 512, 0x5, 0x0, 2 }, | ||
1198 | { 544, 0x5, 0x1, 2 }, | ||
1199 | { 500, 0x5, 0x2, 2 }, | ||
1200 | { 768, 0x6, 0x0, 2 }, | ||
1201 | { 816, 0x6, 0x1, 2 }, | ||
1202 | { 750, 0x6, 0x2, 2 }, | ||
1203 | { 1024, 0x7, 0x0, 2 }, | ||
1204 | { 1088, 0x7, 0x1, 2 }, | ||
1205 | { 1000, 0x7, 0x2, 2 }, | ||
1206 | { 1408, 0x8, 0x0, 2 }, | ||
1207 | { 1496, 0x8, 0x1, 2 }, | ||
1208 | { 1536, 0x9, 0x0, 2 }, | ||
1209 | { 1632, 0x9, 0x1, 2 }, | ||
1210 | { 1500, 0x9, 0x2, 2 }, | ||
1211 | }; | ||
1212 | |||
1213 | /* CLK_SYS/BCLK ratios - multiplied by 10 due to .5s */ | ||
1214 | static struct { | ||
1215 | int ratio; | ||
1216 | int div; | ||
1217 | } bclk_divs[] = { | ||
1218 | { 10, 0 }, | ||
1219 | { 15, 1 }, | ||
1220 | { 20, 2 }, | ||
1221 | { 30, 3 }, | ||
1222 | { 40, 4 }, | ||
1223 | { 50, 5 }, | ||
1224 | { 55, 6 }, | ||
1225 | { 60, 7 }, | ||
1226 | { 80, 8 }, | ||
1227 | { 100, 9 }, | ||
1228 | { 110, 10 }, | ||
1229 | { 120, 11 }, | ||
1230 | { 160, 12 }, | ||
1231 | { 200, 13 }, | ||
1232 | { 220, 14 }, | ||
1233 | { 240, 15 }, | ||
1234 | { 250, 16 }, | ||
1235 | { 300, 17 }, | ||
1236 | { 320, 18 }, | ||
1237 | { 440, 19 }, | ||
1238 | { 480, 20 }, | ||
1239 | }; | ||
1240 | |||
1241 | /* Sample rates for DSP */ | ||
1242 | static struct { | ||
1243 | int rate; | ||
1244 | int value; | ||
1245 | } sample_rates[] = { | ||
1246 | { 8000, 0 }, | ||
1247 | { 11025, 1 }, | ||
1248 | { 12000, 2 }, | ||
1249 | { 16000, 3 }, | ||
1250 | { 22050, 4 }, | ||
1251 | { 24000, 5 }, | ||
1252 | { 32000, 6 }, | ||
1253 | { 44100, 7 }, | ||
1254 | { 48000, 8 }, | ||
1255 | { 88200, 9 }, | ||
1256 | { 96000, 10 }, | ||
1257 | { 0, 0 }, | ||
1258 | }; | ||
1259 | |||
1260 | static int wm8903_startup(struct snd_pcm_substream *substream) | ||
1261 | { | ||
1262 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1263 | struct snd_soc_device *socdev = rtd->socdev; | ||
1264 | struct snd_soc_codec *codec = socdev->codec; | ||
1265 | struct wm8903_priv *wm8903 = codec->private_data; | ||
1266 | struct i2c_client *i2c = codec->control_data; | ||
1267 | struct snd_pcm_runtime *master_runtime; | ||
1268 | |||
1269 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1270 | wm8903->playback_active++; | ||
1271 | else | ||
1272 | wm8903->capture_active++; | ||
1273 | |||
1274 | /* The DAI has shared clocks so if we already have a playback or | ||
1275 | * capture going then constrain this substream to match it. | ||
1276 | */ | ||
1277 | if (wm8903->master_substream) { | ||
1278 | master_runtime = wm8903->master_substream->runtime; | ||
1279 | |||
1280 | dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", | ||
1281 | master_runtime->sample_bits, | ||
1282 | master_runtime->rate); | ||
1283 | |||
1284 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1285 | SNDRV_PCM_HW_PARAM_RATE, | ||
1286 | master_runtime->rate, | ||
1287 | master_runtime->rate); | ||
1288 | |||
1289 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1290 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
1291 | master_runtime->sample_bits, | ||
1292 | master_runtime->sample_bits); | ||
1293 | |||
1294 | wm8903->slave_substream = substream; | ||
1295 | } else | ||
1296 | wm8903->master_substream = substream; | ||
1297 | |||
1298 | return 0; | ||
1299 | } | ||
1300 | |||
1301 | static void wm8903_shutdown(struct snd_pcm_substream *substream) | ||
1302 | { | ||
1303 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1304 | struct snd_soc_device *socdev = rtd->socdev; | ||
1305 | struct snd_soc_codec *codec = socdev->codec; | ||
1306 | struct wm8903_priv *wm8903 = codec->private_data; | ||
1307 | |||
1308 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1309 | wm8903->playback_active--; | ||
1310 | else | ||
1311 | wm8903->capture_active--; | ||
1312 | |||
1313 | if (wm8903->master_substream == substream) | ||
1314 | wm8903->master_substream = wm8903->slave_substream; | ||
1315 | |||
1316 | wm8903->slave_substream = NULL; | ||
1317 | } | ||
1318 | |||
1319 | static int wm8903_hw_params(struct snd_pcm_substream *substream, | ||
1320 | struct snd_pcm_hw_params *params) | ||
1321 | { | ||
1322 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1323 | struct snd_soc_device *socdev = rtd->socdev; | ||
1324 | struct snd_soc_codec *codec = socdev->codec; | ||
1325 | struct wm8903_priv *wm8903 = codec->private_data; | ||
1326 | struct i2c_client *i2c = codec->control_data; | ||
1327 | int fs = params_rate(params); | ||
1328 | int bclk; | ||
1329 | int bclk_div; | ||
1330 | int i; | ||
1331 | int dsp_config; | ||
1332 | int clk_config; | ||
1333 | int best_val; | ||
1334 | int cur_val; | ||
1335 | int clk_sys; | ||
1336 | |||
1337 | u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); | ||
1338 | u16 aif2 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_2); | ||
1339 | u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3); | ||
1340 | u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0); | ||
1341 | u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1); | ||
1342 | |||
1343 | if (substream == wm8903->slave_substream) { | ||
1344 | dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); | ||
1345 | return 0; | ||
1346 | } | ||
1347 | |||
1348 | /* Configure sample rate logic for DSP - choose nearest rate */ | ||
1349 | dsp_config = 0; | ||
1350 | best_val = abs(sample_rates[dsp_config].rate - fs); | ||
1351 | for (i = 1; i < ARRAY_SIZE(sample_rates); i++) { | ||
1352 | cur_val = abs(sample_rates[i].rate - fs); | ||
1353 | if (cur_val <= best_val) { | ||
1354 | dsp_config = i; | ||
1355 | best_val = cur_val; | ||
1356 | } | ||
1357 | } | ||
1358 | |||
1359 | /* Constraints should stop us hitting this but let's make sure */ | ||
1360 | if (wm8903->capture_active) | ||
1361 | switch (sample_rates[dsp_config].rate) { | ||
1362 | case 88200: | ||
1363 | case 96000: | ||
1364 | dev_err(&i2c->dev, "%dHz unsupported by ADC\n", | ||
1365 | fs); | ||
1366 | return -EINVAL; | ||
1367 | |||
1368 | default: | ||
1369 | break; | ||
1370 | } | ||
1371 | |||
1372 | dev_dbg(&i2c->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate); | ||
1373 | clock1 &= ~WM8903_SAMPLE_RATE_MASK; | ||
1374 | clock1 |= sample_rates[dsp_config].value; | ||
1375 | |||
1376 | aif1 &= ~WM8903_AIF_WL_MASK; | ||
1377 | bclk = 2 * fs; | ||
1378 | switch (params_format(params)) { | ||
1379 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1380 | bclk *= 16; | ||
1381 | break; | ||
1382 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
1383 | bclk *= 20; | ||
1384 | aif1 |= 0x4; | ||
1385 | break; | ||
1386 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1387 | bclk *= 24; | ||
1388 | aif1 |= 0x8; | ||
1389 | break; | ||
1390 | case SNDRV_PCM_FORMAT_S32_LE: | ||
1391 | bclk *= 32; | ||
1392 | aif1 |= 0xc; | ||
1393 | break; | ||
1394 | default: | ||
1395 | return -EINVAL; | ||
1396 | } | ||
1397 | |||
1398 | dev_dbg(&i2c->dev, "MCLK = %dHz, target sample rate = %dHz\n", | ||
1399 | wm8903->sysclk, fs); | ||
1400 | |||
1401 | /* We may not have an MCLK which allows us to generate exactly | ||
1402 | * the clock we want, particularly with USB derived inputs, so | ||
1403 | * approximate. | ||
1404 | */ | ||
1405 | clk_config = 0; | ||
1406 | best_val = abs((wm8903->sysclk / | ||
1407 | (clk_sys_ratios[0].mclk_div * | ||
1408 | clk_sys_ratios[0].div)) - fs); | ||
1409 | for (i = 1; i < ARRAY_SIZE(clk_sys_ratios); i++) { | ||
1410 | cur_val = abs((wm8903->sysclk / | ||
1411 | (clk_sys_ratios[i].mclk_div * | ||
1412 | clk_sys_ratios[i].div)) - fs); | ||
1413 | |||
1414 | if (cur_val <= best_val) { | ||
1415 | clk_config = i; | ||
1416 | best_val = cur_val; | ||
1417 | } | ||
1418 | } | ||
1419 | |||
1420 | if (clk_sys_ratios[clk_config].mclk_div == 2) { | ||
1421 | clock0 |= WM8903_MCLKDIV2; | ||
1422 | clk_sys = wm8903->sysclk / 2; | ||
1423 | } else { | ||
1424 | clock0 &= ~WM8903_MCLKDIV2; | ||
1425 | clk_sys = wm8903->sysclk; | ||
1426 | } | ||
1427 | |||
1428 | clock1 &= ~(WM8903_CLK_SYS_RATE_MASK | | ||
1429 | WM8903_CLK_SYS_MODE_MASK); | ||
1430 | clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT; | ||
1431 | clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT; | ||
1432 | |||
1433 | dev_dbg(&i2c->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n", | ||
1434 | clk_sys_ratios[clk_config].rate, | ||
1435 | clk_sys_ratios[clk_config].mode, | ||
1436 | clk_sys_ratios[clk_config].div); | ||
1437 | |||
1438 | dev_dbg(&i2c->dev, "Actual CLK_SYS = %dHz\n", clk_sys); | ||
1439 | |||
1440 | /* We may not get quite the right frequency if using | ||
1441 | * approximate clocks so look for the closest match that is | ||
1442 | * higher than the target (we need to ensure that there enough | ||
1443 | * BCLKs to clock out the samples). | ||
1444 | */ | ||
1445 | bclk_div = 0; | ||
1446 | best_val = ((clk_sys * 10) / bclk_divs[0].ratio) - bclk; | ||
1447 | i = 1; | ||
1448 | while (i < ARRAY_SIZE(bclk_divs)) { | ||
1449 | cur_val = ((clk_sys * 10) / bclk_divs[i].ratio) - bclk; | ||
1450 | if (cur_val < 0) /* BCLK table is sorted */ | ||
1451 | break; | ||
1452 | bclk_div = i; | ||
1453 | best_val = cur_val; | ||
1454 | i++; | ||
1455 | } | ||
1456 | |||
1457 | aif2 &= ~WM8903_BCLK_DIV_MASK; | ||
1458 | aif3 &= ~WM8903_LRCLK_RATE_MASK; | ||
1459 | |||
1460 | dev_dbg(&i2c->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n", | ||
1461 | bclk_divs[bclk_div].ratio / 10, bclk, | ||
1462 | (clk_sys * 10) / bclk_divs[bclk_div].ratio); | ||
1463 | |||
1464 | aif2 |= bclk_divs[bclk_div].div; | ||
1465 | aif3 |= bclk / fs; | ||
1466 | |||
1467 | wm8903_write(codec, WM8903_CLOCK_RATES_0, clock0); | ||
1468 | wm8903_write(codec, WM8903_CLOCK_RATES_1, clock1); | ||
1469 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); | ||
1470 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); | ||
1471 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); | ||
1472 | |||
1473 | return 0; | ||
1474 | } | ||
1475 | |||
1476 | #define WM8903_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\ | ||
1477 | SNDRV_PCM_RATE_11025 | \ | ||
1478 | SNDRV_PCM_RATE_16000 | \ | ||
1479 | SNDRV_PCM_RATE_22050 | \ | ||
1480 | SNDRV_PCM_RATE_32000 | \ | ||
1481 | SNDRV_PCM_RATE_44100 | \ | ||
1482 | SNDRV_PCM_RATE_48000 | \ | ||
1483 | SNDRV_PCM_RATE_88200 | \ | ||
1484 | SNDRV_PCM_RATE_96000) | ||
1485 | |||
1486 | #define WM8903_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ | ||
1487 | SNDRV_PCM_RATE_11025 | \ | ||
1488 | SNDRV_PCM_RATE_16000 | \ | ||
1489 | SNDRV_PCM_RATE_22050 | \ | ||
1490 | SNDRV_PCM_RATE_32000 | \ | ||
1491 | SNDRV_PCM_RATE_44100 | \ | ||
1492 | SNDRV_PCM_RATE_48000) | ||
1493 | |||
1494 | #define WM8903_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ | ||
1495 | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
1496 | SNDRV_PCM_FMTBIT_S24_LE) | ||
1497 | |||
1498 | struct snd_soc_dai wm8903_dai = { | ||
1499 | .name = "WM8903", | ||
1500 | .playback = { | ||
1501 | .stream_name = "Playback", | ||
1502 | .channels_min = 2, | ||
1503 | .channels_max = 2, | ||
1504 | .rates = WM8903_PLAYBACK_RATES, | ||
1505 | .formats = WM8903_FORMATS, | ||
1506 | }, | ||
1507 | .capture = { | ||
1508 | .stream_name = "Capture", | ||
1509 | .channels_min = 2, | ||
1510 | .channels_max = 2, | ||
1511 | .rates = WM8903_CAPTURE_RATES, | ||
1512 | .formats = WM8903_FORMATS, | ||
1513 | }, | ||
1514 | .ops = { | ||
1515 | .startup = wm8903_startup, | ||
1516 | .shutdown = wm8903_shutdown, | ||
1517 | .hw_params = wm8903_hw_params, | ||
1518 | }, | ||
1519 | .dai_ops = { | ||
1520 | .digital_mute = wm8903_digital_mute, | ||
1521 | .set_fmt = wm8903_set_dai_fmt, | ||
1522 | .set_sysclk = wm8903_set_dai_sysclk | ||
1523 | } | ||
1524 | }; | ||
1525 | EXPORT_SYMBOL_GPL(wm8903_dai); | ||
1526 | |||
1527 | static int wm8903_suspend(struct platform_device *pdev, pm_message_t state) | ||
1528 | { | ||
1529 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1530 | struct snd_soc_codec *codec = socdev->codec; | ||
1531 | |||
1532 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1533 | |||
1534 | return 0; | ||
1535 | } | ||
1536 | |||
1537 | static int wm8903_resume(struct platform_device *pdev) | ||
1538 | { | ||
1539 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1540 | struct snd_soc_codec *codec = socdev->codec; | ||
1541 | struct i2c_client *i2c = codec->control_data; | ||
1542 | int i; | ||
1543 | u16 *reg_cache = codec->reg_cache; | ||
1544 | u16 *tmp_cache = kmemdup(codec->reg_cache, sizeof(wm8903_reg_defaults), | ||
1545 | GFP_KERNEL); | ||
1546 | |||
1547 | /* Bring the codec back up to standby first to minimise pop/clicks */ | ||
1548 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1549 | wm8903_set_bias_level(codec, codec->suspend_bias_level); | ||
1550 | |||
1551 | /* Sync back everything else */ | ||
1552 | if (tmp_cache) { | ||
1553 | for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++) | ||
1554 | if (tmp_cache[i] != reg_cache[i]) | ||
1555 | wm8903_write(codec, i, tmp_cache[i]); | ||
1556 | } else { | ||
1557 | dev_err(&i2c->dev, "Failed to allocate temporary cache\n"); | ||
1558 | } | ||
1559 | |||
1560 | return 0; | ||
1561 | } | ||
1562 | |||
1563 | /* | ||
1564 | * initialise the WM8903 driver | ||
1565 | * register the mixer and dsp interfaces with the kernel | ||
1566 | */ | ||
1567 | static int wm8903_init(struct snd_soc_device *socdev) | ||
1568 | { | ||
1569 | struct snd_soc_codec *codec = socdev->codec; | ||
1570 | struct i2c_client *i2c = codec->control_data; | ||
1571 | int ret = 0; | ||
1572 | u16 val; | ||
1573 | |||
1574 | val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); | ||
1575 | if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { | ||
1576 | dev_err(&i2c->dev, | ||
1577 | "Device with ID register %x is not a WM8903\n", val); | ||
1578 | return -ENODEV; | ||
1579 | } | ||
1580 | |||
1581 | codec->name = "WM8903"; | ||
1582 | codec->owner = THIS_MODULE; | ||
1583 | codec->read = wm8903_read; | ||
1584 | codec->write = wm8903_write; | ||
1585 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1586 | codec->set_bias_level = wm8903_set_bias_level; | ||
1587 | codec->dai = &wm8903_dai; | ||
1588 | codec->num_dai = 1; | ||
1589 | codec->reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults); | ||
1590 | codec->reg_cache = kmemdup(wm8903_reg_defaults, | ||
1591 | sizeof(wm8903_reg_defaults), | ||
1592 | GFP_KERNEL); | ||
1593 | if (codec->reg_cache == NULL) { | ||
1594 | dev_err(&i2c->dev, "Failed to allocate register cache\n"); | ||
1595 | return -ENOMEM; | ||
1596 | } | ||
1597 | |||
1598 | val = wm8903_read(codec, WM8903_REVISION_NUMBER); | ||
1599 | dev_info(&i2c->dev, "WM8903 revision %d\n", | ||
1600 | val & WM8903_CHIP_REV_MASK); | ||
1601 | |||
1602 | wm8903_reset(codec); | ||
1603 | |||
1604 | /* register pcms */ | ||
1605 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1606 | if (ret < 0) { | ||
1607 | dev_err(&i2c->dev, "failed to create pcms\n"); | ||
1608 | goto pcm_err; | ||
1609 | } | ||
1610 | |||
1611 | /* SYSCLK is required for pretty much anything */ | ||
1612 | wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); | ||
1613 | |||
1614 | /* power on device */ | ||
1615 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1616 | |||
1617 | /* Latch volume update bits */ | ||
1618 | val = wm8903_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT); | ||
1619 | val |= WM8903_ADCVU; | ||
1620 | wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val); | ||
1621 | wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val); | ||
1622 | |||
1623 | val = wm8903_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT); | ||
1624 | val |= WM8903_DACVU; | ||
1625 | wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val); | ||
1626 | wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val); | ||
1627 | |||
1628 | val = wm8903_read(codec, WM8903_ANALOGUE_OUT1_LEFT); | ||
1629 | val |= WM8903_HPOUTVU; | ||
1630 | wm8903_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val); | ||
1631 | wm8903_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val); | ||
1632 | |||
1633 | val = wm8903_read(codec, WM8903_ANALOGUE_OUT2_LEFT); | ||
1634 | val |= WM8903_LINEOUTVU; | ||
1635 | wm8903_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val); | ||
1636 | wm8903_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val); | ||
1637 | |||
1638 | val = wm8903_read(codec, WM8903_ANALOGUE_OUT3_LEFT); | ||
1639 | val |= WM8903_SPKVU; | ||
1640 | wm8903_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val); | ||
1641 | wm8903_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); | ||
1642 | |||
1643 | /* Enable DAC soft mute by default */ | ||
1644 | val = wm8903_read(codec, WM8903_DAC_DIGITAL_1); | ||
1645 | val |= WM8903_DAC_MUTEMODE; | ||
1646 | wm8903_write(codec, WM8903_DAC_DIGITAL_1, val); | ||
1647 | |||
1648 | wm8903_add_controls(codec); | ||
1649 | wm8903_add_widgets(codec); | ||
1650 | ret = snd_soc_register_card(socdev); | ||
1651 | if (ret < 0) { | ||
1652 | dev_err(&i2c->dev, "wm8903: failed to register card\n"); | ||
1653 | goto card_err; | ||
1654 | } | ||
1655 | |||
1656 | return ret; | ||
1657 | |||
1658 | card_err: | ||
1659 | snd_soc_free_pcms(socdev); | ||
1660 | snd_soc_dapm_free(socdev); | ||
1661 | pcm_err: | ||
1662 | kfree(codec->reg_cache); | ||
1663 | return ret; | ||
1664 | } | ||
1665 | |||
1666 | static struct snd_soc_device *wm8903_socdev; | ||
1667 | |||
1668 | static int wm8903_i2c_probe(struct i2c_client *i2c, | ||
1669 | const struct i2c_device_id *id) | ||
1670 | { | ||
1671 | struct snd_soc_device *socdev = wm8903_socdev; | ||
1672 | struct snd_soc_codec *codec = socdev->codec; | ||
1673 | int ret; | ||
1674 | |||
1675 | i2c_set_clientdata(i2c, codec); | ||
1676 | codec->control_data = i2c; | ||
1677 | |||
1678 | ret = wm8903_init(socdev); | ||
1679 | if (ret < 0) | ||
1680 | dev_err(&i2c->dev, "Device initialisation failed\n"); | ||
1681 | |||
1682 | return ret; | ||
1683 | } | ||
1684 | |||
1685 | static int wm8903_i2c_remove(struct i2c_client *client) | ||
1686 | { | ||
1687 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
1688 | kfree(codec->reg_cache); | ||
1689 | return 0; | ||
1690 | } | ||
1691 | |||
1692 | /* i2c codec control layer */ | ||
1693 | static const struct i2c_device_id wm8903_i2c_id[] = { | ||
1694 | { "wm8903", 0 }, | ||
1695 | { } | ||
1696 | }; | ||
1697 | MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id); | ||
1698 | |||
1699 | static struct i2c_driver wm8903_i2c_driver = { | ||
1700 | .driver = { | ||
1701 | .name = "WM8903", | ||
1702 | .owner = THIS_MODULE, | ||
1703 | }, | ||
1704 | .probe = wm8903_i2c_probe, | ||
1705 | .remove = wm8903_i2c_remove, | ||
1706 | .id_table = wm8903_i2c_id, | ||
1707 | }; | ||
1708 | |||
1709 | static int wm8903_probe(struct platform_device *pdev) | ||
1710 | { | ||
1711 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1712 | struct wm8903_setup_data *setup; | ||
1713 | struct snd_soc_codec *codec; | ||
1714 | struct wm8903_priv *wm8903; | ||
1715 | struct i2c_board_info board_info; | ||
1716 | struct i2c_adapter *adapter; | ||
1717 | struct i2c_client *i2c_client; | ||
1718 | int ret = 0; | ||
1719 | |||
1720 | setup = socdev->codec_data; | ||
1721 | |||
1722 | if (!setup->i2c_address) { | ||
1723 | dev_err(&pdev->dev, "No codec address provided\n"); | ||
1724 | return -ENODEV; | ||
1725 | } | ||
1726 | |||
1727 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1728 | if (codec == NULL) | ||
1729 | return -ENOMEM; | ||
1730 | |||
1731 | wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); | ||
1732 | if (wm8903 == NULL) { | ||
1733 | ret = -ENOMEM; | ||
1734 | goto err_codec; | ||
1735 | } | ||
1736 | |||
1737 | codec->private_data = wm8903; | ||
1738 | socdev->codec = codec; | ||
1739 | mutex_init(&codec->mutex); | ||
1740 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1741 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1742 | |||
1743 | wm8903_socdev = socdev; | ||
1744 | |||
1745 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1746 | ret = i2c_add_driver(&wm8903_i2c_driver); | ||
1747 | if (ret != 0) { | ||
1748 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1749 | goto err_priv; | ||
1750 | } else { | ||
1751 | memset(&board_info, 0, sizeof(board_info)); | ||
1752 | strlcpy(board_info.type, "wm8903", I2C_NAME_SIZE); | ||
1753 | board_info.addr = setup->i2c_address; | ||
1754 | |||
1755 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1756 | if (!adapter) { | ||
1757 | dev_err(&pdev->dev, "Can't get I2C bus %d\n", | ||
1758 | setup->i2c_bus); | ||
1759 | ret = -ENODEV; | ||
1760 | goto err_adapter; | ||
1761 | } | ||
1762 | |||
1763 | i2c_client = i2c_new_device(adapter, &board_info); | ||
1764 | i2c_put_adapter(adapter); | ||
1765 | if (i2c_client == NULL) { | ||
1766 | dev_err(&pdev->dev, | ||
1767 | "I2C driver registration failed\n"); | ||
1768 | ret = -ENODEV; | ||
1769 | goto err_adapter; | ||
1770 | } | ||
1771 | } | ||
1772 | |||
1773 | return ret; | ||
1774 | |||
1775 | err_adapter: | ||
1776 | i2c_del_driver(&wm8903_i2c_driver); | ||
1777 | err_priv: | ||
1778 | kfree(codec->private_data); | ||
1779 | err_codec: | ||
1780 | kfree(codec); | ||
1781 | return ret; | ||
1782 | } | ||
1783 | |||
1784 | /* power down chip */ | ||
1785 | static int wm8903_remove(struct platform_device *pdev) | ||
1786 | { | ||
1787 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1788 | struct snd_soc_codec *codec = socdev->codec; | ||
1789 | |||
1790 | if (codec->control_data) | ||
1791 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1792 | |||
1793 | snd_soc_free_pcms(socdev); | ||
1794 | snd_soc_dapm_free(socdev); | ||
1795 | i2c_unregister_device(socdev->codec->control_data); | ||
1796 | i2c_del_driver(&wm8903_i2c_driver); | ||
1797 | kfree(codec->private_data); | ||
1798 | kfree(codec); | ||
1799 | |||
1800 | return 0; | ||
1801 | } | ||
1802 | |||
1803 | struct snd_soc_codec_device soc_codec_dev_wm8903 = { | ||
1804 | .probe = wm8903_probe, | ||
1805 | .remove = wm8903_remove, | ||
1806 | .suspend = wm8903_suspend, | ||
1807 | .resume = wm8903_resume, | ||
1808 | }; | ||
1809 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); | ||
1810 | |||
1811 | MODULE_DESCRIPTION("ASoC WM8903 driver"); | ||
1812 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>"); | ||
1813 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h new file mode 100644 index 00000000000..cec622f2f66 --- /dev/null +++ b/sound/soc/codecs/wm8903.h | |||
@@ -0,0 +1,1463 @@ | |||
1 | /* | ||
2 | * wm8903.h - WM8903 audio codec interface | ||
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 | #ifndef _WM8903_H | ||
14 | #define _WM8903_H | ||
15 | |||
16 | #include <linux/i2c.h> | ||
17 | |||
18 | extern struct snd_soc_dai wm8903_dai; | ||
19 | extern struct snd_soc_codec_device soc_codec_dev_wm8903; | ||
20 | |||
21 | struct wm8903_setup_data { | ||
22 | int i2c_bus; | ||
23 | int i2c_address; | ||
24 | }; | ||
25 | |||
26 | #define WM8903_MCLK_DIV_2 1 | ||
27 | #define WM8903_CLK_SYS 2 | ||
28 | #define WM8903_BCLK 3 | ||
29 | #define WM8903_LRCLK 4 | ||
30 | |||
31 | /* | ||
32 | * Register values. | ||
33 | */ | ||
34 | #define WM8903_SW_RESET_AND_ID 0x00 | ||
35 | #define WM8903_REVISION_NUMBER 0x01 | ||
36 | #define WM8903_BIAS_CONTROL_0 0x04 | ||
37 | #define WM8903_VMID_CONTROL_0 0x05 | ||
38 | #define WM8903_MIC_BIAS_CONTROL_0 0x06 | ||
39 | #define WM8903_ANALOGUE_DAC_0 0x08 | ||
40 | #define WM8903_ANALOGUE_ADC_0 0x0A | ||
41 | #define WM8903_POWER_MANAGEMENT_0 0x0C | ||
42 | #define WM8903_POWER_MANAGEMENT_1 0x0D | ||
43 | #define WM8903_POWER_MANAGEMENT_2 0x0E | ||
44 | #define WM8903_POWER_MANAGEMENT_3 0x0F | ||
45 | #define WM8903_POWER_MANAGEMENT_4 0x10 | ||
46 | #define WM8903_POWER_MANAGEMENT_5 0x11 | ||
47 | #define WM8903_POWER_MANAGEMENT_6 0x12 | ||
48 | #define WM8903_CLOCK_RATES_0 0x14 | ||
49 | #define WM8903_CLOCK_RATES_1 0x15 | ||
50 | #define WM8903_CLOCK_RATES_2 0x16 | ||
51 | #define WM8903_AUDIO_INTERFACE_0 0x18 | ||
52 | #define WM8903_AUDIO_INTERFACE_1 0x19 | ||
53 | #define WM8903_AUDIO_INTERFACE_2 0x1A | ||
54 | #define WM8903_AUDIO_INTERFACE_3 0x1B | ||
55 | #define WM8903_DAC_DIGITAL_VOLUME_LEFT 0x1E | ||
56 | #define WM8903_DAC_DIGITAL_VOLUME_RIGHT 0x1F | ||
57 | #define WM8903_DAC_DIGITAL_0 0x20 | ||
58 | #define WM8903_DAC_DIGITAL_1 0x21 | ||
59 | #define WM8903_ADC_DIGITAL_VOLUME_LEFT 0x24 | ||
60 | #define WM8903_ADC_DIGITAL_VOLUME_RIGHT 0x25 | ||
61 | #define WM8903_ADC_DIGITAL_0 0x26 | ||
62 | #define WM8903_DIGITAL_MICROPHONE_0 0x27 | ||
63 | #define WM8903_DRC_0 0x28 | ||
64 | #define WM8903_DRC_1 0x29 | ||
65 | #define WM8903_DRC_2 0x2A | ||
66 | #define WM8903_DRC_3 0x2B | ||
67 | #define WM8903_ANALOGUE_LEFT_INPUT_0 0x2C | ||
68 | #define WM8903_ANALOGUE_RIGHT_INPUT_0 0x2D | ||
69 | #define WM8903_ANALOGUE_LEFT_INPUT_1 0x2E | ||
70 | #define WM8903_ANALOGUE_RIGHT_INPUT_1 0x2F | ||
71 | #define WM8903_ANALOGUE_LEFT_MIX_0 0x32 | ||
72 | #define WM8903_ANALOGUE_RIGHT_MIX_0 0x33 | ||
73 | #define WM8903_ANALOGUE_SPK_MIX_LEFT_0 0x34 | ||
74 | #define WM8903_ANALOGUE_SPK_MIX_LEFT_1 0x35 | ||
75 | #define WM8903_ANALOGUE_SPK_MIX_RIGHT_0 0x36 | ||
76 | #define WM8903_ANALOGUE_SPK_MIX_RIGHT_1 0x37 | ||
77 | #define WM8903_ANALOGUE_OUT1_LEFT 0x39 | ||
78 | #define WM8903_ANALOGUE_OUT1_RIGHT 0x3A | ||
79 | #define WM8903_ANALOGUE_OUT2_LEFT 0x3B | ||
80 | #define WM8903_ANALOGUE_OUT2_RIGHT 0x3C | ||
81 | #define WM8903_ANALOGUE_OUT3_LEFT 0x3E | ||
82 | #define WM8903_ANALOGUE_OUT3_RIGHT 0x3F | ||
83 | #define WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0 0x41 | ||
84 | #define WM8903_DC_SERVO_0 0x43 | ||
85 | #define WM8903_DC_SERVO_2 0x45 | ||
86 | #define WM8903_ANALOGUE_HP_0 0x5A | ||
87 | #define WM8903_ANALOGUE_LINEOUT_0 0x5E | ||
88 | #define WM8903_CHARGE_PUMP_0 0x62 | ||
89 | #define WM8903_CLASS_W_0 0x68 | ||
90 | #define WM8903_WRITE_SEQUENCER_0 0x6C | ||
91 | #define WM8903_WRITE_SEQUENCER_1 0x6D | ||
92 | #define WM8903_WRITE_SEQUENCER_2 0x6E | ||
93 | #define WM8903_WRITE_SEQUENCER_3 0x6F | ||
94 | #define WM8903_WRITE_SEQUENCER_4 0x70 | ||
95 | #define WM8903_CONTROL_INTERFACE 0x72 | ||
96 | #define WM8903_GPIO_CONTROL_1 0x74 | ||
97 | #define WM8903_GPIO_CONTROL_2 0x75 | ||
98 | #define WM8903_GPIO_CONTROL_3 0x76 | ||
99 | #define WM8903_GPIO_CONTROL_4 0x77 | ||
100 | #define WM8903_GPIO_CONTROL_5 0x78 | ||
101 | #define WM8903_INTERRUPT_STATUS_1 0x79 | ||
102 | #define WM8903_INTERRUPT_STATUS_1_MASK 0x7A | ||
103 | #define WM8903_INTERRUPT_POLARITY_1 0x7B | ||
104 | #define WM8903_INTERRUPT_CONTROL 0x7E | ||
105 | #define WM8903_CONTROL_INTERFACE_TEST_1 0x81 | ||
106 | #define WM8903_CHARGE_PUMP_TEST_1 0x95 | ||
107 | #define WM8903_CLOCK_RATE_TEST_4 0xA4 | ||
108 | #define WM8903_ANALOGUE_OUTPUT_BIAS_0 0xAC | ||
109 | |||
110 | #define WM8903_REGISTER_COUNT 75 | ||
111 | #define WM8903_MAX_REGISTER 0xAC | ||
112 | |||
113 | /* | ||
114 | * Field Definitions. | ||
115 | */ | ||
116 | |||
117 | /* | ||
118 | * R0 (0x00) - SW Reset and ID | ||
119 | */ | ||
120 | #define WM8903_SW_RESET_DEV_ID1_MASK 0xFFFF /* SW_RESET_DEV_ID1 - [15:0] */ | ||
121 | #define WM8903_SW_RESET_DEV_ID1_SHIFT 0 /* SW_RESET_DEV_ID1 - [15:0] */ | ||
122 | #define WM8903_SW_RESET_DEV_ID1_WIDTH 16 /* SW_RESET_DEV_ID1 - [15:0] */ | ||
123 | |||
124 | /* | ||
125 | * R1 (0x01) - Revision Number | ||
126 | */ | ||
127 | #define WM8903_CHIP_REV_MASK 0x000F /* CHIP_REV - [3:0] */ | ||
128 | #define WM8903_CHIP_REV_SHIFT 0 /* CHIP_REV - [3:0] */ | ||
129 | #define WM8903_CHIP_REV_WIDTH 4 /* CHIP_REV - [3:0] */ | ||
130 | |||
131 | /* | ||
132 | * R4 (0x04) - Bias Control 0 | ||
133 | */ | ||
134 | #define WM8903_POBCTRL 0x0010 /* POBCTRL */ | ||
135 | #define WM8903_POBCTRL_MASK 0x0010 /* POBCTRL */ | ||
136 | #define WM8903_POBCTRL_SHIFT 4 /* POBCTRL */ | ||
137 | #define WM8903_POBCTRL_WIDTH 1 /* POBCTRL */ | ||
138 | #define WM8903_ISEL_MASK 0x000C /* ISEL - [3:2] */ | ||
139 | #define WM8903_ISEL_SHIFT 2 /* ISEL - [3:2] */ | ||
140 | #define WM8903_ISEL_WIDTH 2 /* ISEL - [3:2] */ | ||
141 | #define WM8903_STARTUP_BIAS_ENA 0x0002 /* STARTUP_BIAS_ENA */ | ||
142 | #define WM8903_STARTUP_BIAS_ENA_MASK 0x0002 /* STARTUP_BIAS_ENA */ | ||
143 | #define WM8903_STARTUP_BIAS_ENA_SHIFT 1 /* STARTUP_BIAS_ENA */ | ||
144 | #define WM8903_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */ | ||
145 | #define WM8903_BIAS_ENA 0x0001 /* BIAS_ENA */ | ||
146 | #define WM8903_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */ | ||
147 | #define WM8903_BIAS_ENA_SHIFT 0 /* BIAS_ENA */ | ||
148 | #define WM8903_BIAS_ENA_WIDTH 1 /* BIAS_ENA */ | ||
149 | |||
150 | /* | ||
151 | * R5 (0x05) - VMID Control 0 | ||
152 | */ | ||
153 | #define WM8903_VMID_TIE_ENA 0x0080 /* VMID_TIE_ENA */ | ||
154 | #define WM8903_VMID_TIE_ENA_MASK 0x0080 /* VMID_TIE_ENA */ | ||
155 | #define WM8903_VMID_TIE_ENA_SHIFT 7 /* VMID_TIE_ENA */ | ||
156 | #define WM8903_VMID_TIE_ENA_WIDTH 1 /* VMID_TIE_ENA */ | ||
157 | #define WM8903_BUFIO_ENA 0x0040 /* BUFIO_ENA */ | ||
158 | #define WM8903_BUFIO_ENA_MASK 0x0040 /* BUFIO_ENA */ | ||
159 | #define WM8903_BUFIO_ENA_SHIFT 6 /* BUFIO_ENA */ | ||
160 | #define WM8903_BUFIO_ENA_WIDTH 1 /* BUFIO_ENA */ | ||
161 | #define WM8903_VMID_IO_ENA 0x0020 /* VMID_IO_ENA */ | ||
162 | #define WM8903_VMID_IO_ENA_MASK 0x0020 /* VMID_IO_ENA */ | ||
163 | #define WM8903_VMID_IO_ENA_SHIFT 5 /* VMID_IO_ENA */ | ||
164 | #define WM8903_VMID_IO_ENA_WIDTH 1 /* VMID_IO_ENA */ | ||
165 | #define WM8903_VMID_SOFT_MASK 0x0018 /* VMID_SOFT - [4:3] */ | ||
166 | #define WM8903_VMID_SOFT_SHIFT 3 /* VMID_SOFT - [4:3] */ | ||
167 | #define WM8903_VMID_SOFT_WIDTH 2 /* VMID_SOFT - [4:3] */ | ||
168 | #define WM8903_VMID_RES_MASK 0x0006 /* VMID_RES - [2:1] */ | ||
169 | #define WM8903_VMID_RES_SHIFT 1 /* VMID_RES - [2:1] */ | ||
170 | #define WM8903_VMID_RES_WIDTH 2 /* VMID_RES - [2:1] */ | ||
171 | #define WM8903_VMID_BUF_ENA 0x0001 /* VMID_BUF_ENA */ | ||
172 | #define WM8903_VMID_BUF_ENA_MASK 0x0001 /* VMID_BUF_ENA */ | ||
173 | #define WM8903_VMID_BUF_ENA_SHIFT 0 /* VMID_BUF_ENA */ | ||
174 | #define WM8903_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ | ||
175 | |||
176 | #define WM8903_VMID_RES_50K 2 | ||
177 | #define WM8903_VMID_RES_250K 3 | ||
178 | #define WM8903_VMID_RES_5K 4 | ||
179 | |||
180 | /* | ||
181 | * R6 (0x06) - Mic Bias Control 0 | ||
182 | */ | ||
183 | #define WM8903_MICDET_HYST_ENA 0x0080 /* MICDET_HYST_ENA */ | ||
184 | #define WM8903_MICDET_HYST_ENA_MASK 0x0080 /* MICDET_HYST_ENA */ | ||
185 | #define WM8903_MICDET_HYST_ENA_SHIFT 7 /* MICDET_HYST_ENA */ | ||
186 | #define WM8903_MICDET_HYST_ENA_WIDTH 1 /* MICDET_HYST_ENA */ | ||
187 | #define WM8903_MICDET_THR_MASK 0x0070 /* MICDET_THR - [6:4] */ | ||
188 | #define WM8903_MICDET_THR_SHIFT 4 /* MICDET_THR - [6:4] */ | ||
189 | #define WM8903_MICDET_THR_WIDTH 3 /* MICDET_THR - [6:4] */ | ||
190 | #define WM8903_MICSHORT_THR_MASK 0x000C /* MICSHORT_THR - [3:2] */ | ||
191 | #define WM8903_MICSHORT_THR_SHIFT 2 /* MICSHORT_THR - [3:2] */ | ||
192 | #define WM8903_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [3:2] */ | ||
193 | #define WM8903_MICDET_ENA 0x0002 /* MICDET_ENA */ | ||
194 | #define WM8903_MICDET_ENA_MASK 0x0002 /* MICDET_ENA */ | ||
195 | #define WM8903_MICDET_ENA_SHIFT 1 /* MICDET_ENA */ | ||
196 | #define WM8903_MICDET_ENA_WIDTH 1 /* MICDET_ENA */ | ||
197 | #define WM8903_MICBIAS_ENA 0x0001 /* MICBIAS_ENA */ | ||
198 | #define WM8903_MICBIAS_ENA_MASK 0x0001 /* MICBIAS_ENA */ | ||
199 | #define WM8903_MICBIAS_ENA_SHIFT 0 /* MICBIAS_ENA */ | ||
200 | #define WM8903_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */ | ||
201 | |||
202 | /* | ||
203 | * R8 (0x08) - Analogue DAC 0 | ||
204 | */ | ||
205 | #define WM8903_DACBIAS_SEL_MASK 0x0018 /* DACBIAS_SEL - [4:3] */ | ||
206 | #define WM8903_DACBIAS_SEL_SHIFT 3 /* DACBIAS_SEL - [4:3] */ | ||
207 | #define WM8903_DACBIAS_SEL_WIDTH 2 /* DACBIAS_SEL - [4:3] */ | ||
208 | #define WM8903_DACVMID_BIAS_SEL_MASK 0x0006 /* DACVMID_BIAS_SEL - [2:1] */ | ||
209 | #define WM8903_DACVMID_BIAS_SEL_SHIFT 1 /* DACVMID_BIAS_SEL - [2:1] */ | ||
210 | #define WM8903_DACVMID_BIAS_SEL_WIDTH 2 /* DACVMID_BIAS_SEL - [2:1] */ | ||
211 | |||
212 | /* | ||
213 | * R10 (0x0A) - Analogue ADC 0 | ||
214 | */ | ||
215 | #define WM8903_ADC_OSR128 0x0001 /* ADC_OSR128 */ | ||
216 | #define WM8903_ADC_OSR128_MASK 0x0001 /* ADC_OSR128 */ | ||
217 | #define WM8903_ADC_OSR128_SHIFT 0 /* ADC_OSR128 */ | ||
218 | #define WM8903_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */ | ||
219 | |||
220 | /* | ||
221 | * R12 (0x0C) - Power Management 0 | ||
222 | */ | ||
223 | #define WM8903_INL_ENA 0x0002 /* INL_ENA */ | ||
224 | #define WM8903_INL_ENA_MASK 0x0002 /* INL_ENA */ | ||
225 | #define WM8903_INL_ENA_SHIFT 1 /* INL_ENA */ | ||
226 | #define WM8903_INL_ENA_WIDTH 1 /* INL_ENA */ | ||
227 | #define WM8903_INR_ENA 0x0001 /* INR_ENA */ | ||
228 | #define WM8903_INR_ENA_MASK 0x0001 /* INR_ENA */ | ||
229 | #define WM8903_INR_ENA_SHIFT 0 /* INR_ENA */ | ||
230 | #define WM8903_INR_ENA_WIDTH 1 /* INR_ENA */ | ||
231 | |||
232 | /* | ||
233 | * R13 (0x0D) - Power Management 1 | ||
234 | */ | ||
235 | #define WM8903_MIXOUTL_ENA 0x0002 /* MIXOUTL_ENA */ | ||
236 | #define WM8903_MIXOUTL_ENA_MASK 0x0002 /* MIXOUTL_ENA */ | ||
237 | #define WM8903_MIXOUTL_ENA_SHIFT 1 /* MIXOUTL_ENA */ | ||
238 | #define WM8903_MIXOUTL_ENA_WIDTH 1 /* MIXOUTL_ENA */ | ||
239 | #define WM8903_MIXOUTR_ENA 0x0001 /* MIXOUTR_ENA */ | ||
240 | #define WM8903_MIXOUTR_ENA_MASK 0x0001 /* MIXOUTR_ENA */ | ||
241 | #define WM8903_MIXOUTR_ENA_SHIFT 0 /* MIXOUTR_ENA */ | ||
242 | #define WM8903_MIXOUTR_ENA_WIDTH 1 /* MIXOUTR_ENA */ | ||
243 | |||
244 | /* | ||
245 | * R14 (0x0E) - Power Management 2 | ||
246 | */ | ||
247 | #define WM8903_HPL_PGA_ENA 0x0002 /* HPL_PGA_ENA */ | ||
248 | #define WM8903_HPL_PGA_ENA_MASK 0x0002 /* HPL_PGA_ENA */ | ||
249 | #define WM8903_HPL_PGA_ENA_SHIFT 1 /* HPL_PGA_ENA */ | ||
250 | #define WM8903_HPL_PGA_ENA_WIDTH 1 /* HPL_PGA_ENA */ | ||
251 | #define WM8903_HPR_PGA_ENA 0x0001 /* HPR_PGA_ENA */ | ||
252 | #define WM8903_HPR_PGA_ENA_MASK 0x0001 /* HPR_PGA_ENA */ | ||
253 | #define WM8903_HPR_PGA_ENA_SHIFT 0 /* HPR_PGA_ENA */ | ||
254 | #define WM8903_HPR_PGA_ENA_WIDTH 1 /* HPR_PGA_ENA */ | ||
255 | |||
256 | /* | ||
257 | * R15 (0x0F) - Power Management 3 | ||
258 | */ | ||
259 | #define WM8903_LINEOUTL_PGA_ENA 0x0002 /* LINEOUTL_PGA_ENA */ | ||
260 | #define WM8903_LINEOUTL_PGA_ENA_MASK 0x0002 /* LINEOUTL_PGA_ENA */ | ||
261 | #define WM8903_LINEOUTL_PGA_ENA_SHIFT 1 /* LINEOUTL_PGA_ENA */ | ||
262 | #define WM8903_LINEOUTL_PGA_ENA_WIDTH 1 /* LINEOUTL_PGA_ENA */ | ||
263 | #define WM8903_LINEOUTR_PGA_ENA 0x0001 /* LINEOUTR_PGA_ENA */ | ||
264 | #define WM8903_LINEOUTR_PGA_ENA_MASK 0x0001 /* LINEOUTR_PGA_ENA */ | ||
265 | #define WM8903_LINEOUTR_PGA_ENA_SHIFT 0 /* LINEOUTR_PGA_ENA */ | ||
266 | #define WM8903_LINEOUTR_PGA_ENA_WIDTH 1 /* LINEOUTR_PGA_ENA */ | ||
267 | |||
268 | /* | ||
269 | * R16 (0x10) - Power Management 4 | ||
270 | */ | ||
271 | #define WM8903_MIXSPKL_ENA 0x0002 /* MIXSPKL_ENA */ | ||
272 | #define WM8903_MIXSPKL_ENA_MASK 0x0002 /* MIXSPKL_ENA */ | ||
273 | #define WM8903_MIXSPKL_ENA_SHIFT 1 /* MIXSPKL_ENA */ | ||
274 | #define WM8903_MIXSPKL_ENA_WIDTH 1 /* MIXSPKL_ENA */ | ||
275 | #define WM8903_MIXSPKR_ENA 0x0001 /* MIXSPKR_ENA */ | ||
276 | #define WM8903_MIXSPKR_ENA_MASK 0x0001 /* MIXSPKR_ENA */ | ||
277 | #define WM8903_MIXSPKR_ENA_SHIFT 0 /* MIXSPKR_ENA */ | ||
278 | #define WM8903_MIXSPKR_ENA_WIDTH 1 /* MIXSPKR_ENA */ | ||
279 | |||
280 | /* | ||
281 | * R17 (0x11) - Power Management 5 | ||
282 | */ | ||
283 | #define WM8903_SPKL_ENA 0x0002 /* SPKL_ENA */ | ||
284 | #define WM8903_SPKL_ENA_MASK 0x0002 /* SPKL_ENA */ | ||
285 | #define WM8903_SPKL_ENA_SHIFT 1 /* SPKL_ENA */ | ||
286 | #define WM8903_SPKL_ENA_WIDTH 1 /* SPKL_ENA */ | ||
287 | #define WM8903_SPKR_ENA 0x0001 /* SPKR_ENA */ | ||
288 | #define WM8903_SPKR_ENA_MASK 0x0001 /* SPKR_ENA */ | ||
289 | #define WM8903_SPKR_ENA_SHIFT 0 /* SPKR_ENA */ | ||
290 | #define WM8903_SPKR_ENA_WIDTH 1 /* SPKR_ENA */ | ||
291 | |||
292 | /* | ||
293 | * R18 (0x12) - Power Management 6 | ||
294 | */ | ||
295 | #define WM8903_DACL_ENA 0x0008 /* DACL_ENA */ | ||
296 | #define WM8903_DACL_ENA_MASK 0x0008 /* DACL_ENA */ | ||
297 | #define WM8903_DACL_ENA_SHIFT 3 /* DACL_ENA */ | ||
298 | #define WM8903_DACL_ENA_WIDTH 1 /* DACL_ENA */ | ||
299 | #define WM8903_DACR_ENA 0x0004 /* DACR_ENA */ | ||
300 | #define WM8903_DACR_ENA_MASK 0x0004 /* DACR_ENA */ | ||
301 | #define WM8903_DACR_ENA_SHIFT 2 /* DACR_ENA */ | ||
302 | #define WM8903_DACR_ENA_WIDTH 1 /* DACR_ENA */ | ||
303 | #define WM8903_ADCL_ENA 0x0002 /* ADCL_ENA */ | ||
304 | #define WM8903_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */ | ||
305 | #define WM8903_ADCL_ENA_SHIFT 1 /* ADCL_ENA */ | ||
306 | #define WM8903_ADCL_ENA_WIDTH 1 /* ADCL_ENA */ | ||
307 | #define WM8903_ADCR_ENA 0x0001 /* ADCR_ENA */ | ||
308 | #define WM8903_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */ | ||
309 | #define WM8903_ADCR_ENA_SHIFT 0 /* ADCR_ENA */ | ||
310 | #define WM8903_ADCR_ENA_WIDTH 1 /* ADCR_ENA */ | ||
311 | |||
312 | /* | ||
313 | * R20 (0x14) - Clock Rates 0 | ||
314 | */ | ||
315 | #define WM8903_MCLKDIV2 0x0001 /* MCLKDIV2 */ | ||
316 | #define WM8903_MCLKDIV2_MASK 0x0001 /* MCLKDIV2 */ | ||
317 | #define WM8903_MCLKDIV2_SHIFT 0 /* MCLKDIV2 */ | ||
318 | #define WM8903_MCLKDIV2_WIDTH 1 /* MCLKDIV2 */ | ||
319 | |||
320 | /* | ||
321 | * R21 (0x15) - Clock Rates 1 | ||
322 | */ | ||
323 | #define WM8903_CLK_SYS_RATE_MASK 0x3C00 /* CLK_SYS_RATE - [13:10] */ | ||
324 | #define WM8903_CLK_SYS_RATE_SHIFT 10 /* CLK_SYS_RATE - [13:10] */ | ||
325 | #define WM8903_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [13:10] */ | ||
326 | #define WM8903_CLK_SYS_MODE_MASK 0x0300 /* CLK_SYS_MODE - [9:8] */ | ||
327 | #define WM8903_CLK_SYS_MODE_SHIFT 8 /* CLK_SYS_MODE - [9:8] */ | ||
328 | #define WM8903_CLK_SYS_MODE_WIDTH 2 /* CLK_SYS_MODE - [9:8] */ | ||
329 | #define WM8903_SAMPLE_RATE_MASK 0x000F /* SAMPLE_RATE - [3:0] */ | ||
330 | #define WM8903_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [3:0] */ | ||
331 | #define WM8903_SAMPLE_RATE_WIDTH 4 /* SAMPLE_RATE - [3:0] */ | ||
332 | |||
333 | /* | ||
334 | * R22 (0x16) - Clock Rates 2 | ||
335 | */ | ||
336 | #define WM8903_CLK_SYS_ENA 0x0004 /* CLK_SYS_ENA */ | ||
337 | #define WM8903_CLK_SYS_ENA_MASK 0x0004 /* CLK_SYS_ENA */ | ||
338 | #define WM8903_CLK_SYS_ENA_SHIFT 2 /* CLK_SYS_ENA */ | ||
339 | #define WM8903_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */ | ||
340 | #define WM8903_CLK_DSP_ENA 0x0002 /* CLK_DSP_ENA */ | ||
341 | #define WM8903_CLK_DSP_ENA_MASK 0x0002 /* CLK_DSP_ENA */ | ||
342 | #define WM8903_CLK_DSP_ENA_SHIFT 1 /* CLK_DSP_ENA */ | ||
343 | #define WM8903_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */ | ||
344 | #define WM8903_TO_ENA 0x0001 /* TO_ENA */ | ||
345 | #define WM8903_TO_ENA_MASK 0x0001 /* TO_ENA */ | ||
346 | #define WM8903_TO_ENA_SHIFT 0 /* TO_ENA */ | ||
347 | #define WM8903_TO_ENA_WIDTH 1 /* TO_ENA */ | ||
348 | |||
349 | /* | ||
350 | * R24 (0x18) - Audio Interface 0 | ||
351 | */ | ||
352 | #define WM8903_DACL_DATINV 0x1000 /* DACL_DATINV */ | ||
353 | #define WM8903_DACL_DATINV_MASK 0x1000 /* DACL_DATINV */ | ||
354 | #define WM8903_DACL_DATINV_SHIFT 12 /* DACL_DATINV */ | ||
355 | #define WM8903_DACL_DATINV_WIDTH 1 /* DACL_DATINV */ | ||
356 | #define WM8903_DACR_DATINV 0x0800 /* DACR_DATINV */ | ||
357 | #define WM8903_DACR_DATINV_MASK 0x0800 /* DACR_DATINV */ | ||
358 | #define WM8903_DACR_DATINV_SHIFT 11 /* DACR_DATINV */ | ||
359 | #define WM8903_DACR_DATINV_WIDTH 1 /* DACR_DATINV */ | ||
360 | #define WM8903_DAC_BOOST_MASK 0x0600 /* DAC_BOOST - [10:9] */ | ||
361 | #define WM8903_DAC_BOOST_SHIFT 9 /* DAC_BOOST - [10:9] */ | ||
362 | #define WM8903_DAC_BOOST_WIDTH 2 /* DAC_BOOST - [10:9] */ | ||
363 | #define WM8903_LOOPBACK 0x0100 /* LOOPBACK */ | ||
364 | #define WM8903_LOOPBACK_MASK 0x0100 /* LOOPBACK */ | ||
365 | #define WM8903_LOOPBACK_SHIFT 8 /* LOOPBACK */ | ||
366 | #define WM8903_LOOPBACK_WIDTH 1 /* LOOPBACK */ | ||
367 | #define WM8903_AIFADCL_SRC 0x0080 /* AIFADCL_SRC */ | ||
368 | #define WM8903_AIFADCL_SRC_MASK 0x0080 /* AIFADCL_SRC */ | ||
369 | #define WM8903_AIFADCL_SRC_SHIFT 7 /* AIFADCL_SRC */ | ||
370 | #define WM8903_AIFADCL_SRC_WIDTH 1 /* AIFADCL_SRC */ | ||
371 | #define WM8903_AIFADCR_SRC 0x0040 /* AIFADCR_SRC */ | ||
372 | #define WM8903_AIFADCR_SRC_MASK 0x0040 /* AIFADCR_SRC */ | ||
373 | #define WM8903_AIFADCR_SRC_SHIFT 6 /* AIFADCR_SRC */ | ||
374 | #define WM8903_AIFADCR_SRC_WIDTH 1 /* AIFADCR_SRC */ | ||
375 | #define WM8903_AIFDACL_SRC 0x0020 /* AIFDACL_SRC */ | ||
376 | #define WM8903_AIFDACL_SRC_MASK 0x0020 /* AIFDACL_SRC */ | ||
377 | #define WM8903_AIFDACL_SRC_SHIFT 5 /* AIFDACL_SRC */ | ||
378 | #define WM8903_AIFDACL_SRC_WIDTH 1 /* AIFDACL_SRC */ | ||
379 | #define WM8903_AIFDACR_SRC 0x0010 /* AIFDACR_SRC */ | ||
380 | #define WM8903_AIFDACR_SRC_MASK 0x0010 /* AIFDACR_SRC */ | ||
381 | #define WM8903_AIFDACR_SRC_SHIFT 4 /* AIFDACR_SRC */ | ||
382 | #define WM8903_AIFDACR_SRC_WIDTH 1 /* AIFDACR_SRC */ | ||
383 | #define WM8903_ADC_COMP 0x0008 /* ADC_COMP */ | ||
384 | #define WM8903_ADC_COMP_MASK 0x0008 /* ADC_COMP */ | ||
385 | #define WM8903_ADC_COMP_SHIFT 3 /* ADC_COMP */ | ||
386 | #define WM8903_ADC_COMP_WIDTH 1 /* ADC_COMP */ | ||
387 | #define WM8903_ADC_COMPMODE 0x0004 /* ADC_COMPMODE */ | ||
388 | #define WM8903_ADC_COMPMODE_MASK 0x0004 /* ADC_COMPMODE */ | ||
389 | #define WM8903_ADC_COMPMODE_SHIFT 2 /* ADC_COMPMODE */ | ||
390 | #define WM8903_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */ | ||
391 | #define WM8903_DAC_COMP 0x0002 /* DAC_COMP */ | ||
392 | #define WM8903_DAC_COMP_MASK 0x0002 /* DAC_COMP */ | ||
393 | #define WM8903_DAC_COMP_SHIFT 1 /* DAC_COMP */ | ||
394 | #define WM8903_DAC_COMP_WIDTH 1 /* DAC_COMP */ | ||
395 | #define WM8903_DAC_COMPMODE 0x0001 /* DAC_COMPMODE */ | ||
396 | #define WM8903_DAC_COMPMODE_MASK 0x0001 /* DAC_COMPMODE */ | ||
397 | #define WM8903_DAC_COMPMODE_SHIFT 0 /* DAC_COMPMODE */ | ||
398 | #define WM8903_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */ | ||
399 | |||
400 | /* | ||
401 | * R25 (0x19) - Audio Interface 1 | ||
402 | */ | ||
403 | #define WM8903_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ | ||
404 | #define WM8903_AIFDAC_TDM_MASK 0x2000 /* AIFDAC_TDM */ | ||
405 | #define WM8903_AIFDAC_TDM_SHIFT 13 /* AIFDAC_TDM */ | ||
406 | #define WM8903_AIFDAC_TDM_WIDTH 1 /* AIFDAC_TDM */ | ||
407 | #define WM8903_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ | ||
408 | #define WM8903_AIFDAC_TDM_CHAN_MASK 0x1000 /* AIFDAC_TDM_CHAN */ | ||
409 | #define WM8903_AIFDAC_TDM_CHAN_SHIFT 12 /* AIFDAC_TDM_CHAN */ | ||
410 | #define WM8903_AIFDAC_TDM_CHAN_WIDTH 1 /* AIFDAC_TDM_CHAN */ | ||
411 | #define WM8903_AIFADC_TDM 0x0800 /* AIFADC_TDM */ | ||
412 | #define WM8903_AIFADC_TDM_MASK 0x0800 /* AIFADC_TDM */ | ||
413 | #define WM8903_AIFADC_TDM_SHIFT 11 /* AIFADC_TDM */ | ||
414 | #define WM8903_AIFADC_TDM_WIDTH 1 /* AIFADC_TDM */ | ||
415 | #define WM8903_AIFADC_TDM_CHAN 0x0400 /* AIFADC_TDM_CHAN */ | ||
416 | #define WM8903_AIFADC_TDM_CHAN_MASK 0x0400 /* AIFADC_TDM_CHAN */ | ||
417 | #define WM8903_AIFADC_TDM_CHAN_SHIFT 10 /* AIFADC_TDM_CHAN */ | ||
418 | #define WM8903_AIFADC_TDM_CHAN_WIDTH 1 /* AIFADC_TDM_CHAN */ | ||
419 | #define WM8903_LRCLK_DIR 0x0200 /* LRCLK_DIR */ | ||
420 | #define WM8903_LRCLK_DIR_MASK 0x0200 /* LRCLK_DIR */ | ||
421 | #define WM8903_LRCLK_DIR_SHIFT 9 /* LRCLK_DIR */ | ||
422 | #define WM8903_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */ | ||
423 | #define WM8903_AIF_BCLK_INV 0x0080 /* AIF_BCLK_INV */ | ||
424 | #define WM8903_AIF_BCLK_INV_MASK 0x0080 /* AIF_BCLK_INV */ | ||
425 | #define WM8903_AIF_BCLK_INV_SHIFT 7 /* AIF_BCLK_INV */ | ||
426 | #define WM8903_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */ | ||
427 | #define WM8903_BCLK_DIR 0x0040 /* BCLK_DIR */ | ||
428 | #define WM8903_BCLK_DIR_MASK 0x0040 /* BCLK_DIR */ | ||
429 | #define WM8903_BCLK_DIR_SHIFT 6 /* BCLK_DIR */ | ||
430 | #define WM8903_BCLK_DIR_WIDTH 1 /* BCLK_DIR */ | ||
431 | #define WM8903_AIF_LRCLK_INV 0x0010 /* AIF_LRCLK_INV */ | ||
432 | #define WM8903_AIF_LRCLK_INV_MASK 0x0010 /* AIF_LRCLK_INV */ | ||
433 | #define WM8903_AIF_LRCLK_INV_SHIFT 4 /* AIF_LRCLK_INV */ | ||
434 | #define WM8903_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */ | ||
435 | #define WM8903_AIF_WL_MASK 0x000C /* AIF_WL - [3:2] */ | ||
436 | #define WM8903_AIF_WL_SHIFT 2 /* AIF_WL - [3:2] */ | ||
437 | #define WM8903_AIF_WL_WIDTH 2 /* AIF_WL - [3:2] */ | ||
438 | #define WM8903_AIF_FMT_MASK 0x0003 /* AIF_FMT - [1:0] */ | ||
439 | #define WM8903_AIF_FMT_SHIFT 0 /* AIF_FMT - [1:0] */ | ||
440 | #define WM8903_AIF_FMT_WIDTH 2 /* AIF_FMT - [1:0] */ | ||
441 | |||
442 | /* | ||
443 | * R26 (0x1A) - Audio Interface 2 | ||
444 | */ | ||
445 | #define WM8903_BCLK_DIV_MASK 0x001F /* BCLK_DIV - [4:0] */ | ||
446 | #define WM8903_BCLK_DIV_SHIFT 0 /* BCLK_DIV - [4:0] */ | ||
447 | #define WM8903_BCLK_DIV_WIDTH 5 /* BCLK_DIV - [4:0] */ | ||
448 | |||
449 | /* | ||
450 | * R27 (0x1B) - Audio Interface 3 | ||
451 | */ | ||
452 | #define WM8903_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */ | ||
453 | #define WM8903_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */ | ||
454 | #define WM8903_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */ | ||
455 | |||
456 | /* | ||
457 | * R30 (0x1E) - DAC Digital Volume Left | ||
458 | */ | ||
459 | #define WM8903_DACVU 0x0100 /* DACVU */ | ||
460 | #define WM8903_DACVU_MASK 0x0100 /* DACVU */ | ||
461 | #define WM8903_DACVU_SHIFT 8 /* DACVU */ | ||
462 | #define WM8903_DACVU_WIDTH 1 /* DACVU */ | ||
463 | #define WM8903_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ | ||
464 | #define WM8903_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */ | ||
465 | #define WM8903_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */ | ||
466 | |||
467 | /* | ||
468 | * R31 (0x1F) - DAC Digital Volume Right | ||
469 | */ | ||
470 | #define WM8903_DACVU 0x0100 /* DACVU */ | ||
471 | #define WM8903_DACVU_MASK 0x0100 /* DACVU */ | ||
472 | #define WM8903_DACVU_SHIFT 8 /* DACVU */ | ||
473 | #define WM8903_DACVU_WIDTH 1 /* DACVU */ | ||
474 | #define WM8903_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ | ||
475 | #define WM8903_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */ | ||
476 | #define WM8903_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */ | ||
477 | |||
478 | /* | ||
479 | * R32 (0x20) - DAC Digital 0 | ||
480 | */ | ||
481 | #define WM8903_ADCL_DAC_SVOL_MASK 0x0F00 /* ADCL_DAC_SVOL - [11:8] */ | ||
482 | #define WM8903_ADCL_DAC_SVOL_SHIFT 8 /* ADCL_DAC_SVOL - [11:8] */ | ||
483 | #define WM8903_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [11:8] */ | ||
484 | #define WM8903_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */ | ||
485 | #define WM8903_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */ | ||
486 | #define WM8903_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */ | ||
487 | #define WM8903_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */ | ||
488 | #define WM8903_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */ | ||
489 | #define WM8903_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */ | ||
490 | #define WM8903_ADC_TO_DACR_MASK 0x0003 /* ADC_TO_DACR - [1:0] */ | ||
491 | #define WM8903_ADC_TO_DACR_SHIFT 0 /* ADC_TO_DACR - [1:0] */ | ||
492 | #define WM8903_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [1:0] */ | ||
493 | |||
494 | /* | ||
495 | * R33 (0x21) - DAC Digital 1 | ||
496 | */ | ||
497 | #define WM8903_DAC_MONO 0x1000 /* DAC_MONO */ | ||
498 | #define WM8903_DAC_MONO_MASK 0x1000 /* DAC_MONO */ | ||
499 | #define WM8903_DAC_MONO_SHIFT 12 /* DAC_MONO */ | ||
500 | #define WM8903_DAC_MONO_WIDTH 1 /* DAC_MONO */ | ||
501 | #define WM8903_DAC_SB_FILT 0x0800 /* DAC_SB_FILT */ | ||
502 | #define WM8903_DAC_SB_FILT_MASK 0x0800 /* DAC_SB_FILT */ | ||
503 | #define WM8903_DAC_SB_FILT_SHIFT 11 /* DAC_SB_FILT */ | ||
504 | #define WM8903_DAC_SB_FILT_WIDTH 1 /* DAC_SB_FILT */ | ||
505 | #define WM8903_DAC_MUTERATE 0x0400 /* DAC_MUTERATE */ | ||
506 | #define WM8903_DAC_MUTERATE_MASK 0x0400 /* DAC_MUTERATE */ | ||
507 | #define WM8903_DAC_MUTERATE_SHIFT 10 /* DAC_MUTERATE */ | ||
508 | #define WM8903_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */ | ||
509 | #define WM8903_DAC_MUTEMODE 0x0200 /* DAC_MUTEMODE */ | ||
510 | #define WM8903_DAC_MUTEMODE_MASK 0x0200 /* DAC_MUTEMODE */ | ||
511 | #define WM8903_DAC_MUTEMODE_SHIFT 9 /* DAC_MUTEMODE */ | ||
512 | #define WM8903_DAC_MUTEMODE_WIDTH 1 /* DAC_MUTEMODE */ | ||
513 | #define WM8903_DAC_MUTE 0x0008 /* DAC_MUTE */ | ||
514 | #define WM8903_DAC_MUTE_MASK 0x0008 /* DAC_MUTE */ | ||
515 | #define WM8903_DAC_MUTE_SHIFT 3 /* DAC_MUTE */ | ||
516 | #define WM8903_DAC_MUTE_WIDTH 1 /* DAC_MUTE */ | ||
517 | #define WM8903_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ | ||
518 | #define WM8903_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ | ||
519 | #define WM8903_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ | ||
520 | |||
521 | /* | ||
522 | * R36 (0x24) - ADC Digital Volume Left | ||
523 | */ | ||
524 | #define WM8903_ADCVU 0x0100 /* ADCVU */ | ||
525 | #define WM8903_ADCVU_MASK 0x0100 /* ADCVU */ | ||
526 | #define WM8903_ADCVU_SHIFT 8 /* ADCVU */ | ||
527 | #define WM8903_ADCVU_WIDTH 1 /* ADCVU */ | ||
528 | #define WM8903_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ | ||
529 | #define WM8903_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */ | ||
530 | #define WM8903_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */ | ||
531 | |||
532 | /* | ||
533 | * R37 (0x25) - ADC Digital Volume Right | ||
534 | */ | ||
535 | #define WM8903_ADCVU 0x0100 /* ADCVU */ | ||
536 | #define WM8903_ADCVU_MASK 0x0100 /* ADCVU */ | ||
537 | #define WM8903_ADCVU_SHIFT 8 /* ADCVU */ | ||
538 | #define WM8903_ADCVU_WIDTH 1 /* ADCVU */ | ||
539 | #define WM8903_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ | ||
540 | #define WM8903_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */ | ||
541 | #define WM8903_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */ | ||
542 | |||
543 | /* | ||
544 | * R38 (0x26) - ADC Digital 0 | ||
545 | */ | ||
546 | #define WM8903_ADC_HPF_CUT_MASK 0x0060 /* ADC_HPF_CUT - [6:5] */ | ||
547 | #define WM8903_ADC_HPF_CUT_SHIFT 5 /* ADC_HPF_CUT - [6:5] */ | ||
548 | #define WM8903_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [6:5] */ | ||
549 | #define WM8903_ADC_HPF_ENA 0x0010 /* ADC_HPF_ENA */ | ||
550 | #define WM8903_ADC_HPF_ENA_MASK 0x0010 /* ADC_HPF_ENA */ | ||
551 | #define WM8903_ADC_HPF_ENA_SHIFT 4 /* ADC_HPF_ENA */ | ||
552 | #define WM8903_ADC_HPF_ENA_WIDTH 1 /* ADC_HPF_ENA */ | ||
553 | #define WM8903_ADCL_DATINV 0x0002 /* ADCL_DATINV */ | ||
554 | #define WM8903_ADCL_DATINV_MASK 0x0002 /* ADCL_DATINV */ | ||
555 | #define WM8903_ADCL_DATINV_SHIFT 1 /* ADCL_DATINV */ | ||
556 | #define WM8903_ADCL_DATINV_WIDTH 1 /* ADCL_DATINV */ | ||
557 | #define WM8903_ADCR_DATINV 0x0001 /* ADCR_DATINV */ | ||
558 | #define WM8903_ADCR_DATINV_MASK 0x0001 /* ADCR_DATINV */ | ||
559 | #define WM8903_ADCR_DATINV_SHIFT 0 /* ADCR_DATINV */ | ||
560 | #define WM8903_ADCR_DATINV_WIDTH 1 /* ADCR_DATINV */ | ||
561 | |||
562 | /* | ||
563 | * R39 (0x27) - Digital Microphone 0 | ||
564 | */ | ||
565 | #define WM8903_DIGMIC_MODE_SEL 0x0100 /* DIGMIC_MODE_SEL */ | ||
566 | #define WM8903_DIGMIC_MODE_SEL_MASK 0x0100 /* DIGMIC_MODE_SEL */ | ||
567 | #define WM8903_DIGMIC_MODE_SEL_SHIFT 8 /* DIGMIC_MODE_SEL */ | ||
568 | #define WM8903_DIGMIC_MODE_SEL_WIDTH 1 /* DIGMIC_MODE_SEL */ | ||
569 | #define WM8903_DIGMIC_CLK_SEL_L_MASK 0x00C0 /* DIGMIC_CLK_SEL_L - [7:6] */ | ||
570 | #define WM8903_DIGMIC_CLK_SEL_L_SHIFT 6 /* DIGMIC_CLK_SEL_L - [7:6] */ | ||
571 | #define WM8903_DIGMIC_CLK_SEL_L_WIDTH 2 /* DIGMIC_CLK_SEL_L - [7:6] */ | ||
572 | #define WM8903_DIGMIC_CLK_SEL_R_MASK 0x0030 /* DIGMIC_CLK_SEL_R - [5:4] */ | ||
573 | #define WM8903_DIGMIC_CLK_SEL_R_SHIFT 4 /* DIGMIC_CLK_SEL_R - [5:4] */ | ||
574 | #define WM8903_DIGMIC_CLK_SEL_R_WIDTH 2 /* DIGMIC_CLK_SEL_R - [5:4] */ | ||
575 | #define WM8903_DIGMIC_CLK_SEL_RT_MASK 0x000C /* DIGMIC_CLK_SEL_RT - [3:2] */ | ||
576 | #define WM8903_DIGMIC_CLK_SEL_RT_SHIFT 2 /* DIGMIC_CLK_SEL_RT - [3:2] */ | ||
577 | #define WM8903_DIGMIC_CLK_SEL_RT_WIDTH 2 /* DIGMIC_CLK_SEL_RT - [3:2] */ | ||
578 | #define WM8903_DIGMIC_CLK_SEL_MASK 0x0003 /* DIGMIC_CLK_SEL - [1:0] */ | ||
579 | #define WM8903_DIGMIC_CLK_SEL_SHIFT 0 /* DIGMIC_CLK_SEL - [1:0] */ | ||
580 | #define WM8903_DIGMIC_CLK_SEL_WIDTH 2 /* DIGMIC_CLK_SEL - [1:0] */ | ||
581 | |||
582 | /* | ||
583 | * R40 (0x28) - DRC 0 | ||
584 | */ | ||
585 | #define WM8903_DRC_ENA 0x8000 /* DRC_ENA */ | ||
586 | #define WM8903_DRC_ENA_MASK 0x8000 /* DRC_ENA */ | ||
587 | #define WM8903_DRC_ENA_SHIFT 15 /* DRC_ENA */ | ||
588 | #define WM8903_DRC_ENA_WIDTH 1 /* DRC_ENA */ | ||
589 | #define WM8903_DRC_THRESH_HYST_MASK 0x1800 /* DRC_THRESH_HYST - [12:11] */ | ||
590 | #define WM8903_DRC_THRESH_HYST_SHIFT 11 /* DRC_THRESH_HYST - [12:11] */ | ||
591 | #define WM8903_DRC_THRESH_HYST_WIDTH 2 /* DRC_THRESH_HYST - [12:11] */ | ||
592 | #define WM8903_DRC_STARTUP_GAIN_MASK 0x07C0 /* DRC_STARTUP_GAIN - [10:6] */ | ||
593 | #define WM8903_DRC_STARTUP_GAIN_SHIFT 6 /* DRC_STARTUP_GAIN - [10:6] */ | ||
594 | #define WM8903_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [10:6] */ | ||
595 | #define WM8903_DRC_FF_DELAY 0x0020 /* DRC_FF_DELAY */ | ||
596 | #define WM8903_DRC_FF_DELAY_MASK 0x0020 /* DRC_FF_DELAY */ | ||
597 | #define WM8903_DRC_FF_DELAY_SHIFT 5 /* DRC_FF_DELAY */ | ||
598 | #define WM8903_DRC_FF_DELAY_WIDTH 1 /* DRC_FF_DELAY */ | ||
599 | #define WM8903_DRC_SMOOTH_ENA 0x0008 /* DRC_SMOOTH_ENA */ | ||
600 | #define WM8903_DRC_SMOOTH_ENA_MASK 0x0008 /* DRC_SMOOTH_ENA */ | ||
601 | #define WM8903_DRC_SMOOTH_ENA_SHIFT 3 /* DRC_SMOOTH_ENA */ | ||
602 | #define WM8903_DRC_SMOOTH_ENA_WIDTH 1 /* DRC_SMOOTH_ENA */ | ||
603 | #define WM8903_DRC_QR_ENA 0x0004 /* DRC_QR_ENA */ | ||
604 | #define WM8903_DRC_QR_ENA_MASK 0x0004 /* DRC_QR_ENA */ | ||
605 | #define WM8903_DRC_QR_ENA_SHIFT 2 /* DRC_QR_ENA */ | ||
606 | #define WM8903_DRC_QR_ENA_WIDTH 1 /* DRC_QR_ENA */ | ||
607 | #define WM8903_DRC_ANTICLIP_ENA 0x0002 /* DRC_ANTICLIP_ENA */ | ||
608 | #define WM8903_DRC_ANTICLIP_ENA_MASK 0x0002 /* DRC_ANTICLIP_ENA */ | ||
609 | #define WM8903_DRC_ANTICLIP_ENA_SHIFT 1 /* DRC_ANTICLIP_ENA */ | ||
610 | #define WM8903_DRC_ANTICLIP_ENA_WIDTH 1 /* DRC_ANTICLIP_ENA */ | ||
611 | #define WM8903_DRC_HYST_ENA 0x0001 /* DRC_HYST_ENA */ | ||
612 | #define WM8903_DRC_HYST_ENA_MASK 0x0001 /* DRC_HYST_ENA */ | ||
613 | #define WM8903_DRC_HYST_ENA_SHIFT 0 /* DRC_HYST_ENA */ | ||
614 | #define WM8903_DRC_HYST_ENA_WIDTH 1 /* DRC_HYST_ENA */ | ||
615 | |||
616 | /* | ||
617 | * R41 (0x29) - DRC 1 | ||
618 | */ | ||
619 | #define WM8903_DRC_ATTACK_RATE_MASK 0xF000 /* DRC_ATTACK_RATE - [15:12] */ | ||
620 | #define WM8903_DRC_ATTACK_RATE_SHIFT 12 /* DRC_ATTACK_RATE - [15:12] */ | ||
621 | #define WM8903_DRC_ATTACK_RATE_WIDTH 4 /* DRC_ATTACK_RATE - [15:12] */ | ||
622 | #define WM8903_DRC_DECAY_RATE_MASK 0x0F00 /* DRC_DECAY_RATE - [11:8] */ | ||
623 | #define WM8903_DRC_DECAY_RATE_SHIFT 8 /* DRC_DECAY_RATE - [11:8] */ | ||
624 | #define WM8903_DRC_DECAY_RATE_WIDTH 4 /* DRC_DECAY_RATE - [11:8] */ | ||
625 | #define WM8903_DRC_THRESH_QR_MASK 0x00C0 /* DRC_THRESH_QR - [7:6] */ | ||
626 | #define WM8903_DRC_THRESH_QR_SHIFT 6 /* DRC_THRESH_QR - [7:6] */ | ||
627 | #define WM8903_DRC_THRESH_QR_WIDTH 2 /* DRC_THRESH_QR - [7:6] */ | ||
628 | #define WM8903_DRC_RATE_QR_MASK 0x0030 /* DRC_RATE_QR - [5:4] */ | ||
629 | #define WM8903_DRC_RATE_QR_SHIFT 4 /* DRC_RATE_QR - [5:4] */ | ||
630 | #define WM8903_DRC_RATE_QR_WIDTH 2 /* DRC_RATE_QR - [5:4] */ | ||
631 | #define WM8903_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */ | ||
632 | #define WM8903_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */ | ||
633 | #define WM8903_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */ | ||
634 | #define WM8903_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */ | ||
635 | #define WM8903_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */ | ||
636 | #define WM8903_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */ | ||
637 | |||
638 | /* | ||
639 | * R42 (0x2A) - DRC 2 | ||
640 | */ | ||
641 | #define WM8903_DRC_R0_SLOPE_COMP_MASK 0x0038 /* DRC_R0_SLOPE_COMP - [5:3] */ | ||
642 | #define WM8903_DRC_R0_SLOPE_COMP_SHIFT 3 /* DRC_R0_SLOPE_COMP - [5:3] */ | ||
643 | #define WM8903_DRC_R0_SLOPE_COMP_WIDTH 3 /* DRC_R0_SLOPE_COMP - [5:3] */ | ||
644 | #define WM8903_DRC_R1_SLOPE_COMP_MASK 0x0007 /* DRC_R1_SLOPE_COMP - [2:0] */ | ||
645 | #define WM8903_DRC_R1_SLOPE_COMP_SHIFT 0 /* DRC_R1_SLOPE_COMP - [2:0] */ | ||
646 | #define WM8903_DRC_R1_SLOPE_COMP_WIDTH 3 /* DRC_R1_SLOPE_COMP - [2:0] */ | ||
647 | |||
648 | /* | ||
649 | * R43 (0x2B) - DRC 3 | ||
650 | */ | ||
651 | #define WM8903_DRC_THRESH_COMP_MASK 0x07E0 /* DRC_THRESH_COMP - [10:5] */ | ||
652 | #define WM8903_DRC_THRESH_COMP_SHIFT 5 /* DRC_THRESH_COMP - [10:5] */ | ||
653 | #define WM8903_DRC_THRESH_COMP_WIDTH 6 /* DRC_THRESH_COMP - [10:5] */ | ||
654 | #define WM8903_DRC_AMP_COMP_MASK 0x001F /* DRC_AMP_COMP - [4:0] */ | ||
655 | #define WM8903_DRC_AMP_COMP_SHIFT 0 /* DRC_AMP_COMP - [4:0] */ | ||
656 | #define WM8903_DRC_AMP_COMP_WIDTH 5 /* DRC_AMP_COMP - [4:0] */ | ||
657 | |||
658 | /* | ||
659 | * R44 (0x2C) - Analogue Left Input 0 | ||
660 | */ | ||
661 | #define WM8903_LINMUTE 0x0080 /* LINMUTE */ | ||
662 | #define WM8903_LINMUTE_MASK 0x0080 /* LINMUTE */ | ||
663 | #define WM8903_LINMUTE_SHIFT 7 /* LINMUTE */ | ||
664 | #define WM8903_LINMUTE_WIDTH 1 /* LINMUTE */ | ||
665 | #define WM8903_LIN_VOL_MASK 0x001F /* LIN_VOL - [4:0] */ | ||
666 | #define WM8903_LIN_VOL_SHIFT 0 /* LIN_VOL - [4:0] */ | ||
667 | #define WM8903_LIN_VOL_WIDTH 5 /* LIN_VOL - [4:0] */ | ||
668 | |||
669 | /* | ||
670 | * R45 (0x2D) - Analogue Right Input 0 | ||
671 | */ | ||
672 | #define WM8903_RINMUTE 0x0080 /* RINMUTE */ | ||
673 | #define WM8903_RINMUTE_MASK 0x0080 /* RINMUTE */ | ||
674 | #define WM8903_RINMUTE_SHIFT 7 /* RINMUTE */ | ||
675 | #define WM8903_RINMUTE_WIDTH 1 /* RINMUTE */ | ||
676 | #define WM8903_RIN_VOL_MASK 0x001F /* RIN_VOL - [4:0] */ | ||
677 | #define WM8903_RIN_VOL_SHIFT 0 /* RIN_VOL - [4:0] */ | ||
678 | #define WM8903_RIN_VOL_WIDTH 5 /* RIN_VOL - [4:0] */ | ||
679 | |||
680 | /* | ||
681 | * R46 (0x2E) - Analogue Left Input 1 | ||
682 | */ | ||
683 | #define WM8903_INL_CM_ENA 0x0040 /* INL_CM_ENA */ | ||
684 | #define WM8903_INL_CM_ENA_MASK 0x0040 /* INL_CM_ENA */ | ||
685 | #define WM8903_INL_CM_ENA_SHIFT 6 /* INL_CM_ENA */ | ||
686 | #define WM8903_INL_CM_ENA_WIDTH 1 /* INL_CM_ENA */ | ||
687 | #define WM8903_L_IP_SEL_N_MASK 0x0030 /* L_IP_SEL_N - [5:4] */ | ||
688 | #define WM8903_L_IP_SEL_N_SHIFT 4 /* L_IP_SEL_N - [5:4] */ | ||
689 | #define WM8903_L_IP_SEL_N_WIDTH 2 /* L_IP_SEL_N - [5:4] */ | ||
690 | #define WM8903_L_IP_SEL_P_MASK 0x000C /* L_IP_SEL_P - [3:2] */ | ||
691 | #define WM8903_L_IP_SEL_P_SHIFT 2 /* L_IP_SEL_P - [3:2] */ | ||
692 | #define WM8903_L_IP_SEL_P_WIDTH 2 /* L_IP_SEL_P - [3:2] */ | ||
693 | #define WM8903_L_MODE_MASK 0x0003 /* L_MODE - [1:0] */ | ||
694 | #define WM8903_L_MODE_SHIFT 0 /* L_MODE - [1:0] */ | ||
695 | #define WM8903_L_MODE_WIDTH 2 /* L_MODE - [1:0] */ | ||
696 | |||
697 | /* | ||
698 | * R47 (0x2F) - Analogue Right Input 1 | ||
699 | */ | ||
700 | #define WM8903_INR_CM_ENA 0x0040 /* INR_CM_ENA */ | ||
701 | #define WM8903_INR_CM_ENA_MASK 0x0040 /* INR_CM_ENA */ | ||
702 | #define WM8903_INR_CM_ENA_SHIFT 6 /* INR_CM_ENA */ | ||
703 | #define WM8903_INR_CM_ENA_WIDTH 1 /* INR_CM_ENA */ | ||
704 | #define WM8903_R_IP_SEL_N_MASK 0x0030 /* R_IP_SEL_N - [5:4] */ | ||
705 | #define WM8903_R_IP_SEL_N_SHIFT 4 /* R_IP_SEL_N - [5:4] */ | ||
706 | #define WM8903_R_IP_SEL_N_WIDTH 2 /* R_IP_SEL_N - [5:4] */ | ||
707 | #define WM8903_R_IP_SEL_P_MASK 0x000C /* R_IP_SEL_P - [3:2] */ | ||
708 | #define WM8903_R_IP_SEL_P_SHIFT 2 /* R_IP_SEL_P - [3:2] */ | ||
709 | #define WM8903_R_IP_SEL_P_WIDTH 2 /* R_IP_SEL_P - [3:2] */ | ||
710 | #define WM8903_R_MODE_MASK 0x0003 /* R_MODE - [1:0] */ | ||
711 | #define WM8903_R_MODE_SHIFT 0 /* R_MODE - [1:0] */ | ||
712 | #define WM8903_R_MODE_WIDTH 2 /* R_MODE - [1:0] */ | ||
713 | |||
714 | /* | ||
715 | * R50 (0x32) - Analogue Left Mix 0 | ||
716 | */ | ||
717 | #define WM8903_DACL_TO_MIXOUTL 0x0008 /* DACL_TO_MIXOUTL */ | ||
718 | #define WM8903_DACL_TO_MIXOUTL_MASK 0x0008 /* DACL_TO_MIXOUTL */ | ||
719 | #define WM8903_DACL_TO_MIXOUTL_SHIFT 3 /* DACL_TO_MIXOUTL */ | ||
720 | #define WM8903_DACL_TO_MIXOUTL_WIDTH 1 /* DACL_TO_MIXOUTL */ | ||
721 | #define WM8903_DACR_TO_MIXOUTL 0x0004 /* DACR_TO_MIXOUTL */ | ||
722 | #define WM8903_DACR_TO_MIXOUTL_MASK 0x0004 /* DACR_TO_MIXOUTL */ | ||
723 | #define WM8903_DACR_TO_MIXOUTL_SHIFT 2 /* DACR_TO_MIXOUTL */ | ||
724 | #define WM8903_DACR_TO_MIXOUTL_WIDTH 1 /* DACR_TO_MIXOUTL */ | ||
725 | #define WM8903_BYPASSL_TO_MIXOUTL 0x0002 /* BYPASSL_TO_MIXOUTL */ | ||
726 | #define WM8903_BYPASSL_TO_MIXOUTL_MASK 0x0002 /* BYPASSL_TO_MIXOUTL */ | ||
727 | #define WM8903_BYPASSL_TO_MIXOUTL_SHIFT 1 /* BYPASSL_TO_MIXOUTL */ | ||
728 | #define WM8903_BYPASSL_TO_MIXOUTL_WIDTH 1 /* BYPASSL_TO_MIXOUTL */ | ||
729 | #define WM8903_BYPASSR_TO_MIXOUTL 0x0001 /* BYPASSR_TO_MIXOUTL */ | ||
730 | #define WM8903_BYPASSR_TO_MIXOUTL_MASK 0x0001 /* BYPASSR_TO_MIXOUTL */ | ||
731 | #define WM8903_BYPASSR_TO_MIXOUTL_SHIFT 0 /* BYPASSR_TO_MIXOUTL */ | ||
732 | #define WM8903_BYPASSR_TO_MIXOUTL_WIDTH 1 /* BYPASSR_TO_MIXOUTL */ | ||
733 | |||
734 | /* | ||
735 | * R51 (0x33) - Analogue Right Mix 0 | ||
736 | */ | ||
737 | #define WM8903_DACL_TO_MIXOUTR 0x0008 /* DACL_TO_MIXOUTR */ | ||
738 | #define WM8903_DACL_TO_MIXOUTR_MASK 0x0008 /* DACL_TO_MIXOUTR */ | ||
739 | #define WM8903_DACL_TO_MIXOUTR_SHIFT 3 /* DACL_TO_MIXOUTR */ | ||
740 | #define WM8903_DACL_TO_MIXOUTR_WIDTH 1 /* DACL_TO_MIXOUTR */ | ||
741 | #define WM8903_DACR_TO_MIXOUTR 0x0004 /* DACR_TO_MIXOUTR */ | ||
742 | #define WM8903_DACR_TO_MIXOUTR_MASK 0x0004 /* DACR_TO_MIXOUTR */ | ||
743 | #define WM8903_DACR_TO_MIXOUTR_SHIFT 2 /* DACR_TO_MIXOUTR */ | ||
744 | #define WM8903_DACR_TO_MIXOUTR_WIDTH 1 /* DACR_TO_MIXOUTR */ | ||
745 | #define WM8903_BYPASSL_TO_MIXOUTR 0x0002 /* BYPASSL_TO_MIXOUTR */ | ||
746 | #define WM8903_BYPASSL_TO_MIXOUTR_MASK 0x0002 /* BYPASSL_TO_MIXOUTR */ | ||
747 | #define WM8903_BYPASSL_TO_MIXOUTR_SHIFT 1 /* BYPASSL_TO_MIXOUTR */ | ||
748 | #define WM8903_BYPASSL_TO_MIXOUTR_WIDTH 1 /* BYPASSL_TO_MIXOUTR */ | ||
749 | #define WM8903_BYPASSR_TO_MIXOUTR 0x0001 /* BYPASSR_TO_MIXOUTR */ | ||
750 | #define WM8903_BYPASSR_TO_MIXOUTR_MASK 0x0001 /* BYPASSR_TO_MIXOUTR */ | ||
751 | #define WM8903_BYPASSR_TO_MIXOUTR_SHIFT 0 /* BYPASSR_TO_MIXOUTR */ | ||
752 | #define WM8903_BYPASSR_TO_MIXOUTR_WIDTH 1 /* BYPASSR_TO_MIXOUTR */ | ||
753 | |||
754 | /* | ||
755 | * R52 (0x34) - Analogue Spk Mix Left 0 | ||
756 | */ | ||
757 | #define WM8903_DACL_TO_MIXSPKL 0x0008 /* DACL_TO_MIXSPKL */ | ||
758 | #define WM8903_DACL_TO_MIXSPKL_MASK 0x0008 /* DACL_TO_MIXSPKL */ | ||
759 | #define WM8903_DACL_TO_MIXSPKL_SHIFT 3 /* DACL_TO_MIXSPKL */ | ||
760 | #define WM8903_DACL_TO_MIXSPKL_WIDTH 1 /* DACL_TO_MIXSPKL */ | ||
761 | #define WM8903_DACR_TO_MIXSPKL 0x0004 /* DACR_TO_MIXSPKL */ | ||
762 | #define WM8903_DACR_TO_MIXSPKL_MASK 0x0004 /* DACR_TO_MIXSPKL */ | ||
763 | #define WM8903_DACR_TO_MIXSPKL_SHIFT 2 /* DACR_TO_MIXSPKL */ | ||
764 | #define WM8903_DACR_TO_MIXSPKL_WIDTH 1 /* DACR_TO_MIXSPKL */ | ||
765 | #define WM8903_BYPASSL_TO_MIXSPKL 0x0002 /* BYPASSL_TO_MIXSPKL */ | ||
766 | #define WM8903_BYPASSL_TO_MIXSPKL_MASK 0x0002 /* BYPASSL_TO_MIXSPKL */ | ||
767 | #define WM8903_BYPASSL_TO_MIXSPKL_SHIFT 1 /* BYPASSL_TO_MIXSPKL */ | ||
768 | #define WM8903_BYPASSL_TO_MIXSPKL_WIDTH 1 /* BYPASSL_TO_MIXSPKL */ | ||
769 | #define WM8903_BYPASSR_TO_MIXSPKL 0x0001 /* BYPASSR_TO_MIXSPKL */ | ||
770 | #define WM8903_BYPASSR_TO_MIXSPKL_MASK 0x0001 /* BYPASSR_TO_MIXSPKL */ | ||
771 | #define WM8903_BYPASSR_TO_MIXSPKL_SHIFT 0 /* BYPASSR_TO_MIXSPKL */ | ||
772 | #define WM8903_BYPASSR_TO_MIXSPKL_WIDTH 1 /* BYPASSR_TO_MIXSPKL */ | ||
773 | |||
774 | /* | ||
775 | * R53 (0x35) - Analogue Spk Mix Left 1 | ||
776 | */ | ||
777 | #define WM8903_DACL_MIXSPKL_VOL 0x0008 /* DACL_MIXSPKL_VOL */ | ||
778 | #define WM8903_DACL_MIXSPKL_VOL_MASK 0x0008 /* DACL_MIXSPKL_VOL */ | ||
779 | #define WM8903_DACL_MIXSPKL_VOL_SHIFT 3 /* DACL_MIXSPKL_VOL */ | ||
780 | #define WM8903_DACL_MIXSPKL_VOL_WIDTH 1 /* DACL_MIXSPKL_VOL */ | ||
781 | #define WM8903_DACR_MIXSPKL_VOL 0x0004 /* DACR_MIXSPKL_VOL */ | ||
782 | #define WM8903_DACR_MIXSPKL_VOL_MASK 0x0004 /* DACR_MIXSPKL_VOL */ | ||
783 | #define WM8903_DACR_MIXSPKL_VOL_SHIFT 2 /* DACR_MIXSPKL_VOL */ | ||
784 | #define WM8903_DACR_MIXSPKL_VOL_WIDTH 1 /* DACR_MIXSPKL_VOL */ | ||
785 | #define WM8903_BYPASSL_MIXSPKL_VOL 0x0002 /* BYPASSL_MIXSPKL_VOL */ | ||
786 | #define WM8903_BYPASSL_MIXSPKL_VOL_MASK 0x0002 /* BYPASSL_MIXSPKL_VOL */ | ||
787 | #define WM8903_BYPASSL_MIXSPKL_VOL_SHIFT 1 /* BYPASSL_MIXSPKL_VOL */ | ||
788 | #define WM8903_BYPASSL_MIXSPKL_VOL_WIDTH 1 /* BYPASSL_MIXSPKL_VOL */ | ||
789 | #define WM8903_BYPASSR_MIXSPKL_VOL 0x0001 /* BYPASSR_MIXSPKL_VOL */ | ||
790 | #define WM8903_BYPASSR_MIXSPKL_VOL_MASK 0x0001 /* BYPASSR_MIXSPKL_VOL */ | ||
791 | #define WM8903_BYPASSR_MIXSPKL_VOL_SHIFT 0 /* BYPASSR_MIXSPKL_VOL */ | ||
792 | #define WM8903_BYPASSR_MIXSPKL_VOL_WIDTH 1 /* BYPASSR_MIXSPKL_VOL */ | ||
793 | |||
794 | /* | ||
795 | * R54 (0x36) - Analogue Spk Mix Right 0 | ||
796 | */ | ||
797 | #define WM8903_DACL_TO_MIXSPKR 0x0008 /* DACL_TO_MIXSPKR */ | ||
798 | #define WM8903_DACL_TO_MIXSPKR_MASK 0x0008 /* DACL_TO_MIXSPKR */ | ||
799 | #define WM8903_DACL_TO_MIXSPKR_SHIFT 3 /* DACL_TO_MIXSPKR */ | ||
800 | #define WM8903_DACL_TO_MIXSPKR_WIDTH 1 /* DACL_TO_MIXSPKR */ | ||
801 | #define WM8903_DACR_TO_MIXSPKR 0x0004 /* DACR_TO_MIXSPKR */ | ||
802 | #define WM8903_DACR_TO_MIXSPKR_MASK 0x0004 /* DACR_TO_MIXSPKR */ | ||
803 | #define WM8903_DACR_TO_MIXSPKR_SHIFT 2 /* DACR_TO_MIXSPKR */ | ||
804 | #define WM8903_DACR_TO_MIXSPKR_WIDTH 1 /* DACR_TO_MIXSPKR */ | ||
805 | #define WM8903_BYPASSL_TO_MIXSPKR 0x0002 /* BYPASSL_TO_MIXSPKR */ | ||
806 | #define WM8903_BYPASSL_TO_MIXSPKR_MASK 0x0002 /* BYPASSL_TO_MIXSPKR */ | ||
807 | #define WM8903_BYPASSL_TO_MIXSPKR_SHIFT 1 /* BYPASSL_TO_MIXSPKR */ | ||
808 | #define WM8903_BYPASSL_TO_MIXSPKR_WIDTH 1 /* BYPASSL_TO_MIXSPKR */ | ||
809 | #define WM8903_BYPASSR_TO_MIXSPKR 0x0001 /* BYPASSR_TO_MIXSPKR */ | ||
810 | #define WM8903_BYPASSR_TO_MIXSPKR_MASK 0x0001 /* BYPASSR_TO_MIXSPKR */ | ||
811 | #define WM8903_BYPASSR_TO_MIXSPKR_SHIFT 0 /* BYPASSR_TO_MIXSPKR */ | ||
812 | #define WM8903_BYPASSR_TO_MIXSPKR_WIDTH 1 /* BYPASSR_TO_MIXSPKR */ | ||
813 | |||
814 | /* | ||
815 | * R55 (0x37) - Analogue Spk Mix Right 1 | ||
816 | */ | ||
817 | #define WM8903_DACL_MIXSPKR_VOL 0x0008 /* DACL_MIXSPKR_VOL */ | ||
818 | #define WM8903_DACL_MIXSPKR_VOL_MASK 0x0008 /* DACL_MIXSPKR_VOL */ | ||
819 | #define WM8903_DACL_MIXSPKR_VOL_SHIFT 3 /* DACL_MIXSPKR_VOL */ | ||
820 | #define WM8903_DACL_MIXSPKR_VOL_WIDTH 1 /* DACL_MIXSPKR_VOL */ | ||
821 | #define WM8903_DACR_MIXSPKR_VOL 0x0004 /* DACR_MIXSPKR_VOL */ | ||
822 | #define WM8903_DACR_MIXSPKR_VOL_MASK 0x0004 /* DACR_MIXSPKR_VOL */ | ||
823 | #define WM8903_DACR_MIXSPKR_VOL_SHIFT 2 /* DACR_MIXSPKR_VOL */ | ||
824 | #define WM8903_DACR_MIXSPKR_VOL_WIDTH 1 /* DACR_MIXSPKR_VOL */ | ||
825 | #define WM8903_BYPASSL_MIXSPKR_VOL 0x0002 /* BYPASSL_MIXSPKR_VOL */ | ||
826 | #define WM8903_BYPASSL_MIXSPKR_VOL_MASK 0x0002 /* BYPASSL_MIXSPKR_VOL */ | ||
827 | #define WM8903_BYPASSL_MIXSPKR_VOL_SHIFT 1 /* BYPASSL_MIXSPKR_VOL */ | ||
828 | #define WM8903_BYPASSL_MIXSPKR_VOL_WIDTH 1 /* BYPASSL_MIXSPKR_VOL */ | ||
829 | #define WM8903_BYPASSR_MIXSPKR_VOL 0x0001 /* BYPASSR_MIXSPKR_VOL */ | ||
830 | #define WM8903_BYPASSR_MIXSPKR_VOL_MASK 0x0001 /* BYPASSR_MIXSPKR_VOL */ | ||
831 | #define WM8903_BYPASSR_MIXSPKR_VOL_SHIFT 0 /* BYPASSR_MIXSPKR_VOL */ | ||
832 | #define WM8903_BYPASSR_MIXSPKR_VOL_WIDTH 1 /* BYPASSR_MIXSPKR_VOL */ | ||
833 | |||
834 | /* | ||
835 | * R57 (0x39) - Analogue OUT1 Left | ||
836 | */ | ||
837 | #define WM8903_HPL_MUTE 0x0100 /* HPL_MUTE */ | ||
838 | #define WM8903_HPL_MUTE_MASK 0x0100 /* HPL_MUTE */ | ||
839 | #define WM8903_HPL_MUTE_SHIFT 8 /* HPL_MUTE */ | ||
840 | #define WM8903_HPL_MUTE_WIDTH 1 /* HPL_MUTE */ | ||
841 | #define WM8903_HPOUTVU 0x0080 /* HPOUTVU */ | ||
842 | #define WM8903_HPOUTVU_MASK 0x0080 /* HPOUTVU */ | ||
843 | #define WM8903_HPOUTVU_SHIFT 7 /* HPOUTVU */ | ||
844 | #define WM8903_HPOUTVU_WIDTH 1 /* HPOUTVU */ | ||
845 | #define WM8903_HPOUTLZC 0x0040 /* HPOUTLZC */ | ||
846 | #define WM8903_HPOUTLZC_MASK 0x0040 /* HPOUTLZC */ | ||
847 | #define WM8903_HPOUTLZC_SHIFT 6 /* HPOUTLZC */ | ||
848 | #define WM8903_HPOUTLZC_WIDTH 1 /* HPOUTLZC */ | ||
849 | #define WM8903_HPOUTL_VOL_MASK 0x003F /* HPOUTL_VOL - [5:0] */ | ||
850 | #define WM8903_HPOUTL_VOL_SHIFT 0 /* HPOUTL_VOL - [5:0] */ | ||
851 | #define WM8903_HPOUTL_VOL_WIDTH 6 /* HPOUTL_VOL - [5:0] */ | ||
852 | |||
853 | /* | ||
854 | * R58 (0x3A) - Analogue OUT1 Right | ||
855 | */ | ||
856 | #define WM8903_HPR_MUTE 0x0100 /* HPR_MUTE */ | ||
857 | #define WM8903_HPR_MUTE_MASK 0x0100 /* HPR_MUTE */ | ||
858 | #define WM8903_HPR_MUTE_SHIFT 8 /* HPR_MUTE */ | ||
859 | #define WM8903_HPR_MUTE_WIDTH 1 /* HPR_MUTE */ | ||
860 | #define WM8903_HPOUTVU 0x0080 /* HPOUTVU */ | ||
861 | #define WM8903_HPOUTVU_MASK 0x0080 /* HPOUTVU */ | ||
862 | #define WM8903_HPOUTVU_SHIFT 7 /* HPOUTVU */ | ||
863 | #define WM8903_HPOUTVU_WIDTH 1 /* HPOUTVU */ | ||
864 | #define WM8903_HPOUTRZC 0x0040 /* HPOUTRZC */ | ||
865 | #define WM8903_HPOUTRZC_MASK 0x0040 /* HPOUTRZC */ | ||
866 | #define WM8903_HPOUTRZC_SHIFT 6 /* HPOUTRZC */ | ||
867 | #define WM8903_HPOUTRZC_WIDTH 1 /* HPOUTRZC */ | ||
868 | #define WM8903_HPOUTR_VOL_MASK 0x003F /* HPOUTR_VOL - [5:0] */ | ||
869 | #define WM8903_HPOUTR_VOL_SHIFT 0 /* HPOUTR_VOL - [5:0] */ | ||
870 | #define WM8903_HPOUTR_VOL_WIDTH 6 /* HPOUTR_VOL - [5:0] */ | ||
871 | |||
872 | /* | ||
873 | * R59 (0x3B) - Analogue OUT2 Left | ||
874 | */ | ||
875 | #define WM8903_LINEOUTL_MUTE 0x0100 /* LINEOUTL_MUTE */ | ||
876 | #define WM8903_LINEOUTL_MUTE_MASK 0x0100 /* LINEOUTL_MUTE */ | ||
877 | #define WM8903_LINEOUTL_MUTE_SHIFT 8 /* LINEOUTL_MUTE */ | ||
878 | #define WM8903_LINEOUTL_MUTE_WIDTH 1 /* LINEOUTL_MUTE */ | ||
879 | #define WM8903_LINEOUTVU 0x0080 /* LINEOUTVU */ | ||
880 | #define WM8903_LINEOUTVU_MASK 0x0080 /* LINEOUTVU */ | ||
881 | #define WM8903_LINEOUTVU_SHIFT 7 /* LINEOUTVU */ | ||
882 | #define WM8903_LINEOUTVU_WIDTH 1 /* LINEOUTVU */ | ||
883 | #define WM8903_LINEOUTLZC 0x0040 /* LINEOUTLZC */ | ||
884 | #define WM8903_LINEOUTLZC_MASK 0x0040 /* LINEOUTLZC */ | ||
885 | #define WM8903_LINEOUTLZC_SHIFT 6 /* LINEOUTLZC */ | ||
886 | #define WM8903_LINEOUTLZC_WIDTH 1 /* LINEOUTLZC */ | ||
887 | #define WM8903_LINEOUTL_VOL_MASK 0x003F /* LINEOUTL_VOL - [5:0] */ | ||
888 | #define WM8903_LINEOUTL_VOL_SHIFT 0 /* LINEOUTL_VOL - [5:0] */ | ||
889 | #define WM8903_LINEOUTL_VOL_WIDTH 6 /* LINEOUTL_VOL - [5:0] */ | ||
890 | |||
891 | /* | ||
892 | * R60 (0x3C) - Analogue OUT2 Right | ||
893 | */ | ||
894 | #define WM8903_LINEOUTR_MUTE 0x0100 /* LINEOUTR_MUTE */ | ||
895 | #define WM8903_LINEOUTR_MUTE_MASK 0x0100 /* LINEOUTR_MUTE */ | ||
896 | #define WM8903_LINEOUTR_MUTE_SHIFT 8 /* LINEOUTR_MUTE */ | ||
897 | #define WM8903_LINEOUTR_MUTE_WIDTH 1 /* LINEOUTR_MUTE */ | ||
898 | #define WM8903_LINEOUTVU 0x0080 /* LINEOUTVU */ | ||
899 | #define WM8903_LINEOUTVU_MASK 0x0080 /* LINEOUTVU */ | ||
900 | #define WM8903_LINEOUTVU_SHIFT 7 /* LINEOUTVU */ | ||
901 | #define WM8903_LINEOUTVU_WIDTH 1 /* LINEOUTVU */ | ||
902 | #define WM8903_LINEOUTRZC 0x0040 /* LINEOUTRZC */ | ||
903 | #define WM8903_LINEOUTRZC_MASK 0x0040 /* LINEOUTRZC */ | ||
904 | #define WM8903_LINEOUTRZC_SHIFT 6 /* LINEOUTRZC */ | ||
905 | #define WM8903_LINEOUTRZC_WIDTH 1 /* LINEOUTRZC */ | ||
906 | #define WM8903_LINEOUTR_VOL_MASK 0x003F /* LINEOUTR_VOL - [5:0] */ | ||
907 | #define WM8903_LINEOUTR_VOL_SHIFT 0 /* LINEOUTR_VOL - [5:0] */ | ||
908 | #define WM8903_LINEOUTR_VOL_WIDTH 6 /* LINEOUTR_VOL - [5:0] */ | ||
909 | |||
910 | /* | ||
911 | * R62 (0x3E) - Analogue OUT3 Left | ||
912 | */ | ||
913 | #define WM8903_SPKL_MUTE 0x0100 /* SPKL_MUTE */ | ||
914 | #define WM8903_SPKL_MUTE_MASK 0x0100 /* SPKL_MUTE */ | ||
915 | #define WM8903_SPKL_MUTE_SHIFT 8 /* SPKL_MUTE */ | ||
916 | #define WM8903_SPKL_MUTE_WIDTH 1 /* SPKL_MUTE */ | ||
917 | #define WM8903_SPKVU 0x0080 /* SPKVU */ | ||
918 | #define WM8903_SPKVU_MASK 0x0080 /* SPKVU */ | ||
919 | #define WM8903_SPKVU_SHIFT 7 /* SPKVU */ | ||
920 | #define WM8903_SPKVU_WIDTH 1 /* SPKVU */ | ||
921 | #define WM8903_SPKLZC 0x0040 /* SPKLZC */ | ||
922 | #define WM8903_SPKLZC_MASK 0x0040 /* SPKLZC */ | ||
923 | #define WM8903_SPKLZC_SHIFT 6 /* SPKLZC */ | ||
924 | #define WM8903_SPKLZC_WIDTH 1 /* SPKLZC */ | ||
925 | #define WM8903_SPKL_VOL_MASK 0x003F /* SPKL_VOL - [5:0] */ | ||
926 | #define WM8903_SPKL_VOL_SHIFT 0 /* SPKL_VOL - [5:0] */ | ||
927 | #define WM8903_SPKL_VOL_WIDTH 6 /* SPKL_VOL - [5:0] */ | ||
928 | |||
929 | /* | ||
930 | * R63 (0x3F) - Analogue OUT3 Right | ||
931 | */ | ||
932 | #define WM8903_SPKR_MUTE 0x0100 /* SPKR_MUTE */ | ||
933 | #define WM8903_SPKR_MUTE_MASK 0x0100 /* SPKR_MUTE */ | ||
934 | #define WM8903_SPKR_MUTE_SHIFT 8 /* SPKR_MUTE */ | ||
935 | #define WM8903_SPKR_MUTE_WIDTH 1 /* SPKR_MUTE */ | ||
936 | #define WM8903_SPKVU 0x0080 /* SPKVU */ | ||
937 | #define WM8903_SPKVU_MASK 0x0080 /* SPKVU */ | ||
938 | #define WM8903_SPKVU_SHIFT 7 /* SPKVU */ | ||
939 | #define WM8903_SPKVU_WIDTH 1 /* SPKVU */ | ||
940 | #define WM8903_SPKRZC 0x0040 /* SPKRZC */ | ||
941 | #define WM8903_SPKRZC_MASK 0x0040 /* SPKRZC */ | ||
942 | #define WM8903_SPKRZC_SHIFT 6 /* SPKRZC */ | ||
943 | #define WM8903_SPKRZC_WIDTH 1 /* SPKRZC */ | ||
944 | #define WM8903_SPKR_VOL_MASK 0x003F /* SPKR_VOL - [5:0] */ | ||
945 | #define WM8903_SPKR_VOL_SHIFT 0 /* SPKR_VOL - [5:0] */ | ||
946 | #define WM8903_SPKR_VOL_WIDTH 6 /* SPKR_VOL - [5:0] */ | ||
947 | |||
948 | /* | ||
949 | * R65 (0x41) - Analogue SPK Output Control 0 | ||
950 | */ | ||
951 | #define WM8903_SPK_DISCHARGE 0x0002 /* SPK_DISCHARGE */ | ||
952 | #define WM8903_SPK_DISCHARGE_MASK 0x0002 /* SPK_DISCHARGE */ | ||
953 | #define WM8903_SPK_DISCHARGE_SHIFT 1 /* SPK_DISCHARGE */ | ||
954 | #define WM8903_SPK_DISCHARGE_WIDTH 1 /* SPK_DISCHARGE */ | ||
955 | #define WM8903_VROI 0x0001 /* VROI */ | ||
956 | #define WM8903_VROI_MASK 0x0001 /* VROI */ | ||
957 | #define WM8903_VROI_SHIFT 0 /* VROI */ | ||
958 | #define WM8903_VROI_WIDTH 1 /* VROI */ | ||
959 | |||
960 | /* | ||
961 | * R67 (0x43) - DC Servo 0 | ||
962 | */ | ||
963 | #define WM8903_DCS_MASTER_ENA 0x0010 /* DCS_MASTER_ENA */ | ||
964 | #define WM8903_DCS_MASTER_ENA_MASK 0x0010 /* DCS_MASTER_ENA */ | ||
965 | #define WM8903_DCS_MASTER_ENA_SHIFT 4 /* DCS_MASTER_ENA */ | ||
966 | #define WM8903_DCS_MASTER_ENA_WIDTH 1 /* DCS_MASTER_ENA */ | ||
967 | #define WM8903_DCS_ENA_MASK 0x000F /* DCS_ENA - [3:0] */ | ||
968 | #define WM8903_DCS_ENA_SHIFT 0 /* DCS_ENA - [3:0] */ | ||
969 | #define WM8903_DCS_ENA_WIDTH 4 /* DCS_ENA - [3:0] */ | ||
970 | |||
971 | /* | ||
972 | * R69 (0x45) - DC Servo 2 | ||
973 | */ | ||
974 | #define WM8903_DCS_MODE_MASK 0x0003 /* DCS_MODE - [1:0] */ | ||
975 | #define WM8903_DCS_MODE_SHIFT 0 /* DCS_MODE - [1:0] */ | ||
976 | #define WM8903_DCS_MODE_WIDTH 2 /* DCS_MODE - [1:0] */ | ||
977 | |||
978 | /* | ||
979 | * R90 (0x5A) - Analogue HP 0 | ||
980 | */ | ||
981 | #define WM8903_HPL_RMV_SHORT 0x0080 /* HPL_RMV_SHORT */ | ||
982 | #define WM8903_HPL_RMV_SHORT_MASK 0x0080 /* HPL_RMV_SHORT */ | ||
983 | #define WM8903_HPL_RMV_SHORT_SHIFT 7 /* HPL_RMV_SHORT */ | ||
984 | #define WM8903_HPL_RMV_SHORT_WIDTH 1 /* HPL_RMV_SHORT */ | ||
985 | #define WM8903_HPL_ENA_OUTP 0x0040 /* HPL_ENA_OUTP */ | ||
986 | #define WM8903_HPL_ENA_OUTP_MASK 0x0040 /* HPL_ENA_OUTP */ | ||
987 | #define WM8903_HPL_ENA_OUTP_SHIFT 6 /* HPL_ENA_OUTP */ | ||
988 | #define WM8903_HPL_ENA_OUTP_WIDTH 1 /* HPL_ENA_OUTP */ | ||
989 | #define WM8903_HPL_ENA_DLY 0x0020 /* HPL_ENA_DLY */ | ||
990 | #define WM8903_HPL_ENA_DLY_MASK 0x0020 /* HPL_ENA_DLY */ | ||
991 | #define WM8903_HPL_ENA_DLY_SHIFT 5 /* HPL_ENA_DLY */ | ||
992 | #define WM8903_HPL_ENA_DLY_WIDTH 1 /* HPL_ENA_DLY */ | ||
993 | #define WM8903_HPL_ENA 0x0010 /* HPL_ENA */ | ||
994 | #define WM8903_HPL_ENA_MASK 0x0010 /* HPL_ENA */ | ||
995 | #define WM8903_HPL_ENA_SHIFT 4 /* HPL_ENA */ | ||
996 | #define WM8903_HPL_ENA_WIDTH 1 /* HPL_ENA */ | ||
997 | #define WM8903_HPR_RMV_SHORT 0x0008 /* HPR_RMV_SHORT */ | ||
998 | #define WM8903_HPR_RMV_SHORT_MASK 0x0008 /* HPR_RMV_SHORT */ | ||
999 | #define WM8903_HPR_RMV_SHORT_SHIFT 3 /* HPR_RMV_SHORT */ | ||
1000 | #define WM8903_HPR_RMV_SHORT_WIDTH 1 /* HPR_RMV_SHORT */ | ||
1001 | #define WM8903_HPR_ENA_OUTP 0x0004 /* HPR_ENA_OUTP */ | ||
1002 | #define WM8903_HPR_ENA_OUTP_MASK 0x0004 /* HPR_ENA_OUTP */ | ||
1003 | #define WM8903_HPR_ENA_OUTP_SHIFT 2 /* HPR_ENA_OUTP */ | ||
1004 | #define WM8903_HPR_ENA_OUTP_WIDTH 1 /* HPR_ENA_OUTP */ | ||
1005 | #define WM8903_HPR_ENA_DLY 0x0002 /* HPR_ENA_DLY */ | ||
1006 | #define WM8903_HPR_ENA_DLY_MASK 0x0002 /* HPR_ENA_DLY */ | ||
1007 | #define WM8903_HPR_ENA_DLY_SHIFT 1 /* HPR_ENA_DLY */ | ||
1008 | #define WM8903_HPR_ENA_DLY_WIDTH 1 /* HPR_ENA_DLY */ | ||
1009 | #define WM8903_HPR_ENA 0x0001 /* HPR_ENA */ | ||
1010 | #define WM8903_HPR_ENA_MASK 0x0001 /* HPR_ENA */ | ||
1011 | #define WM8903_HPR_ENA_SHIFT 0 /* HPR_ENA */ | ||
1012 | #define WM8903_HPR_ENA_WIDTH 1 /* HPR_ENA */ | ||
1013 | |||
1014 | /* | ||
1015 | * R94 (0x5E) - Analogue Lineout 0 | ||
1016 | */ | ||
1017 | #define WM8903_LINEOUTL_RMV_SHORT 0x0080 /* LINEOUTL_RMV_SHORT */ | ||
1018 | #define WM8903_LINEOUTL_RMV_SHORT_MASK 0x0080 /* LINEOUTL_RMV_SHORT */ | ||
1019 | #define WM8903_LINEOUTL_RMV_SHORT_SHIFT 7 /* LINEOUTL_RMV_SHORT */ | ||
1020 | #define WM8903_LINEOUTL_RMV_SHORT_WIDTH 1 /* LINEOUTL_RMV_SHORT */ | ||
1021 | #define WM8903_LINEOUTL_ENA_OUTP 0x0040 /* LINEOUTL_ENA_OUTP */ | ||
1022 | #define WM8903_LINEOUTL_ENA_OUTP_MASK 0x0040 /* LINEOUTL_ENA_OUTP */ | ||
1023 | #define WM8903_LINEOUTL_ENA_OUTP_SHIFT 6 /* LINEOUTL_ENA_OUTP */ | ||
1024 | #define WM8903_LINEOUTL_ENA_OUTP_WIDTH 1 /* LINEOUTL_ENA_OUTP */ | ||
1025 | #define WM8903_LINEOUTL_ENA_DLY 0x0020 /* LINEOUTL_ENA_DLY */ | ||
1026 | #define WM8903_LINEOUTL_ENA_DLY_MASK 0x0020 /* LINEOUTL_ENA_DLY */ | ||
1027 | #define WM8903_LINEOUTL_ENA_DLY_SHIFT 5 /* LINEOUTL_ENA_DLY */ | ||
1028 | #define WM8903_LINEOUTL_ENA_DLY_WIDTH 1 /* LINEOUTL_ENA_DLY */ | ||
1029 | #define WM8903_LINEOUTL_ENA 0x0010 /* LINEOUTL_ENA */ | ||
1030 | #define WM8903_LINEOUTL_ENA_MASK 0x0010 /* LINEOUTL_ENA */ | ||
1031 | #define WM8903_LINEOUTL_ENA_SHIFT 4 /* LINEOUTL_ENA */ | ||
1032 | #define WM8903_LINEOUTL_ENA_WIDTH 1 /* LINEOUTL_ENA */ | ||
1033 | #define WM8903_LINEOUTR_RMV_SHORT 0x0008 /* LINEOUTR_RMV_SHORT */ | ||
1034 | #define WM8903_LINEOUTR_RMV_SHORT_MASK 0x0008 /* LINEOUTR_RMV_SHORT */ | ||
1035 | #define WM8903_LINEOUTR_RMV_SHORT_SHIFT 3 /* LINEOUTR_RMV_SHORT */ | ||
1036 | #define WM8903_LINEOUTR_RMV_SHORT_WIDTH 1 /* LINEOUTR_RMV_SHORT */ | ||
1037 | #define WM8903_LINEOUTR_ENA_OUTP 0x0004 /* LINEOUTR_ENA_OUTP */ | ||
1038 | #define WM8903_LINEOUTR_ENA_OUTP_MASK 0x0004 /* LINEOUTR_ENA_OUTP */ | ||
1039 | #define WM8903_LINEOUTR_ENA_OUTP_SHIFT 2 /* LINEOUTR_ENA_OUTP */ | ||
1040 | #define WM8903_LINEOUTR_ENA_OUTP_WIDTH 1 /* LINEOUTR_ENA_OUTP */ | ||
1041 | #define WM8903_LINEOUTR_ENA_DLY 0x0002 /* LINEOUTR_ENA_DLY */ | ||
1042 | #define WM8903_LINEOUTR_ENA_DLY_MASK 0x0002 /* LINEOUTR_ENA_DLY */ | ||
1043 | #define WM8903_LINEOUTR_ENA_DLY_SHIFT 1 /* LINEOUTR_ENA_DLY */ | ||
1044 | #define WM8903_LINEOUTR_ENA_DLY_WIDTH 1 /* LINEOUTR_ENA_DLY */ | ||
1045 | #define WM8903_LINEOUTR_ENA 0x0001 /* LINEOUTR_ENA */ | ||
1046 | #define WM8903_LINEOUTR_ENA_MASK 0x0001 /* LINEOUTR_ENA */ | ||
1047 | #define WM8903_LINEOUTR_ENA_SHIFT 0 /* LINEOUTR_ENA */ | ||
1048 | #define WM8903_LINEOUTR_ENA_WIDTH 1 /* LINEOUTR_ENA */ | ||
1049 | |||
1050 | /* | ||
1051 | * R98 (0x62) - Charge Pump 0 | ||
1052 | */ | ||
1053 | #define WM8903_CP_ENA 0x0001 /* CP_ENA */ | ||
1054 | #define WM8903_CP_ENA_MASK 0x0001 /* CP_ENA */ | ||
1055 | #define WM8903_CP_ENA_SHIFT 0 /* CP_ENA */ | ||
1056 | #define WM8903_CP_ENA_WIDTH 1 /* CP_ENA */ | ||
1057 | |||
1058 | /* | ||
1059 | * R104 (0x68) - Class W 0 | ||
1060 | */ | ||
1061 | #define WM8903_CP_DYN_FREQ 0x0002 /* CP_DYN_FREQ */ | ||
1062 | #define WM8903_CP_DYN_FREQ_MASK 0x0002 /* CP_DYN_FREQ */ | ||
1063 | #define WM8903_CP_DYN_FREQ_SHIFT 1 /* CP_DYN_FREQ */ | ||
1064 | #define WM8903_CP_DYN_FREQ_WIDTH 1 /* CP_DYN_FREQ */ | ||
1065 | #define WM8903_CP_DYN_V 0x0001 /* CP_DYN_V */ | ||
1066 | #define WM8903_CP_DYN_V_MASK 0x0001 /* CP_DYN_V */ | ||
1067 | #define WM8903_CP_DYN_V_SHIFT 0 /* CP_DYN_V */ | ||
1068 | #define WM8903_CP_DYN_V_WIDTH 1 /* CP_DYN_V */ | ||
1069 | |||
1070 | /* | ||
1071 | * R108 (0x6C) - Write Sequencer 0 | ||
1072 | */ | ||
1073 | #define WM8903_WSEQ_ENA 0x0100 /* WSEQ_ENA */ | ||
1074 | #define WM8903_WSEQ_ENA_MASK 0x0100 /* WSEQ_ENA */ | ||
1075 | #define WM8903_WSEQ_ENA_SHIFT 8 /* WSEQ_ENA */ | ||
1076 | #define WM8903_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ | ||
1077 | #define WM8903_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */ | ||
1078 | #define WM8903_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */ | ||
1079 | #define WM8903_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */ | ||
1080 | |||
1081 | /* | ||
1082 | * R109 (0x6D) - Write Sequencer 1 | ||
1083 | */ | ||
1084 | #define WM8903_WSEQ_DATA_WIDTH_MASK 0x7000 /* WSEQ_DATA_WIDTH - [14:12] */ | ||
1085 | #define WM8903_WSEQ_DATA_WIDTH_SHIFT 12 /* WSEQ_DATA_WIDTH - [14:12] */ | ||
1086 | #define WM8903_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [14:12] */ | ||
1087 | #define WM8903_WSEQ_DATA_START_MASK 0x0F00 /* WSEQ_DATA_START - [11:8] */ | ||
1088 | #define WM8903_WSEQ_DATA_START_SHIFT 8 /* WSEQ_DATA_START - [11:8] */ | ||
1089 | #define WM8903_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [11:8] */ | ||
1090 | #define WM8903_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */ | ||
1091 | #define WM8903_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */ | ||
1092 | #define WM8903_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */ | ||
1093 | |||
1094 | /* | ||
1095 | * R110 (0x6E) - Write Sequencer 2 | ||
1096 | */ | ||
1097 | #define WM8903_WSEQ_EOS 0x4000 /* WSEQ_EOS */ | ||
1098 | #define WM8903_WSEQ_EOS_MASK 0x4000 /* WSEQ_EOS */ | ||
1099 | #define WM8903_WSEQ_EOS_SHIFT 14 /* WSEQ_EOS */ | ||
1100 | #define WM8903_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */ | ||
1101 | #define WM8903_WSEQ_DELAY_MASK 0x0F00 /* WSEQ_DELAY - [11:8] */ | ||
1102 | #define WM8903_WSEQ_DELAY_SHIFT 8 /* WSEQ_DELAY - [11:8] */ | ||
1103 | #define WM8903_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [11:8] */ | ||
1104 | #define WM8903_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */ | ||
1105 | #define WM8903_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */ | ||
1106 | #define WM8903_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */ | ||
1107 | |||
1108 | /* | ||
1109 | * R111 (0x6F) - Write Sequencer 3 | ||
1110 | */ | ||
1111 | #define WM8903_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */ | ||
1112 | #define WM8903_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */ | ||
1113 | #define WM8903_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */ | ||
1114 | #define WM8903_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ | ||
1115 | #define WM8903_WSEQ_START 0x0100 /* WSEQ_START */ | ||
1116 | #define WM8903_WSEQ_START_MASK 0x0100 /* WSEQ_START */ | ||
1117 | #define WM8903_WSEQ_START_SHIFT 8 /* WSEQ_START */ | ||
1118 | #define WM8903_WSEQ_START_WIDTH 1 /* WSEQ_START */ | ||
1119 | #define WM8903_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */ | ||
1120 | #define WM8903_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */ | ||
1121 | #define WM8903_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */ | ||
1122 | |||
1123 | /* | ||
1124 | * R112 (0x70) - Write Sequencer 4 | ||
1125 | */ | ||
1126 | #define WM8903_WSEQ_CURRENT_INDEX_MASK 0x03F0 /* WSEQ_CURRENT_INDEX - [9:4] */ | ||
1127 | #define WM8903_WSEQ_CURRENT_INDEX_SHIFT 4 /* WSEQ_CURRENT_INDEX - [9:4] */ | ||
1128 | #define WM8903_WSEQ_CURRENT_INDEX_WIDTH 6 /* WSEQ_CURRENT_INDEX - [9:4] */ | ||
1129 | #define WM8903_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */ | ||
1130 | #define WM8903_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */ | ||
1131 | #define WM8903_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */ | ||
1132 | #define WM8903_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ | ||
1133 | |||
1134 | /* | ||
1135 | * R114 (0x72) - Control Interface | ||
1136 | */ | ||
1137 | #define WM8903_MASK_WRITE_ENA 0x0001 /* MASK_WRITE_ENA */ | ||
1138 | #define WM8903_MASK_WRITE_ENA_MASK 0x0001 /* MASK_WRITE_ENA */ | ||
1139 | #define WM8903_MASK_WRITE_ENA_SHIFT 0 /* MASK_WRITE_ENA */ | ||
1140 | #define WM8903_MASK_WRITE_ENA_WIDTH 1 /* MASK_WRITE_ENA */ | ||
1141 | |||
1142 | /* | ||
1143 | * R116 (0x74) - GPIO Control 1 | ||
1144 | */ | ||
1145 | #define WM8903_GP1_FN_MASK 0x1F00 /* GP1_FN - [12:8] */ | ||
1146 | #define WM8903_GP1_FN_SHIFT 8 /* GP1_FN - [12:8] */ | ||
1147 | #define WM8903_GP1_FN_WIDTH 5 /* GP1_FN - [12:8] */ | ||
1148 | #define WM8903_GP1_DIR 0x0080 /* GP1_DIR */ | ||
1149 | #define WM8903_GP1_DIR_MASK 0x0080 /* GP1_DIR */ | ||
1150 | #define WM8903_GP1_DIR_SHIFT 7 /* GP1_DIR */ | ||
1151 | #define WM8903_GP1_DIR_WIDTH 1 /* GP1_DIR */ | ||
1152 | #define WM8903_GP1_OP_CFG 0x0040 /* GP1_OP_CFG */ | ||
1153 | #define WM8903_GP1_OP_CFG_MASK 0x0040 /* GP1_OP_CFG */ | ||
1154 | #define WM8903_GP1_OP_CFG_SHIFT 6 /* GP1_OP_CFG */ | ||
1155 | #define WM8903_GP1_OP_CFG_WIDTH 1 /* GP1_OP_CFG */ | ||
1156 | #define WM8903_GP1_IP_CFG 0x0020 /* GP1_IP_CFG */ | ||
1157 | #define WM8903_GP1_IP_CFG_MASK 0x0020 /* GP1_IP_CFG */ | ||
1158 | #define WM8903_GP1_IP_CFG_SHIFT 5 /* GP1_IP_CFG */ | ||
1159 | #define WM8903_GP1_IP_CFG_WIDTH 1 /* GP1_IP_CFG */ | ||
1160 | #define WM8903_GP1_LVL 0x0010 /* GP1_LVL */ | ||
1161 | #define WM8903_GP1_LVL_MASK 0x0010 /* GP1_LVL */ | ||
1162 | #define WM8903_GP1_LVL_SHIFT 4 /* GP1_LVL */ | ||
1163 | #define WM8903_GP1_LVL_WIDTH 1 /* GP1_LVL */ | ||
1164 | #define WM8903_GP1_PD 0x0008 /* GP1_PD */ | ||
1165 | #define WM8903_GP1_PD_MASK 0x0008 /* GP1_PD */ | ||
1166 | #define WM8903_GP1_PD_SHIFT 3 /* GP1_PD */ | ||
1167 | #define WM8903_GP1_PD_WIDTH 1 /* GP1_PD */ | ||
1168 | #define WM8903_GP1_PU 0x0004 /* GP1_PU */ | ||
1169 | #define WM8903_GP1_PU_MASK 0x0004 /* GP1_PU */ | ||
1170 | #define WM8903_GP1_PU_SHIFT 2 /* GP1_PU */ | ||
1171 | #define WM8903_GP1_PU_WIDTH 1 /* GP1_PU */ | ||
1172 | #define WM8903_GP1_INTMODE 0x0002 /* GP1_INTMODE */ | ||
1173 | #define WM8903_GP1_INTMODE_MASK 0x0002 /* GP1_INTMODE */ | ||
1174 | #define WM8903_GP1_INTMODE_SHIFT 1 /* GP1_INTMODE */ | ||
1175 | #define WM8903_GP1_INTMODE_WIDTH 1 /* GP1_INTMODE */ | ||
1176 | #define WM8903_GP1_DB 0x0001 /* GP1_DB */ | ||
1177 | #define WM8903_GP1_DB_MASK 0x0001 /* GP1_DB */ | ||
1178 | #define WM8903_GP1_DB_SHIFT 0 /* GP1_DB */ | ||
1179 | #define WM8903_GP1_DB_WIDTH 1 /* GP1_DB */ | ||
1180 | |||
1181 | /* | ||
1182 | * R117 (0x75) - GPIO Control 2 | ||
1183 | */ | ||
1184 | #define WM8903_GP2_FN_MASK 0x1F00 /* GP2_FN - [12:8] */ | ||
1185 | #define WM8903_GP2_FN_SHIFT 8 /* GP2_FN - [12:8] */ | ||
1186 | #define WM8903_GP2_FN_WIDTH 5 /* GP2_FN - [12:8] */ | ||
1187 | #define WM8903_GP2_DIR 0x0080 /* GP2_DIR */ | ||
1188 | #define WM8903_GP2_DIR_MASK 0x0080 /* GP2_DIR */ | ||
1189 | #define WM8903_GP2_DIR_SHIFT 7 /* GP2_DIR */ | ||
1190 | #define WM8903_GP2_DIR_WIDTH 1 /* GP2_DIR */ | ||
1191 | #define WM8903_GP2_OP_CFG 0x0040 /* GP2_OP_CFG */ | ||
1192 | #define WM8903_GP2_OP_CFG_MASK 0x0040 /* GP2_OP_CFG */ | ||
1193 | #define WM8903_GP2_OP_CFG_SHIFT 6 /* GP2_OP_CFG */ | ||
1194 | #define WM8903_GP2_OP_CFG_WIDTH 1 /* GP2_OP_CFG */ | ||
1195 | #define WM8903_GP2_IP_CFG 0x0020 /* GP2_IP_CFG */ | ||
1196 | #define WM8903_GP2_IP_CFG_MASK 0x0020 /* GP2_IP_CFG */ | ||
1197 | #define WM8903_GP2_IP_CFG_SHIFT 5 /* GP2_IP_CFG */ | ||
1198 | #define WM8903_GP2_IP_CFG_WIDTH 1 /* GP2_IP_CFG */ | ||
1199 | #define WM8903_GP2_LVL 0x0010 /* GP2_LVL */ | ||
1200 | #define WM8903_GP2_LVL_MASK 0x0010 /* GP2_LVL */ | ||
1201 | #define WM8903_GP2_LVL_SHIFT 4 /* GP2_LVL */ | ||
1202 | #define WM8903_GP2_LVL_WIDTH 1 /* GP2_LVL */ | ||
1203 | #define WM8903_GP2_PD 0x0008 /* GP2_PD */ | ||
1204 | #define WM8903_GP2_PD_MASK 0x0008 /* GP2_PD */ | ||
1205 | #define WM8903_GP2_PD_SHIFT 3 /* GP2_PD */ | ||
1206 | #define WM8903_GP2_PD_WIDTH 1 /* GP2_PD */ | ||
1207 | #define WM8903_GP2_PU 0x0004 /* GP2_PU */ | ||
1208 | #define WM8903_GP2_PU_MASK 0x0004 /* GP2_PU */ | ||
1209 | #define WM8903_GP2_PU_SHIFT 2 /* GP2_PU */ | ||
1210 | #define WM8903_GP2_PU_WIDTH 1 /* GP2_PU */ | ||
1211 | #define WM8903_GP2_INTMODE 0x0002 /* GP2_INTMODE */ | ||
1212 | #define WM8903_GP2_INTMODE_MASK 0x0002 /* GP2_INTMODE */ | ||
1213 | #define WM8903_GP2_INTMODE_SHIFT 1 /* GP2_INTMODE */ | ||
1214 | #define WM8903_GP2_INTMODE_WIDTH 1 /* GP2_INTMODE */ | ||
1215 | #define WM8903_GP2_DB 0x0001 /* GP2_DB */ | ||
1216 | #define WM8903_GP2_DB_MASK 0x0001 /* GP2_DB */ | ||
1217 | #define WM8903_GP2_DB_SHIFT 0 /* GP2_DB */ | ||
1218 | #define WM8903_GP2_DB_WIDTH 1 /* GP2_DB */ | ||
1219 | |||
1220 | /* | ||
1221 | * R118 (0x76) - GPIO Control 3 | ||
1222 | */ | ||
1223 | #define WM8903_GP3_FN_MASK 0x1F00 /* GP3_FN - [12:8] */ | ||
1224 | #define WM8903_GP3_FN_SHIFT 8 /* GP3_FN - [12:8] */ | ||
1225 | #define WM8903_GP3_FN_WIDTH 5 /* GP3_FN - [12:8] */ | ||
1226 | #define WM8903_GP3_DIR 0x0080 /* GP3_DIR */ | ||
1227 | #define WM8903_GP3_DIR_MASK 0x0080 /* GP3_DIR */ | ||
1228 | #define WM8903_GP3_DIR_SHIFT 7 /* GP3_DIR */ | ||
1229 | #define WM8903_GP3_DIR_WIDTH 1 /* GP3_DIR */ | ||
1230 | #define WM8903_GP3_OP_CFG 0x0040 /* GP3_OP_CFG */ | ||
1231 | #define WM8903_GP3_OP_CFG_MASK 0x0040 /* GP3_OP_CFG */ | ||
1232 | #define WM8903_GP3_OP_CFG_SHIFT 6 /* GP3_OP_CFG */ | ||
1233 | #define WM8903_GP3_OP_CFG_WIDTH 1 /* GP3_OP_CFG */ | ||
1234 | #define WM8903_GP3_IP_CFG 0x0020 /* GP3_IP_CFG */ | ||
1235 | #define WM8903_GP3_IP_CFG_MASK 0x0020 /* GP3_IP_CFG */ | ||
1236 | #define WM8903_GP3_IP_CFG_SHIFT 5 /* GP3_IP_CFG */ | ||
1237 | #define WM8903_GP3_IP_CFG_WIDTH 1 /* GP3_IP_CFG */ | ||
1238 | #define WM8903_GP3_LVL 0x0010 /* GP3_LVL */ | ||
1239 | #define WM8903_GP3_LVL_MASK 0x0010 /* GP3_LVL */ | ||
1240 | #define WM8903_GP3_LVL_SHIFT 4 /* GP3_LVL */ | ||
1241 | #define WM8903_GP3_LVL_WIDTH 1 /* GP3_LVL */ | ||
1242 | #define WM8903_GP3_PD 0x0008 /* GP3_PD */ | ||
1243 | #define WM8903_GP3_PD_MASK 0x0008 /* GP3_PD */ | ||
1244 | #define WM8903_GP3_PD_SHIFT 3 /* GP3_PD */ | ||
1245 | #define WM8903_GP3_PD_WIDTH 1 /* GP3_PD */ | ||
1246 | #define WM8903_GP3_PU 0x0004 /* GP3_PU */ | ||
1247 | #define WM8903_GP3_PU_MASK 0x0004 /* GP3_PU */ | ||
1248 | #define WM8903_GP3_PU_SHIFT 2 /* GP3_PU */ | ||
1249 | #define WM8903_GP3_PU_WIDTH 1 /* GP3_PU */ | ||
1250 | #define WM8903_GP3_INTMODE 0x0002 /* GP3_INTMODE */ | ||
1251 | #define WM8903_GP3_INTMODE_MASK 0x0002 /* GP3_INTMODE */ | ||
1252 | #define WM8903_GP3_INTMODE_SHIFT 1 /* GP3_INTMODE */ | ||
1253 | #define WM8903_GP3_INTMODE_WIDTH 1 /* GP3_INTMODE */ | ||
1254 | #define WM8903_GP3_DB 0x0001 /* GP3_DB */ | ||
1255 | #define WM8903_GP3_DB_MASK 0x0001 /* GP3_DB */ | ||
1256 | #define WM8903_GP3_DB_SHIFT 0 /* GP3_DB */ | ||
1257 | #define WM8903_GP3_DB_WIDTH 1 /* GP3_DB */ | ||
1258 | |||
1259 | /* | ||
1260 | * R119 (0x77) - GPIO Control 4 | ||
1261 | */ | ||
1262 | #define WM8903_GP4_FN_MASK 0x1F00 /* GP4_FN - [12:8] */ | ||
1263 | #define WM8903_GP4_FN_SHIFT 8 /* GP4_FN - [12:8] */ | ||
1264 | #define WM8903_GP4_FN_WIDTH 5 /* GP4_FN - [12:8] */ | ||
1265 | #define WM8903_GP4_DIR 0x0080 /* GP4_DIR */ | ||
1266 | #define WM8903_GP4_DIR_MASK 0x0080 /* GP4_DIR */ | ||
1267 | #define WM8903_GP4_DIR_SHIFT 7 /* GP4_DIR */ | ||
1268 | #define WM8903_GP4_DIR_WIDTH 1 /* GP4_DIR */ | ||
1269 | #define WM8903_GP4_OP_CFG 0x0040 /* GP4_OP_CFG */ | ||
1270 | #define WM8903_GP4_OP_CFG_MASK 0x0040 /* GP4_OP_CFG */ | ||
1271 | #define WM8903_GP4_OP_CFG_SHIFT 6 /* GP4_OP_CFG */ | ||
1272 | #define WM8903_GP4_OP_CFG_WIDTH 1 /* GP4_OP_CFG */ | ||
1273 | #define WM8903_GP4_IP_CFG 0x0020 /* GP4_IP_CFG */ | ||
1274 | #define WM8903_GP4_IP_CFG_MASK 0x0020 /* GP4_IP_CFG */ | ||
1275 | #define WM8903_GP4_IP_CFG_SHIFT 5 /* GP4_IP_CFG */ | ||
1276 | #define WM8903_GP4_IP_CFG_WIDTH 1 /* GP4_IP_CFG */ | ||
1277 | #define WM8903_GP4_LVL 0x0010 /* GP4_LVL */ | ||
1278 | #define WM8903_GP4_LVL_MASK 0x0010 /* GP4_LVL */ | ||
1279 | #define WM8903_GP4_LVL_SHIFT 4 /* GP4_LVL */ | ||
1280 | #define WM8903_GP4_LVL_WIDTH 1 /* GP4_LVL */ | ||
1281 | #define WM8903_GP4_PD 0x0008 /* GP4_PD */ | ||
1282 | #define WM8903_GP4_PD_MASK 0x0008 /* GP4_PD */ | ||
1283 | #define WM8903_GP4_PD_SHIFT 3 /* GP4_PD */ | ||
1284 | #define WM8903_GP4_PD_WIDTH 1 /* GP4_PD */ | ||
1285 | #define WM8903_GP4_PU 0x0004 /* GP4_PU */ | ||
1286 | #define WM8903_GP4_PU_MASK 0x0004 /* GP4_PU */ | ||
1287 | #define WM8903_GP4_PU_SHIFT 2 /* GP4_PU */ | ||
1288 | #define WM8903_GP4_PU_WIDTH 1 /* GP4_PU */ | ||
1289 | #define WM8903_GP4_INTMODE 0x0002 /* GP4_INTMODE */ | ||
1290 | #define WM8903_GP4_INTMODE_MASK 0x0002 /* GP4_INTMODE */ | ||
1291 | #define WM8903_GP4_INTMODE_SHIFT 1 /* GP4_INTMODE */ | ||
1292 | #define WM8903_GP4_INTMODE_WIDTH 1 /* GP4_INTMODE */ | ||
1293 | #define WM8903_GP4_DB 0x0001 /* GP4_DB */ | ||
1294 | #define WM8903_GP4_DB_MASK 0x0001 /* GP4_DB */ | ||
1295 | #define WM8903_GP4_DB_SHIFT 0 /* GP4_DB */ | ||
1296 | #define WM8903_GP4_DB_WIDTH 1 /* GP4_DB */ | ||
1297 | |||
1298 | /* | ||
1299 | * R120 (0x78) - GPIO Control 5 | ||
1300 | */ | ||
1301 | #define WM8903_GP5_FN_MASK 0x1F00 /* GP5_FN - [12:8] */ | ||
1302 | #define WM8903_GP5_FN_SHIFT 8 /* GP5_FN - [12:8] */ | ||
1303 | #define WM8903_GP5_FN_WIDTH 5 /* GP5_FN - [12:8] */ | ||
1304 | #define WM8903_GP5_DIR 0x0080 /* GP5_DIR */ | ||
1305 | #define WM8903_GP5_DIR_MASK 0x0080 /* GP5_DIR */ | ||
1306 | #define WM8903_GP5_DIR_SHIFT 7 /* GP5_DIR */ | ||
1307 | #define WM8903_GP5_DIR_WIDTH 1 /* GP5_DIR */ | ||
1308 | #define WM8903_GP5_OP_CFG 0x0040 /* GP5_OP_CFG */ | ||
1309 | #define WM8903_GP5_OP_CFG_MASK 0x0040 /* GP5_OP_CFG */ | ||
1310 | #define WM8903_GP5_OP_CFG_SHIFT 6 /* GP5_OP_CFG */ | ||
1311 | #define WM8903_GP5_OP_CFG_WIDTH 1 /* GP5_OP_CFG */ | ||
1312 | #define WM8903_GP5_IP_CFG 0x0020 /* GP5_IP_CFG */ | ||
1313 | #define WM8903_GP5_IP_CFG_MASK 0x0020 /* GP5_IP_CFG */ | ||
1314 | #define WM8903_GP5_IP_CFG_SHIFT 5 /* GP5_IP_CFG */ | ||
1315 | #define WM8903_GP5_IP_CFG_WIDTH 1 /* GP5_IP_CFG */ | ||
1316 | #define WM8903_GP5_LVL 0x0010 /* GP5_LVL */ | ||
1317 | #define WM8903_GP5_LVL_MASK 0x0010 /* GP5_LVL */ | ||
1318 | #define WM8903_GP5_LVL_SHIFT 4 /* GP5_LVL */ | ||
1319 | #define WM8903_GP5_LVL_WIDTH 1 /* GP5_LVL */ | ||
1320 | #define WM8903_GP5_PD 0x0008 /* GP5_PD */ | ||
1321 | #define WM8903_GP5_PD_MASK 0x0008 /* GP5_PD */ | ||
1322 | #define WM8903_GP5_PD_SHIFT 3 /* GP5_PD */ | ||
1323 | #define WM8903_GP5_PD_WIDTH 1 /* GP5_PD */ | ||
1324 | #define WM8903_GP5_PU 0x0004 /* GP5_PU */ | ||
1325 | #define WM8903_GP5_PU_MASK 0x0004 /* GP5_PU */ | ||
1326 | #define WM8903_GP5_PU_SHIFT 2 /* GP5_PU */ | ||
1327 | #define WM8903_GP5_PU_WIDTH 1 /* GP5_PU */ | ||
1328 | #define WM8903_GP5_INTMODE 0x0002 /* GP5_INTMODE */ | ||
1329 | #define WM8903_GP5_INTMODE_MASK 0x0002 /* GP5_INTMODE */ | ||
1330 | #define WM8903_GP5_INTMODE_SHIFT 1 /* GP5_INTMODE */ | ||
1331 | #define WM8903_GP5_INTMODE_WIDTH 1 /* GP5_INTMODE */ | ||
1332 | #define WM8903_GP5_DB 0x0001 /* GP5_DB */ | ||
1333 | #define WM8903_GP5_DB_MASK 0x0001 /* GP5_DB */ | ||
1334 | #define WM8903_GP5_DB_SHIFT 0 /* GP5_DB */ | ||
1335 | #define WM8903_GP5_DB_WIDTH 1 /* GP5_DB */ | ||
1336 | |||
1337 | /* | ||
1338 | * R121 (0x79) - Interrupt Status 1 | ||
1339 | */ | ||
1340 | #define WM8903_MICSHRT_EINT 0x8000 /* MICSHRT_EINT */ | ||
1341 | #define WM8903_MICSHRT_EINT_MASK 0x8000 /* MICSHRT_EINT */ | ||
1342 | #define WM8903_MICSHRT_EINT_SHIFT 15 /* MICSHRT_EINT */ | ||
1343 | #define WM8903_MICSHRT_EINT_WIDTH 1 /* MICSHRT_EINT */ | ||
1344 | #define WM8903_MICDET_EINT 0x4000 /* MICDET_EINT */ | ||
1345 | #define WM8903_MICDET_EINT_MASK 0x4000 /* MICDET_EINT */ | ||
1346 | #define WM8903_MICDET_EINT_SHIFT 14 /* MICDET_EINT */ | ||
1347 | #define WM8903_MICDET_EINT_WIDTH 1 /* MICDET_EINT */ | ||
1348 | #define WM8903_WSEQ_BUSY_EINT 0x2000 /* WSEQ_BUSY_EINT */ | ||
1349 | #define WM8903_WSEQ_BUSY_EINT_MASK 0x2000 /* WSEQ_BUSY_EINT */ | ||
1350 | #define WM8903_WSEQ_BUSY_EINT_SHIFT 13 /* WSEQ_BUSY_EINT */ | ||
1351 | #define WM8903_WSEQ_BUSY_EINT_WIDTH 1 /* WSEQ_BUSY_EINT */ | ||
1352 | #define WM8903_GP5_EINT 0x0010 /* GP5_EINT */ | ||
1353 | #define WM8903_GP5_EINT_MASK 0x0010 /* GP5_EINT */ | ||
1354 | #define WM8903_GP5_EINT_SHIFT 4 /* GP5_EINT */ | ||
1355 | #define WM8903_GP5_EINT_WIDTH 1 /* GP5_EINT */ | ||
1356 | #define WM8903_GP4_EINT 0x0008 /* GP4_EINT */ | ||
1357 | #define WM8903_GP4_EINT_MASK 0x0008 /* GP4_EINT */ | ||
1358 | #define WM8903_GP4_EINT_SHIFT 3 /* GP4_EINT */ | ||
1359 | #define WM8903_GP4_EINT_WIDTH 1 /* GP4_EINT */ | ||
1360 | #define WM8903_GP3_EINT 0x0004 /* GP3_EINT */ | ||
1361 | #define WM8903_GP3_EINT_MASK 0x0004 /* GP3_EINT */ | ||
1362 | #define WM8903_GP3_EINT_SHIFT 2 /* GP3_EINT */ | ||
1363 | #define WM8903_GP3_EINT_WIDTH 1 /* GP3_EINT */ | ||
1364 | #define WM8903_GP2_EINT 0x0002 /* GP2_EINT */ | ||
1365 | #define WM8903_GP2_EINT_MASK 0x0002 /* GP2_EINT */ | ||
1366 | #define WM8903_GP2_EINT_SHIFT 1 /* GP2_EINT */ | ||
1367 | #define WM8903_GP2_EINT_WIDTH 1 /* GP2_EINT */ | ||
1368 | #define WM8903_GP1_EINT 0x0001 /* GP1_EINT */ | ||
1369 | #define WM8903_GP1_EINT_MASK 0x0001 /* GP1_EINT */ | ||
1370 | #define WM8903_GP1_EINT_SHIFT 0 /* GP1_EINT */ | ||
1371 | #define WM8903_GP1_EINT_WIDTH 1 /* GP1_EINT */ | ||
1372 | |||
1373 | /* | ||
1374 | * R122 (0x7A) - Interrupt Status 1 Mask | ||
1375 | */ | ||
1376 | #define WM8903_IM_MICSHRT_EINT 0x8000 /* IM_MICSHRT_EINT */ | ||
1377 | #define WM8903_IM_MICSHRT_EINT_MASK 0x8000 /* IM_MICSHRT_EINT */ | ||
1378 | #define WM8903_IM_MICSHRT_EINT_SHIFT 15 /* IM_MICSHRT_EINT */ | ||
1379 | #define WM8903_IM_MICSHRT_EINT_WIDTH 1 /* IM_MICSHRT_EINT */ | ||
1380 | #define WM8903_IM_MICDET_EINT 0x4000 /* IM_MICDET_EINT */ | ||
1381 | #define WM8903_IM_MICDET_EINT_MASK 0x4000 /* IM_MICDET_EINT */ | ||
1382 | #define WM8903_IM_MICDET_EINT_SHIFT 14 /* IM_MICDET_EINT */ | ||
1383 | #define WM8903_IM_MICDET_EINT_WIDTH 1 /* IM_MICDET_EINT */ | ||
1384 | #define WM8903_IM_WSEQ_BUSY_EINT 0x2000 /* IM_WSEQ_BUSY_EINT */ | ||
1385 | #define WM8903_IM_WSEQ_BUSY_EINT_MASK 0x2000 /* IM_WSEQ_BUSY_EINT */ | ||
1386 | #define WM8903_IM_WSEQ_BUSY_EINT_SHIFT 13 /* IM_WSEQ_BUSY_EINT */ | ||
1387 | #define WM8903_IM_WSEQ_BUSY_EINT_WIDTH 1 /* IM_WSEQ_BUSY_EINT */ | ||
1388 | #define WM8903_IM_GP5_EINT 0x0010 /* IM_GP5_EINT */ | ||
1389 | #define WM8903_IM_GP5_EINT_MASK 0x0010 /* IM_GP5_EINT */ | ||
1390 | #define WM8903_IM_GP5_EINT_SHIFT 4 /* IM_GP5_EINT */ | ||
1391 | #define WM8903_IM_GP5_EINT_WIDTH 1 /* IM_GP5_EINT */ | ||
1392 | #define WM8903_IM_GP4_EINT 0x0008 /* IM_GP4_EINT */ | ||
1393 | #define WM8903_IM_GP4_EINT_MASK 0x0008 /* IM_GP4_EINT */ | ||
1394 | #define WM8903_IM_GP4_EINT_SHIFT 3 /* IM_GP4_EINT */ | ||
1395 | #define WM8903_IM_GP4_EINT_WIDTH 1 /* IM_GP4_EINT */ | ||
1396 | #define WM8903_IM_GP3_EINT 0x0004 /* IM_GP3_EINT */ | ||
1397 | #define WM8903_IM_GP3_EINT_MASK 0x0004 /* IM_GP3_EINT */ | ||
1398 | #define WM8903_IM_GP3_EINT_SHIFT 2 /* IM_GP3_EINT */ | ||
1399 | #define WM8903_IM_GP3_EINT_WIDTH 1 /* IM_GP3_EINT */ | ||
1400 | #define WM8903_IM_GP2_EINT 0x0002 /* IM_GP2_EINT */ | ||
1401 | #define WM8903_IM_GP2_EINT_MASK 0x0002 /* IM_GP2_EINT */ | ||
1402 | #define WM8903_IM_GP2_EINT_SHIFT 1 /* IM_GP2_EINT */ | ||
1403 | #define WM8903_IM_GP2_EINT_WIDTH 1 /* IM_GP2_EINT */ | ||
1404 | #define WM8903_IM_GP1_EINT 0x0001 /* IM_GP1_EINT */ | ||
1405 | #define WM8903_IM_GP1_EINT_MASK 0x0001 /* IM_GP1_EINT */ | ||
1406 | #define WM8903_IM_GP1_EINT_SHIFT 0 /* IM_GP1_EINT */ | ||
1407 | #define WM8903_IM_GP1_EINT_WIDTH 1 /* IM_GP1_EINT */ | ||
1408 | |||
1409 | /* | ||
1410 | * R123 (0x7B) - Interrupt Polarity 1 | ||
1411 | */ | ||
1412 | #define WM8903_MICSHRT_INV 0x8000 /* MICSHRT_INV */ | ||
1413 | #define WM8903_MICSHRT_INV_MASK 0x8000 /* MICSHRT_INV */ | ||
1414 | #define WM8903_MICSHRT_INV_SHIFT 15 /* MICSHRT_INV */ | ||
1415 | #define WM8903_MICSHRT_INV_WIDTH 1 /* MICSHRT_INV */ | ||
1416 | #define WM8903_MICDET_INV 0x4000 /* MICDET_INV */ | ||
1417 | #define WM8903_MICDET_INV_MASK 0x4000 /* MICDET_INV */ | ||
1418 | #define WM8903_MICDET_INV_SHIFT 14 /* MICDET_INV */ | ||
1419 | #define WM8903_MICDET_INV_WIDTH 1 /* MICDET_INV */ | ||
1420 | |||
1421 | /* | ||
1422 | * R126 (0x7E) - Interrupt Control | ||
1423 | */ | ||
1424 | #define WM8903_IRQ_POL 0x0001 /* IRQ_POL */ | ||
1425 | #define WM8903_IRQ_POL_MASK 0x0001 /* IRQ_POL */ | ||
1426 | #define WM8903_IRQ_POL_SHIFT 0 /* IRQ_POL */ | ||
1427 | #define WM8903_IRQ_POL_WIDTH 1 /* IRQ_POL */ | ||
1428 | |||
1429 | /* | ||
1430 | * R129 (0x81) - Control Interface Test 1 | ||
1431 | */ | ||
1432 | #define WM8903_USER_KEY 0x0002 /* USER_KEY */ | ||
1433 | #define WM8903_USER_KEY_MASK 0x0002 /* USER_KEY */ | ||
1434 | #define WM8903_USER_KEY_SHIFT 1 /* USER_KEY */ | ||
1435 | #define WM8903_USER_KEY_WIDTH 1 /* USER_KEY */ | ||
1436 | #define WM8903_TEST_KEY 0x0001 /* TEST_KEY */ | ||
1437 | #define WM8903_TEST_KEY_MASK 0x0001 /* TEST_KEY */ | ||
1438 | #define WM8903_TEST_KEY_SHIFT 0 /* TEST_KEY */ | ||
1439 | #define WM8903_TEST_KEY_WIDTH 1 /* TEST_KEY */ | ||
1440 | |||
1441 | /* | ||
1442 | * R149 (0x95) - Charge Pump Test 1 | ||
1443 | */ | ||
1444 | #define WM8903_CP_SW_KELVIN_MODE_MASK 0x0006 /* CP_SW_KELVIN_MODE - [2:1] */ | ||
1445 | #define WM8903_CP_SW_KELVIN_MODE_SHIFT 1 /* CP_SW_KELVIN_MODE - [2:1] */ | ||
1446 | #define WM8903_CP_SW_KELVIN_MODE_WIDTH 2 /* CP_SW_KELVIN_MODE - [2:1] */ | ||
1447 | |||
1448 | /* | ||
1449 | * R164 (0xA4) - Clock Rate Test 4 | ||
1450 | */ | ||
1451 | #define WM8903_ADC_DIG_MIC 0x0200 /* ADC_DIG_MIC */ | ||
1452 | #define WM8903_ADC_DIG_MIC_MASK 0x0200 /* ADC_DIG_MIC */ | ||
1453 | #define WM8903_ADC_DIG_MIC_SHIFT 9 /* ADC_DIG_MIC */ | ||
1454 | #define WM8903_ADC_DIG_MIC_WIDTH 1 /* ADC_DIG_MIC */ | ||
1455 | |||
1456 | /* | ||
1457 | * R172 (0xAC) - Analogue Output Bias 0 | ||
1458 | */ | ||
1459 | #define WM8903_PGA_BIAS_MASK 0x0070 /* PGA_BIAS - [6:4] */ | ||
1460 | #define WM8903_PGA_BIAS_SHIFT 4 /* PGA_BIAS - [6:4] */ | ||
1461 | #define WM8903_PGA_BIAS_WIDTH 3 /* PGA_BIAS - [6:4] */ | ||
1462 | |||
1463 | #endif | ||
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c new file mode 100644 index 00000000000..974a4cd0f3f --- /dev/null +++ b/sound/soc/codecs/wm8971.c | |||
@@ -0,0 +1,942 @@ | |||
1 | /* | ||
2 | * wm8971.c -- WM8971 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2005 Lab126, Inc. | ||
5 | * | ||
6 | * Author: Kenneth Kiraly <kiraly@lab126.com> | ||
7 | * | ||
8 | * Based on wm8753.c by Liam Girdwood | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/moduleparam.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/pm.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dapm.h> | ||
28 | #include <sound/initval.h> | ||
29 | |||
30 | #include "wm8971.h" | ||
31 | |||
32 | #define AUDIO_NAME "wm8971" | ||
33 | #define WM8971_VERSION "0.9" | ||
34 | |||
35 | #define WM8971_REG_COUNT 43 | ||
36 | |||
37 | static struct workqueue_struct *wm8971_workq = NULL; | ||
38 | |||
39 | /* codec private data */ | ||
40 | struct wm8971_priv { | ||
41 | unsigned int sysclk; | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * wm8971 register cache | ||
46 | * We can't read the WM8971 register space when we | ||
47 | * are using 2 wire for device control, so we cache them instead. | ||
48 | */ | ||
49 | static const u16 wm8971_reg[] = { | ||
50 | 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ | ||
51 | 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ | ||
52 | 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ | ||
53 | 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ | ||
54 | 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ | ||
55 | 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ | ||
56 | 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ | ||
57 | 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ | ||
58 | 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ | ||
59 | 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ | ||
60 | 0x0079, 0x0079, 0x0079, /* 40 */ | ||
61 | }; | ||
62 | |||
63 | static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec, | ||
64 | unsigned int reg) | ||
65 | { | ||
66 | u16 *cache = codec->reg_cache; | ||
67 | if (reg < WM8971_REG_COUNT) | ||
68 | return cache[reg]; | ||
69 | |||
70 | return -1; | ||
71 | } | ||
72 | |||
73 | static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec, | ||
74 | unsigned int reg, unsigned int value) | ||
75 | { | ||
76 | u16 *cache = codec->reg_cache; | ||
77 | if (reg < WM8971_REG_COUNT) | ||
78 | cache[reg] = value; | ||
79 | } | ||
80 | |||
81 | static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg, | ||
82 | unsigned int value) | ||
83 | { | ||
84 | u8 data[2]; | ||
85 | |||
86 | /* data is | ||
87 | * D15..D9 WM8753 register offset | ||
88 | * D8...D0 register data | ||
89 | */ | ||
90 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
91 | data[1] = value & 0x00ff; | ||
92 | |||
93 | wm8971_write_reg_cache (codec, reg, value); | ||
94 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
95 | return 0; | ||
96 | else | ||
97 | return -EIO; | ||
98 | } | ||
99 | |||
100 | #define wm8971_reset(c) wm8971_write(c, WM8971_RESET, 0) | ||
101 | |||
102 | /* WM8971 Controls */ | ||
103 | static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" }; | ||
104 | static const char *wm8971_bass_filter[] = { "130Hz @ 48kHz", | ||
105 | "200Hz @ 48kHz" }; | ||
106 | static const char *wm8971_treble[] = { "8kHz", "4kHz" }; | ||
107 | static const char *wm8971_alc_func[] = { "Off", "Right", "Left", "Stereo" }; | ||
108 | static const char *wm8971_ng_type[] = { "Constant PGA Gain", | ||
109 | "Mute ADC Output" }; | ||
110 | static const char *wm8971_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | ||
111 | static const char *wm8971_mono_mux[] = {"Stereo", "Mono (Left)", | ||
112 | "Mono (Right)", "Digital Mono"}; | ||
113 | static const char *wm8971_dac_phase[] = { "Non Inverted", "Inverted" }; | ||
114 | static const char *wm8971_lline_mux[] = {"Line", "NC", "NC", "PGA", | ||
115 | "Differential"}; | ||
116 | static const char *wm8971_rline_mux[] = {"Line", "Mic", "NC", "PGA", | ||
117 | "Differential"}; | ||
118 | static const char *wm8971_lpga_sel[] = {"Line", "NC", "NC", "Differential"}; | ||
119 | static const char *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"}; | ||
120 | static const char *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert", | ||
121 | "L + R Invert"}; | ||
122 | |||
123 | static const struct soc_enum wm8971_enum[] = { | ||
124 | SOC_ENUM_SINGLE(WM8971_BASS, 7, 2, wm8971_bass), /* 0 */ | ||
125 | SOC_ENUM_SINGLE(WM8971_BASS, 6, 2, wm8971_bass_filter), | ||
126 | SOC_ENUM_SINGLE(WM8971_TREBLE, 6, 2, wm8971_treble), | ||
127 | SOC_ENUM_SINGLE(WM8971_ALC1, 7, 4, wm8971_alc_func), | ||
128 | SOC_ENUM_SINGLE(WM8971_NGATE, 1, 2, wm8971_ng_type), /* 4 */ | ||
129 | SOC_ENUM_SINGLE(WM8971_ADCDAC, 1, 4, wm8971_deemp), | ||
130 | SOC_ENUM_SINGLE(WM8971_ADCTL1, 4, 4, wm8971_mono_mux), | ||
131 | SOC_ENUM_SINGLE(WM8971_ADCTL1, 1, 2, wm8971_dac_phase), | ||
132 | SOC_ENUM_SINGLE(WM8971_LOUTM1, 0, 5, wm8971_lline_mux), /* 8 */ | ||
133 | SOC_ENUM_SINGLE(WM8971_ROUTM1, 0, 5, wm8971_rline_mux), | ||
134 | SOC_ENUM_SINGLE(WM8971_LADCIN, 6, 4, wm8971_lpga_sel), | ||
135 | SOC_ENUM_SINGLE(WM8971_RADCIN, 6, 4, wm8971_rpga_sel), | ||
136 | SOC_ENUM_SINGLE(WM8971_ADCDAC, 5, 4, wm8971_adcpol), /* 12 */ | ||
137 | SOC_ENUM_SINGLE(WM8971_ADCIN, 6, 4, wm8971_mono_mux), | ||
138 | }; | ||
139 | |||
140 | static const struct snd_kcontrol_new wm8971_snd_controls[] = { | ||
141 | SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0), | ||
142 | SOC_DOUBLE_R("Capture ZC Switch", WM8971_LINVOL, WM8971_RINVOL, | ||
143 | 6, 1, 0), | ||
144 | SOC_DOUBLE_R("Capture Switch", WM8971_LINVOL, WM8971_RINVOL, 7, 1, 1), | ||
145 | |||
146 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8971_LOUT1V, | ||
147 | WM8971_ROUT1V, 7, 1, 0), | ||
148 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8971_LOUT2V, | ||
149 | WM8971_ROUT2V, 7, 1, 0), | ||
150 | SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0), | ||
151 | |||
152 | SOC_DOUBLE_R("PCM Volume", WM8971_LDAC, WM8971_RDAC, 0, 255, 0), | ||
153 | |||
154 | SOC_DOUBLE_R("Bypass Left Playback Volume", WM8971_LOUTM1, | ||
155 | WM8971_LOUTM2, 4, 7, 1), | ||
156 | SOC_DOUBLE_R("Bypass Right Playback Volume", WM8971_ROUTM1, | ||
157 | WM8971_ROUTM2, 4, 7, 1), | ||
158 | SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8971_MOUTM1, | ||
159 | WM8971_MOUTM2, 4, 7, 1), | ||
160 | |||
161 | SOC_DOUBLE_R("Headphone Playback Volume", WM8971_LOUT1V, | ||
162 | WM8971_ROUT1V, 0, 127, 0), | ||
163 | SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V, | ||
164 | WM8971_ROUT2V, 0, 127, 0), | ||
165 | |||
166 | SOC_ENUM("Bass Boost", wm8971_enum[0]), | ||
167 | SOC_ENUM("Bass Filter", wm8971_enum[1]), | ||
168 | SOC_SINGLE("Bass Volume", WM8971_BASS, 0, 7, 1), | ||
169 | |||
170 | SOC_SINGLE("Treble Volume", WM8971_TREBLE, 0, 7, 0), | ||
171 | SOC_ENUM("Treble Cut-off", wm8971_enum[2]), | ||
172 | |||
173 | SOC_SINGLE("Capture Filter Switch", WM8971_ADCDAC, 0, 1, 1), | ||
174 | |||
175 | SOC_SINGLE("ALC Target Volume", WM8971_ALC1, 0, 7, 0), | ||
176 | SOC_SINGLE("ALC Max Volume", WM8971_ALC1, 4, 7, 0), | ||
177 | |||
178 | SOC_SINGLE("ALC Capture Target Volume", WM8971_ALC1, 0, 7, 0), | ||
179 | SOC_SINGLE("ALC Capture Max Volume", WM8971_ALC1, 4, 7, 0), | ||
180 | SOC_ENUM("ALC Capture Function", wm8971_enum[3]), | ||
181 | SOC_SINGLE("ALC Capture ZC Switch", WM8971_ALC2, 7, 1, 0), | ||
182 | SOC_SINGLE("ALC Capture Hold Time", WM8971_ALC2, 0, 15, 0), | ||
183 | SOC_SINGLE("ALC Capture Decay Time", WM8971_ALC3, 4, 15, 0), | ||
184 | SOC_SINGLE("ALC Capture Attack Time", WM8971_ALC3, 0, 15, 0), | ||
185 | SOC_SINGLE("ALC Capture NG Threshold", WM8971_NGATE, 3, 31, 0), | ||
186 | SOC_ENUM("ALC Capture NG Type", wm8971_enum[4]), | ||
187 | SOC_SINGLE("ALC Capture NG Switch", WM8971_NGATE, 0, 1, 0), | ||
188 | |||
189 | SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0), | ||
190 | SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0), | ||
191 | |||
192 | SOC_ENUM("Playback De-emphasis", wm8971_enum[5]), | ||
193 | SOC_ENUM("Playback Function", wm8971_enum[6]), | ||
194 | SOC_ENUM("Playback Phase", wm8971_enum[7]), | ||
195 | |||
196 | SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0), | ||
197 | }; | ||
198 | |||
199 | /* add non-DAPM controls */ | ||
200 | static int wm8971_add_controls(struct snd_soc_codec *codec) | ||
201 | { | ||
202 | int err, i; | ||
203 | |||
204 | for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) { | ||
205 | err = snd_ctl_add(codec->card, | ||
206 | snd_soc_cnew(&wm8971_snd_controls[i], | ||
207 | codec, NULL)); | ||
208 | if (err < 0) | ||
209 | return err; | ||
210 | } | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * DAPM Controls | ||
216 | */ | ||
217 | |||
218 | /* Left Mixer */ | ||
219 | static const struct snd_kcontrol_new wm8971_left_mixer_controls[] = { | ||
220 | SOC_DAPM_SINGLE("Playback Switch", WM8971_LOUTM1, 8, 1, 0), | ||
221 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_LOUTM1, 7, 1, 0), | ||
222 | SOC_DAPM_SINGLE("Right Playback Switch", WM8971_LOUTM2, 8, 1, 0), | ||
223 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_LOUTM2, 7, 1, 0), | ||
224 | }; | ||
225 | |||
226 | /* Right Mixer */ | ||
227 | static const struct snd_kcontrol_new wm8971_right_mixer_controls[] = { | ||
228 | SOC_DAPM_SINGLE("Left Playback Switch", WM8971_ROUTM1, 8, 1, 0), | ||
229 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_ROUTM1, 7, 1, 0), | ||
230 | SOC_DAPM_SINGLE("Playback Switch", WM8971_ROUTM2, 8, 1, 0), | ||
231 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_ROUTM2, 7, 1, 0), | ||
232 | }; | ||
233 | |||
234 | /* Mono Mixer */ | ||
235 | static const struct snd_kcontrol_new wm8971_mono_mixer_controls[] = { | ||
236 | SOC_DAPM_SINGLE("Left Playback Switch", WM8971_MOUTM1, 8, 1, 0), | ||
237 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_MOUTM1, 7, 1, 0), | ||
238 | SOC_DAPM_SINGLE("Right Playback Switch", WM8971_MOUTM2, 8, 1, 0), | ||
239 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_MOUTM2, 7, 1, 0), | ||
240 | }; | ||
241 | |||
242 | /* Left Line Mux */ | ||
243 | static const struct snd_kcontrol_new wm8971_left_line_controls = | ||
244 | SOC_DAPM_ENUM("Route", wm8971_enum[8]); | ||
245 | |||
246 | /* Right Line Mux */ | ||
247 | static const struct snd_kcontrol_new wm8971_right_line_controls = | ||
248 | SOC_DAPM_ENUM("Route", wm8971_enum[9]); | ||
249 | |||
250 | /* Left PGA Mux */ | ||
251 | static const struct snd_kcontrol_new wm8971_left_pga_controls = | ||
252 | SOC_DAPM_ENUM("Route", wm8971_enum[10]); | ||
253 | |||
254 | /* Right PGA Mux */ | ||
255 | static const struct snd_kcontrol_new wm8971_right_pga_controls = | ||
256 | SOC_DAPM_ENUM("Route", wm8971_enum[11]); | ||
257 | |||
258 | /* Mono ADC Mux */ | ||
259 | static const struct snd_kcontrol_new wm8971_monomux_controls = | ||
260 | SOC_DAPM_ENUM("Route", wm8971_enum[13]); | ||
261 | |||
262 | static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { | ||
263 | SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, | ||
264 | &wm8971_left_mixer_controls[0], | ||
265 | ARRAY_SIZE(wm8971_left_mixer_controls)), | ||
266 | SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, | ||
267 | &wm8971_right_mixer_controls[0], | ||
268 | ARRAY_SIZE(wm8971_right_mixer_controls)), | ||
269 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8971_PWR2, 2, 0, | ||
270 | &wm8971_mono_mixer_controls[0], | ||
271 | ARRAY_SIZE(wm8971_mono_mixer_controls)), | ||
272 | |||
273 | SND_SOC_DAPM_PGA("Right Out 2", WM8971_PWR2, 3, 0, NULL, 0), | ||
274 | SND_SOC_DAPM_PGA("Left Out 2", WM8971_PWR2, 4, 0, NULL, 0), | ||
275 | SND_SOC_DAPM_PGA("Right Out 1", WM8971_PWR2, 5, 0, NULL, 0), | ||
276 | SND_SOC_DAPM_PGA("Left Out 1", WM8971_PWR2, 6, 0, NULL, 0), | ||
277 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8971_PWR2, 7, 0), | ||
278 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8971_PWR2, 8, 0), | ||
279 | SND_SOC_DAPM_PGA("Mono Out 1", WM8971_PWR2, 2, 0, NULL, 0), | ||
280 | |||
281 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8971_PWR1, 1, 0), | ||
282 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0), | ||
283 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0), | ||
284 | |||
285 | SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0, | ||
286 | &wm8971_left_pga_controls), | ||
287 | SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0, | ||
288 | &wm8971_right_pga_controls), | ||
289 | SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, | ||
290 | &wm8971_left_line_controls), | ||
291 | SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, | ||
292 | &wm8971_right_line_controls), | ||
293 | |||
294 | SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, | ||
295 | &wm8971_monomux_controls), | ||
296 | SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, | ||
297 | &wm8971_monomux_controls), | ||
298 | |||
299 | SND_SOC_DAPM_OUTPUT("LOUT1"), | ||
300 | SND_SOC_DAPM_OUTPUT("ROUT1"), | ||
301 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
302 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
303 | SND_SOC_DAPM_OUTPUT("MONO"), | ||
304 | |||
305 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
306 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
307 | SND_SOC_DAPM_INPUT("MIC"), | ||
308 | }; | ||
309 | |||
310 | static const struct snd_soc_dapm_route audio_map[] = { | ||
311 | /* left mixer */ | ||
312 | {"Left Mixer", "Playback Switch", "Left DAC"}, | ||
313 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
314 | {"Left Mixer", "Right Playback Switch", "Right DAC"}, | ||
315 | {"Left Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
316 | |||
317 | /* right mixer */ | ||
318 | {"Right Mixer", "Left Playback Switch", "Left DAC"}, | ||
319 | {"Right Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
320 | {"Right Mixer", "Playback Switch", "Right DAC"}, | ||
321 | {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
322 | |||
323 | /* left out 1 */ | ||
324 | {"Left Out 1", NULL, "Left Mixer"}, | ||
325 | {"LOUT1", NULL, "Left Out 1"}, | ||
326 | |||
327 | /* left out 2 */ | ||
328 | {"Left Out 2", NULL, "Left Mixer"}, | ||
329 | {"LOUT2", NULL, "Left Out 2"}, | ||
330 | |||
331 | /* right out 1 */ | ||
332 | {"Right Out 1", NULL, "Right Mixer"}, | ||
333 | {"ROUT1", NULL, "Right Out 1"}, | ||
334 | |||
335 | /* right out 2 */ | ||
336 | {"Right Out 2", NULL, "Right Mixer"}, | ||
337 | {"ROUT2", NULL, "Right Out 2"}, | ||
338 | |||
339 | /* mono mixer */ | ||
340 | {"Mono Mixer", "Left Playback Switch", "Left DAC"}, | ||
341 | {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
342 | {"Mono Mixer", "Right Playback Switch", "Right DAC"}, | ||
343 | {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
344 | |||
345 | /* mono out */ | ||
346 | {"Mono Out", NULL, "Mono Mixer"}, | ||
347 | {"MONO1", NULL, "Mono Out"}, | ||
348 | |||
349 | /* Left Line Mux */ | ||
350 | {"Left Line Mux", "Line", "LINPUT1"}, | ||
351 | {"Left Line Mux", "PGA", "Left PGA Mux"}, | ||
352 | {"Left Line Mux", "Differential", "Differential Mux"}, | ||
353 | |||
354 | /* Right Line Mux */ | ||
355 | {"Right Line Mux", "Line", "RINPUT1"}, | ||
356 | {"Right Line Mux", "Mic", "MIC"}, | ||
357 | {"Right Line Mux", "PGA", "Right PGA Mux"}, | ||
358 | {"Right Line Mux", "Differential", "Differential Mux"}, | ||
359 | |||
360 | /* Left PGA Mux */ | ||
361 | {"Left PGA Mux", "Line", "LINPUT1"}, | ||
362 | {"Left PGA Mux", "Differential", "Differential Mux"}, | ||
363 | |||
364 | /* Right PGA Mux */ | ||
365 | {"Right PGA Mux", "Line", "RINPUT1"}, | ||
366 | {"Right PGA Mux", "Differential", "Differential Mux"}, | ||
367 | |||
368 | /* Differential Mux */ | ||
369 | {"Differential Mux", "Line", "LINPUT1"}, | ||
370 | {"Differential Mux", "Line", "RINPUT1"}, | ||
371 | |||
372 | /* Left ADC Mux */ | ||
373 | {"Left ADC Mux", "Stereo", "Left PGA Mux"}, | ||
374 | {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, | ||
375 | {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, | ||
376 | |||
377 | /* Right ADC Mux */ | ||
378 | {"Right ADC Mux", "Stereo", "Right PGA Mux"}, | ||
379 | {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, | ||
380 | {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, | ||
381 | |||
382 | /* ADC */ | ||
383 | {"Left ADC", NULL, "Left ADC Mux"}, | ||
384 | {"Right ADC", NULL, "Right ADC Mux"}, | ||
385 | }; | ||
386 | |||
387 | static int wm8971_add_widgets(struct snd_soc_codec *codec) | ||
388 | { | ||
389 | snd_soc_dapm_new_controls(codec, wm8971_dapm_widgets, | ||
390 | ARRAY_SIZE(wm8971_dapm_widgets)); | ||
391 | |||
392 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
393 | |||
394 | snd_soc_dapm_new_widgets(codec); | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | struct _coeff_div { | ||
400 | u32 mclk; | ||
401 | u32 rate; | ||
402 | u16 fs; | ||
403 | u8 sr:5; | ||
404 | u8 usb:1; | ||
405 | }; | ||
406 | |||
407 | /* codec hifi mclk clock divider coefficients */ | ||
408 | static const struct _coeff_div coeff_div[] = { | ||
409 | /* 8k */ | ||
410 | {12288000, 8000, 1536, 0x6, 0x0}, | ||
411 | {11289600, 8000, 1408, 0x16, 0x0}, | ||
412 | {18432000, 8000, 2304, 0x7, 0x0}, | ||
413 | {16934400, 8000, 2112, 0x17, 0x0}, | ||
414 | {12000000, 8000, 1500, 0x6, 0x1}, | ||
415 | |||
416 | /* 11.025k */ | ||
417 | {11289600, 11025, 1024, 0x18, 0x0}, | ||
418 | {16934400, 11025, 1536, 0x19, 0x0}, | ||
419 | {12000000, 11025, 1088, 0x19, 0x1}, | ||
420 | |||
421 | /* 16k */ | ||
422 | {12288000, 16000, 768, 0xa, 0x0}, | ||
423 | {18432000, 16000, 1152, 0xb, 0x0}, | ||
424 | {12000000, 16000, 750, 0xa, 0x1}, | ||
425 | |||
426 | /* 22.05k */ | ||
427 | {11289600, 22050, 512, 0x1a, 0x0}, | ||
428 | {16934400, 22050, 768, 0x1b, 0x0}, | ||
429 | {12000000, 22050, 544, 0x1b, 0x1}, | ||
430 | |||
431 | /* 32k */ | ||
432 | {12288000, 32000, 384, 0xc, 0x0}, | ||
433 | {18432000, 32000, 576, 0xd, 0x0}, | ||
434 | {12000000, 32000, 375, 0xa, 0x1}, | ||
435 | |||
436 | /* 44.1k */ | ||
437 | {11289600, 44100, 256, 0x10, 0x0}, | ||
438 | {16934400, 44100, 384, 0x11, 0x0}, | ||
439 | {12000000, 44100, 272, 0x11, 0x1}, | ||
440 | |||
441 | /* 48k */ | ||
442 | {12288000, 48000, 256, 0x0, 0x0}, | ||
443 | {18432000, 48000, 384, 0x1, 0x0}, | ||
444 | {12000000, 48000, 250, 0x0, 0x1}, | ||
445 | |||
446 | /* 88.2k */ | ||
447 | {11289600, 88200, 128, 0x1e, 0x0}, | ||
448 | {16934400, 88200, 192, 0x1f, 0x0}, | ||
449 | {12000000, 88200, 136, 0x1f, 0x1}, | ||
450 | |||
451 | /* 96k */ | ||
452 | {12288000, 96000, 128, 0xe, 0x0}, | ||
453 | {18432000, 96000, 192, 0xf, 0x0}, | ||
454 | {12000000, 96000, 125, 0xe, 0x1}, | ||
455 | }; | ||
456 | |||
457 | static int get_coeff(int mclk, int rate) | ||
458 | { | ||
459 | int i; | ||
460 | |||
461 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | ||
462 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | ||
463 | return i; | ||
464 | } | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | |||
468 | static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
469 | int clk_id, unsigned int freq, int dir) | ||
470 | { | ||
471 | struct snd_soc_codec *codec = codec_dai->codec; | ||
472 | struct wm8971_priv *wm8971 = codec->private_data; | ||
473 | |||
474 | switch (freq) { | ||
475 | case 11289600: | ||
476 | case 12000000: | ||
477 | case 12288000: | ||
478 | case 16934400: | ||
479 | case 18432000: | ||
480 | wm8971->sysclk = freq; | ||
481 | return 0; | ||
482 | } | ||
483 | return -EINVAL; | ||
484 | } | ||
485 | |||
486 | static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
487 | unsigned int fmt) | ||
488 | { | ||
489 | struct snd_soc_codec *codec = codec_dai->codec; | ||
490 | u16 iface = 0; | ||
491 | |||
492 | /* set master/slave audio interface */ | ||
493 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
494 | case SND_SOC_DAIFMT_CBM_CFM: | ||
495 | iface = 0x0040; | ||
496 | break; | ||
497 | case SND_SOC_DAIFMT_CBS_CFS: | ||
498 | break; | ||
499 | default: | ||
500 | return -EINVAL; | ||
501 | } | ||
502 | |||
503 | /* interface format */ | ||
504 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
505 | case SND_SOC_DAIFMT_I2S: | ||
506 | iface |= 0x0002; | ||
507 | break; | ||
508 | case SND_SOC_DAIFMT_RIGHT_J: | ||
509 | break; | ||
510 | case SND_SOC_DAIFMT_LEFT_J: | ||
511 | iface |= 0x0001; | ||
512 | break; | ||
513 | case SND_SOC_DAIFMT_DSP_A: | ||
514 | iface |= 0x0003; | ||
515 | break; | ||
516 | case SND_SOC_DAIFMT_DSP_B: | ||
517 | iface |= 0x0013; | ||
518 | break; | ||
519 | default: | ||
520 | return -EINVAL; | ||
521 | } | ||
522 | |||
523 | /* clock inversion */ | ||
524 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
525 | case SND_SOC_DAIFMT_NB_NF: | ||
526 | break; | ||
527 | case SND_SOC_DAIFMT_IB_IF: | ||
528 | iface |= 0x0090; | ||
529 | break; | ||
530 | case SND_SOC_DAIFMT_IB_NF: | ||
531 | iface |= 0x0080; | ||
532 | break; | ||
533 | case SND_SOC_DAIFMT_NB_IF: | ||
534 | iface |= 0x0010; | ||
535 | break; | ||
536 | default: | ||
537 | return -EINVAL; | ||
538 | } | ||
539 | |||
540 | wm8971_write(codec, WM8971_IFACE, iface); | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, | ||
545 | struct snd_pcm_hw_params *params) | ||
546 | { | ||
547 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
548 | struct snd_soc_device *socdev = rtd->socdev; | ||
549 | struct snd_soc_codec *codec = socdev->codec; | ||
550 | struct wm8971_priv *wm8971 = codec->private_data; | ||
551 | u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3; | ||
552 | u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0; | ||
553 | int coeff = get_coeff(wm8971->sysclk, params_rate(params)); | ||
554 | |||
555 | /* bit size */ | ||
556 | switch (params_format(params)) { | ||
557 | case SNDRV_PCM_FORMAT_S16_LE: | ||
558 | break; | ||
559 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
560 | iface |= 0x0004; | ||
561 | break; | ||
562 | case SNDRV_PCM_FORMAT_S24_LE: | ||
563 | iface |= 0x0008; | ||
564 | break; | ||
565 | case SNDRV_PCM_FORMAT_S32_LE: | ||
566 | iface |= 0x000c; | ||
567 | break; | ||
568 | } | ||
569 | |||
570 | /* set iface & srate */ | ||
571 | wm8971_write(codec, WM8971_IFACE, iface); | ||
572 | if (coeff >= 0) | ||
573 | wm8971_write(codec, WM8971_SRATE, srate | | ||
574 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); | ||
575 | |||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static int wm8971_mute(struct snd_soc_dai *dai, int mute) | ||
580 | { | ||
581 | struct snd_soc_codec *codec = dai->codec; | ||
582 | u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7; | ||
583 | |||
584 | if (mute) | ||
585 | wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8); | ||
586 | else | ||
587 | wm8971_write(codec, WM8971_ADCDAC, mute_reg); | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static int wm8971_set_bias_level(struct snd_soc_codec *codec, | ||
592 | enum snd_soc_bias_level level) | ||
593 | { | ||
594 | u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; | ||
595 | |||
596 | switch (level) { | ||
597 | case SND_SOC_BIAS_ON: | ||
598 | /* set vmid to 50k and unmute dac */ | ||
599 | wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); | ||
600 | break; | ||
601 | case SND_SOC_BIAS_PREPARE: | ||
602 | break; | ||
603 | case SND_SOC_BIAS_STANDBY: | ||
604 | /* mute dac and set vmid to 500k, enable VREF */ | ||
605 | wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140); | ||
606 | break; | ||
607 | case SND_SOC_BIAS_OFF: | ||
608 | wm8971_write(codec, WM8971_PWR1, 0x0001); | ||
609 | break; | ||
610 | } | ||
611 | codec->bias_level = level; | ||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | #define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
616 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
617 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
618 | |||
619 | #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
620 | SNDRV_PCM_FMTBIT_S24_LE) | ||
621 | |||
622 | struct snd_soc_dai wm8971_dai = { | ||
623 | .name = "WM8971", | ||
624 | .playback = { | ||
625 | .stream_name = "Playback", | ||
626 | .channels_min = 1, | ||
627 | .channels_max = 2, | ||
628 | .rates = WM8971_RATES, | ||
629 | .formats = WM8971_FORMATS,}, | ||
630 | .capture = { | ||
631 | .stream_name = "Capture", | ||
632 | .channels_min = 1, | ||
633 | .channels_max = 2, | ||
634 | .rates = WM8971_RATES, | ||
635 | .formats = WM8971_FORMATS,}, | ||
636 | .ops = { | ||
637 | .hw_params = wm8971_pcm_hw_params, | ||
638 | }, | ||
639 | .dai_ops = { | ||
640 | .digital_mute = wm8971_mute, | ||
641 | .set_fmt = wm8971_set_dai_fmt, | ||
642 | .set_sysclk = wm8971_set_dai_sysclk, | ||
643 | }, | ||
644 | }; | ||
645 | EXPORT_SYMBOL_GPL(wm8971_dai); | ||
646 | |||
647 | static void wm8971_work(struct work_struct *work) | ||
648 | { | ||
649 | struct snd_soc_codec *codec = | ||
650 | container_of(work, struct snd_soc_codec, delayed_work.work); | ||
651 | wm8971_set_bias_level(codec, codec->bias_level); | ||
652 | } | ||
653 | |||
654 | static int wm8971_suspend(struct platform_device *pdev, pm_message_t state) | ||
655 | { | ||
656 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
657 | struct snd_soc_codec *codec = socdev->codec; | ||
658 | |||
659 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | static int wm8971_resume(struct platform_device *pdev) | ||
664 | { | ||
665 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
666 | struct snd_soc_codec *codec = socdev->codec; | ||
667 | int i; | ||
668 | u8 data[2]; | ||
669 | u16 *cache = codec->reg_cache; | ||
670 | u16 reg; | ||
671 | |||
672 | /* Sync reg_cache with the hardware */ | ||
673 | for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) { | ||
674 | if (i + 1 == WM8971_RESET) | ||
675 | continue; | ||
676 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
677 | data[1] = cache[i] & 0x00ff; | ||
678 | codec->hw_write(codec->control_data, data, 2); | ||
679 | } | ||
680 | |||
681 | wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
682 | |||
683 | /* charge wm8971 caps */ | ||
684 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { | ||
685 | reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; | ||
686 | wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); | ||
687 | codec->bias_level = SND_SOC_BIAS_ON; | ||
688 | queue_delayed_work(wm8971_workq, &codec->delayed_work, | ||
689 | msecs_to_jiffies(1000)); | ||
690 | } | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static int wm8971_init(struct snd_soc_device *socdev) | ||
696 | { | ||
697 | struct snd_soc_codec *codec = socdev->codec; | ||
698 | int reg, ret = 0; | ||
699 | |||
700 | codec->name = "WM8971"; | ||
701 | codec->owner = THIS_MODULE; | ||
702 | codec->read = wm8971_read_reg_cache; | ||
703 | codec->write = wm8971_write; | ||
704 | codec->set_bias_level = wm8971_set_bias_level; | ||
705 | codec->dai = &wm8971_dai; | ||
706 | codec->reg_cache_size = ARRAY_SIZE(wm8971_reg); | ||
707 | codec->num_dai = 1; | ||
708 | codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL); | ||
709 | |||
710 | if (codec->reg_cache == NULL) | ||
711 | return -ENOMEM; | ||
712 | |||
713 | wm8971_reset(codec); | ||
714 | |||
715 | /* register pcms */ | ||
716 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
717 | if (ret < 0) { | ||
718 | printk(KERN_ERR "wm8971: failed to create pcms\n"); | ||
719 | goto pcm_err; | ||
720 | } | ||
721 | |||
722 | /* charge output caps - set vmid to 5k for quick power up */ | ||
723 | reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; | ||
724 | wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); | ||
725 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
726 | queue_delayed_work(wm8971_workq, &codec->delayed_work, | ||
727 | msecs_to_jiffies(1000)); | ||
728 | |||
729 | /* set the update bits */ | ||
730 | reg = wm8971_read_reg_cache(codec, WM8971_LDAC); | ||
731 | wm8971_write(codec, WM8971_LDAC, reg | 0x0100); | ||
732 | reg = wm8971_read_reg_cache(codec, WM8971_RDAC); | ||
733 | wm8971_write(codec, WM8971_RDAC, reg | 0x0100); | ||
734 | |||
735 | reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V); | ||
736 | wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100); | ||
737 | reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V); | ||
738 | wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100); | ||
739 | |||
740 | reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V); | ||
741 | wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100); | ||
742 | reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V); | ||
743 | wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100); | ||
744 | |||
745 | reg = wm8971_read_reg_cache(codec, WM8971_LINVOL); | ||
746 | wm8971_write(codec, WM8971_LINVOL, reg | 0x0100); | ||
747 | reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); | ||
748 | wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); | ||
749 | |||
750 | wm8971_add_controls(codec); | ||
751 | wm8971_add_widgets(codec); | ||
752 | ret = snd_soc_register_card(socdev); | ||
753 | if (ret < 0) { | ||
754 | printk(KERN_ERR "wm8971: failed to register card\n"); | ||
755 | goto card_err; | ||
756 | } | ||
757 | return ret; | ||
758 | |||
759 | card_err: | ||
760 | snd_soc_free_pcms(socdev); | ||
761 | snd_soc_dapm_free(socdev); | ||
762 | pcm_err: | ||
763 | kfree(codec->reg_cache); | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
768 | around */ | ||
769 | static struct snd_soc_device *wm8971_socdev; | ||
770 | |||
771 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
772 | |||
773 | static int wm8971_i2c_probe(struct i2c_client *i2c, | ||
774 | const struct i2c_device_id *id) | ||
775 | { | ||
776 | struct snd_soc_device *socdev = wm8971_socdev; | ||
777 | struct snd_soc_codec *codec = socdev->codec; | ||
778 | int ret; | ||
779 | |||
780 | i2c_set_clientdata(i2c, codec); | ||
781 | |||
782 | codec->control_data = i2c; | ||
783 | |||
784 | ret = wm8971_init(socdev); | ||
785 | if (ret < 0) | ||
786 | pr_err("failed to initialise WM8971\n"); | ||
787 | |||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | static int wm8971_i2c_remove(struct i2c_client *client) | ||
792 | { | ||
793 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
794 | kfree(codec->reg_cache); | ||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | static const struct i2c_device_id wm8971_i2c_id[] = { | ||
799 | { "wm8971", 0 }, | ||
800 | { } | ||
801 | }; | ||
802 | MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id); | ||
803 | |||
804 | static struct i2c_driver wm8971_i2c_driver = { | ||
805 | .driver = { | ||
806 | .name = "WM8971 I2C Codec", | ||
807 | .owner = THIS_MODULE, | ||
808 | }, | ||
809 | .probe = wm8971_i2c_probe, | ||
810 | .remove = wm8971_i2c_remove, | ||
811 | .id_table = wm8971_i2c_id, | ||
812 | }; | ||
813 | |||
814 | static int wm8971_add_i2c_device(struct platform_device *pdev, | ||
815 | const struct wm8971_setup_data *setup) | ||
816 | { | ||
817 | struct i2c_board_info info; | ||
818 | struct i2c_adapter *adapter; | ||
819 | struct i2c_client *client; | ||
820 | int ret; | ||
821 | |||
822 | ret = i2c_add_driver(&wm8971_i2c_driver); | ||
823 | if (ret != 0) { | ||
824 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
829 | info.addr = setup->i2c_address; | ||
830 | strlcpy(info.type, "wm8971", I2C_NAME_SIZE); | ||
831 | |||
832 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
833 | if (!adapter) { | ||
834 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
835 | setup->i2c_bus); | ||
836 | goto err_driver; | ||
837 | } | ||
838 | |||
839 | client = i2c_new_device(adapter, &info); | ||
840 | i2c_put_adapter(adapter); | ||
841 | if (!client) { | ||
842 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
843 | (unsigned int)info.addr); | ||
844 | goto err_driver; | ||
845 | } | ||
846 | |||
847 | return 0; | ||
848 | |||
849 | err_driver: | ||
850 | i2c_del_driver(&wm8971_i2c_driver); | ||
851 | return -ENODEV; | ||
852 | } | ||
853 | |||
854 | #endif | ||
855 | |||
856 | static int wm8971_probe(struct platform_device *pdev) | ||
857 | { | ||
858 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
859 | struct wm8971_setup_data *setup; | ||
860 | struct snd_soc_codec *codec; | ||
861 | struct wm8971_priv *wm8971; | ||
862 | int ret = 0; | ||
863 | |||
864 | pr_info("WM8971 Audio Codec %s", WM8971_VERSION); | ||
865 | |||
866 | setup = socdev->codec_data; | ||
867 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
868 | if (codec == NULL) | ||
869 | return -ENOMEM; | ||
870 | |||
871 | wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL); | ||
872 | if (wm8971 == NULL) { | ||
873 | kfree(codec); | ||
874 | return -ENOMEM; | ||
875 | } | ||
876 | |||
877 | codec->private_data = wm8971; | ||
878 | socdev->codec = codec; | ||
879 | mutex_init(&codec->mutex); | ||
880 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
881 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
882 | wm8971_socdev = socdev; | ||
883 | |||
884 | INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work); | ||
885 | wm8971_workq = create_workqueue("wm8971"); | ||
886 | if (wm8971_workq == NULL) { | ||
887 | kfree(codec->private_data); | ||
888 | kfree(codec); | ||
889 | return -ENOMEM; | ||
890 | } | ||
891 | |||
892 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
893 | if (setup->i2c_address) { | ||
894 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
895 | ret = wm8971_add_i2c_device(pdev, setup); | ||
896 | } | ||
897 | #endif | ||
898 | /* Add other interfaces here */ | ||
899 | |||
900 | if (ret != 0) { | ||
901 | destroy_workqueue(wm8971_workq); | ||
902 | kfree(codec->private_data); | ||
903 | kfree(codec); | ||
904 | } | ||
905 | |||
906 | return ret; | ||
907 | } | ||
908 | |||
909 | /* power down chip */ | ||
910 | static int wm8971_remove(struct platform_device *pdev) | ||
911 | { | ||
912 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
913 | struct snd_soc_codec *codec = socdev->codec; | ||
914 | |||
915 | if (codec->control_data) | ||
916 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
917 | if (wm8971_workq) | ||
918 | destroy_workqueue(wm8971_workq); | ||
919 | snd_soc_free_pcms(socdev); | ||
920 | snd_soc_dapm_free(socdev); | ||
921 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
922 | i2c_unregister_device(codec->control_data); | ||
923 | i2c_del_driver(&wm8971_i2c_driver); | ||
924 | #endif | ||
925 | kfree(codec->private_data); | ||
926 | kfree(codec); | ||
927 | |||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | struct snd_soc_codec_device soc_codec_dev_wm8971 = { | ||
932 | .probe = wm8971_probe, | ||
933 | .remove = wm8971_remove, | ||
934 | .suspend = wm8971_suspend, | ||
935 | .resume = wm8971_resume, | ||
936 | }; | ||
937 | |||
938 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); | ||
939 | |||
940 | MODULE_DESCRIPTION("ASoC WM8971 driver"); | ||
941 | MODULE_AUTHOR("Lab126"); | ||
942 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h new file mode 100644 index 00000000000..ef4f08f9f34 --- /dev/null +++ b/sound/soc/codecs/wm8971.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * wm8971.h -- audio driver for WM8971 | ||
3 | * | ||
4 | * Copyright 2005 Lab126, Inc. | ||
5 | * | ||
6 | * Author: Kenneth Kiraly <kiraly@lab126.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 | |||
15 | #ifndef _WM8971_H | ||
16 | #define _WM8971_H | ||
17 | |||
18 | #define WM8971_LINVOL 0x00 | ||
19 | #define WM8971_RINVOL 0x01 | ||
20 | #define WM8971_LOUT1V 0x02 | ||
21 | #define WM8971_ROUT1V 0x03 | ||
22 | #define WM8971_ADCDAC 0x05 | ||
23 | #define WM8971_IFACE 0x07 | ||
24 | #define WM8971_SRATE 0x08 | ||
25 | #define WM8971_LDAC 0x0a | ||
26 | #define WM8971_RDAC 0x0b | ||
27 | #define WM8971_BASS 0x0c | ||
28 | #define WM8971_TREBLE 0x0d | ||
29 | #define WM8971_RESET 0x0f | ||
30 | #define WM8971_ALC1 0x11 | ||
31 | #define WM8971_ALC2 0x12 | ||
32 | #define WM8971_ALC3 0x13 | ||
33 | #define WM8971_NGATE 0x14 | ||
34 | #define WM8971_LADC 0x15 | ||
35 | #define WM8971_RADC 0x16 | ||
36 | #define WM8971_ADCTL1 0x17 | ||
37 | #define WM8971_ADCTL2 0x18 | ||
38 | #define WM8971_PWR1 0x19 | ||
39 | #define WM8971_PWR2 0x1a | ||
40 | #define WM8971_ADCTL3 0x1b | ||
41 | #define WM8971_ADCIN 0x1f | ||
42 | #define WM8971_LADCIN 0x20 | ||
43 | #define WM8971_RADCIN 0x21 | ||
44 | #define WM8971_LOUTM1 0x22 | ||
45 | #define WM8971_LOUTM2 0x23 | ||
46 | #define WM8971_ROUTM1 0x24 | ||
47 | #define WM8971_ROUTM2 0x25 | ||
48 | #define WM8971_MOUTM1 0x26 | ||
49 | #define WM8971_MOUTM2 0x27 | ||
50 | #define WM8971_LOUT2V 0x28 | ||
51 | #define WM8971_ROUT2V 0x29 | ||
52 | #define WM8971_MOUTV 0x2A | ||
53 | |||
54 | #define WM8971_SYSCLK 0 | ||
55 | |||
56 | struct wm8971_setup_data { | ||
57 | int i2c_bus; | ||
58 | unsigned short i2c_address; | ||
59 | }; | ||
60 | |||
61 | extern struct snd_soc_dai wm8971_dai; | ||
62 | extern struct snd_soc_codec_device soc_codec_dev_wm8971; | ||
63 | |||
64 | #endif | ||
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index dd995ef448b..63410d7b5ef 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -1477,81 +1477,86 @@ static struct snd_soc_device *wm8990_socdev; | |||
1477 | * low = 0x34 | 1477 | * low = 0x34 |
1478 | * high = 0x36 | 1478 | * high = 0x36 |
1479 | */ | 1479 | */ |
1480 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1481 | 1480 | ||
1482 | /* Magic definition of all other variables and things */ | 1481 | static int wm8990_i2c_probe(struct i2c_client *i2c, |
1483 | I2C_CLIENT_INSMOD; | 1482 | const struct i2c_device_id *id) |
1484 | |||
1485 | static struct i2c_driver wm8990_i2c_driver; | ||
1486 | static struct i2c_client client_template; | ||
1487 | |||
1488 | static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1489 | { | 1483 | { |
1490 | struct snd_soc_device *socdev = wm8990_socdev; | 1484 | struct snd_soc_device *socdev = wm8990_socdev; |
1491 | struct wm8990_setup_data *setup = socdev->codec_data; | ||
1492 | struct snd_soc_codec *codec = socdev->codec; | 1485 | struct snd_soc_codec *codec = socdev->codec; |
1493 | struct i2c_client *i2c; | ||
1494 | int ret; | 1486 | int ret; |
1495 | 1487 | ||
1496 | if (addr != setup->i2c_address) | ||
1497 | return -ENODEV; | ||
1498 | |||
1499 | client_template.adapter = adap; | ||
1500 | client_template.addr = addr; | ||
1501 | |||
1502 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1503 | if (i2c == NULL) | ||
1504 | return -ENOMEM; | ||
1505 | |||
1506 | i2c_set_clientdata(i2c, codec); | 1488 | i2c_set_clientdata(i2c, codec); |
1507 | codec->control_data = i2c; | 1489 | codec->control_data = i2c; |
1508 | 1490 | ||
1509 | ret = i2c_attach_client(i2c); | ||
1510 | if (ret < 0) { | ||
1511 | pr_err("failed to attach codec at addr %x\n", addr); | ||
1512 | goto err; | ||
1513 | } | ||
1514 | |||
1515 | ret = wm8990_init(socdev); | 1491 | ret = wm8990_init(socdev); |
1516 | if (ret < 0) { | 1492 | if (ret < 0) |
1517 | pr_err("failed to initialise WM8990\n"); | 1493 | pr_err("failed to initialise WM8990\n"); |
1518 | goto err; | ||
1519 | } | ||
1520 | return ret; | ||
1521 | 1494 | ||
1522 | err: | ||
1523 | kfree(i2c); | ||
1524 | return ret; | 1495 | return ret; |
1525 | } | 1496 | } |
1526 | 1497 | ||
1527 | static int wm8990_i2c_detach(struct i2c_client *client) | 1498 | static int wm8990_i2c_remove(struct i2c_client *client) |
1528 | { | 1499 | { |
1529 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1500 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1530 | i2c_detach_client(client); | ||
1531 | kfree(codec->reg_cache); | 1501 | kfree(codec->reg_cache); |
1532 | kfree(client); | ||
1533 | return 0; | 1502 | return 0; |
1534 | } | 1503 | } |
1535 | 1504 | ||
1536 | static int wm8990_i2c_attach(struct i2c_adapter *adap) | 1505 | static const struct i2c_device_id wm8990_i2c_id[] = { |
1537 | { | 1506 | { "wm8990", 0 }, |
1538 | return i2c_probe(adap, &addr_data, wm8990_codec_probe); | 1507 | { } |
1539 | } | 1508 | }; |
1509 | MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id); | ||
1540 | 1510 | ||
1541 | static struct i2c_driver wm8990_i2c_driver = { | 1511 | static struct i2c_driver wm8990_i2c_driver = { |
1542 | .driver = { | 1512 | .driver = { |
1543 | .name = "WM8990 I2C Codec", | 1513 | .name = "WM8990 I2C Codec", |
1544 | .owner = THIS_MODULE, | 1514 | .owner = THIS_MODULE, |
1545 | }, | 1515 | }, |
1546 | .attach_adapter = wm8990_i2c_attach, | 1516 | .probe = wm8990_i2c_probe, |
1547 | .detach_client = wm8990_i2c_detach, | 1517 | .remove = wm8990_i2c_remove, |
1548 | .command = NULL, | 1518 | .id_table = wm8990_i2c_id, |
1549 | }; | 1519 | }; |
1550 | 1520 | ||
1551 | static struct i2c_client client_template = { | 1521 | static int wm8990_add_i2c_device(struct platform_device *pdev, |
1552 | .name = "WM8990", | 1522 | const struct wm8990_setup_data *setup) |
1553 | .driver = &wm8990_i2c_driver, | 1523 | { |
1554 | }; | 1524 | struct i2c_board_info info; |
1525 | struct i2c_adapter *adapter; | ||
1526 | struct i2c_client *client; | ||
1527 | int ret; | ||
1528 | |||
1529 | ret = i2c_add_driver(&wm8990_i2c_driver); | ||
1530 | if (ret != 0) { | ||
1531 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1532 | return ret; | ||
1533 | } | ||
1534 | |||
1535 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1536 | info.addr = setup->i2c_address; | ||
1537 | strlcpy(info.type, "wm8990", I2C_NAME_SIZE); | ||
1538 | |||
1539 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1540 | if (!adapter) { | ||
1541 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1542 | setup->i2c_bus); | ||
1543 | goto err_driver; | ||
1544 | } | ||
1545 | |||
1546 | client = i2c_new_device(adapter, &info); | ||
1547 | i2c_put_adapter(adapter); | ||
1548 | if (!client) { | ||
1549 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1550 | (unsigned int)info.addr); | ||
1551 | goto err_driver; | ||
1552 | } | ||
1553 | |||
1554 | return 0; | ||
1555 | |||
1556 | err_driver: | ||
1557 | i2c_del_driver(&wm8990_i2c_driver); | ||
1558 | return -ENODEV; | ||
1559 | } | ||
1555 | #endif | 1560 | #endif |
1556 | 1561 | ||
1557 | static int wm8990_probe(struct platform_device *pdev) | 1562 | static int wm8990_probe(struct platform_device *pdev) |
@@ -1560,7 +1565,7 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1560 | struct wm8990_setup_data *setup; | 1565 | struct wm8990_setup_data *setup; |
1561 | struct snd_soc_codec *codec; | 1566 | struct snd_soc_codec *codec; |
1562 | struct wm8990_priv *wm8990; | 1567 | struct wm8990_priv *wm8990; |
1563 | int ret = 0; | 1568 | int ret; |
1564 | 1569 | ||
1565 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); | 1570 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); |
1566 | 1571 | ||
@@ -1582,16 +1587,13 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1582 | INIT_LIST_HEAD(&codec->dapm_paths); | 1587 | INIT_LIST_HEAD(&codec->dapm_paths); |
1583 | wm8990_socdev = socdev; | 1588 | wm8990_socdev = socdev; |
1584 | 1589 | ||
1590 | ret = -ENODEV; | ||
1591 | |||
1585 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1592 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1586 | if (setup->i2c_address) { | 1593 | if (setup->i2c_address) { |
1587 | normal_i2c[0] = setup->i2c_address; | ||
1588 | codec->hw_write = (hw_write_t)i2c_master_send; | 1594 | codec->hw_write = (hw_write_t)i2c_master_send; |
1589 | ret = i2c_add_driver(&wm8990_i2c_driver); | 1595 | ret = wm8990_add_i2c_device(pdev, setup); |
1590 | if (ret != 0) | ||
1591 | printk(KERN_ERR "can't add i2c driver"); | ||
1592 | } | 1596 | } |
1593 | #else | ||
1594 | /* Add other interfaces here */ | ||
1595 | #endif | 1597 | #endif |
1596 | 1598 | ||
1597 | if (ret != 0) { | 1599 | if (ret != 0) { |
@@ -1612,6 +1614,7 @@ static int wm8990_remove(struct platform_device *pdev) | |||
1612 | snd_soc_free_pcms(socdev); | 1614 | snd_soc_free_pcms(socdev); |
1613 | snd_soc_dapm_free(socdev); | 1615 | snd_soc_dapm_free(socdev); |
1614 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1616 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1617 | i2c_unregister_device(codec->control_data); | ||
1615 | i2c_del_driver(&wm8990_i2c_driver); | 1618 | i2c_del_driver(&wm8990_i2c_driver); |
1616 | #endif | 1619 | #endif |
1617 | kfree(codec->private_data); | 1620 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h index 0a08325d544..0e192f3b078 100644 --- a/sound/soc/codecs/wm8990.h +++ b/sound/soc/codecs/wm8990.h | |||
@@ -827,6 +827,7 @@ | |||
827 | #define WM8990_AINRMUX_PWR_BIT 3 | 827 | #define WM8990_AINRMUX_PWR_BIT 3 |
828 | 828 | ||
829 | struct wm8990_setup_data { | 829 | struct wm8990_setup_data { |
830 | unsigned i2c_bus; | ||
830 | unsigned short i2c_address; | 831 | unsigned short i2c_address; |
831 | }; | 832 | }; |
832 | 833 | ||
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 38d1fe0971f..441d0580db1 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -419,8 +419,12 @@ SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | |||
419 | SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | 419 | SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), |
420 | SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1), | 420 | SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1), |
421 | SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1), | 421 | SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1), |
422 | SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_EXTENDED_MID, 5, 1), | 422 | SND_SOC_DAPM_PGA("Left ADC", AC97_EXTENDED_MID, 5, 1, NULL, 0), |
423 | SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_EXTENDED_MID, 4, 1), | 423 | SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0), |
424 | SND_SOC_DAPM_ADC("Left HiFi ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
425 | SND_SOC_DAPM_ADC("Right HiFi ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
426 | SND_SOC_DAPM_ADC("Left Voice ADC", "Left Voice Capture", SND_SOC_NOPM, 0, 0), | ||
427 | SND_SOC_DAPM_ADC("Right Voice ADC", "Right Voice Capture", SND_SOC_NOPM, 0, 0), | ||
424 | SND_SOC_DAPM_PGA("Left Headphone", AC97_EXTENDED_MSTATUS, 10, 1, NULL, 0), | 428 | SND_SOC_DAPM_PGA("Left Headphone", AC97_EXTENDED_MSTATUS, 10, 1, NULL, 0), |
425 | SND_SOC_DAPM_PGA("Right Headphone", AC97_EXTENDED_MSTATUS, 9, 1, NULL, 0), | 429 | SND_SOC_DAPM_PGA("Right Headphone", AC97_EXTENDED_MSTATUS, 9, 1, NULL, 0), |
426 | SND_SOC_DAPM_PGA("Left Speaker", AC97_EXTENDED_MSTATUS, 8, 1, NULL, 0), | 430 | SND_SOC_DAPM_PGA("Left Speaker", AC97_EXTENDED_MSTATUS, 8, 1, NULL, 0), |
@@ -583,9 +587,13 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
583 | 587 | ||
584 | /* left ADC */ | 588 | /* left ADC */ |
585 | {"Left ADC", NULL, "Left Capture Source"}, | 589 | {"Left ADC", NULL, "Left Capture Source"}, |
590 | {"Left Voice ADC", NULL, "Left ADC"}, | ||
591 | {"Left HiFi ADC", NULL, "Left ADC"}, | ||
586 | 592 | ||
587 | /* right ADC */ | 593 | /* right ADC */ |
588 | {"Right ADC", NULL, "Right Capture Source"}, | 594 | {"Right ADC", NULL, "Right Capture Source"}, |
595 | {"Right Voice ADC", NULL, "Right ADC"}, | ||
596 | {"Right HiFi ADC", NULL, "Right ADC"}, | ||
589 | 597 | ||
590 | /* mic */ | 598 | /* mic */ |
591 | {"Mic A Pre Amp", NULL, "Mic A Source"}, | 599 | {"Mic A Pre Amp", NULL, "Mic A Source"}, |
@@ -949,17 +957,17 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, | |||
949 | 957 | ||
950 | static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) | 958 | static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) |
951 | { | 959 | { |
952 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 960 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
953 | struct snd_soc_device *socdev = rtd->socdev; | 961 | struct snd_soc_device *socdev = rtd->socdev; |
954 | struct snd_soc_codec *codec = socdev->codec; | 962 | struct snd_soc_codec *codec = socdev->codec; |
955 | u16 status; | 963 | u16 status; |
956 | 964 | ||
957 | /* Gracefully shut down the voice interface. */ | 965 | /* Gracefully shut down the voice interface. */ |
958 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; | 966 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; |
959 | ac97_write(codec, AC97_HANDSET_RATE, 0x0280); | 967 | ac97_write(codec, AC97_HANDSET_RATE, 0x0280); |
960 | schedule_timeout_interruptible(msecs_to_jiffies(1)); | 968 | schedule_timeout_interruptible(msecs_to_jiffies(1)); |
961 | ac97_write(codec, AC97_HANDSET_RATE, 0x0F80); | 969 | ac97_write(codec, AC97_HANDSET_RATE, 0x0F80); |
962 | ac97_write(codec, AC97_EXTENDED_MID, status); | 970 | ac97_write(codec, AC97_EXTENDED_MID, status); |
963 | } | 971 | } |
964 | 972 | ||
965 | static int ac97_hifi_prepare(struct snd_pcm_substream *substream) | 973 | static int ac97_hifi_prepare(struct snd_pcm_substream *substream) |
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 65fdbd81a37..9e6062cd6b5 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ASoC driver for TI DAVINCI EVM platform | 2 | * ASoC driver for TI DAVINCI EVM platform |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -136,6 +136,7 @@ static struct snd_soc_machine snd_soc_machine_evm = { | |||
136 | 136 | ||
137 | /* evm audio private data */ | 137 | /* evm audio private data */ |
138 | static struct aic3x_setup_data evm_aic3x_setup = { | 138 | static struct aic3x_setup_data evm_aic3x_setup = { |
139 | .i2c_bus = 0, | ||
139 | .i2c_address = 0x1b, | 140 | .i2c_address = 0x1b, |
140 | }; | 141 | }; |
141 | 142 | ||
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 5ebf1ff71c4..abb5fedb0b1 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor | 2 | * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -256,7 +256,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
256 | mcbsp_word_length = DAVINCI_MCBSP_WORD_32; | 256 | mcbsp_word_length = DAVINCI_MCBSP_WORD_32; |
257 | break; | 257 | break; |
258 | default: | 258 | default: |
259 | printk(KERN_WARNING "davinci-i2s: unsupported PCM format"); | 259 | printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n"); |
260 | return -EINVAL; | 260 | return -EINVAL; |
261 | } | 261 | } |
262 | 262 | ||
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h index c5b091807ee..241648ce887 100644 --- a/sound/soc/davinci/davinci-i2s.h +++ b/sound/soc/davinci/davinci-i2s.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor | 2 | * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 6a5e56a782b..76feaa65737 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ALSA PCM interface for the TI DAVINCI processor | 2 | * ALSA PCM interface for the TI DAVINCI processor |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index 8d6a45e75a6..62cb4eb07e3 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ALSA PCM interface for the TI DAVINCI processor | 2 | * ALSA PCM interface for the TI DAVINCI processor |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 3368ace6097..bba9546ba5f 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -1,3 +1,6 @@ | |||
1 | config SND_SOC_OF_SIMPLE | ||
2 | tristate | ||
3 | |||
1 | config SND_SOC_MPC8610 | 4 | config SND_SOC_MPC8610 |
2 | bool "ALSA SoC support for the MPC8610 SOC" | 5 | bool "ALSA SoC support for the MPC8610 SOC" |
3 | depends on MPC8610_HPCD | 6 | depends on MPC8610_HPCD |
@@ -14,3 +17,10 @@ config SND_SOC_MPC8610_HPCD | |||
14 | default y if MPC8610_HPCD | 17 | default y if MPC8610_HPCD |
15 | help | 18 | help |
16 | Say Y if you want to enable audio on the Freescale MPC8610 HPCD. | 19 | Say Y if you want to enable audio on the Freescale MPC8610 HPCD. |
20 | |||
21 | config SND_SOC_MPC5200_I2S | ||
22 | tristate "Freescale MPC5200 PSC in I2S mode driver" | ||
23 | select SND_SOC_OF_SIMPLE | ||
24 | depends on SND_SOC && PPC_MPC52xx | ||
25 | help | ||
26 | Say Y here to support the MPC5200 PSCs in I2S mode. | ||
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 62f680a4a77..035da4afec3 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile | |||
@@ -1,6 +1,11 @@ | |||
1 | # Simple machine driver that extracts configuration from the OF device tree | ||
2 | obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o | ||
3 | |||
1 | # MPC8610 HPCD Machine Support | 4 | # MPC8610 HPCD Machine Support |
2 | obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o | 5 | obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o |
3 | 6 | ||
4 | # MPC8610 Platform Support | 7 | # MPC8610 Platform Support |
5 | obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o | 8 | obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o |
6 | 9 | ||
10 | obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o | ||
11 | |||
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c new file mode 100644 index 00000000000..86923299bc1 --- /dev/null +++ b/sound/soc/fsl/mpc5200_psc_i2s.c | |||
@@ -0,0 +1,884 @@ | |||
1 | /* | ||
2 | * Freescale MPC5200 PSC in I2S mode | ||
3 | * ALSA SoC Digital Audio Interface (DAI) driver | ||
4 | * | ||
5 | * Copyright (C) 2008 Secret Lab Technologies Ltd. | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/device.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/of_device.h> | ||
14 | #include <linux/of_platform.h> | ||
15 | #include <linux/dma-mapping.h> | ||
16 | |||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/pcm_params.h> | ||
20 | #include <sound/initval.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/soc-of-simple.h> | ||
23 | |||
24 | #include <sysdev/bestcomm/bestcomm.h> | ||
25 | #include <sysdev/bestcomm/gen_bd.h> | ||
26 | #include <asm/mpc52xx_psc.h> | ||
27 | |||
28 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); | ||
29 | MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver"); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | /** | ||
33 | * PSC_I2S_RATES: sample rates supported by the I2S | ||
34 | * | ||
35 | * This driver currently only supports the PSC running in I2S slave mode, | ||
36 | * which means the codec determines the sample rate. Therefore, we tell | ||
37 | * ALSA that we support all rates and let the codec driver decide what rates | ||
38 | * are really supported. | ||
39 | */ | ||
40 | #define PSC_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \ | ||
41 | SNDRV_PCM_RATE_CONTINUOUS) | ||
42 | |||
43 | /** | ||
44 | * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode | ||
45 | */ | ||
46 | #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
47 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \ | ||
48 | SNDRV_PCM_FMTBIT_S32_BE) | ||
49 | |||
50 | /** | ||
51 | * psc_i2s_stream - Data specific to a single stream (playback or capture) | ||
52 | * @active: flag indicating if the stream is active | ||
53 | * @psc_i2s: pointer back to parent psc_i2s data structure | ||
54 | * @bcom_task: bestcomm task structure | ||
55 | * @irq: irq number for bestcomm task | ||
56 | * @period_start: physical address of start of DMA region | ||
57 | * @period_end: physical address of end of DMA region | ||
58 | * @period_next_pt: physical address of next DMA buffer to enqueue | ||
59 | * @period_bytes: size of DMA period in bytes | ||
60 | */ | ||
61 | struct psc_i2s_stream { | ||
62 | int active; | ||
63 | struct psc_i2s *psc_i2s; | ||
64 | struct bcom_task *bcom_task; | ||
65 | int irq; | ||
66 | struct snd_pcm_substream *stream; | ||
67 | dma_addr_t period_start; | ||
68 | dma_addr_t period_end; | ||
69 | dma_addr_t period_next_pt; | ||
70 | dma_addr_t period_current_pt; | ||
71 | int period_bytes; | ||
72 | }; | ||
73 | |||
74 | /** | ||
75 | * psc_i2s - Private driver data | ||
76 | * @name: short name for this device ("PSC0", "PSC1", etc) | ||
77 | * @psc_regs: pointer to the PSC's registers | ||
78 | * @fifo_regs: pointer to the PSC's FIFO registers | ||
79 | * @irq: IRQ of this PSC | ||
80 | * @dev: struct device pointer | ||
81 | * @dai: the CPU DAI for this device | ||
82 | * @sicr: Base value used in serial interface control register; mode is ORed | ||
83 | * with this value. | ||
84 | * @playback: Playback stream context data | ||
85 | * @capture: Capture stream context data | ||
86 | */ | ||
87 | struct psc_i2s { | ||
88 | char name[32]; | ||
89 | struct mpc52xx_psc __iomem *psc_regs; | ||
90 | struct mpc52xx_psc_fifo __iomem *fifo_regs; | ||
91 | unsigned int irq; | ||
92 | struct device *dev; | ||
93 | struct snd_soc_dai dai; | ||
94 | spinlock_t lock; | ||
95 | u32 sicr; | ||
96 | |||
97 | /* per-stream data */ | ||
98 | struct psc_i2s_stream playback; | ||
99 | struct psc_i2s_stream capture; | ||
100 | |||
101 | /* Statistics */ | ||
102 | struct { | ||
103 | int overrun_count; | ||
104 | int underrun_count; | ||
105 | } stats; | ||
106 | }; | ||
107 | |||
108 | /* | ||
109 | * Interrupt handlers | ||
110 | */ | ||
111 | static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s) | ||
112 | { | ||
113 | struct psc_i2s *psc_i2s = _psc_i2s; | ||
114 | struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs; | ||
115 | u16 isr; | ||
116 | |||
117 | isr = in_be16(®s->mpc52xx_psc_isr); | ||
118 | |||
119 | /* Playback underrun error */ | ||
120 | if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP)) | ||
121 | psc_i2s->stats.underrun_count++; | ||
122 | |||
123 | /* Capture overrun error */ | ||
124 | if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR)) | ||
125 | psc_i2s->stats.overrun_count++; | ||
126 | |||
127 | out_8(®s->command, 4 << 4); /* reset the error status */ | ||
128 | |||
129 | return IRQ_HANDLED; | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer | ||
134 | * @s: pointer to stream private data structure | ||
135 | * | ||
136 | * Enqueues another audio period buffer into the bestcomm queue. | ||
137 | * | ||
138 | * Note: The routine must only be called when there is space available in | ||
139 | * the queue. Otherwise the enqueue will fail and the audio ring buffer | ||
140 | * will get out of sync | ||
141 | */ | ||
142 | static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s) | ||
143 | { | ||
144 | struct bcom_bd *bd; | ||
145 | |||
146 | /* Prepare and enqueue the next buffer descriptor */ | ||
147 | bd = bcom_prepare_next_buffer(s->bcom_task); | ||
148 | bd->status = s->period_bytes; | ||
149 | bd->data[0] = s->period_next_pt; | ||
150 | bcom_submit_next_buffer(s->bcom_task, NULL); | ||
151 | |||
152 | /* Update for next period */ | ||
153 | s->period_next_pt += s->period_bytes; | ||
154 | if (s->period_next_pt >= s->period_end) | ||
155 | s->period_next_pt = s->period_start; | ||
156 | } | ||
157 | |||
158 | /* Bestcomm DMA irq handler */ | ||
159 | static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream) | ||
160 | { | ||
161 | struct psc_i2s_stream *s = _psc_i2s_stream; | ||
162 | |||
163 | /* For each finished period, dequeue the completed period buffer | ||
164 | * and enqueue a new one in it's place. */ | ||
165 | while (bcom_buffer_done(s->bcom_task)) { | ||
166 | bcom_retrieve_buffer(s->bcom_task, NULL, NULL); | ||
167 | s->period_current_pt += s->period_bytes; | ||
168 | if (s->period_current_pt >= s->period_end) | ||
169 | s->period_current_pt = s->period_start; | ||
170 | psc_i2s_bcom_enqueue_next_buffer(s); | ||
171 | bcom_enable(s->bcom_task); | ||
172 | } | ||
173 | |||
174 | /* If the stream is active, then also inform the PCM middle layer | ||
175 | * of the period finished event. */ | ||
176 | if (s->active) | ||
177 | snd_pcm_period_elapsed(s->stream); | ||
178 | |||
179 | return IRQ_HANDLED; | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * psc_i2s_startup: create a new substream | ||
184 | * | ||
185 | * This is the first function called when a stream is opened. | ||
186 | * | ||
187 | * If this is the first stream open, then grab the IRQ and program most of | ||
188 | * the PSC registers. | ||
189 | */ | ||
190 | static int psc_i2s_startup(struct snd_pcm_substream *substream) | ||
191 | { | ||
192 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
193 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | ||
194 | int rc; | ||
195 | |||
196 | dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=%p)\n", substream); | ||
197 | |||
198 | if (!psc_i2s->playback.active && | ||
199 | !psc_i2s->capture.active) { | ||
200 | /* Setup the IRQs */ | ||
201 | rc = request_irq(psc_i2s->irq, &psc_i2s_status_irq, IRQF_SHARED, | ||
202 | "psc-i2s-status", psc_i2s); | ||
203 | rc |= request_irq(psc_i2s->capture.irq, | ||
204 | &psc_i2s_bcom_irq, IRQF_SHARED, | ||
205 | "psc-i2s-capture", &psc_i2s->capture); | ||
206 | rc |= request_irq(psc_i2s->playback.irq, | ||
207 | &psc_i2s_bcom_irq, IRQF_SHARED, | ||
208 | "psc-i2s-playback", &psc_i2s->playback); | ||
209 | if (rc) { | ||
210 | free_irq(psc_i2s->irq, psc_i2s); | ||
211 | free_irq(psc_i2s->capture.irq, | ||
212 | &psc_i2s->capture); | ||
213 | free_irq(psc_i2s->playback.irq, | ||
214 | &psc_i2s->playback); | ||
215 | return -ENODEV; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int psc_i2s_hw_params(struct snd_pcm_substream *substream, | ||
223 | struct snd_pcm_hw_params *params) | ||
224 | { | ||
225 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
226 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | ||
227 | u32 mode; | ||
228 | |||
229 | dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i" | ||
230 | " periods=%i buffer_size=%i buffer_bytes=%i\n", | ||
231 | __func__, substream, params_period_size(params), | ||
232 | params_period_bytes(params), params_periods(params), | ||
233 | params_buffer_size(params), params_buffer_bytes(params)); | ||
234 | |||
235 | switch (params_format(params)) { | ||
236 | case SNDRV_PCM_FORMAT_S8: | ||
237 | mode = MPC52xx_PSC_SICR_SIM_CODEC_8; | ||
238 | break; | ||
239 | case SNDRV_PCM_FORMAT_S16_BE: | ||
240 | mode = MPC52xx_PSC_SICR_SIM_CODEC_16; | ||
241 | break; | ||
242 | case SNDRV_PCM_FORMAT_S24_BE: | ||
243 | mode = MPC52xx_PSC_SICR_SIM_CODEC_24; | ||
244 | break; | ||
245 | case SNDRV_PCM_FORMAT_S32_BE: | ||
246 | mode = MPC52xx_PSC_SICR_SIM_CODEC_32; | ||
247 | break; | ||
248 | default: | ||
249 | dev_dbg(psc_i2s->dev, "invalid format\n"); | ||
250 | return -EINVAL; | ||
251 | } | ||
252 | out_be32(&psc_i2s->psc_regs->sicr, psc_i2s->sicr | mode); | ||
253 | |||
254 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int psc_i2s_hw_free(struct snd_pcm_substream *substream) | ||
260 | { | ||
261 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | /** | ||
266 | * psc_i2s_trigger: start and stop the DMA transfer. | ||
267 | * | ||
268 | * This function is called by ALSA to start, stop, pause, and resume the DMA | ||
269 | * transfer of data. | ||
270 | */ | ||
271 | static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) | ||
272 | { | ||
273 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
274 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | ||
275 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
276 | struct psc_i2s_stream *s; | ||
277 | struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs; | ||
278 | u16 imr; | ||
279 | u8 psc_cmd; | ||
280 | long flags; | ||
281 | |||
282 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
283 | s = &psc_i2s->capture; | ||
284 | else | ||
285 | s = &psc_i2s->playback; | ||
286 | |||
287 | dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=%p, cmd=%i)" | ||
288 | " stream_id=%i\n", | ||
289 | substream, cmd, substream->pstr->stream); | ||
290 | |||
291 | switch (cmd) { | ||
292 | case SNDRV_PCM_TRIGGER_START: | ||
293 | s->period_bytes = frames_to_bytes(runtime, | ||
294 | runtime->period_size); | ||
295 | s->period_start = virt_to_phys(runtime->dma_area); | ||
296 | s->period_end = s->period_start + | ||
297 | (s->period_bytes * runtime->periods); | ||
298 | s->period_next_pt = s->period_start; | ||
299 | s->period_current_pt = s->period_start; | ||
300 | s->active = 1; | ||
301 | |||
302 | /* First; reset everything */ | ||
303 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
304 | out_8(®s->command, MPC52xx_PSC_RST_RX); | ||
305 | out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); | ||
306 | } else { | ||
307 | out_8(®s->command, MPC52xx_PSC_RST_TX); | ||
308 | out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); | ||
309 | } | ||
310 | |||
311 | /* Next, fill up the bestcomm bd queue and enable DMA. | ||
312 | * This will begin filling the PSC's fifo. */ | ||
313 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
314 | bcom_gen_bd_rx_reset(s->bcom_task); | ||
315 | else | ||
316 | bcom_gen_bd_tx_reset(s->bcom_task); | ||
317 | while (!bcom_queue_full(s->bcom_task)) | ||
318 | psc_i2s_bcom_enqueue_next_buffer(s); | ||
319 | bcom_enable(s->bcom_task); | ||
320 | |||
321 | /* Due to errata in the i2s mode; need to line up enabling | ||
322 | * the transmitter with a transition on the frame sync | ||
323 | * line */ | ||
324 | |||
325 | spin_lock_irqsave(&psc_i2s->lock, flags); | ||
326 | /* first make sure it is low */ | ||
327 | while ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0) | ||
328 | ; | ||
329 | /* then wait for the transition to high */ | ||
330 | while ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0) | ||
331 | ; | ||
332 | /* Finally, enable the PSC. | ||
333 | * Receiver must always be enabled; even when we only want | ||
334 | * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */ | ||
335 | psc_cmd = MPC52xx_PSC_RX_ENABLE; | ||
336 | if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
337 | psc_cmd |= MPC52xx_PSC_TX_ENABLE; | ||
338 | out_8(®s->command, psc_cmd); | ||
339 | spin_unlock_irqrestore(&psc_i2s->lock, flags); | ||
340 | |||
341 | break; | ||
342 | |||
343 | case SNDRV_PCM_TRIGGER_STOP: | ||
344 | /* Turn off the PSC */ | ||
345 | s->active = 0; | ||
346 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
347 | if (!psc_i2s->playback.active) { | ||
348 | out_8(®s->command, 2 << 4); /* reset rx */ | ||
349 | out_8(®s->command, 3 << 4); /* reset tx */ | ||
350 | out_8(®s->command, 4 << 4); /* reset err */ | ||
351 | } | ||
352 | } else { | ||
353 | out_8(®s->command, 3 << 4); /* reset tx */ | ||
354 | out_8(®s->command, 4 << 4); /* reset err */ | ||
355 | if (!psc_i2s->capture.active) | ||
356 | out_8(®s->command, 2 << 4); /* reset rx */ | ||
357 | } | ||
358 | |||
359 | bcom_disable(s->bcom_task); | ||
360 | while (!bcom_queue_empty(s->bcom_task)) | ||
361 | bcom_retrieve_buffer(s->bcom_task, NULL, NULL); | ||
362 | |||
363 | break; | ||
364 | |||
365 | default: | ||
366 | dev_dbg(psc_i2s->dev, "invalid command\n"); | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | /* Update interrupt enable settings */ | ||
371 | imr = 0; | ||
372 | if (psc_i2s->playback.active) | ||
373 | imr |= MPC52xx_PSC_IMR_TXEMP; | ||
374 | if (psc_i2s->capture.active) | ||
375 | imr |= MPC52xx_PSC_IMR_ORERR; | ||
376 | out_be16(®s->isr_imr.imr, imr); | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * psc_i2s_shutdown: shutdown the data transfer on a stream | ||
383 | * | ||
384 | * Shutdown the PSC if there are no other substreams open. | ||
385 | */ | ||
386 | static void psc_i2s_shutdown(struct snd_pcm_substream *substream) | ||
387 | { | ||
388 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
389 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | ||
390 | |||
391 | dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=%p)\n", substream); | ||
392 | |||
393 | /* | ||
394 | * If this is the last active substream, disable the PSC and release | ||
395 | * the IRQ. | ||
396 | */ | ||
397 | if (!psc_i2s->playback.active && | ||
398 | !psc_i2s->capture.active) { | ||
399 | |||
400 | /* Disable all interrupts and reset the PSC */ | ||
401 | out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0); | ||
402 | out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset tx */ | ||
403 | out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset rx */ | ||
404 | out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */ | ||
405 | out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */ | ||
406 | |||
407 | /* Release irqs */ | ||
408 | free_irq(psc_i2s->irq, psc_i2s); | ||
409 | free_irq(psc_i2s->capture.irq, &psc_i2s->capture); | ||
410 | free_irq(psc_i2s->playback.irq, &psc_i2s->playback); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | /** | ||
415 | * psc_i2s_set_sysclk: set the clock frequency and direction | ||
416 | * | ||
417 | * This function is called by the machine driver to tell us what the clock | ||
418 | * frequency and direction are. | ||
419 | * | ||
420 | * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN), | ||
421 | * and we don't care about the frequency. Return an error if the direction | ||
422 | * is not SND_SOC_CLOCK_IN. | ||
423 | * | ||
424 | * @clk_id: reserved, should be zero | ||
425 | * @freq: the frequency of the given clock ID, currently ignored | ||
426 | * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) | ||
427 | */ | ||
428 | static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | ||
429 | int clk_id, unsigned int freq, int dir) | ||
430 | { | ||
431 | struct psc_i2s *psc_i2s = cpu_dai->private_data; | ||
432 | dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n", | ||
433 | cpu_dai, dir); | ||
434 | return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL; | ||
435 | } | ||
436 | |||
437 | /** | ||
438 | * psc_i2s_set_fmt: set the serial format. | ||
439 | * | ||
440 | * This function is called by the machine driver to tell us what serial | ||
441 | * format to use. | ||
442 | * | ||
443 | * This driver only supports I2S mode. Return an error if the format is | ||
444 | * not SND_SOC_DAIFMT_I2S. | ||
445 | * | ||
446 | * @format: one of SND_SOC_DAIFMT_xxx | ||
447 | */ | ||
448 | static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) | ||
449 | { | ||
450 | struct psc_i2s *psc_i2s = cpu_dai->private_data; | ||
451 | dev_dbg(psc_i2s->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n", | ||
452 | cpu_dai, format); | ||
453 | return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; | ||
454 | } | ||
455 | |||
456 | /* --------------------------------------------------------------------- | ||
457 | * ALSA SoC Bindings | ||
458 | * | ||
459 | * - Digital Audio Interface (DAI) template | ||
460 | * - create/destroy dai hooks | ||
461 | */ | ||
462 | |||
463 | /** | ||
464 | * psc_i2s_dai_template: template CPU Digital Audio Interface | ||
465 | */ | ||
466 | static struct snd_soc_dai psc_i2s_dai_template = { | ||
467 | .type = SND_SOC_DAI_I2S, | ||
468 | .playback = { | ||
469 | .channels_min = 2, | ||
470 | .channels_max = 2, | ||
471 | .rates = PSC_I2S_RATES, | ||
472 | .formats = PSC_I2S_FORMATS, | ||
473 | }, | ||
474 | .capture = { | ||
475 | .channels_min = 2, | ||
476 | .channels_max = 2, | ||
477 | .rates = PSC_I2S_RATES, | ||
478 | .formats = PSC_I2S_FORMATS, | ||
479 | }, | ||
480 | .ops = { | ||
481 | .startup = psc_i2s_startup, | ||
482 | .hw_params = psc_i2s_hw_params, | ||
483 | .hw_free = psc_i2s_hw_free, | ||
484 | .shutdown = psc_i2s_shutdown, | ||
485 | .trigger = psc_i2s_trigger, | ||
486 | }, | ||
487 | .dai_ops = { | ||
488 | .set_sysclk = psc_i2s_set_sysclk, | ||
489 | .set_fmt = psc_i2s_set_fmt, | ||
490 | }, | ||
491 | }; | ||
492 | |||
493 | /* --------------------------------------------------------------------- | ||
494 | * The PSC I2S 'ASoC platform' driver | ||
495 | * | ||
496 | * Can be referenced by an 'ASoC machine' driver | ||
497 | * This driver only deals with the audio bus; it doesn't have any | ||
498 | * interaction with the attached codec | ||
499 | */ | ||
500 | |||
501 | static const struct snd_pcm_hardware psc_i2s_pcm_hardware = { | ||
502 | .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | ||
503 | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
504 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | | ||
505 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE, | ||
506 | .rate_min = 8000, | ||
507 | .rate_max = 48000, | ||
508 | .channels_min = 2, | ||
509 | .channels_max = 2, | ||
510 | .period_bytes_max = 1024 * 1024, | ||
511 | .period_bytes_min = 32, | ||
512 | .periods_min = 2, | ||
513 | .periods_max = 256, | ||
514 | .buffer_bytes_max = 2 * 1024 * 1024, | ||
515 | .fifo_size = 0, | ||
516 | }; | ||
517 | |||
518 | static int psc_i2s_pcm_open(struct snd_pcm_substream *substream) | ||
519 | { | ||
520 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
521 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | ||
522 | struct psc_i2s_stream *s; | ||
523 | |||
524 | dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=%p)\n", substream); | ||
525 | |||
526 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
527 | s = &psc_i2s->capture; | ||
528 | else | ||
529 | s = &psc_i2s->playback; | ||
530 | |||
531 | snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardware); | ||
532 | |||
533 | s->stream = substream; | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int psc_i2s_pcm_close(struct snd_pcm_substream *substream) | ||
538 | { | ||
539 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
540 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | ||
541 | struct psc_i2s_stream *s; | ||
542 | |||
543 | dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=%p)\n", substream); | ||
544 | |||
545 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
546 | s = &psc_i2s->capture; | ||
547 | else | ||
548 | s = &psc_i2s->playback; | ||
549 | |||
550 | s->stream = NULL; | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static snd_pcm_uframes_t | ||
555 | psc_i2s_pcm_pointer(struct snd_pcm_substream *substream) | ||
556 | { | ||
557 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
558 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | ||
559 | struct psc_i2s_stream *s; | ||
560 | dma_addr_t count; | ||
561 | |||
562 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
563 | s = &psc_i2s->capture; | ||
564 | else | ||
565 | s = &psc_i2s->playback; | ||
566 | |||
567 | count = s->period_current_pt - s->period_start; | ||
568 | |||
569 | return bytes_to_frames(substream->runtime, count); | ||
570 | } | ||
571 | |||
572 | static struct snd_pcm_ops psc_i2s_pcm_ops = { | ||
573 | .open = psc_i2s_pcm_open, | ||
574 | .close = psc_i2s_pcm_close, | ||
575 | .ioctl = snd_pcm_lib_ioctl, | ||
576 | .pointer = psc_i2s_pcm_pointer, | ||
577 | }; | ||
578 | |||
579 | static u64 psc_i2s_pcm_dmamask = 0xffffffff; | ||
580 | static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
581 | struct snd_pcm *pcm) | ||
582 | { | ||
583 | struct snd_soc_pcm_runtime *rtd = pcm->private_data; | ||
584 | size_t size = psc_i2s_pcm_hardware.buffer_bytes_max; | ||
585 | int rc = 0; | ||
586 | |||
587 | dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=%p, dai=%p, pcm=%p)\n", | ||
588 | card, dai, pcm); | ||
589 | |||
590 | if (!card->dev->dma_mask) | ||
591 | card->dev->dma_mask = &psc_i2s_pcm_dmamask; | ||
592 | if (!card->dev->coherent_dma_mask) | ||
593 | card->dev->coherent_dma_mask = 0xffffffff; | ||
594 | |||
595 | if (pcm->streams[0].substream) { | ||
596 | rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size, | ||
597 | &pcm->streams[0].substream->dma_buffer); | ||
598 | if (rc) | ||
599 | goto playback_alloc_err; | ||
600 | } | ||
601 | |||
602 | if (pcm->streams[1].substream) { | ||
603 | rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size, | ||
604 | &pcm->streams[1].substream->dma_buffer); | ||
605 | if (rc) | ||
606 | goto capture_alloc_err; | ||
607 | } | ||
608 | |||
609 | return 0; | ||
610 | |||
611 | capture_alloc_err: | ||
612 | if (pcm->streams[0].substream) | ||
613 | snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); | ||
614 | playback_alloc_err: | ||
615 | dev_err(card->dev, "Cannot allocate buffer(s)\n"); | ||
616 | return -ENOMEM; | ||
617 | } | ||
618 | |||
619 | static void psc_i2s_pcm_free(struct snd_pcm *pcm) | ||
620 | { | ||
621 | struct snd_soc_pcm_runtime *rtd = pcm->private_data; | ||
622 | struct snd_pcm_substream *substream; | ||
623 | int stream; | ||
624 | |||
625 | dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=%p)\n", pcm); | ||
626 | |||
627 | for (stream = 0; stream < 2; stream++) { | ||
628 | substream = pcm->streams[stream].substream; | ||
629 | if (substream) { | ||
630 | snd_dma_free_pages(&substream->dma_buffer); | ||
631 | substream->dma_buffer.area = NULL; | ||
632 | substream->dma_buffer.addr = 0; | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | |||
637 | struct snd_soc_platform psc_i2s_pcm_soc_platform = { | ||
638 | .name = "mpc5200-psc-audio", | ||
639 | .pcm_ops = &psc_i2s_pcm_ops, | ||
640 | .pcm_new = &psc_i2s_pcm_new, | ||
641 | .pcm_free = &psc_i2s_pcm_free, | ||
642 | }; | ||
643 | |||
644 | /* --------------------------------------------------------------------- | ||
645 | * Sysfs attributes for debugging | ||
646 | */ | ||
647 | |||
648 | static ssize_t psc_i2s_status_show(struct device *dev, | ||
649 | struct device_attribute *attr, char *buf) | ||
650 | { | ||
651 | struct psc_i2s *psc_i2s = dev_get_drvdata(dev); | ||
652 | |||
653 | return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x " | ||
654 | "tfnum=%i tfstat=0x%.4x\n", | ||
655 | in_be16(&psc_i2s->psc_regs->sr_csr.status), | ||
656 | in_be32(&psc_i2s->psc_regs->sicr), | ||
657 | in_be16(&psc_i2s->fifo_regs->rfnum) & 0x1ff, | ||
658 | in_be16(&psc_i2s->fifo_regs->rfstat), | ||
659 | in_be16(&psc_i2s->fifo_regs->tfnum) & 0x1ff, | ||
660 | in_be16(&psc_i2s->fifo_regs->tfstat)); | ||
661 | } | ||
662 | |||
663 | static int *psc_i2s_get_stat_attr(struct psc_i2s *psc_i2s, const char *name) | ||
664 | { | ||
665 | if (strcmp(name, "playback_underrun") == 0) | ||
666 | return &psc_i2s->stats.underrun_count; | ||
667 | if (strcmp(name, "capture_overrun") == 0) | ||
668 | return &psc_i2s->stats.overrun_count; | ||
669 | |||
670 | return NULL; | ||
671 | } | ||
672 | |||
673 | static ssize_t psc_i2s_stat_show(struct device *dev, | ||
674 | struct device_attribute *attr, char *buf) | ||
675 | { | ||
676 | struct psc_i2s *psc_i2s = dev_get_drvdata(dev); | ||
677 | int *attrib; | ||
678 | |||
679 | attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name); | ||
680 | if (!attrib) | ||
681 | return 0; | ||
682 | |||
683 | return sprintf(buf, "%i\n", *attrib); | ||
684 | } | ||
685 | |||
686 | static ssize_t psc_i2s_stat_store(struct device *dev, | ||
687 | struct device_attribute *attr, | ||
688 | const char *buf, | ||
689 | size_t count) | ||
690 | { | ||
691 | struct psc_i2s *psc_i2s = dev_get_drvdata(dev); | ||
692 | int *attrib; | ||
693 | |||
694 | attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name); | ||
695 | if (!attrib) | ||
696 | return 0; | ||
697 | |||
698 | *attrib = simple_strtoul(buf, NULL, 0); | ||
699 | return count; | ||
700 | } | ||
701 | |||
702 | DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL); | ||
703 | DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show, psc_i2s_stat_store); | ||
704 | DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show, psc_i2s_stat_store); | ||
705 | |||
706 | /* --------------------------------------------------------------------- | ||
707 | * OF platform bus binding code: | ||
708 | * - Probe/remove operations | ||
709 | * - OF device match table | ||
710 | */ | ||
711 | static int __devinit psc_i2s_of_probe(struct of_device *op, | ||
712 | const struct of_device_id *match) | ||
713 | { | ||
714 | phys_addr_t fifo; | ||
715 | struct psc_i2s *psc_i2s; | ||
716 | struct resource res; | ||
717 | int size, psc_id, irq, rc; | ||
718 | const __be32 *prop; | ||
719 | void __iomem *regs; | ||
720 | |||
721 | dev_dbg(&op->dev, "probing psc i2s device\n"); | ||
722 | |||
723 | /* Get the PSC ID */ | ||
724 | prop = of_get_property(op->node, "cell-index", &size); | ||
725 | if (!prop || size < sizeof *prop) | ||
726 | return -ENODEV; | ||
727 | psc_id = be32_to_cpu(*prop); | ||
728 | |||
729 | /* Fetch the registers and IRQ of the PSC */ | ||
730 | irq = irq_of_parse_and_map(op->node, 0); | ||
731 | if (of_address_to_resource(op->node, 0, &res)) { | ||
732 | dev_err(&op->dev, "Missing reg property\n"); | ||
733 | return -ENODEV; | ||
734 | } | ||
735 | regs = ioremap(res.start, 1 + res.end - res.start); | ||
736 | if (!regs) { | ||
737 | dev_err(&op->dev, "Could not map registers\n"); | ||
738 | return -ENODEV; | ||
739 | } | ||
740 | |||
741 | /* Allocate and initialize the driver private data */ | ||
742 | psc_i2s = kzalloc(sizeof *psc_i2s, GFP_KERNEL); | ||
743 | if (!psc_i2s) { | ||
744 | iounmap(regs); | ||
745 | return -ENOMEM; | ||
746 | } | ||
747 | spin_lock_init(&psc_i2s->lock); | ||
748 | psc_i2s->irq = irq; | ||
749 | psc_i2s->psc_regs = regs; | ||
750 | psc_i2s->fifo_regs = regs + sizeof *psc_i2s->psc_regs; | ||
751 | psc_i2s->dev = &op->dev; | ||
752 | psc_i2s->playback.psc_i2s = psc_i2s; | ||
753 | psc_i2s->capture.psc_i2s = psc_i2s; | ||
754 | snprintf(psc_i2s->name, sizeof psc_i2s->name, "PSC%u", psc_id+1); | ||
755 | |||
756 | /* Fill out the CPU DAI structure */ | ||
757 | memcpy(&psc_i2s->dai, &psc_i2s_dai_template, sizeof psc_i2s->dai); | ||
758 | psc_i2s->dai.private_data = psc_i2s; | ||
759 | psc_i2s->dai.name = psc_i2s->name; | ||
760 | psc_i2s->dai.id = psc_id; | ||
761 | |||
762 | /* Find the address of the fifo data registers and setup the | ||
763 | * DMA tasks */ | ||
764 | fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); | ||
765 | psc_i2s->capture.bcom_task = | ||
766 | bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512); | ||
767 | psc_i2s->playback.bcom_task = | ||
768 | bcom_psc_gen_bd_tx_init(psc_id, 10, fifo); | ||
769 | if (!psc_i2s->capture.bcom_task || | ||
770 | !psc_i2s->playback.bcom_task) { | ||
771 | dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); | ||
772 | iounmap(regs); | ||
773 | kfree(psc_i2s); | ||
774 | return -ENODEV; | ||
775 | } | ||
776 | |||
777 | /* Disable all interrupts and reset the PSC */ | ||
778 | out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0); | ||
779 | out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset transmitter */ | ||
780 | out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset receiver */ | ||
781 | out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */ | ||
782 | out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */ | ||
783 | |||
784 | /* Configure the serial interface mode; defaulting to CODEC8 mode */ | ||
785 | psc_i2s->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S | | ||
786 | MPC52xx_PSC_SICR_CLKPOL; | ||
787 | if (of_get_property(op->node, "fsl,cellslave", NULL)) | ||
788 | psc_i2s->sicr |= MPC52xx_PSC_SICR_CELLSLAVE | | ||
789 | MPC52xx_PSC_SICR_GENCLK; | ||
790 | out_be32(&psc_i2s->psc_regs->sicr, | ||
791 | psc_i2s->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8); | ||
792 | |||
793 | /* Check for the codec handle. If it is not present then we | ||
794 | * are done */ | ||
795 | if (!of_get_property(op->node, "codec-handle", NULL)) | ||
796 | return 0; | ||
797 | |||
798 | /* Set up mode register; | ||
799 | * First write: RxRdy (FIFO Alarm) generates rx FIFO irq | ||
800 | * Second write: register Normal mode for non loopback | ||
801 | */ | ||
802 | out_8(&psc_i2s->psc_regs->mode, 0); | ||
803 | out_8(&psc_i2s->psc_regs->mode, 0); | ||
804 | |||
805 | /* Set the TX and RX fifo alarm thresholds */ | ||
806 | out_be16(&psc_i2s->fifo_regs->rfalarm, 0x100); | ||
807 | out_8(&psc_i2s->fifo_regs->rfcntl, 0x4); | ||
808 | out_be16(&psc_i2s->fifo_regs->tfalarm, 0x100); | ||
809 | out_8(&psc_i2s->fifo_regs->tfcntl, 0x7); | ||
810 | |||
811 | /* Lookup the IRQ numbers */ | ||
812 | psc_i2s->playback.irq = | ||
813 | bcom_get_task_irq(psc_i2s->playback.bcom_task); | ||
814 | psc_i2s->capture.irq = | ||
815 | bcom_get_task_irq(psc_i2s->capture.bcom_task); | ||
816 | |||
817 | /* Save what we've done so it can be found again later */ | ||
818 | dev_set_drvdata(&op->dev, psc_i2s); | ||
819 | |||
820 | /* Register the SYSFS files */ | ||
821 | rc = device_create_file(psc_i2s->dev, &dev_attr_status); | ||
822 | rc = device_create_file(psc_i2s->dev, &dev_attr_capture_overrun); | ||
823 | rc = device_create_file(psc_i2s->dev, &dev_attr_playback_underrun); | ||
824 | if (rc) | ||
825 | dev_info(psc_i2s->dev, "error creating sysfs files\n"); | ||
826 | |||
827 | /* Tell the ASoC OF helpers about it */ | ||
828 | of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node, | ||
829 | &psc_i2s->dai); | ||
830 | |||
831 | return 0; | ||
832 | } | ||
833 | |||
834 | static int __devexit psc_i2s_of_remove(struct of_device *op) | ||
835 | { | ||
836 | struct psc_i2s *psc_i2s = dev_get_drvdata(&op->dev); | ||
837 | |||
838 | dev_dbg(&op->dev, "psc_i2s_remove()\n"); | ||
839 | |||
840 | bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task); | ||
841 | bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task); | ||
842 | |||
843 | iounmap(psc_i2s->psc_regs); | ||
844 | iounmap(psc_i2s->fifo_regs); | ||
845 | kfree(psc_i2s); | ||
846 | dev_set_drvdata(&op->dev, NULL); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | /* Match table for of_platform binding */ | ||
852 | static struct of_device_id psc_i2s_match[] __devinitdata = { | ||
853 | { .compatible = "fsl,mpc5200-psc-i2s", }, | ||
854 | {} | ||
855 | }; | ||
856 | MODULE_DEVICE_TABLE(of, psc_i2s_match); | ||
857 | |||
858 | static struct of_platform_driver psc_i2s_driver = { | ||
859 | .match_table = psc_i2s_match, | ||
860 | .probe = psc_i2s_of_probe, | ||
861 | .remove = __devexit_p(psc_i2s_of_remove), | ||
862 | .driver = { | ||
863 | .name = "mpc5200-psc-i2s", | ||
864 | .owner = THIS_MODULE, | ||
865 | }, | ||
866 | }; | ||
867 | |||
868 | /* --------------------------------------------------------------------- | ||
869 | * Module setup and teardown; simply register the of_platform driver | ||
870 | * for the PSC in I2S mode. | ||
871 | */ | ||
872 | static int __init psc_i2s_init(void) | ||
873 | { | ||
874 | return of_register_platform_driver(&psc_i2s_driver); | ||
875 | } | ||
876 | module_init(psc_i2s_init); | ||
877 | |||
878 | static void __exit psc_i2s_exit(void) | ||
879 | { | ||
880 | of_unregister_platform_driver(&psc_i2s_driver); | ||
881 | } | ||
882 | module_exit(psc_i2s_exit); | ||
883 | |||
884 | |||
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 4bdc9d8fc90..94f89debde1 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
@@ -68,10 +68,6 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) | |||
68 | guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, | 68 | guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, |
69 | machine_data->dma_channel_id[1], 0); | 69 | machine_data->dma_channel_id[1], 0); |
70 | 70 | ||
71 | guts_set_pmuxcr_dma(machine_data->guts, 1, 0, 0); | ||
72 | guts_set_pmuxcr_dma(machine_data->guts, 1, 3, 0); | ||
73 | guts_set_pmuxcr_dma(machine_data->guts, 0, 3, 0); | ||
74 | |||
75 | switch (machine_data->ssi_id) { | 71 | switch (machine_data->ssi_id) { |
76 | case 0: | 72 | case 0: |
77 | clrsetbits_be32(&machine_data->guts->pmuxcr, | 73 | clrsetbits_be32(&machine_data->guts->pmuxcr, |
@@ -230,6 +226,8 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, | |||
230 | struct fsl_ssi_info ssi_info; | 226 | struct fsl_ssi_info ssi_info; |
231 | struct fsl_dma_info dma_info; | 227 | struct fsl_dma_info dma_info; |
232 | int ret = -ENODEV; | 228 | int ret = -ENODEV; |
229 | unsigned int playback_dma_channel; | ||
230 | unsigned int capture_dma_channel; | ||
233 | 231 | ||
234 | machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL); | 232 | machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL); |
235 | if (!machine_data) | 233 | if (!machine_data) |
@@ -381,8 +379,9 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, | |||
381 | goto error; | 379 | goto error; |
382 | } | 380 | } |
383 | 381 | ||
384 | /* Find the DMA channels to use. For now, we always use the first DMA | 382 | /* Find the DMA channels to use. Both SSIs need to use the same DMA |
385 | controller. */ | 383 | * controller, so let's use DMA#1. |
384 | */ | ||
386 | for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") { | 385 | for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") { |
387 | iprop = of_get_property(dma_np, "cell-index", NULL); | 386 | iprop = of_get_property(dma_np, "cell-index", NULL); |
388 | if (iprop && (*iprop == 0)) { | 387 | if (iprop && (*iprop == 0)) { |
@@ -397,14 +396,19 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, | |||
397 | } | 396 | } |
398 | machine_data->dma_id = *iprop; | 397 | machine_data->dma_id = *iprop; |
399 | 398 | ||
399 | /* SSI1 needs to use DMA Channels 0 and 1, and SSI2 needs to use DMA | ||
400 | * channels 2 and 3. This is just how the MPC8610 is wired | ||
401 | * internally. | ||
402 | */ | ||
403 | playback_dma_channel = (machine_data->ssi_id == 0) ? 0 : 2; | ||
404 | capture_dma_channel = (machine_data->ssi_id == 0) ? 1 : 3; | ||
405 | |||
400 | /* | 406 | /* |
401 | * Find the DMA channels to use. For now, we always use DMA channel 0 | 407 | * Find the DMA channels to use. |
402 | * for playback, and DMA channel 1 for capture. | ||
403 | */ | 408 | */ |
404 | while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) { | 409 | while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) { |
405 | iprop = of_get_property(dma_channel_np, "cell-index", NULL); | 410 | iprop = of_get_property(dma_channel_np, "cell-index", NULL); |
406 | /* Is it DMA channel 0? */ | 411 | if (iprop && (*iprop == playback_dma_channel)) { |
407 | if (iprop && (*iprop == 0)) { | ||
408 | /* dma_channel[0] and dma_irq[0] are for playback */ | 412 | /* dma_channel[0] and dma_irq[0] are for playback */ |
409 | dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0); | 413 | dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0); |
410 | dma_info.dma_irq[0] = | 414 | dma_info.dma_irq[0] = |
@@ -412,7 +416,7 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, | |||
412 | machine_data->dma_channel_id[0] = *iprop; | 416 | machine_data->dma_channel_id[0] = *iprop; |
413 | continue; | 417 | continue; |
414 | } | 418 | } |
415 | if (iprop && (*iprop == 1)) { | 419 | if (iprop && (*iprop == capture_dma_channel)) { |
416 | /* dma_channel[1] and dma_irq[1] are for capture */ | 420 | /* dma_channel[1] and dma_irq[1] are for capture */ |
417 | dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0); | 421 | dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0); |
418 | dma_info.dma_irq[1] = | 422 | dma_info.dma_irq[1] = |
diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c new file mode 100644 index 00000000000..0382fdac51c --- /dev/null +++ b/sound/soc/fsl/soc-of-simple.c | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * OF helpers for ALSA SoC Layer | ||
3 | * | ||
4 | * Copyright (C) 2008, Secret Lab Technologies Ltd. | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/moduleparam.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/delay.h> | ||
11 | #include <linux/pm.h> | ||
12 | #include <linux/bitops.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/of.h> | ||
15 | #include <sound/core.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-of-simple.h> | ||
20 | #include <sound/initval.h> | ||
21 | |||
22 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); | ||
23 | MODULE_LICENSE("GPL"); | ||
24 | MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings"); | ||
25 | |||
26 | static DEFINE_MUTEX(of_snd_soc_mutex); | ||
27 | static LIST_HEAD(of_snd_soc_device_list); | ||
28 | static int of_snd_soc_next_index; | ||
29 | |||
30 | struct of_snd_soc_device { | ||
31 | int id; | ||
32 | struct list_head list; | ||
33 | struct snd_soc_device device; | ||
34 | struct snd_soc_machine machine; | ||
35 | struct snd_soc_dai_link dai_link; | ||
36 | struct platform_device *pdev; | ||
37 | struct device_node *platform_node; | ||
38 | struct device_node *codec_node; | ||
39 | }; | ||
40 | |||
41 | static struct snd_soc_ops of_snd_soc_ops = { | ||
42 | }; | ||
43 | |||
44 | static struct of_snd_soc_device * | ||
45 | of_snd_soc_get_device(struct device_node *codec_node) | ||
46 | { | ||
47 | struct of_snd_soc_device *of_soc; | ||
48 | |||
49 | list_for_each_entry(of_soc, &of_snd_soc_device_list, list) { | ||
50 | if (of_soc->codec_node == codec_node) | ||
51 | return of_soc; | ||
52 | } | ||
53 | |||
54 | of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL); | ||
55 | if (!of_soc) | ||
56 | return NULL; | ||
57 | |||
58 | /* Initialize the structure and add it to the global list */ | ||
59 | of_soc->codec_node = codec_node; | ||
60 | of_soc->id = of_snd_soc_next_index++; | ||
61 | of_soc->machine.dai_link = &of_soc->dai_link; | ||
62 | of_soc->machine.num_links = 1; | ||
63 | of_soc->device.machine = &of_soc->machine; | ||
64 | of_soc->dai_link.ops = &of_snd_soc_ops; | ||
65 | list_add(&of_soc->list, &of_snd_soc_device_list); | ||
66 | |||
67 | return of_soc; | ||
68 | } | ||
69 | |||
70 | static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc) | ||
71 | { | ||
72 | struct platform_device *pdev; | ||
73 | int rc; | ||
74 | |||
75 | /* Only register the device if both the codec and platform have | ||
76 | * been registered */ | ||
77 | if ((!of_soc->device.codec_data) || (!of_soc->platform_node)) | ||
78 | return; | ||
79 | |||
80 | pr_info("platform<-->codec match achieved; registering machine\n"); | ||
81 | |||
82 | pdev = platform_device_alloc("soc-audio", of_soc->id); | ||
83 | if (!pdev) { | ||
84 | pr_err("of_soc: platform_device_alloc() failed\n"); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | pdev->dev.platform_data = of_soc; | ||
89 | platform_set_drvdata(pdev, &of_soc->device); | ||
90 | of_soc->device.dev = &pdev->dev; | ||
91 | |||
92 | /* The ASoC device is complete; register it */ | ||
93 | rc = platform_device_add(pdev); | ||
94 | if (rc) { | ||
95 | pr_err("of_soc: platform_device_add() failed\n"); | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | } | ||
100 | |||
101 | int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev, | ||
102 | void *codec_data, struct snd_soc_dai *dai, | ||
103 | struct device_node *node) | ||
104 | { | ||
105 | struct of_snd_soc_device *of_soc; | ||
106 | int rc = 0; | ||
107 | |||
108 | pr_info("registering ASoC codec driver: %s\n", node->full_name); | ||
109 | |||
110 | mutex_lock(&of_snd_soc_mutex); | ||
111 | of_soc = of_snd_soc_get_device(node); | ||
112 | if (!of_soc) { | ||
113 | rc = -ENOMEM; | ||
114 | goto out; | ||
115 | } | ||
116 | |||
117 | /* Store the codec data */ | ||
118 | of_soc->device.codec_data = codec_data; | ||
119 | of_soc->device.codec_dev = codec_dev; | ||
120 | of_soc->dai_link.name = (char *)node->name; | ||
121 | of_soc->dai_link.stream_name = (char *)node->name; | ||
122 | of_soc->dai_link.codec_dai = dai; | ||
123 | |||
124 | /* Now try to register the SoC device */ | ||
125 | of_snd_soc_register_device(of_soc); | ||
126 | |||
127 | out: | ||
128 | mutex_unlock(&of_snd_soc_mutex); | ||
129 | return rc; | ||
130 | } | ||
131 | EXPORT_SYMBOL_GPL(of_snd_soc_register_codec); | ||
132 | |||
133 | int of_snd_soc_register_platform(struct snd_soc_platform *platform, | ||
134 | struct device_node *node, | ||
135 | struct snd_soc_dai *cpu_dai) | ||
136 | { | ||
137 | struct of_snd_soc_device *of_soc; | ||
138 | struct device_node *codec_node; | ||
139 | const phandle *handle; | ||
140 | int len, rc = 0; | ||
141 | |||
142 | pr_info("registering ASoC platform driver: %s\n", node->full_name); | ||
143 | |||
144 | handle = of_get_property(node, "codec-handle", &len); | ||
145 | if (!handle || len < sizeof(handle)) | ||
146 | return -ENODEV; | ||
147 | codec_node = of_find_node_by_phandle(*handle); | ||
148 | if (!codec_node) | ||
149 | return -ENODEV; | ||
150 | pr_info("looking for codec: %s\n", codec_node->full_name); | ||
151 | |||
152 | mutex_lock(&of_snd_soc_mutex); | ||
153 | of_soc = of_snd_soc_get_device(codec_node); | ||
154 | if (!of_soc) { | ||
155 | rc = -ENOMEM; | ||
156 | goto out; | ||
157 | } | ||
158 | |||
159 | of_soc->platform_node = node; | ||
160 | of_soc->dai_link.cpu_dai = cpu_dai; | ||
161 | of_soc->device.platform = platform; | ||
162 | of_soc->machine.name = of_soc->dai_link.cpu_dai->name; | ||
163 | |||
164 | /* Now try to register the SoC device */ | ||
165 | of_snd_soc_register_device(of_soc); | ||
166 | |||
167 | out: | ||
168 | mutex_unlock(&of_snd_soc_mutex); | ||
169 | return rc; | ||
170 | } | ||
171 | EXPORT_SYMBOL_GPL(of_snd_soc_register_platform); | ||
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 87d0ed01f65..d166b6b2a60 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c | |||
@@ -290,6 +290,7 @@ static struct snd_soc_machine snd_soc_machine_n810 = { | |||
290 | 290 | ||
291 | /* Audio private data */ | 291 | /* Audio private data */ |
292 | static struct aic3x_setup_data n810_aic33_setup = { | 292 | static struct aic3x_setup_data n810_aic33_setup = { |
293 | .i2c_bus = 2, | ||
293 | .i2c_address = 0x18, | 294 | .i2c_address = 0x18, |
294 | .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, | 295 | .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, |
295 | .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, | 296 | .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, |
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 9212c37a33b..f8c1cdd940a 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config SND_PXA2XX_SOC | 1 | config SND_PXA2XX_SOC |
2 | tristate "SoC Audio for the Intel PXA2xx chip" | 2 | tristate "SoC Audio for the Intel PXA2xx chip" |
3 | depends on ARCH_PXA | 3 | depends on ARCH_PXA |
4 | select SND_PXA2XX_LIB | ||
4 | help | 5 | help |
5 | Say Y or M if you want to add support for codecs attached to | 6 | Say Y or M if you want to add support for codecs attached to |
6 | the PXA2xx AC97, I2S or SSP interface. You will also need | 7 | the PXA2xx AC97, I2S or SSP interface. You will also need |
@@ -13,6 +14,8 @@ config SND_PXA2XX_AC97 | |||
13 | config SND_PXA2XX_SOC_AC97 | 14 | config SND_PXA2XX_SOC_AC97 |
14 | tristate | 15 | tristate |
15 | select AC97_BUS | 16 | select AC97_BUS |
17 | select SND_ARM | ||
18 | select SND_PXA2XX_LIB_AC97 | ||
16 | select SND_SOC_AC97_BUS | 19 | select SND_SOC_AC97_BUS |
17 | 20 | ||
18 | config SND_PXA2XX_SOC_I2S | 21 | config SND_PXA2XX_SOC_I2S |
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 0a53f72077f..1a8373de7f3 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c | |||
@@ -18,13 +18,13 @@ | |||
18 | #include <linux/timer.h> | 18 | #include <linux/timer.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/gpio.h> | ||
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
23 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
24 | #include <sound/soc-dapm.h> | 25 | #include <sound/soc-dapm.h> |
25 | 26 | ||
26 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
27 | #include <asm/hardware/scoop.h> | ||
28 | #include <mach/pxa-regs.h> | 28 | #include <mach/pxa-regs.h> |
29 | #include <mach/hardware.h> | 29 | #include <mach/hardware.h> |
30 | #include <mach/corgi.h> | 30 | #include <mach/corgi.h> |
@@ -54,8 +54,8 @@ static void corgi_ext_control(struct snd_soc_codec *codec) | |||
54 | switch (corgi_jack_func) { | 54 | switch (corgi_jack_func) { |
55 | case CORGI_HP: | 55 | case CORGI_HP: |
56 | /* set = unmute headphone */ | 56 | /* set = unmute headphone */ |
57 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 57 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); |
58 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 58 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
59 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); | 59 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
60 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | 60 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
61 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | 61 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
@@ -63,24 +63,24 @@ static void corgi_ext_control(struct snd_soc_codec *codec) | |||
63 | break; | 63 | break; |
64 | case CORGI_MIC: | 64 | case CORGI_MIC: |
65 | /* reset = mute headphone */ | 65 | /* reset = mute headphone */ |
66 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 66 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
67 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 67 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); |
68 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | 68 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
69 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | 69 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
70 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | 70 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
71 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | 71 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
72 | break; | 72 | break; |
73 | case CORGI_LINE: | 73 | case CORGI_LINE: |
74 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 74 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
75 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 75 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); |
76 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); | 76 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
77 | snd_soc_dapm_enable_pin(codec, "Line Jack"); | 77 | snd_soc_dapm_enable_pin(codec, "Line Jack"); |
78 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | 78 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
79 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | 79 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
80 | break; | 80 | break; |
81 | case CORGI_HEADSET: | 81 | case CORGI_HEADSET: |
82 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 82 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
83 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 83 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
84 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | 84 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
85 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | 85 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
86 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | 86 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
@@ -114,8 +114,8 @@ static int corgi_shutdown(struct snd_pcm_substream *substream) | |||
114 | struct snd_soc_codec *codec = rtd->socdev->codec; | 114 | struct snd_soc_codec *codec = rtd->socdev->codec; |
115 | 115 | ||
116 | /* set = unmute headphone */ | 116 | /* set = unmute headphone */ |
117 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 117 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); |
118 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 118 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
119 | return 0; | 119 | return 0; |
120 | } | 120 | } |
121 | 121 | ||
@@ -218,22 +218,14 @@ static int corgi_set_spk(struct snd_kcontrol *kcontrol, | |||
218 | static int corgi_amp_event(struct snd_soc_dapm_widget *w, | 218 | static int corgi_amp_event(struct snd_soc_dapm_widget *w, |
219 | struct snd_kcontrol *k, int event) | 219 | struct snd_kcontrol *k, int event) |
220 | { | 220 | { |
221 | if (SND_SOC_DAPM_EVENT_ON(event)) | 221 | gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event)); |
222 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); | ||
223 | else | ||
224 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); | ||
225 | |||
226 | return 0; | 222 | return 0; |
227 | } | 223 | } |
228 | 224 | ||
229 | static int corgi_mic_event(struct snd_soc_dapm_widget *w, | 225 | static int corgi_mic_event(struct snd_soc_dapm_widget *w, |
230 | struct snd_kcontrol *k, int event) | 226 | struct snd_kcontrol *k, int event) |
231 | { | 227 | { |
232 | if (SND_SOC_DAPM_EVENT_ON(event)) | 228 | gpio_set_value(CORGI_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event)); |
233 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); | ||
234 | else | ||
235 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); | ||
236 | |||
237 | return 0; | 229 | return 0; |
238 | } | 230 | } |
239 | 231 | ||
@@ -330,6 +322,7 @@ static struct snd_soc_machine snd_soc_machine_corgi = { | |||
330 | 322 | ||
331 | /* corgi audio private data */ | 323 | /* corgi audio private data */ |
332 | static struct wm8731_setup_data corgi_wm8731_setup = { | 324 | static struct wm8731_setup_data corgi_wm8731_setup = { |
325 | .i2c_bus = 0, | ||
333 | .i2c_address = 0x1b, | 326 | .i2c_address = 0x1b, |
334 | }; | 327 | }; |
335 | 328 | ||
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index a4697f7e292..f84f7d8db09 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c | |||
@@ -284,6 +284,7 @@ static struct snd_soc_machine snd_soc_machine_poodle = { | |||
284 | 284 | ||
285 | /* poodle audio private data */ | 285 | /* poodle audio private data */ |
286 | static struct wm8731_setup_data poodle_wm8731_setup = { | 286 | static struct wm8731_setup_data poodle_wm8731_setup = { |
287 | .i2c_bus = 0, | ||
287 | .i2c_address = 0x1b, | 288 | .i2c_address = 0x1b, |
288 | }; | 289 | }; |
289 | 290 | ||
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index d94a495bd6b..a7a3a9c5c6f 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -13,225 +13,30 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/wait.h> | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/delay.h> | ||
20 | 16 | ||
21 | #include <sound/core.h> | 17 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | ||
23 | #include <sound/ac97_codec.h> | 18 | #include <sound/ac97_codec.h> |
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc.h> | 19 | #include <sound/soc.h> |
20 | #include <sound/pxa2xx-lib.h> | ||
26 | 21 | ||
27 | #include <asm/irq.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <mach/hardware.h> | 22 | #include <mach/hardware.h> |
30 | #include <mach/pxa-regs.h> | 23 | #include <mach/pxa-regs.h> |
31 | #include <mach/pxa2xx-gpio.h> | ||
32 | #include <mach/audio.h> | ||
33 | 24 | ||
34 | #include "pxa2xx-pcm.h" | 25 | #include "pxa2xx-pcm.h" |
35 | #include "pxa2xx-ac97.h" | 26 | #include "pxa2xx-ac97.h" |
36 | 27 | ||
37 | static DEFINE_MUTEX(car_mutex); | ||
38 | static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); | ||
39 | static volatile long gsr_bits; | ||
40 | static struct clk *ac97_clk; | ||
41 | #ifdef CONFIG_PXA27x | ||
42 | static struct clk *ac97conf_clk; | ||
43 | #endif | ||
44 | |||
45 | /* | ||
46 | * Beware PXA27x bugs: | ||
47 | * | ||
48 | * o Slot 12 read from modem space will hang controller. | ||
49 | * o CDONE, SDONE interrupt fails after any slot 12 IO. | ||
50 | * | ||
51 | * We therefore have an hybrid approach for waiting on SDONE (interrupt or | ||
52 | * 1 jiffy timeout if interrupt never comes). | ||
53 | */ | ||
54 | |||
55 | static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, | ||
56 | unsigned short reg) | ||
57 | { | ||
58 | unsigned short val = -1; | ||
59 | volatile u32 *reg_addr; | ||
60 | |||
61 | mutex_lock(&car_mutex); | ||
62 | |||
63 | /* set up primary or secondary codec/modem space */ | ||
64 | #if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) | ||
65 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
66 | #else | ||
67 | if (reg == AC97_GPIO_STATUS) | ||
68 | reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; | ||
69 | else | ||
70 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
71 | #endif | ||
72 | reg_addr += (reg >> 1); | ||
73 | |||
74 | #ifndef CONFIG_PXA27x | ||
75 | if (reg == AC97_GPIO_STATUS) { | ||
76 | /* read from controller cache */ | ||
77 | val = *reg_addr; | ||
78 | goto out; | ||
79 | } | ||
80 | #endif | ||
81 | |||
82 | /* start read access across the ac97 link */ | ||
83 | GSR = GSR_CDONE | GSR_SDONE; | ||
84 | gsr_bits = 0; | ||
85 | val = *reg_addr; | ||
86 | |||
87 | wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); | ||
88 | if (!((GSR | gsr_bits) & GSR_SDONE)) { | ||
89 | printk(KERN_ERR "%s: read error (ac97_reg=%x GSR=%#lx)\n", | ||
90 | __func__, reg, GSR | gsr_bits); | ||
91 | val = -1; | ||
92 | goto out; | ||
93 | } | ||
94 | |||
95 | /* valid data now */ | ||
96 | GSR = GSR_CDONE | GSR_SDONE; | ||
97 | gsr_bits = 0; | ||
98 | val = *reg_addr; | ||
99 | /* but we've just started another cycle... */ | ||
100 | wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); | ||
101 | |||
102 | out: mutex_unlock(&car_mutex); | ||
103 | return val; | ||
104 | } | ||
105 | |||
106 | static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
107 | unsigned short val) | ||
108 | { | ||
109 | volatile u32 *reg_addr; | ||
110 | |||
111 | mutex_lock(&car_mutex); | ||
112 | |||
113 | /* set up primary or secondary codec/modem space */ | ||
114 | #if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) | ||
115 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
116 | #else | ||
117 | if (reg == AC97_GPIO_STATUS) | ||
118 | reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; | ||
119 | else | ||
120 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
121 | #endif | ||
122 | reg_addr += (reg >> 1); | ||
123 | |||
124 | GSR = GSR_CDONE | GSR_SDONE; | ||
125 | gsr_bits = 0; | ||
126 | *reg_addr = val; | ||
127 | wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1); | ||
128 | if (!((GSR | gsr_bits) & GSR_CDONE)) | ||
129 | printk(KERN_ERR "%s: write error (ac97_reg=%x GSR=%#lx)\n", | ||
130 | __func__, reg, GSR | gsr_bits); | ||
131 | |||
132 | mutex_unlock(&car_mutex); | ||
133 | } | ||
134 | |||
135 | static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) | 28 | static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) |
136 | { | 29 | { |
137 | #ifdef CONFIG_PXA3xx | 30 | pxa2xx_ac97_try_warm_reset(ac97); |
138 | int timeout = 100; | ||
139 | #endif | ||
140 | gsr_bits = 0; | ||
141 | |||
142 | #ifdef CONFIG_PXA27x | ||
143 | /* warm reset broken on Bulverde, | ||
144 | so manually keep AC97 reset high */ | ||
145 | pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); | ||
146 | udelay(10); | ||
147 | GCR |= GCR_WARM_RST; | ||
148 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | ||
149 | udelay(500); | ||
150 | #elif defined(CONFIG_PXA3xx) | ||
151 | /* Can't use interrupts */ | ||
152 | GCR |= GCR_WARM_RST; | ||
153 | while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) | ||
154 | mdelay(1); | ||
155 | #else | ||
156 | GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN; | ||
157 | wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); | ||
158 | #endif | ||
159 | |||
160 | if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) | ||
161 | printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", | ||
162 | __func__, gsr_bits); | ||
163 | 31 | ||
164 | GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); | 32 | pxa2xx_ac97_finish_reset(ac97); |
165 | GCR |= GCR_SDONE_IE|GCR_CDONE_IE; | ||
166 | } | 33 | } |
167 | 34 | ||
168 | static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) | 35 | static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) |
169 | { | 36 | { |
170 | #ifdef CONFIG_PXA3xx | 37 | pxa2xx_ac97_try_cold_reset(ac97); |
171 | int timeout = 1000; | ||
172 | |||
173 | /* Hold CLKBPB for 100us */ | ||
174 | GCR = 0; | ||
175 | GCR = GCR_CLKBPB; | ||
176 | udelay(100); | ||
177 | GCR = 0; | ||
178 | #endif | ||
179 | 38 | ||
180 | GCR &= GCR_COLD_RST; /* clear everything but nCRST */ | 39 | pxa2xx_ac97_finish_reset(ac97); |
181 | GCR &= ~GCR_COLD_RST; /* then assert nCRST */ | ||
182 | |||
183 | gsr_bits = 0; | ||
184 | #ifdef CONFIG_PXA27x | ||
185 | /* PXA27x Developers Manual section 13.5.2.2.1 */ | ||
186 | clk_enable(ac97conf_clk); | ||
187 | udelay(5); | ||
188 | clk_disable(ac97conf_clk); | ||
189 | GCR = GCR_COLD_RST; | ||
190 | udelay(50); | ||
191 | #elif defined(CONFIG_PXA3xx) | ||
192 | /* Can't use interrupts on PXA3xx */ | ||
193 | GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); | ||
194 | |||
195 | GCR = GCR_WARM_RST | GCR_COLD_RST; | ||
196 | while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--) | ||
197 | mdelay(10); | ||
198 | #else | ||
199 | GCR = GCR_COLD_RST; | ||
200 | GCR |= GCR_CDONE_IE|GCR_SDONE_IE; | ||
201 | wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); | ||
202 | #endif | ||
203 | |||
204 | if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) | ||
205 | printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", | ||
206 | __func__, gsr_bits); | ||
207 | |||
208 | GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); | ||
209 | GCR |= GCR_SDONE_IE|GCR_CDONE_IE; | ||
210 | } | ||
211 | |||
212 | static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) | ||
213 | { | ||
214 | long status; | ||
215 | |||
216 | status = GSR; | ||
217 | if (status) { | ||
218 | GSR = status; | ||
219 | gsr_bits |= status; | ||
220 | wake_up(&gsr_wq); | ||
221 | |||
222 | #ifdef CONFIG_PXA27x | ||
223 | /* Although we don't use those we still need to clear them | ||
224 | since they tend to spuriously trigger when MMC is used | ||
225 | (hardware bug? go figure)... */ | ||
226 | MISR = MISR_EOC; | ||
227 | PISR = PISR_EOC; | ||
228 | MCSR = MCSR_EOC; | ||
229 | #endif | ||
230 | |||
231 | return IRQ_HANDLED; | ||
232 | } | ||
233 | |||
234 | return IRQ_NONE; | ||
235 | } | 40 | } |
236 | 41 | ||
237 | struct snd_ac97_bus_ops soc_ac97_ops = { | 42 | struct snd_ac97_bus_ops soc_ac97_ops = { |
@@ -244,7 +49,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { | |||
244 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { | 49 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { |
245 | .name = "AC97 PCM Stereo out", | 50 | .name = "AC97 PCM Stereo out", |
246 | .dev_addr = __PREG(PCDR), | 51 | .dev_addr = __PREG(PCDR), |
247 | .drcmr = &DRCMRTXPCDR, | 52 | .drcmr = &DRCMR(12), |
248 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | 53 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | |
249 | DCMD_BURST32 | DCMD_WIDTH4, | 54 | DCMD_BURST32 | DCMD_WIDTH4, |
250 | }; | 55 | }; |
@@ -252,7 +57,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { | |||
252 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = { | 57 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = { |
253 | .name = "AC97 PCM Stereo in", | 58 | .name = "AC97 PCM Stereo in", |
254 | .dev_addr = __PREG(PCDR), | 59 | .dev_addr = __PREG(PCDR), |
255 | .drcmr = &DRCMRRXPCDR, | 60 | .drcmr = &DRCMR(11), |
256 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | 61 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | |
257 | DCMD_BURST32 | DCMD_WIDTH4, | 62 | DCMD_BURST32 | DCMD_WIDTH4, |
258 | }; | 63 | }; |
@@ -260,7 +65,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = { | |||
260 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = { | 65 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = { |
261 | .name = "AC97 Aux PCM (Slot 5) Mono out", | 66 | .name = "AC97 Aux PCM (Slot 5) Mono out", |
262 | .dev_addr = __PREG(MODR), | 67 | .dev_addr = __PREG(MODR), |
263 | .drcmr = &DRCMRTXMODR, | 68 | .drcmr = &DRCMR(10), |
264 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | 69 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | |
265 | DCMD_BURST16 | DCMD_WIDTH2, | 70 | DCMD_BURST16 | DCMD_WIDTH2, |
266 | }; | 71 | }; |
@@ -268,7 +73,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = { | |||
268 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = { | 73 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = { |
269 | .name = "AC97 Aux PCM (Slot 5) Mono in", | 74 | .name = "AC97 Aux PCM (Slot 5) Mono in", |
270 | .dev_addr = __PREG(MODR), | 75 | .dev_addr = __PREG(MODR), |
271 | .drcmr = &DRCMRRXMODR, | 76 | .drcmr = &DRCMR(9), |
272 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | 77 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | |
273 | DCMD_BURST16 | DCMD_WIDTH2, | 78 | DCMD_BURST16 | DCMD_WIDTH2, |
274 | }; | 79 | }; |
@@ -276,7 +81,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = { | |||
276 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { | 81 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { |
277 | .name = "AC97 Mic PCM (Slot 6) Mono in", | 82 | .name = "AC97 Mic PCM (Slot 6) Mono in", |
278 | .dev_addr = __PREG(MCDR), | 83 | .dev_addr = __PREG(MCDR), |
279 | .drcmr = &DRCMRRXMCDR, | 84 | .drcmr = &DRCMR(8), |
280 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | 85 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | |
281 | DCMD_BURST16 | DCMD_WIDTH2, | 86 | DCMD_BURST16 | DCMD_WIDTH2, |
282 | }; | 87 | }; |
@@ -285,24 +90,13 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { | |||
285 | static int pxa2xx_ac97_suspend(struct platform_device *pdev, | 90 | static int pxa2xx_ac97_suspend(struct platform_device *pdev, |
286 | struct snd_soc_dai *dai) | 91 | struct snd_soc_dai *dai) |
287 | { | 92 | { |
288 | GCR |= GCR_ACLINK_OFF; | 93 | return pxa2xx_ac97_hw_suspend(); |
289 | clk_disable(ac97_clk); | ||
290 | return 0; | ||
291 | } | 94 | } |
292 | 95 | ||
293 | static int pxa2xx_ac97_resume(struct platform_device *pdev, | 96 | static int pxa2xx_ac97_resume(struct platform_device *pdev, |
294 | struct snd_soc_dai *dai) | 97 | struct snd_soc_dai *dai) |
295 | { | 98 | { |
296 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | 99 | return pxa2xx_ac97_hw_resume(); |
297 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); | ||
298 | pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); | ||
299 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); | ||
300 | #ifdef CONFIG_PXA27x | ||
301 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | ||
302 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | ||
303 | #endif | ||
304 | clk_enable(ac97_clk); | ||
305 | return 0; | ||
306 | } | 100 | } |
307 | 101 | ||
308 | #else | 102 | #else |
@@ -313,61 +107,13 @@ static int pxa2xx_ac97_resume(struct platform_device *pdev, | |||
313 | static int pxa2xx_ac97_probe(struct platform_device *pdev, | 107 | static int pxa2xx_ac97_probe(struct platform_device *pdev, |
314 | struct snd_soc_dai *dai) | 108 | struct snd_soc_dai *dai) |
315 | { | 109 | { |
316 | int ret; | 110 | return pxa2xx_ac97_hw_probe(pdev); |
317 | |||
318 | ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL); | ||
319 | if (ret < 0) | ||
320 | goto err; | ||
321 | |||
322 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | ||
323 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); | ||
324 | pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); | ||
325 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); | ||
326 | #ifdef CONFIG_PXA27x | ||
327 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | ||
328 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | ||
329 | |||
330 | ac97conf_clk = clk_get(&pdev->dev, "AC97CONFCLK"); | ||
331 | if (IS_ERR(ac97conf_clk)) { | ||
332 | ret = PTR_ERR(ac97conf_clk); | ||
333 | ac97conf_clk = NULL; | ||
334 | goto err_irq; | ||
335 | } | ||
336 | #endif | ||
337 | ac97_clk = clk_get(&pdev->dev, "AC97CLK"); | ||
338 | if (IS_ERR(ac97_clk)) { | ||
339 | ret = PTR_ERR(ac97_clk); | ||
340 | ac97_clk = NULL; | ||
341 | goto err_irq; | ||
342 | } | ||
343 | clk_enable(ac97_clk); | ||
344 | return 0; | ||
345 | |||
346 | err_irq: | ||
347 | GCR |= GCR_ACLINK_OFF; | ||
348 | #ifdef CONFIG_PXA27x | ||
349 | if (ac97conf_clk) { | ||
350 | clk_put(ac97conf_clk); | ||
351 | ac97conf_clk = NULL; | ||
352 | } | ||
353 | #endif | ||
354 | free_irq(IRQ_AC97, NULL); | ||
355 | err: | ||
356 | return ret; | ||
357 | } | 111 | } |
358 | 112 | ||
359 | static void pxa2xx_ac97_remove(struct platform_device *pdev, | 113 | static void pxa2xx_ac97_remove(struct platform_device *pdev, |
360 | struct snd_soc_dai *dai) | 114 | struct snd_soc_dai *dai) |
361 | { | 115 | { |
362 | GCR |= GCR_ACLINK_OFF; | 116 | pxa2xx_ac97_hw_remove(pdev); |
363 | free_irq(IRQ_AC97, NULL); | ||
364 | #ifdef CONFIG_PXA27x | ||
365 | clk_put(ac97conf_clk); | ||
366 | ac97conf_clk = NULL; | ||
367 | #endif | ||
368 | clk_disable(ac97_clk); | ||
369 | clk_put(ac97_clk); | ||
370 | ac97_clk = NULL; | ||
371 | } | 117 | } |
372 | 118 | ||
373 | static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, | 119 | static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, |
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index c796b188277..2fb58298513 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
22 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/pxa2xx-lib.h> | ||
24 | 25 | ||
25 | #include <mach/hardware.h> | 26 | #include <mach/hardware.h> |
26 | #include <mach/pxa-regs.h> | 27 | #include <mach/pxa-regs.h> |
@@ -30,6 +31,54 @@ | |||
30 | #include "pxa2xx-pcm.h" | 31 | #include "pxa2xx-pcm.h" |
31 | #include "pxa2xx-i2s.h" | 32 | #include "pxa2xx-i2s.h" |
32 | 33 | ||
34 | struct pxa2xx_gpio { | ||
35 | u32 sys; | ||
36 | u32 rx; | ||
37 | u32 tx; | ||
38 | u32 clk; | ||
39 | u32 frm; | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * I2S Controller Register and Bit Definitions | ||
44 | */ | ||
45 | #define SACR0 __REG(0x40400000) /* Global Control Register */ | ||
46 | #define SACR1 __REG(0x40400004) /* Serial Audio I 2 S/MSB-Justified Control Register */ | ||
47 | #define SASR0 __REG(0x4040000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */ | ||
48 | #define SAIMR __REG(0x40400014) /* Serial Audio Interrupt Mask Register */ | ||
49 | #define SAICR __REG(0x40400018) /* Serial Audio Interrupt Clear Register */ | ||
50 | #define SADIV __REG(0x40400060) /* Audio Clock Divider Register. */ | ||
51 | #define SADR __REG(0x40400080) /* Serial Audio Data Register (TX and RX FIFO access Register). */ | ||
52 | |||
53 | #define SACR0_RFTH(x) ((x) << 12) /* Rx FIFO Interrupt or DMA Trigger Threshold */ | ||
54 | #define SACR0_TFTH(x) ((x) << 8) /* Tx FIFO Interrupt or DMA Trigger Threshold */ | ||
55 | #define SACR0_STRF (1 << 5) /* FIFO Select for EFWR Special Function */ | ||
56 | #define SACR0_EFWR (1 << 4) /* Enable EFWR Function */ | ||
57 | #define SACR0_RST (1 << 3) /* FIFO, i2s Register Reset */ | ||
58 | #define SACR0_BCKD (1 << 2) /* Bit Clock Direction */ | ||
59 | #define SACR0_ENB (1 << 0) /* Enable I2S Link */ | ||
60 | #define SACR1_ENLBF (1 << 5) /* Enable Loopback */ | ||
61 | #define SACR1_DRPL (1 << 4) /* Disable Replaying Function */ | ||
62 | #define SACR1_DREC (1 << 3) /* Disable Recording Function */ | ||
63 | #define SACR1_AMSL (1 << 0) /* Specify Alternate Mode */ | ||
64 | |||
65 | #define SASR0_I2SOFF (1 << 7) /* Controller Status */ | ||
66 | #define SASR0_ROR (1 << 6) /* Rx FIFO Overrun */ | ||
67 | #define SASR0_TUR (1 << 5) /* Tx FIFO Underrun */ | ||
68 | #define SASR0_RFS (1 << 4) /* Rx FIFO Service Request */ | ||
69 | #define SASR0_TFS (1 << 3) /* Tx FIFO Service Request */ | ||
70 | #define SASR0_BSY (1 << 2) /* I2S Busy */ | ||
71 | #define SASR0_RNE (1 << 1) /* Rx FIFO Not Empty */ | ||
72 | #define SASR0_TNF (1 << 0) /* Tx FIFO Not Empty */ | ||
73 | |||
74 | #define SAICR_ROR (1 << 6) /* Clear Rx FIFO Overrun Interrupt */ | ||
75 | #define SAICR_TUR (1 << 5) /* Clear Tx FIFO Underrun Interrupt */ | ||
76 | |||
77 | #define SAIMR_ROR (1 << 6) /* Enable Rx FIFO Overrun Condition Interrupt */ | ||
78 | #define SAIMR_TUR (1 << 5) /* Enable Tx FIFO Underrun Condition Interrupt */ | ||
79 | #define SAIMR_RFS (1 << 4) /* Enable Rx FIFO Service Interrupt */ | ||
80 | #define SAIMR_TFS (1 << 3) /* Enable Tx FIFO Service Interrupt */ | ||
81 | |||
33 | struct pxa_i2s_port { | 82 | struct pxa_i2s_port { |
34 | u32 sadiv; | 83 | u32 sadiv; |
35 | u32 sacr0; | 84 | u32 sacr0; |
@@ -44,7 +93,7 @@ static struct clk *clk_i2s; | |||
44 | static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { | 93 | static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { |
45 | .name = "I2S PCM Stereo out", | 94 | .name = "I2S PCM Stereo out", |
46 | .dev_addr = __PREG(SADR), | 95 | .dev_addr = __PREG(SADR), |
47 | .drcmr = &DRCMRTXSADR, | 96 | .drcmr = &DRCMR(3), |
48 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | 97 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | |
49 | DCMD_BURST32 | DCMD_WIDTH4, | 98 | DCMD_BURST32 | DCMD_WIDTH4, |
50 | }; | 99 | }; |
@@ -52,7 +101,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { | |||
52 | static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = { | 101 | static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = { |
53 | .name = "I2S PCM Stereo in", | 102 | .name = "I2S PCM Stereo in", |
54 | .dev_addr = __PREG(SADR), | 103 | .dev_addr = __PREG(SADR), |
55 | .drcmr = &DRCMRRXSADR, | 104 | .drcmr = &DRCMR(2), |
56 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | 105 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | |
57 | DCMD_BURST32 | DCMD_WIDTH4, | 106 | DCMD_BURST32 | DCMD_WIDTH4, |
58 | }; | 107 | }; |
@@ -65,11 +114,6 @@ static struct pxa2xx_gpio gpio_bus[] = { | |||
65 | .frm = GPIO31_SYNC_I2S_MD, | 114 | .frm = GPIO31_SYNC_I2S_MD, |
66 | }, | 115 | }, |
67 | { /* I2S SoC Master */ | 116 | { /* I2S SoC Master */ |
68 | #ifdef CONFIG_PXA27x | ||
69 | .sys = GPIO113_I2S_SYSCLK_MD, | ||
70 | #else | ||
71 | .sys = GPIO32_SYSCLK_I2S_MD, | ||
72 | #endif | ||
73 | .rx = GPIO29_SDATA_IN_I2S_MD, | 117 | .rx = GPIO29_SDATA_IN_I2S_MD, |
74 | .tx = GPIO30_SDATA_OUT_I2S_MD, | 118 | .tx = GPIO30_SDATA_OUT_I2S_MD, |
75 | .clk = GPIO28_BITCLK_OUT_I2S_MD, | 119 | .clk = GPIO28_BITCLK_OUT_I2S_MD, |
@@ -343,6 +387,11 @@ static struct platform_driver pxa2xx_i2s_driver = { | |||
343 | 387 | ||
344 | static int __init pxa2xx_i2s_init(void) | 388 | static int __init pxa2xx_i2s_init(void) |
345 | { | 389 | { |
390 | if (cpu_is_pxa27x()) | ||
391 | gpio_bus[1].sys = GPIO113_I2S_SYSCLK_MD; | ||
392 | else | ||
393 | gpio_bus[1].sys = GPIO32_SYSCLK_I2S_MD; | ||
394 | |||
346 | clk_i2s = ERR_PTR(-ENOENT); | 395 | clk_i2s = ERR_PTR(-ENOENT); |
347 | return platform_driver_register(&pxa2xx_i2s_driver); | 396 | return platform_driver_register(&pxa2xx_i2s_driver); |
348 | } | 397 | } |
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 4345f387fe4..afcd892cd2f 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
@@ -10,64 +10,14 @@ | |||
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/dma-mapping.h> | 13 | #include <linux/dma-mapping.h> |
18 | 14 | ||
19 | #include <sound/core.h> | 15 | #include <sound/core.h> |
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | #include <sound/soc.h> | 16 | #include <sound/soc.h> |
23 | 17 | #include <sound/pxa2xx-lib.h> | |
24 | #include <asm/dma.h> | ||
25 | #include <mach/hardware.h> | ||
26 | #include <mach/pxa-regs.h> | ||
27 | #include <mach/audio.h> | ||
28 | 18 | ||
29 | #include "pxa2xx-pcm.h" | 19 | #include "pxa2xx-pcm.h" |
30 | 20 | #include "../../arm/pxa2xx-pcm.h" | |
31 | static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { | ||
32 | .info = SNDRV_PCM_INFO_MMAP | | ||
33 | SNDRV_PCM_INFO_MMAP_VALID | | ||
34 | SNDRV_PCM_INFO_INTERLEAVED | | ||
35 | SNDRV_PCM_INFO_PAUSE | | ||
36 | SNDRV_PCM_INFO_RESUME, | ||
37 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
38 | SNDRV_PCM_FMTBIT_S24_LE | | ||
39 | SNDRV_PCM_FMTBIT_S32_LE, | ||
40 | .period_bytes_min = 32, | ||
41 | .period_bytes_max = 8192 - 32, | ||
42 | .periods_min = 1, | ||
43 | .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc), | ||
44 | .buffer_bytes_max = 128 * 1024, | ||
45 | .fifo_size = 32, | ||
46 | }; | ||
47 | |||
48 | struct pxa2xx_runtime_data { | ||
49 | int dma_ch; | ||
50 | struct pxa2xx_pcm_dma_params *params; | ||
51 | pxa_dma_desc *dma_desc_array; | ||
52 | dma_addr_t dma_desc_array_phys; | ||
53 | }; | ||
54 | |||
55 | static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) | ||
56 | { | ||
57 | struct snd_pcm_substream *substream = dev_id; | ||
58 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
59 | int dcsr; | ||
60 | |||
61 | dcsr = DCSR(dma_ch); | ||
62 | DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; | ||
63 | |||
64 | if (dcsr & DCSR_ENDINTR) { | ||
65 | snd_pcm_period_elapsed(substream); | ||
66 | } else { | ||
67 | printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", | ||
68 | prtd->params->name, dma_ch, dcsr); | ||
69 | } | ||
70 | } | ||
71 | 21 | ||
72 | static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | 22 | static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, |
73 | struct snd_pcm_hw_params *params) | 23 | struct snd_pcm_hw_params *params) |
@@ -76,10 +26,6 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
76 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | 26 | struct pxa2xx_runtime_data *prtd = runtime->private_data; |
77 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 27 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
78 | struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; | 28 | struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; |
79 | size_t totsize = params_buffer_bytes(params); | ||
80 | size_t period = params_period_bytes(params); | ||
81 | pxa_dma_desc *dma_desc; | ||
82 | dma_addr_t dma_buff_phys, next_desc_phys; | ||
83 | int ret; | 29 | int ret; |
84 | 30 | ||
85 | /* return if this is a bufferless transfer e.g. | 31 | /* return if this is a bufferless transfer e.g. |
@@ -106,42 +52,16 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
106 | prtd->dma_ch = ret; | 52 | prtd->dma_ch = ret; |
107 | } | 53 | } |
108 | 54 | ||
109 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | 55 | return __pxa2xx_pcm_hw_params(substream, params); |
110 | runtime->dma_bytes = totsize; | ||
111 | |||
112 | dma_desc = prtd->dma_desc_array; | ||
113 | next_desc_phys = prtd->dma_desc_array_phys; | ||
114 | dma_buff_phys = runtime->dma_addr; | ||
115 | do { | ||
116 | next_desc_phys += sizeof(pxa_dma_desc); | ||
117 | dma_desc->ddadr = next_desc_phys; | ||
118 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
119 | dma_desc->dsadr = dma_buff_phys; | ||
120 | dma_desc->dtadr = prtd->params->dev_addr; | ||
121 | } else { | ||
122 | dma_desc->dsadr = prtd->params->dev_addr; | ||
123 | dma_desc->dtadr = dma_buff_phys; | ||
124 | } | ||
125 | if (period > totsize) | ||
126 | period = totsize; | ||
127 | dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN; | ||
128 | dma_desc++; | ||
129 | dma_buff_phys += period; | ||
130 | } while (totsize -= period); | ||
131 | dma_desc[-1].ddadr = prtd->dma_desc_array_phys; | ||
132 | |||
133 | return 0; | ||
134 | } | 56 | } |
135 | 57 | ||
136 | static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) | 58 | static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) |
137 | { | 59 | { |
138 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | 60 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; |
139 | 61 | ||
140 | if (prtd && prtd->params) | 62 | __pxa2xx_pcm_hw_free(substream); |
141 | *prtd->params->drcmr = 0; | ||
142 | 63 | ||
143 | if (prtd->dma_ch) { | 64 | if (prtd->dma_ch) { |
144 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
145 | pxa_free_dma(prtd->dma_ch); | 65 | pxa_free_dma(prtd->dma_ch); |
146 | prtd->dma_ch = 0; | 66 | prtd->dma_ch = 0; |
147 | } | 67 | } |
@@ -149,188 +69,21 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) | |||
149 | return 0; | 69 | return 0; |
150 | } | 70 | } |
151 | 71 | ||
152 | static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) | ||
153 | { | ||
154 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
155 | |||
156 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | ||
157 | DCSR(prtd->dma_ch) = 0; | ||
158 | DCMD(prtd->dma_ch) = 0; | ||
159 | *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
165 | { | ||
166 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
167 | int ret = 0; | ||
168 | |||
169 | switch (cmd) { | ||
170 | case SNDRV_PCM_TRIGGER_START: | ||
171 | DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; | ||
172 | DCSR(prtd->dma_ch) = DCSR_RUN; | ||
173 | break; | ||
174 | |||
175 | case SNDRV_PCM_TRIGGER_STOP: | ||
176 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
177 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
178 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | ||
179 | break; | ||
180 | |||
181 | case SNDRV_PCM_TRIGGER_RESUME: | ||
182 | DCSR(prtd->dma_ch) |= DCSR_RUN; | ||
183 | break; | ||
184 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
185 | DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; | ||
186 | DCSR(prtd->dma_ch) |= DCSR_RUN; | ||
187 | break; | ||
188 | |||
189 | default: | ||
190 | ret = -EINVAL; | ||
191 | } | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | static snd_pcm_uframes_t | ||
197 | pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) | ||
198 | { | ||
199 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
200 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | ||
201 | |||
202 | dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
203 | DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch); | ||
204 | snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr); | ||
205 | |||
206 | if (x == runtime->buffer_size) | ||
207 | x = 0; | ||
208 | return x; | ||
209 | } | ||
210 | |||
211 | static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) | ||
212 | { | ||
213 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
214 | struct pxa2xx_runtime_data *prtd; | ||
215 | int ret; | ||
216 | |||
217 | snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware); | ||
218 | |||
219 | /* | ||
220 | * For mysterious reasons (and despite what the manual says) | ||
221 | * playback samples are lost if the DMA count is not a multiple | ||
222 | * of the DMA burst size. Let's add a rule to enforce that. | ||
223 | */ | ||
224 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
225 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); | ||
226 | if (ret) | ||
227 | goto out; | ||
228 | |||
229 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
230 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); | ||
231 | if (ret) | ||
232 | goto out; | ||
233 | |||
234 | ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
235 | if (ret < 0) | ||
236 | goto out; | ||
237 | |||
238 | prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL); | ||
239 | if (prtd == NULL) { | ||
240 | ret = -ENOMEM; | ||
241 | goto out; | ||
242 | } | ||
243 | |||
244 | prtd->dma_desc_array = | ||
245 | dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
246 | &prtd->dma_desc_array_phys, GFP_KERNEL); | ||
247 | if (!prtd->dma_desc_array) { | ||
248 | ret = -ENOMEM; | ||
249 | goto err1; | ||
250 | } | ||
251 | |||
252 | runtime->private_data = prtd; | ||
253 | return 0; | ||
254 | |||
255 | err1: | ||
256 | kfree(prtd); | ||
257 | out: | ||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) | ||
262 | { | ||
263 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
264 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | ||
265 | |||
266 | dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
267 | prtd->dma_desc_array, prtd->dma_desc_array_phys); | ||
268 | kfree(prtd); | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, | ||
273 | struct vm_area_struct *vma) | ||
274 | { | ||
275 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
276 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
277 | runtime->dma_area, | ||
278 | runtime->dma_addr, | ||
279 | runtime->dma_bytes); | ||
280 | } | ||
281 | |||
282 | struct snd_pcm_ops pxa2xx_pcm_ops = { | 72 | struct snd_pcm_ops pxa2xx_pcm_ops = { |
283 | .open = pxa2xx_pcm_open, | 73 | .open = __pxa2xx_pcm_open, |
284 | .close = pxa2xx_pcm_close, | 74 | .close = __pxa2xx_pcm_close, |
285 | .ioctl = snd_pcm_lib_ioctl, | 75 | .ioctl = snd_pcm_lib_ioctl, |
286 | .hw_params = pxa2xx_pcm_hw_params, | 76 | .hw_params = pxa2xx_pcm_hw_params, |
287 | .hw_free = pxa2xx_pcm_hw_free, | 77 | .hw_free = pxa2xx_pcm_hw_free, |
288 | .prepare = pxa2xx_pcm_prepare, | 78 | .prepare = __pxa2xx_pcm_prepare, |
289 | .trigger = pxa2xx_pcm_trigger, | 79 | .trigger = pxa2xx_pcm_trigger, |
290 | .pointer = pxa2xx_pcm_pointer, | 80 | .pointer = pxa2xx_pcm_pointer, |
291 | .mmap = pxa2xx_pcm_mmap, | 81 | .mmap = pxa2xx_pcm_mmap, |
292 | }; | 82 | }; |
293 | 83 | ||
294 | static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
295 | { | ||
296 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
297 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
298 | size_t size = pxa2xx_pcm_hardware.buffer_bytes_max; | ||
299 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
300 | buf->dev.dev = pcm->card->dev; | ||
301 | buf->private_data = NULL; | ||
302 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
303 | &buf->addr, GFP_KERNEL); | ||
304 | if (!buf->area) | ||
305 | return -ENOMEM; | ||
306 | buf->bytes = size; | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
311 | { | ||
312 | struct snd_pcm_substream *substream; | ||
313 | struct snd_dma_buffer *buf; | ||
314 | int stream; | ||
315 | |||
316 | for (stream = 0; stream < 2; stream++) { | ||
317 | substream = pcm->streams[stream].substream; | ||
318 | if (!substream) | ||
319 | continue; | ||
320 | |||
321 | buf = &substream->dma_buffer; | ||
322 | if (!buf->area) | ||
323 | continue; | ||
324 | |||
325 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
326 | buf->area, buf->addr); | ||
327 | buf->area = NULL; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; | 84 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; |
332 | 85 | ||
333 | int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 86 | static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, |
334 | struct snd_pcm *pcm) | 87 | struct snd_pcm *pcm) |
335 | { | 88 | { |
336 | int ret = 0; | 89 | int ret = 0; |
@@ -360,7 +113,7 @@ int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | |||
360 | struct snd_soc_platform pxa2xx_soc_platform = { | 113 | struct snd_soc_platform pxa2xx_soc_platform = { |
361 | .name = "pxa2xx-audio", | 114 | .name = "pxa2xx-audio", |
362 | .pcm_ops = &pxa2xx_pcm_ops, | 115 | .pcm_ops = &pxa2xx_pcm_ops, |
363 | .pcm_new = pxa2xx_pcm_new, | 116 | .pcm_new = pxa2xx_soc_pcm_new, |
364 | .pcm_free = pxa2xx_pcm_free_dma_buffers, | 117 | .pcm_free = pxa2xx_pcm_free_dma_buffers, |
365 | }; | 118 | }; |
366 | EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); | 119 | EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); |
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h index 54c9c755e50..60c3b20aeeb 100644 --- a/sound/soc/pxa/pxa2xx-pcm.h +++ b/sound/soc/pxa/pxa2xx-pcm.h | |||
@@ -13,21 +13,6 @@ | |||
13 | #ifndef _PXA2XX_PCM_H | 13 | #ifndef _PXA2XX_PCM_H |
14 | #define _PXA2XX_PCM_H | 14 | #define _PXA2XX_PCM_H |
15 | 15 | ||
16 | struct pxa2xx_pcm_dma_params { | ||
17 | char *name; /* stream identifier */ | ||
18 | u32 dcmd; /* DMA descriptor dcmd field */ | ||
19 | volatile u32 *drcmr; /* the DMA request channel to use */ | ||
20 | u32 dev_addr; /* device physical address for DMA */ | ||
21 | }; | ||
22 | |||
23 | struct pxa2xx_gpio { | ||
24 | u32 sys; | ||
25 | u32 rx; | ||
26 | u32 tx; | ||
27 | u32 clk; | ||
28 | u32 frm; | ||
29 | }; | ||
30 | |||
31 | /* platform data */ | 16 | /* platform data */ |
32 | extern struct snd_soc_platform pxa2xx_soc_platform; | 17 | extern struct snd_soc_platform pxa2xx_soc_platform; |
33 | 18 | ||
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 37cb768fc93..9a70b00fc30 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
@@ -19,16 +19,15 @@ | |||
19 | #include <linux/timer.h> | 19 | #include <linux/timer.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/gpio.h> | ||
22 | #include <sound/core.h> | 23 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
24 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
25 | #include <sound/soc-dapm.h> | 26 | #include <sound/soc-dapm.h> |
26 | 27 | ||
27 | #include <asm/mach-types.h> | 28 | #include <asm/mach-types.h> |
28 | #include <asm/hardware/scoop.h> | ||
29 | #include <mach/pxa-regs.h> | 29 | #include <mach/pxa-regs.h> |
30 | #include <mach/hardware.h> | 30 | #include <mach/hardware.h> |
31 | #include <mach/akita.h> | ||
32 | #include <mach/spitz.h> | 31 | #include <mach/spitz.h> |
33 | #include "../codecs/wm8750.h" | 32 | #include "../codecs/wm8750.h" |
34 | #include "pxa2xx-pcm.h" | 33 | #include "pxa2xx-pcm.h" |
@@ -63,8 +62,8 @@ static void spitz_ext_control(struct snd_soc_codec *codec) | |||
63 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); | 62 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
64 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | 63 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
65 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | 64 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
66 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 65 | gpio_set_value(SPITZ_GPIO_MUTE_L, 1); |
67 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 66 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); |
68 | break; | 67 | break; |
69 | case SPITZ_MIC: | 68 | case SPITZ_MIC: |
70 | /* enable mic jack and bias, mute hp */ | 69 | /* enable mic jack and bias, mute hp */ |
@@ -72,8 +71,8 @@ static void spitz_ext_control(struct snd_soc_codec *codec) | |||
72 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | 71 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
73 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | 72 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
74 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | 73 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
75 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 74 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
76 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 75 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); |
77 | break; | 76 | break; |
78 | case SPITZ_LINE: | 77 | case SPITZ_LINE: |
79 | /* enable line jack, disable mic bias and mute hp */ | 78 | /* enable line jack, disable mic bias and mute hp */ |
@@ -81,8 +80,8 @@ static void spitz_ext_control(struct snd_soc_codec *codec) | |||
81 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | 80 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
82 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); | 81 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
83 | snd_soc_dapm_enable_pin(codec, "Line Jack"); | 82 | snd_soc_dapm_enable_pin(codec, "Line Jack"); |
84 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 83 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
85 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 84 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); |
86 | break; | 85 | break; |
87 | case SPITZ_HEADSET: | 86 | case SPITZ_HEADSET: |
88 | /* enable and unmute headset jack enable mic bias, mute L hp */ | 87 | /* enable and unmute headset jack enable mic bias, mute L hp */ |
@@ -90,8 +89,8 @@ static void spitz_ext_control(struct snd_soc_codec *codec) | |||
90 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | 89 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
91 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | 90 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
92 | snd_soc_dapm_enable_pin(codec, "Headset Jack"); | 91 | snd_soc_dapm_enable_pin(codec, "Headset Jack"); |
93 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 92 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
94 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 93 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); |
95 | break; | 94 | break; |
96 | case SPITZ_HP_OFF: | 95 | case SPITZ_HP_OFF: |
97 | 96 | ||
@@ -100,8 +99,8 @@ static void spitz_ext_control(struct snd_soc_codec *codec) | |||
100 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | 99 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
101 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); | 100 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
102 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | 101 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
103 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 102 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
104 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 103 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); |
105 | break; | 104 | break; |
106 | } | 105 | } |
107 | snd_soc_dapm_sync(codec); | 106 | snd_soc_dapm_sync(codec); |
@@ -215,23 +214,14 @@ static int spitz_set_spk(struct snd_kcontrol *kcontrol, | |||
215 | static int spitz_mic_bias(struct snd_soc_dapm_widget *w, | 214 | static int spitz_mic_bias(struct snd_soc_dapm_widget *w, |
216 | struct snd_kcontrol *k, int event) | 215 | struct snd_kcontrol *k, int event) |
217 | { | 216 | { |
218 | if (machine_is_borzoi() || machine_is_spitz()) { | 217 | if (machine_is_borzoi() || machine_is_spitz()) |
219 | if (SND_SOC_DAPM_EVENT_ON(event)) | 218 | gpio_set_value(SPITZ_GPIO_MIC_BIAS, |
220 | set_scoop_gpio(&spitzscoop2_device.dev, | 219 | SND_SOC_DAPM_EVENT_ON(event)); |
221 | SPITZ_SCP2_MIC_BIAS); | 220 | |
222 | else | 221 | if (machine_is_akita()) |
223 | reset_scoop_gpio(&spitzscoop2_device.dev, | 222 | gpio_set_value(AKITA_GPIO_MIC_BIAS, |
224 | SPITZ_SCP2_MIC_BIAS); | 223 | SND_SOC_DAPM_EVENT_ON(event)); |
225 | } | ||
226 | 224 | ||
227 | if (machine_is_akita()) { | ||
228 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
229 | akita_set_ioexp(&akitaioexp_device.dev, | ||
230 | AKITA_IOEXP_MIC_BIAS); | ||
231 | else | ||
232 | akita_reset_ioexp(&akitaioexp_device.dev, | ||
233 | AKITA_IOEXP_MIC_BIAS); | ||
234 | } | ||
235 | return 0; | 225 | return 0; |
236 | } | 226 | } |
237 | 227 | ||
@@ -337,6 +327,7 @@ static struct snd_soc_machine snd_soc_machine_spitz = { | |||
337 | 327 | ||
338 | /* spitz audio private data */ | 328 | /* spitz audio private data */ |
339 | static struct wm8750_setup_data spitz_wm8750_setup = { | 329 | static struct wm8750_setup_data spitz_wm8750_setup = { |
330 | .i2c_bus = 0, | ||
340 | .i2c_address = 0x1b, | 331 | .i2c_address = 0x1b, |
341 | }; | 332 | }; |
342 | 333 | ||
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 8089f8ee05c..73a50e93a9a 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <sound/soc-dapm.h> | 24 | #include <sound/soc-dapm.h> |
25 | #include <sound/tlv.h> | 25 | #include <sound/tlv.h> |
26 | 26 | ||
27 | #include <asm/mach-types.h> | ||
27 | #include <asm/hardware/scoop.h> | 28 | #include <asm/hardware/scoop.h> |
28 | #include <mach/regs-clock.h> | 29 | #include <mach/regs-clock.h> |
29 | #include <mach/regs-gpio.h> | 30 | #include <mach/regs-gpio.h> |
@@ -586,6 +587,7 @@ static struct snd_soc_machine neo1973 = { | |||
586 | }; | 587 | }; |
587 | 588 | ||
588 | static struct wm8753_setup_data neo1973_wm8753_setup = { | 589 | static struct wm8753_setup_data neo1973_wm8753_setup = { |
590 | .i2c_bus = 0, | ||
589 | .i2c_address = 0x1a, | 591 | .i2c_address = 0x1a, |
590 | }; | 592 | }; |
591 | 593 | ||
@@ -596,54 +598,20 @@ static struct snd_soc_device neo1973_snd_devdata = { | |||
596 | .codec_data = &neo1973_wm8753_setup, | 598 | .codec_data = &neo1973_wm8753_setup, |
597 | }; | 599 | }; |
598 | 600 | ||
599 | static struct i2c_client client_template; | 601 | static int lm4857_i2c_probe(struct i2c_client *client, |
600 | 602 | const struct i2c_device_id *id) | |
601 | static const unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END }; | ||
602 | |||
603 | /* Magic definition of all other variables and things */ | ||
604 | I2C_CLIENT_INSMOD; | ||
605 | |||
606 | static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind) | ||
607 | { | 603 | { |
608 | int ret; | ||
609 | |||
610 | DBG("Entered %s\n", __func__); | 604 | DBG("Entered %s\n", __func__); |
611 | 605 | ||
612 | client_template.adapter = adap; | ||
613 | client_template.addr = addr; | ||
614 | |||
615 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
616 | if (i2c == NULL) | ||
617 | return -ENOMEM; | ||
618 | |||
619 | ret = i2c_attach_client(i2c); | ||
620 | if (ret < 0) { | ||
621 | printk(KERN_ERR "LM4857 failed to attach at addr %x\n", addr); | ||
622 | goto exit_err; | ||
623 | } | ||
624 | |||
625 | lm4857_write_regs(); | 606 | lm4857_write_regs(); |
626 | return ret; | ||
627 | |||
628 | exit_err: | ||
629 | kfree(i2c); | ||
630 | return ret; | ||
631 | } | ||
632 | |||
633 | static int lm4857_i2c_detach(struct i2c_client *client) | ||
634 | { | ||
635 | DBG("Entered %s\n", __func__); | ||
636 | |||
637 | i2c_detach_client(client); | ||
638 | kfree(client); | ||
639 | return 0; | 607 | return 0; |
640 | } | 608 | } |
641 | 609 | ||
642 | static int lm4857_i2c_attach(struct i2c_adapter *adap) | 610 | static int lm4857_i2c_remove(struct i2c_client *client) |
643 | { | 611 | { |
644 | DBG("Entered %s\n", __func__); | 612 | DBG("Entered %s\n", __func__); |
645 | 613 | ||
646 | return i2c_probe(adap, &addr_data, lm4857_amp_probe); | 614 | return 0; |
647 | } | 615 | } |
648 | 616 | ||
649 | static u8 lm4857_state; | 617 | static u8 lm4857_state; |
@@ -681,27 +649,67 @@ static void lm4857_shutdown(struct i2c_client *dev) | |||
681 | lm4857_write_regs(); | 649 | lm4857_write_regs(); |
682 | } | 650 | } |
683 | 651 | ||
684 | /* corgi i2c codec control layer */ | 652 | static const struct i2c_device_id lm4857_i2c_id[] = { |
653 | { "neo1973_lm4857", 0 } | ||
654 | { } | ||
655 | }; | ||
656 | |||
685 | static struct i2c_driver lm4857_i2c_driver = { | 657 | static struct i2c_driver lm4857_i2c_driver = { |
686 | .driver = { | 658 | .driver = { |
687 | .name = "LM4857 I2C Amp", | 659 | .name = "LM4857 I2C Amp", |
688 | .owner = THIS_MODULE, | 660 | .owner = THIS_MODULE, |
689 | }, | 661 | }, |
690 | .id = I2C_DRIVERID_LM4857, | ||
691 | .suspend = lm4857_suspend, | 662 | .suspend = lm4857_suspend, |
692 | .resume = lm4857_resume, | 663 | .resume = lm4857_resume, |
693 | .shutdown = lm4857_shutdown, | 664 | .shutdown = lm4857_shutdown, |
694 | .attach_adapter = lm4857_i2c_attach, | 665 | .probe = lm4857_i2c_probe, |
695 | .detach_client = lm4857_i2c_detach, | 666 | .remove = lm4857_i2c_remove, |
696 | .command = NULL, | 667 | .id_table = lm4857_i2c_id, |
697 | }; | ||
698 | |||
699 | static struct i2c_client client_template = { | ||
700 | .name = "LM4857", | ||
701 | .driver = &lm4857_i2c_driver, | ||
702 | }; | 668 | }; |
703 | 669 | ||
704 | static struct platform_device *neo1973_snd_device; | 670 | static struct platform_device *neo1973_snd_device; |
671 | static struct i2c_client *lm4857_client; | ||
672 | |||
673 | static int __init neo1973_add_lm4857_device(struct platform_device *pdev, | ||
674 | int i2c_bus, | ||
675 | unsigned short i2c_address) | ||
676 | { | ||
677 | struct i2c_board_info info; | ||
678 | struct i2c_adapter *adapter; | ||
679 | struct i2c_client *client; | ||
680 | int ret; | ||
681 | |||
682 | ret = i2c_add_driver(&lm4857_i2c_driver); | ||
683 | if (ret != 0) { | ||
684 | dev_err(&pdev->dev, "can't add lm4857 driver\n"); | ||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
689 | info.addr = i2c_address; | ||
690 | strlcpy(info.type, "neo1973_lm4857", I2C_NAME_SIZE); | ||
691 | |||
692 | adapter = i2c_get_adapter(i2c_bus); | ||
693 | if (!adapter) { | ||
694 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", i2c_bus); | ||
695 | goto err_driver; | ||
696 | } | ||
697 | |||
698 | client = i2c_new_device(adapter, &info); | ||
699 | i2c_put_adapter(adapter); | ||
700 | if (!client) { | ||
701 | dev_err(&pdev->dev, "can't add lm4857 device at 0x%x\n", | ||
702 | (unsigned int)info.addr); | ||
703 | goto err_driver; | ||
704 | } | ||
705 | |||
706 | lm4857_client = client; | ||
707 | return 0; | ||
708 | |||
709 | err_driver: | ||
710 | i2c_del_driver(&lm4857_i2c_driver); | ||
711 | return -ENODEV; | ||
712 | } | ||
705 | 713 | ||
706 | static int __init neo1973_init(void) | 714 | static int __init neo1973_init(void) |
707 | { | 715 | { |
@@ -709,6 +717,12 @@ static int __init neo1973_init(void) | |||
709 | 717 | ||
710 | DBG("Entered %s\n", __func__); | 718 | DBG("Entered %s\n", __func__); |
711 | 719 | ||
720 | if (!machine_is_neo1973_gta01()) { | ||
721 | printk(KERN_INFO | ||
722 | "Only GTA01 hardware supported by ASoC driver\n"); | ||
723 | return -ENODEV; | ||
724 | } | ||
725 | |||
712 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); | 726 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); |
713 | if (!neo1973_snd_device) | 727 | if (!neo1973_snd_device) |
714 | return -ENOMEM; | 728 | return -ENOMEM; |
@@ -717,12 +731,15 @@ static int __init neo1973_init(void) | |||
717 | neo1973_snd_devdata.dev = &neo1973_snd_device->dev; | 731 | neo1973_snd_devdata.dev = &neo1973_snd_device->dev; |
718 | ret = platform_device_add(neo1973_snd_device); | 732 | ret = platform_device_add(neo1973_snd_device); |
719 | 733 | ||
720 | if (ret) | 734 | if (ret) { |
721 | platform_device_put(neo1973_snd_device); | 735 | platform_device_put(neo1973_snd_device); |
736 | return ret; | ||
737 | } | ||
722 | 738 | ||
723 | ret = i2c_add_driver(&lm4857_i2c_driver); | 739 | ret = neo1973_add_lm4857_device(neo1973_snd_device, |
740 | neo1973_wm8753_setup, 0x7C); | ||
724 | if (ret != 0) | 741 | if (ret != 0) |
725 | printk(KERN_ERR "can't add i2c driver"); | 742 | platform_device_unregister(neo1973_snd_device); |
726 | 743 | ||
727 | return ret; | 744 | return ret; |
728 | } | 745 | } |
@@ -731,6 +748,7 @@ static void __exit neo1973_exit(void) | |||
731 | { | 748 | { |
732 | DBG("Entered %s\n", __func__); | 749 | DBG("Entered %s\n", __func__); |
733 | 750 | ||
751 | i2c_unregister_device(lm4857_client); | ||
734 | i2c_del_driver(&lm4857_i2c_driver); | 752 | i2c_del_driver(&lm4857_i2c_driver); |
735 | platform_device_unregister(neo1973_snd_device); | 753 | platform_device_unregister(neo1973_snd_device); |
736 | } | 754 | } |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 83f1190293a..ad381138fc2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -340,6 +340,12 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
340 | } | 340 | } |
341 | codec->active--; | 341 | codec->active--; |
342 | 342 | ||
343 | /* Muting the DAC suppresses artifacts caused during digital | ||
344 | * shutdown, for example from stopping clocks. | ||
345 | */ | ||
346 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
347 | snd_soc_dai_digital_mute(codec_dai, 1); | ||
348 | |||
343 | if (cpu_dai->ops.shutdown) | 349 | if (cpu_dai->ops.shutdown) |
344 | cpu_dai->ops.shutdown(substream); | 350 | cpu_dai->ops.shutdown(substream); |
345 | 351 | ||
@@ -970,9 +976,29 @@ static ssize_t codec_reg_show(struct device *dev, | |||
970 | step = codec->reg_cache_step; | 976 | step = codec->reg_cache_step; |
971 | 977 | ||
972 | count += sprintf(buf, "%s registers\n", codec->name); | 978 | count += sprintf(buf, "%s registers\n", codec->name); |
973 | for (i = 0; i < codec->reg_cache_size; i += step) | 979 | for (i = 0; i < codec->reg_cache_size; i += step) { |
974 | count += sprintf(buf + count, "%2x: %4x\n", i, | 980 | count += sprintf(buf + count, "%2x: ", i); |
975 | codec->read(codec, i)); | 981 | if (count >= PAGE_SIZE - 1) |
982 | break; | ||
983 | |||
984 | if (codec->display_register) | ||
985 | count += codec->display_register(codec, buf + count, | ||
986 | PAGE_SIZE - count, i); | ||
987 | else | ||
988 | count += snprintf(buf + count, PAGE_SIZE - count, | ||
989 | "%4x", codec->read(codec, i)); | ||
990 | |||
991 | if (count >= PAGE_SIZE - 1) | ||
992 | break; | ||
993 | |||
994 | count += snprintf(buf + count, PAGE_SIZE - count, "\n"); | ||
995 | if (count >= PAGE_SIZE - 1) | ||
996 | break; | ||
997 | } | ||
998 | |||
999 | /* Truncate count; min() would cause a warning */ | ||
1000 | if (count >= PAGE_SIZE) | ||
1001 | count = PAGE_SIZE - 1; | ||
976 | 1002 | ||
977 | return count; | 1003 | return count; |
978 | } | 1004 | } |
@@ -1296,10 +1322,10 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | |||
1296 | 1322 | ||
1297 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1323 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
1298 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | 1324 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; |
1299 | uinfo->value.enumerated.items = e->mask; | 1325 | uinfo->value.enumerated.items = e->max; |
1300 | 1326 | ||
1301 | if (uinfo->value.enumerated.item > e->mask - 1) | 1327 | if (uinfo->value.enumerated.item > e->max - 1) |
1302 | uinfo->value.enumerated.item = e->mask - 1; | 1328 | uinfo->value.enumerated.item = e->max - 1; |
1303 | strcpy(uinfo->value.enumerated.name, | 1329 | strcpy(uinfo->value.enumerated.name, |
1304 | e->texts[uinfo->value.enumerated.item]); | 1330 | e->texts[uinfo->value.enumerated.item]); |
1305 | return 0; | 1331 | return 0; |
@@ -1322,7 +1348,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
1322 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1348 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1323 | unsigned short val, bitmask; | 1349 | unsigned short val, bitmask; |
1324 | 1350 | ||
1325 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | 1351 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1326 | ; | 1352 | ; |
1327 | val = snd_soc_read(codec, e->reg); | 1353 | val = snd_soc_read(codec, e->reg); |
1328 | ucontrol->value.enumerated.item[0] | 1354 | ucontrol->value.enumerated.item[0] |
@@ -1352,14 +1378,14 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1352 | unsigned short val; | 1378 | unsigned short val; |
1353 | unsigned short mask, bitmask; | 1379 | unsigned short mask, bitmask; |
1354 | 1380 | ||
1355 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | 1381 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1356 | ; | 1382 | ; |
1357 | if (ucontrol->value.enumerated.item[0] > e->mask - 1) | 1383 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
1358 | return -EINVAL; | 1384 | return -EINVAL; |
1359 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | 1385 | val = ucontrol->value.enumerated.item[0] << e->shift_l; |
1360 | mask = (bitmask - 1) << e->shift_l; | 1386 | mask = (bitmask - 1) << e->shift_l; |
1361 | if (e->shift_l != e->shift_r) { | 1387 | if (e->shift_l != e->shift_r) { |
1362 | if (ucontrol->value.enumerated.item[1] > e->mask - 1) | 1388 | if (ucontrol->value.enumerated.item[1] > e->max - 1) |
1363 | return -EINVAL; | 1389 | return -EINVAL; |
1364 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | 1390 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; |
1365 | mask |= (bitmask - 1) << e->shift_r; | 1391 | mask |= (bitmask - 1) << e->shift_r; |
@@ -1386,10 +1412,10 @@ int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | |||
1386 | 1412 | ||
1387 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1413 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
1388 | uinfo->count = 1; | 1414 | uinfo->count = 1; |
1389 | uinfo->value.enumerated.items = e->mask; | 1415 | uinfo->value.enumerated.items = e->max; |
1390 | 1416 | ||
1391 | if (uinfo->value.enumerated.item > e->mask - 1) | 1417 | if (uinfo->value.enumerated.item > e->max - 1) |
1392 | uinfo->value.enumerated.item = e->mask - 1; | 1418 | uinfo->value.enumerated.item = e->max - 1; |
1393 | strcpy(uinfo->value.enumerated.name, | 1419 | strcpy(uinfo->value.enumerated.name, |
1394 | e->texts[uinfo->value.enumerated.item]); | 1420 | e->texts[uinfo->value.enumerated.item]); |
1395 | return 0; | 1421 | return 0; |
@@ -1434,9 +1460,11 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); | |||
1434 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | 1460 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, |
1435 | struct snd_ctl_elem_info *uinfo) | 1461 | struct snd_ctl_elem_info *uinfo) |
1436 | { | 1462 | { |
1437 | int max = (kcontrol->private_value >> 16) & 0xff; | 1463 | struct soc_mixer_control *mc = |
1438 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1464 | (struct soc_mixer_control *)kcontrol->private_value; |
1439 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1465 | int max = mc->max; |
1466 | unsigned int shift = mc->min; | ||
1467 | unsigned int rshift = mc->rshift; | ||
1440 | 1468 | ||
1441 | if (max == 1) | 1469 | if (max == 1) |
1442 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 1470 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
@@ -1462,13 +1490,15 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | |||
1462 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | 1490 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, |
1463 | struct snd_ctl_elem_value *ucontrol) | 1491 | struct snd_ctl_elem_value *ucontrol) |
1464 | { | 1492 | { |
1493 | struct soc_mixer_control *mc = | ||
1494 | (struct soc_mixer_control *)kcontrol->private_value; | ||
1465 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1495 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1466 | int reg = kcontrol->private_value & 0xff; | 1496 | unsigned int reg = mc->reg; |
1467 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1497 | unsigned int shift = mc->shift; |
1468 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1498 | unsigned int rshift = mc->rshift; |
1469 | int max = (kcontrol->private_value >> 16) & 0xff; | 1499 | int max = mc->max; |
1470 | int mask = (1 << fls(max)) - 1; | 1500 | unsigned int mask = (1 << fls(max)) - 1; |
1471 | int invert = (kcontrol->private_value >> 24) & 0x01; | 1501 | unsigned int invert = mc->invert; |
1472 | 1502 | ||
1473 | ucontrol->value.integer.value[0] = | 1503 | ucontrol->value.integer.value[0] = |
1474 | (snd_soc_read(codec, reg) >> shift) & mask; | 1504 | (snd_soc_read(codec, reg) >> shift) & mask; |
@@ -1499,13 +1529,15 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | |||
1499 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | 1529 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, |
1500 | struct snd_ctl_elem_value *ucontrol) | 1530 | struct snd_ctl_elem_value *ucontrol) |
1501 | { | 1531 | { |
1532 | struct soc_mixer_control *mc = | ||
1533 | (struct soc_mixer_control *)kcontrol->private_value; | ||
1502 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1534 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1503 | int reg = kcontrol->private_value & 0xff; | 1535 | unsigned int reg = mc->reg; |
1504 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1536 | unsigned int shift = mc->shift; |
1505 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1537 | unsigned int rshift = mc->rshift; |
1506 | int max = (kcontrol->private_value >> 16) & 0xff; | 1538 | int max = mc->max; |
1507 | int mask = (1 << fls(max)) - 1; | 1539 | unsigned int mask = (1 << fls(max)) - 1; |
1508 | int invert = (kcontrol->private_value >> 24) & 0x01; | 1540 | unsigned int invert = mc->invert; |
1509 | unsigned short val, val2, val_mask; | 1541 | unsigned short val, val2, val_mask; |
1510 | 1542 | ||
1511 | val = (ucontrol->value.integer.value[0] & mask); | 1543 | val = (ucontrol->value.integer.value[0] & mask); |
@@ -1537,7 +1569,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | |||
1537 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, | 1569 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, |
1538 | struct snd_ctl_elem_info *uinfo) | 1570 | struct snd_ctl_elem_info *uinfo) |
1539 | { | 1571 | { |
1540 | int max = (kcontrol->private_value >> 12) & 0xff; | 1572 | struct soc_mixer_control *mc = |
1573 | (struct soc_mixer_control *)kcontrol->private_value; | ||
1574 | int max = mc->max; | ||
1541 | 1575 | ||
1542 | if (max == 1) | 1576 | if (max == 1) |
1543 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 1577 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
@@ -1563,13 +1597,15 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); | |||
1563 | int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | 1597 | int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, |
1564 | struct snd_ctl_elem_value *ucontrol) | 1598 | struct snd_ctl_elem_value *ucontrol) |
1565 | { | 1599 | { |
1600 | struct soc_mixer_control *mc = | ||
1601 | (struct soc_mixer_control *)kcontrol->private_value; | ||
1566 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1602 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1567 | int reg = kcontrol->private_value & 0xff; | 1603 | unsigned int reg = mc->reg; |
1568 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | 1604 | unsigned int reg2 = mc->rreg; |
1569 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1605 | unsigned int shift = mc->shift; |
1570 | int max = (kcontrol->private_value >> 12) & 0xff; | 1606 | int max = mc->max; |
1571 | int mask = (1<<fls(max))-1; | 1607 | unsigned int mask = (1<<fls(max))-1; |
1572 | int invert = (kcontrol->private_value >> 20) & 0x01; | 1608 | unsigned int invert = mc->invert; |
1573 | 1609 | ||
1574 | ucontrol->value.integer.value[0] = | 1610 | ucontrol->value.integer.value[0] = |
1575 | (snd_soc_read(codec, reg) >> shift) & mask; | 1611 | (snd_soc_read(codec, reg) >> shift) & mask; |
@@ -1598,13 +1634,15 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r); | |||
1598 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | 1634 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, |
1599 | struct snd_ctl_elem_value *ucontrol) | 1635 | struct snd_ctl_elem_value *ucontrol) |
1600 | { | 1636 | { |
1637 | struct soc_mixer_control *mc = | ||
1638 | (struct soc_mixer_control *)kcontrol->private_value; | ||
1601 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1639 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1602 | int reg = kcontrol->private_value & 0xff; | 1640 | unsigned int reg = mc->reg; |
1603 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | 1641 | unsigned int reg2 = mc->rreg; |
1604 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1642 | unsigned int shift = mc->shift; |
1605 | int max = (kcontrol->private_value >> 12) & 0xff; | 1643 | int max = mc->max; |
1606 | int mask = (1 << fls(max)) - 1; | 1644 | unsigned int mask = (1 << fls(max)) - 1; |
1607 | int invert = (kcontrol->private_value >> 20) & 0x01; | 1645 | unsigned int invert = mc->invert; |
1608 | int err; | 1646 | int err; |
1609 | unsigned short val, val2, val_mask; | 1647 | unsigned short val, val2, val_mask; |
1610 | 1648 | ||
@@ -1641,8 +1679,10 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); | |||
1641 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | 1679 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, |
1642 | struct snd_ctl_elem_info *uinfo) | 1680 | struct snd_ctl_elem_info *uinfo) |
1643 | { | 1681 | { |
1644 | int max = (signed char)((kcontrol->private_value >> 16) & 0xff); | 1682 | struct soc_mixer_control *mc = |
1645 | int min = (signed char)((kcontrol->private_value >> 24) & 0xff); | 1683 | (struct soc_mixer_control *)kcontrol->private_value; |
1684 | int max = mc->max; | ||
1685 | int min = mc->min; | ||
1646 | 1686 | ||
1647 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 1687 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
1648 | uinfo->count = 2; | 1688 | uinfo->count = 2; |
@@ -1664,9 +1704,11 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); | |||
1664 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | 1704 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, |
1665 | struct snd_ctl_elem_value *ucontrol) | 1705 | struct snd_ctl_elem_value *ucontrol) |
1666 | { | 1706 | { |
1707 | struct soc_mixer_control *mc = | ||
1708 | (struct soc_mixer_control *)kcontrol->private_value; | ||
1667 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1709 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1668 | int reg = kcontrol->private_value & 0xff; | 1710 | unsigned int reg = mc->reg; |
1669 | int min = (signed char)((kcontrol->private_value >> 24) & 0xff); | 1711 | int min = mc->min; |
1670 | int val = snd_soc_read(codec, reg); | 1712 | int val = snd_soc_read(codec, reg); |
1671 | 1713 | ||
1672 | ucontrol->value.integer.value[0] = | 1714 | ucontrol->value.integer.value[0] = |
@@ -1689,9 +1731,11 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); | |||
1689 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | 1731 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, |
1690 | struct snd_ctl_elem_value *ucontrol) | 1732 | struct snd_ctl_elem_value *ucontrol) |
1691 | { | 1733 | { |
1734 | struct soc_mixer_control *mc = | ||
1735 | (struct soc_mixer_control *)kcontrol->private_value; | ||
1692 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1736 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1693 | int reg = kcontrol->private_value & 0xff; | 1737 | unsigned int reg = mc->reg; |
1694 | int min = (signed char)((kcontrol->private_value >> 24) & 0xff); | 1738 | int min = mc->min; |
1695 | unsigned short val; | 1739 | unsigned short val; |
1696 | 1740 | ||
1697 | val = (ucontrol->value.integer.value[0]+min) & 0xff; | 1741 | val = (ucontrol->value.integer.value[0]+min) & 0xff; |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f9d100bc847..9ca9c08610f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/bitops.h> | 38 | #include <linux/bitops.h> |
39 | #include <linux/platform_device.h> | 39 | #include <linux/platform_device.h> |
40 | #include <linux/jiffies.h> | 40 | #include <linux/jiffies.h> |
41 | #include <linux/debugfs.h> | ||
41 | #include <sound/core.h> | 42 | #include <sound/core.h> |
42 | #include <sound/pcm.h> | 43 | #include <sound/pcm.h> |
43 | #include <sound/pcm_params.h> | 44 | #include <sound/pcm_params.h> |
@@ -67,7 +68,9 @@ static int dapm_status = 1; | |||
67 | module_param(dapm_status, int, 0); | 68 | module_param(dapm_status, int, 0); |
68 | MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); | 69 | MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); |
69 | 70 | ||
70 | static unsigned int pop_time; | 71 | static struct dentry *asoc_debugfs; |
72 | |||
73 | static u32 pop_time; | ||
71 | 74 | ||
72 | static void pop_wait(void) | 75 | static void pop_wait(void) |
73 | { | 76 | { |
@@ -104,10 +107,13 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
104 | case snd_soc_dapm_switch: | 107 | case snd_soc_dapm_switch: |
105 | case snd_soc_dapm_mixer: { | 108 | case snd_soc_dapm_mixer: { |
106 | int val; | 109 | int val; |
107 | int reg = w->kcontrols[i].private_value & 0xff; | 110 | struct soc_mixer_control *mc = (struct soc_mixer_control *) |
108 | int shift = (w->kcontrols[i].private_value >> 8) & 0x0f; | 111 | w->kcontrols[i].private_value; |
109 | int mask = (w->kcontrols[i].private_value >> 16) & 0xff; | 112 | unsigned int reg = mc->reg; |
110 | int invert = (w->kcontrols[i].private_value >> 24) & 0x01; | 113 | unsigned int shift = mc->shift; |
114 | int max = mc->max; | ||
115 | unsigned int mask = (1 << fls(max)) - 1; | ||
116 | unsigned int invert = mc->invert; | ||
111 | 117 | ||
112 | val = snd_soc_read(w->codec, reg); | 118 | val = snd_soc_read(w->codec, reg); |
113 | val = (val >> shift) & mask; | 119 | val = (val >> shift) & mask; |
@@ -122,13 +128,13 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
122 | struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; | 128 | struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; |
123 | int val, item, bitmask; | 129 | int val, item, bitmask; |
124 | 130 | ||
125 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | 131 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
126 | ; | 132 | ; |
127 | val = snd_soc_read(w->codec, e->reg); | 133 | val = snd_soc_read(w->codec, e->reg); |
128 | item = (val >> e->shift_l) & (bitmask - 1); | 134 | item = (val >> e->shift_l) & (bitmask - 1); |
129 | 135 | ||
130 | p->connect = 0; | 136 | p->connect = 0; |
131 | for (i = 0; i < e->mask; i++) { | 137 | for (i = 0; i < e->max; i++) { |
132 | if (!(strcmp(p->name, e->texts[i])) && item == i) | 138 | if (!(strcmp(p->name, e->texts[i])) && item == i) |
133 | p->connect = 1; | 139 | p->connect = 1; |
134 | } | 140 | } |
@@ -165,7 +171,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec, | |||
165 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 171 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
166 | int i; | 172 | int i; |
167 | 173 | ||
168 | for (i = 0; i < e->mask; i++) { | 174 | for (i = 0; i < e->max; i++) { |
169 | if (!(strcmp(control_name, e->texts[i]))) { | 175 | if (!(strcmp(control_name, e->texts[i]))) { |
170 | list_add(&path->list, &codec->dapm_paths); | 176 | list_add(&path->list, &codec->dapm_paths); |
171 | list_add(&path->list_sink, &dest->sources); | 177 | list_add(&path->list_sink, &dest->sources); |
@@ -247,16 +253,19 @@ static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power) | |||
247 | return 0; | 253 | return 0; |
248 | 254 | ||
249 | if (widget->num_kcontrols && k) { | 255 | if (widget->num_kcontrols && k) { |
250 | int reg = k->private_value & 0xff; | 256 | struct soc_mixer_control *mc = |
251 | int shift = (k->private_value >> 8) & 0x0f; | 257 | (struct soc_mixer_control *)k->private_value; |
252 | int mask = (k->private_value >> 16) & 0xff; | 258 | unsigned int reg = mc->reg; |
253 | int invert = (k->private_value >> 24) & 0x01; | 259 | unsigned int shift = mc->shift; |
260 | int max = mc->max; | ||
261 | unsigned int mask = (1 << fls(max)) - 1; | ||
262 | unsigned int invert = mc->invert; | ||
254 | 263 | ||
255 | if (power) { | 264 | if (power) { |
256 | int i; | 265 | int i; |
257 | /* power up has happended, increase volume to last level */ | 266 | /* power up has happended, increase volume to last level */ |
258 | if (invert) { | 267 | if (invert) { |
259 | for (i = mask; i > widget->saved_value; i--) | 268 | for (i = max; i > widget->saved_value; i--) |
260 | snd_soc_update_bits(widget->codec, reg, mask, i); | 269 | snd_soc_update_bits(widget->codec, reg, mask, i); |
261 | } else { | 270 | } else { |
262 | for (i = 0; i < widget->saved_value; i++) | 271 | for (i = 0; i < widget->saved_value; i++) |
@@ -684,7 +693,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | |||
684 | /* test and update the power status of a mux widget */ | 693 | /* test and update the power status of a mux widget */ |
685 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 694 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, |
686 | struct snd_kcontrol *kcontrol, int mask, | 695 | struct snd_kcontrol *kcontrol, int mask, |
687 | int val, struct soc_enum* e) | 696 | int mux, int val, struct soc_enum *e) |
688 | { | 697 | { |
689 | struct snd_soc_dapm_path *path; | 698 | struct snd_soc_dapm_path *path; |
690 | int found = 0; | 699 | int found = 0; |
@@ -700,12 +709,12 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
700 | if (path->kcontrol != kcontrol) | 709 | if (path->kcontrol != kcontrol) |
701 | continue; | 710 | continue; |
702 | 711 | ||
703 | if (!path->name || ! e->texts[val]) | 712 | if (!path->name || !e->texts[mux]) |
704 | continue; | 713 | continue; |
705 | 714 | ||
706 | found = 1; | 715 | found = 1; |
707 | /* we now need to match the string in the enum to the path */ | 716 | /* we now need to match the string in the enum to the path */ |
708 | if (!(strcmp(path->name, e->texts[val]))) | 717 | if (!(strcmp(path->name, e->texts[mux]))) |
709 | path->connect = 1; /* new connection */ | 718 | path->connect = 1; /* new connection */ |
710 | else | 719 | else |
711 | path->connect = 0; /* old connection must be powered down */ | 720 | path->connect = 0; /* old connection must be powered down */ |
@@ -811,51 +820,35 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
811 | 820 | ||
812 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); | 821 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); |
813 | 822 | ||
814 | /* pop/click delay times */ | ||
815 | static ssize_t dapm_pop_time_show(struct device *dev, | ||
816 | struct device_attribute *attr, char *buf) | ||
817 | { | ||
818 | return sprintf(buf, "%d\n", pop_time); | ||
819 | } | ||
820 | |||
821 | static ssize_t dapm_pop_time_store(struct device *dev, | ||
822 | struct device_attribute *attr, | ||
823 | const char *buf, size_t count) | ||
824 | |||
825 | { | ||
826 | unsigned long val; | ||
827 | |||
828 | if (strict_strtoul(buf, 10, &val) >= 0) | ||
829 | pop_time = val; | ||
830 | else | ||
831 | printk(KERN_ERR "Unable to parse pop_time setting\n"); | ||
832 | |||
833 | return count; | ||
834 | } | ||
835 | |||
836 | static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show, | ||
837 | dapm_pop_time_store); | ||
838 | |||
839 | int snd_soc_dapm_sys_add(struct device *dev) | 823 | int snd_soc_dapm_sys_add(struct device *dev) |
840 | { | 824 | { |
841 | int ret = 0; | 825 | int ret = 0; |
842 | 826 | ||
843 | if (dapm_status) { | 827 | if (!dapm_status) |
844 | ret = device_create_file(dev, &dev_attr_dapm_widget); | 828 | return 0; |
845 | 829 | ||
846 | if (ret == 0) | 830 | ret = device_create_file(dev, &dev_attr_dapm_widget); |
847 | ret = device_create_file(dev, &dev_attr_dapm_pop_time); | 831 | if (ret != 0) |
848 | } | 832 | return ret; |
849 | 833 | ||
850 | return ret; | 834 | asoc_debugfs = debugfs_create_dir("asoc", NULL); |
835 | if (!IS_ERR(asoc_debugfs)) | ||
836 | debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs, | ||
837 | &pop_time); | ||
838 | else | ||
839 | asoc_debugfs = NULL; | ||
840 | |||
841 | return 0; | ||
851 | } | 842 | } |
852 | 843 | ||
853 | static void snd_soc_dapm_sys_remove(struct device *dev) | 844 | static void snd_soc_dapm_sys_remove(struct device *dev) |
854 | { | 845 | { |
855 | if (dapm_status) { | 846 | if (dapm_status) { |
856 | device_remove_file(dev, &dev_attr_dapm_pop_time); | ||
857 | device_remove_file(dev, &dev_attr_dapm_widget); | 847 | device_remove_file(dev, &dev_attr_dapm_widget); |
858 | } | 848 | } |
849 | |||
850 | if (asoc_debugfs) | ||
851 | debugfs_remove_recursive(asoc_debugfs); | ||
859 | } | 852 | } |
860 | 853 | ||
861 | /* free all dapm widgets and resources */ | 854 | /* free all dapm widgets and resources */ |
@@ -1133,12 +1126,14 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
1133 | struct snd_ctl_elem_value *ucontrol) | 1126 | struct snd_ctl_elem_value *ucontrol) |
1134 | { | 1127 | { |
1135 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1128 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1136 | int reg = kcontrol->private_value & 0xff; | 1129 | struct soc_mixer_control *mc = |
1137 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1130 | (struct soc_mixer_control *)kcontrol->private_value; |
1138 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1131 | unsigned int reg = mc->reg; |
1139 | int max = (kcontrol->private_value >> 16) & 0xff; | 1132 | unsigned int shift = mc->shift; |
1140 | int invert = (kcontrol->private_value >> 24) & 0x01; | 1133 | unsigned int rshift = mc->rshift; |
1141 | int mask = (1 << fls(max)) - 1; | 1134 | int max = mc->max; |
1135 | unsigned int invert = mc->invert; | ||
1136 | unsigned int mask = (1 << fls(max)) - 1; | ||
1142 | 1137 | ||
1143 | /* return the saved value if we are powered down */ | 1138 | /* return the saved value if we are powered down */ |
1144 | if (widget->id == snd_soc_dapm_pga && !widget->power) { | 1139 | if (widget->id == snd_soc_dapm_pga && !widget->power) { |
@@ -1176,12 +1171,14 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1176 | struct snd_ctl_elem_value *ucontrol) | 1171 | struct snd_ctl_elem_value *ucontrol) |
1177 | { | 1172 | { |
1178 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1173 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1179 | int reg = kcontrol->private_value & 0xff; | 1174 | struct soc_mixer_control *mc = |
1180 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1175 | (struct soc_mixer_control *)kcontrol->private_value; |
1181 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1176 | unsigned int reg = mc->reg; |
1182 | int max = (kcontrol->private_value >> 16) & 0xff; | 1177 | unsigned int shift = mc->shift; |
1183 | int mask = (1 << fls(max)) - 1; | 1178 | unsigned int rshift = mc->rshift; |
1184 | int invert = (kcontrol->private_value >> 24) & 0x01; | 1179 | int max = mc->max; |
1180 | unsigned int mask = (1 << fls(max)) - 1; | ||
1181 | unsigned int invert = mc->invert; | ||
1185 | unsigned short val, val2, val_mask; | 1182 | unsigned short val, val2, val_mask; |
1186 | int ret; | 1183 | int ret; |
1187 | 1184 | ||
@@ -1248,7 +1245,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
1248 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1245 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1249 | unsigned short val, bitmask; | 1246 | unsigned short val, bitmask; |
1250 | 1247 | ||
1251 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | 1248 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1252 | ; | 1249 | ; |
1253 | val = snd_soc_read(widget->codec, e->reg); | 1250 | val = snd_soc_read(widget->codec, e->reg); |
1254 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); | 1251 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); |
@@ -1278,15 +1275,15 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1278 | unsigned short mask, bitmask; | 1275 | unsigned short mask, bitmask; |
1279 | int ret = 0; | 1276 | int ret = 0; |
1280 | 1277 | ||
1281 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | 1278 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1282 | ; | 1279 | ; |
1283 | if (ucontrol->value.enumerated.item[0] > e->mask - 1) | 1280 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
1284 | return -EINVAL; | 1281 | return -EINVAL; |
1285 | mux = ucontrol->value.enumerated.item[0]; | 1282 | mux = ucontrol->value.enumerated.item[0]; |
1286 | val = mux << e->shift_l; | 1283 | val = mux << e->shift_l; |
1287 | mask = (bitmask - 1) << e->shift_l; | 1284 | mask = (bitmask - 1) << e->shift_l; |
1288 | if (e->shift_l != e->shift_r) { | 1285 | if (e->shift_l != e->shift_r) { |
1289 | if (ucontrol->value.enumerated.item[1] > e->mask - 1) | 1286 | if (ucontrol->value.enumerated.item[1] > e->max - 1) |
1290 | return -EINVAL; | 1287 | return -EINVAL; |
1291 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | 1288 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; |
1292 | mask |= (bitmask - 1) << e->shift_r; | 1289 | mask |= (bitmask - 1) << e->shift_r; |
@@ -1294,7 +1291,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1294 | 1291 | ||
1295 | mutex_lock(&widget->codec->mutex); | 1292 | mutex_lock(&widget->codec->mutex); |
1296 | widget->value = val; | 1293 | widget->value = val; |
1297 | dapm_mux_update_power(widget, kcontrol, mask, mux, e); | 1294 | dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); |
1298 | if (widget->event) { | 1295 | if (widget->event) { |
1299 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1296 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1300 | ret = widget->event(widget, | 1297 | ret = widget->event(widget, |