diff options
Diffstat (limited to 'sound')
152 files changed, 9268 insertions, 2013 deletions
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index ce431e6e07cf..5066a3768b28 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c | |||
@@ -14,12 +14,14 @@ | |||
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/dmaengine.h> | ||
17 | 18 | ||
18 | #include <sound/core.h> | 19 | #include <sound/core.h> |
19 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
20 | #include <sound/ac97_codec.h> | 21 | #include <sound/ac97_codec.h> |
21 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
22 | #include <sound/pxa2xx-lib.h> | 23 | #include <sound/pxa2xx-lib.h> |
24 | #include <sound/dmaengine_pcm.h> | ||
23 | 25 | ||
24 | #include <mach/regs-ac97.h> | 26 | #include <mach/regs-ac97.h> |
25 | #include <mach/audio.h> | 27 | #include <mach/audio.h> |
@@ -41,20 +43,20 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = { | |||
41 | .reset = pxa2xx_ac97_reset, | 43 | .reset = pxa2xx_ac97_reset, |
42 | }; | 44 | }; |
43 | 45 | ||
44 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_out = { | 46 | static unsigned long pxa2xx_ac97_pcm_out_req = 12; |
45 | .name = "AC97 PCM out", | 47 | static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = { |
46 | .dev_addr = __PREG(PCDR), | 48 | .addr = __PREG(PCDR), |
47 | .drcmr = &DRCMR(12), | 49 | .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, |
48 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | 50 | .maxburst = 32, |
49 | DCMD_BURST32 | DCMD_WIDTH4, | 51 | .filter_data = &pxa2xx_ac97_pcm_out_req, |
50 | }; | 52 | }; |
51 | 53 | ||
52 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_in = { | 54 | static unsigned long pxa2xx_ac97_pcm_in_req = 11; |
53 | .name = "AC97 PCM in", | 55 | static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = { |
54 | .dev_addr = __PREG(PCDR), | 56 | .addr = __PREG(PCDR), |
55 | .drcmr = &DRCMR(11), | 57 | .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, |
56 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | 58 | .maxburst = 32, |
57 | DCMD_BURST32 | DCMD_WIDTH4, | 59 | .filter_data = &pxa2xx_ac97_pcm_in_req, |
58 | }; | 60 | }; |
59 | 61 | ||
60 | static struct snd_pcm *pxa2xx_ac97_pcm; | 62 | static struct snd_pcm *pxa2xx_ac97_pcm; |
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index 823359ed95e1..a61d7a9a995e 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c | |||
@@ -7,11 +7,13 @@ | |||
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/dma-mapping.h> | 9 | #include <linux/dma-mapping.h> |
10 | #include <linux/dmaengine.h> | ||
10 | 11 | ||
11 | #include <sound/core.h> | 12 | #include <sound/core.h> |
12 | #include <sound/pcm.h> | 13 | #include <sound/pcm.h> |
13 | #include <sound/pcm_params.h> | 14 | #include <sound/pcm_params.h> |
14 | #include <sound/pxa2xx-lib.h> | 15 | #include <sound/pxa2xx-lib.h> |
16 | #include <sound/dmaengine_pcm.h> | ||
15 | 17 | ||
16 | #include <mach/dma.h> | 18 | #include <mach/dma.h> |
17 | 19 | ||
@@ -43,6 +45,35 @@ int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
43 | size_t period = params_period_bytes(params); | 45 | size_t period = params_period_bytes(params); |
44 | pxa_dma_desc *dma_desc; | 46 | pxa_dma_desc *dma_desc; |
45 | dma_addr_t dma_buff_phys, next_desc_phys; | 47 | dma_addr_t dma_buff_phys, next_desc_phys; |
48 | u32 dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG; | ||
49 | |||
50 | /* temporary transition hack */ | ||
51 | switch (rtd->params->addr_width) { | ||
52 | case DMA_SLAVE_BUSWIDTH_1_BYTE: | ||
53 | dcmd |= DCMD_WIDTH1; | ||
54 | break; | ||
55 | case DMA_SLAVE_BUSWIDTH_2_BYTES: | ||
56 | dcmd |= DCMD_WIDTH2; | ||
57 | break; | ||
58 | case DMA_SLAVE_BUSWIDTH_4_BYTES: | ||
59 | dcmd |= DCMD_WIDTH4; | ||
60 | break; | ||
61 | default: | ||
62 | /* can't happen */ | ||
63 | break; | ||
64 | } | ||
65 | |||
66 | switch (rtd->params->maxburst) { | ||
67 | case 8: | ||
68 | dcmd |= DCMD_BURST8; | ||
69 | break; | ||
70 | case 16: | ||
71 | dcmd |= DCMD_BURST16; | ||
72 | break; | ||
73 | case 32: | ||
74 | dcmd |= DCMD_BURST32; | ||
75 | break; | ||
76 | } | ||
46 | 77 | ||
47 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | 78 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); |
48 | runtime->dma_bytes = totsize; | 79 | runtime->dma_bytes = totsize; |
@@ -55,14 +86,14 @@ int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
55 | dma_desc->ddadr = next_desc_phys; | 86 | dma_desc->ddadr = next_desc_phys; |
56 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 87 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
57 | dma_desc->dsadr = dma_buff_phys; | 88 | dma_desc->dsadr = dma_buff_phys; |
58 | dma_desc->dtadr = rtd->params->dev_addr; | 89 | dma_desc->dtadr = rtd->params->addr; |
59 | } else { | 90 | } else { |
60 | dma_desc->dsadr = rtd->params->dev_addr; | 91 | dma_desc->dsadr = rtd->params->addr; |
61 | dma_desc->dtadr = dma_buff_phys; | 92 | dma_desc->dtadr = dma_buff_phys; |
62 | } | 93 | } |
63 | if (period > totsize) | 94 | if (period > totsize) |
64 | period = totsize; | 95 | period = totsize; |
65 | dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN; | 96 | dma_desc->dcmd = dcmd | period | DCMD_ENDIRQEN; |
66 | dma_desc++; | 97 | dma_desc++; |
67 | dma_buff_phys += period; | 98 | dma_buff_phys += period; |
68 | } while (totsize -= period); | 99 | } while (totsize -= period); |
@@ -76,8 +107,10 @@ int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) | |||
76 | { | 107 | { |
77 | struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; | 108 | struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; |
78 | 109 | ||
79 | if (rtd && rtd->params && rtd->params->drcmr) | 110 | if (rtd && rtd->params && rtd->params->filter_data) { |
80 | *rtd->params->drcmr = 0; | 111 | unsigned long req = *(unsigned long *) rtd->params->filter_data; |
112 | DRCMR(req) = 0; | ||
113 | } | ||
81 | 114 | ||
82 | snd_pcm_set_runtime_buffer(substream, NULL); | 115 | snd_pcm_set_runtime_buffer(substream, NULL); |
83 | return 0; | 116 | return 0; |
@@ -136,6 +169,7 @@ EXPORT_SYMBOL(pxa2xx_pcm_pointer); | |||
136 | int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) | 169 | int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) |
137 | { | 170 | { |
138 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | 171 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; |
172 | unsigned long req; | ||
139 | 173 | ||
140 | if (!prtd || !prtd->params) | 174 | if (!prtd || !prtd->params) |
141 | return 0; | 175 | return 0; |
@@ -146,7 +180,8 @@ int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) | |||
146 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | 180 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; |
147 | DCSR(prtd->dma_ch) = 0; | 181 | DCSR(prtd->dma_ch) = 0; |
148 | DCMD(prtd->dma_ch) = 0; | 182 | DCMD(prtd->dma_ch) = 0; |
149 | *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; | 183 | req = *(unsigned long *) prtd->params->filter_data; |
184 | DRCMR(req) = prtd->dma_ch | DRCMR_MAPVLD; | ||
150 | 185 | ||
151 | return 0; | 186 | return 0; |
152 | } | 187 | } |
@@ -155,7 +190,6 @@ EXPORT_SYMBOL(__pxa2xx_pcm_prepare); | |||
155 | void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) | 190 | void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) |
156 | { | 191 | { |
157 | struct snd_pcm_substream *substream = dev_id; | 192 | struct snd_pcm_substream *substream = dev_id; |
158 | struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; | ||
159 | int dcsr; | 193 | int dcsr; |
160 | 194 | ||
161 | dcsr = DCSR(dma_ch); | 195 | dcsr = DCSR(dma_ch); |
@@ -164,8 +198,8 @@ void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) | |||
164 | if (dcsr & DCSR_ENDINTR) { | 198 | if (dcsr & DCSR_ENDINTR) { |
165 | snd_pcm_period_elapsed(substream); | 199 | snd_pcm_period_elapsed(substream); |
166 | } else { | 200 | } else { |
167 | printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", | 201 | printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n", |
168 | rtd->params->name, dma_ch, dcsr); | 202 | dma_ch, dcsr); |
169 | snd_pcm_stream_lock(substream); | 203 | snd_pcm_stream_lock(substream); |
170 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | 204 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); |
171 | snd_pcm_stream_unlock(substream); | 205 | snd_pcm_stream_unlock(substream); |
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c index 26422a3584ea..69a2455b4472 100644 --- a/sound/arm/pxa2xx-pcm.c +++ b/sound/arm/pxa2xx-pcm.c | |||
@@ -11,8 +11,11 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/dmaengine.h> | ||
15 | |||
14 | #include <sound/core.h> | 16 | #include <sound/core.h> |
15 | #include <sound/pxa2xx-lib.h> | 17 | #include <sound/pxa2xx-lib.h> |
18 | #include <sound/dmaengine_pcm.h> | ||
16 | 19 | ||
17 | #include "pxa2xx-pcm.h" | 20 | #include "pxa2xx-pcm.h" |
18 | 21 | ||
@@ -40,7 +43,7 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) | |||
40 | 43 | ||
41 | rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | 44 | rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
42 | client->playback_params : client->capture_params; | 45 | client->playback_params : client->capture_params; |
43 | ret = pxa_request_dma(rtd->params->name, DMA_PRIO_LOW, | 46 | ret = pxa_request_dma("dma", DMA_PRIO_LOW, |
44 | pxa2xx_pcm_dma_irq, substream); | 47 | pxa2xx_pcm_dma_irq, substream); |
45 | if (ret < 0) | 48 | if (ret < 0) |
46 | goto err2; | 49 | goto err2; |
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h index 65f86b56ba42..2a8fc08d52a1 100644 --- a/sound/arm/pxa2xx-pcm.h +++ b/sound/arm/pxa2xx-pcm.h | |||
@@ -13,14 +13,14 @@ | |||
13 | 13 | ||
14 | struct pxa2xx_runtime_data { | 14 | struct pxa2xx_runtime_data { |
15 | int dma_ch; | 15 | int dma_ch; |
16 | struct pxa2xx_pcm_dma_params *params; | 16 | struct snd_dmaengine_dai_dma_data *params; |
17 | pxa_dma_desc *dma_desc_array; | 17 | pxa_dma_desc *dma_desc_array; |
18 | dma_addr_t dma_desc_array_phys; | 18 | dma_addr_t dma_desc_array_phys; |
19 | }; | 19 | }; |
20 | 20 | ||
21 | struct pxa2xx_pcm_client { | 21 | struct pxa2xx_pcm_client { |
22 | struct pxa2xx_pcm_dma_params *playback_params; | 22 | struct snd_dmaengine_dai_dma_data *playback_params; |
23 | struct pxa2xx_pcm_dma_params *capture_params; | 23 | struct snd_dmaengine_dai_dma_data *capture_params; |
24 | int (*startup)(struct snd_pcm_substream *); | 24 | int (*startup)(struct snd_pcm_substream *); |
25 | void (*shutdown)(struct snd_pcm_substream *); | 25 | void (*shutdown)(struct snd_pcm_substream *); |
26 | int (*prepare)(struct snd_pcm_substream *); | 26 | int (*prepare)(struct snd_pcm_substream *); |
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index c0c2f57a0d6f..313f22e9d929 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig | |||
@@ -6,6 +6,9 @@ config SND_PCM | |||
6 | tristate | 6 | tristate |
7 | select SND_TIMER | 7 | select SND_TIMER |
8 | 8 | ||
9 | config SND_DMAENGINE_PCM | ||
10 | tristate | ||
11 | |||
9 | config SND_HWDEP | 12 | config SND_HWDEP |
10 | tristate | 13 | tristate |
11 | 14 | ||
diff --git a/sound/core/Makefile b/sound/core/Makefile index 43d4117428ac..5e890cfed423 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile | |||
@@ -13,6 +13,8 @@ snd-$(CONFIG_SND_JACK) += jack.o | |||
13 | snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ | 13 | snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ |
14 | pcm_memory.o | 14 | pcm_memory.o |
15 | 15 | ||
16 | snd-pcm-dmaengine-objs := pcm_dmaengine.o | ||
17 | |||
16 | snd-page-alloc-y := memalloc.o | 18 | snd-page-alloc-y := memalloc.o |
17 | snd-page-alloc-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o | 19 | snd-page-alloc-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o |
18 | 20 | ||
@@ -30,6 +32,7 @@ obj-$(CONFIG_SND_TIMER) += snd-timer.o | |||
30 | obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o | 32 | obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o |
31 | obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o | 33 | obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o |
32 | obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o | 34 | obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o |
35 | obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o | ||
33 | obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o | 36 | obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o |
34 | 37 | ||
35 | obj-$(CONFIG_SND_OSSEMUL) += oss/ | 38 | obj-$(CONFIG_SND_OSSEMUL) += oss/ |
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/core/pcm_dmaengine.c index aa924d9b7986..aa924d9b7986 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/core/pcm_dmaengine.c | |||
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 45eeaa9f7fec..5138b8493051 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -26,12 +26,9 @@ if SND_SOC | |||
26 | config SND_SOC_AC97_BUS | 26 | config SND_SOC_AC97_BUS |
27 | bool | 27 | bool |
28 | 28 | ||
29 | config SND_SOC_DMAENGINE_PCM | ||
30 | bool | ||
31 | |||
32 | config SND_SOC_GENERIC_DMAENGINE_PCM | 29 | config SND_SOC_GENERIC_DMAENGINE_PCM |
33 | bool | 30 | bool |
34 | select SND_SOC_DMAENGINE_PCM | 31 | select SND_DMAENGINE_PCM |
35 | 32 | ||
36 | # All the supported SoCs | 33 | # All the supported SoCs |
37 | source "sound/soc/atmel/Kconfig" | 34 | source "sound/soc/atmel/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index bc0261476d7a..61a64d281905 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,10 +1,6 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o |
2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o | 2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o |
3 | 3 | ||
4 | ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),) | ||
5 | snd-soc-core-objs += soc-dmaengine-pcm.o | ||
6 | endif | ||
7 | |||
8 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) | 4 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) |
9 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o | 5 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o |
10 | endif | 6 | endif |
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 3fdd87fa18a9..e48d38a1b95c 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig | |||
@@ -13,6 +13,7 @@ config SND_ATMEL_SOC_PDC | |||
13 | config SND_ATMEL_SOC_DMA | 13 | config SND_ATMEL_SOC_DMA |
14 | tristate | 14 | tristate |
15 | depends on SND_ATMEL_SOC | 15 | depends on SND_ATMEL_SOC |
16 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
16 | 17 | ||
17 | config SND_ATMEL_SOC_SSC | 18 | config SND_ATMEL_SOC_SSC |
18 | tristate | 19 | tristate |
@@ -32,6 +33,26 @@ config SND_AT91_SOC_SAM9G20_WM8731 | |||
32 | Say Y if you want to add support for SoC audio on WM8731-based | 33 | Say Y if you want to add support for SoC audio on WM8731-based |
33 | AT91sam9g20 evaluation board. | 34 | AT91sam9g20 evaluation board. |
34 | 35 | ||
36 | config SND_ATMEL_SOC_WM8904 | ||
37 | tristate "Atmel ASoC driver for boards using WM8904 codec" | ||
38 | depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC | ||
39 | select SND_ATMEL_SOC_SSC | ||
40 | select SND_ATMEL_SOC_DMA | ||
41 | select SND_SOC_WM8904 | ||
42 | help | ||
43 | Say Y if you want to add support for Atmel ASoC driver for boards using | ||
44 | WM8904 codec. | ||
45 | |||
46 | config SND_AT91_SOC_SAM9X5_WM8731 | ||
47 | tristate "SoC Audio support for WM8731-based at91sam9x5 board" | ||
48 | depends on ATMEL_SSC && SND_ATMEL_SOC && SOC_AT91SAM9X5 | ||
49 | select SND_ATMEL_SOC_SSC | ||
50 | select SND_ATMEL_SOC_DMA | ||
51 | select SND_SOC_WM8731 | ||
52 | help | ||
53 | Say Y if you want to add support for audio SoC on an | ||
54 | at91sam9x5 based board that is using WM8731 codec. | ||
55 | |||
35 | config SND_AT91_SOC_AFEB9260 | 56 | config SND_AT91_SOC_AFEB9260 |
36 | tristate "SoC Audio support for AFEB9260 board" | 57 | tristate "SoC Audio support for AFEB9260 board" |
37 | depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC | 58 | depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC |
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index 41967ccb6f41..5baabc8bde3a 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile | |||
@@ -11,6 +11,10 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o | |||
11 | 11 | ||
12 | # AT91 Machine Support | 12 | # AT91 Machine Support |
13 | snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o | 13 | snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o |
14 | snd-atmel-soc-wm8904-objs := atmel_wm8904.o | ||
15 | snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o | ||
14 | 16 | ||
15 | obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o | 17 | obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o |
18 | obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o | ||
19 | obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o | ||
16 | obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o | 20 | obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o |
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index d12826526798..06082e5e5dcb 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c | |||
@@ -91,138 +91,52 @@ static void atmel_pcm_dma_irq(u32 ssc_sr, | |||
91 | } | 91 | } |
92 | } | 92 | } |
93 | 93 | ||
94 | /*--------------------------------------------------------------------------*\ | ||
95 | * DMAENGINE operations | ||
96 | \*--------------------------------------------------------------------------*/ | ||
97 | static bool filter(struct dma_chan *chan, void *slave) | ||
98 | { | ||
99 | struct at_dma_slave *sl = slave; | ||
100 | |||
101 | if (sl->dma_dev == chan->device->dev) { | ||
102 | chan->private = sl; | ||
103 | return true; | ||
104 | } else { | ||
105 | return false; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, | 94 | static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, |
110 | struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd) | 95 | struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config) |
111 | { | 96 | { |
97 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
98 | struct atmel_pcm_dma_params *prtd; | ||
112 | struct ssc_device *ssc; | 99 | struct ssc_device *ssc; |
113 | struct dma_chan *dma_chan; | ||
114 | struct dma_slave_config slave_config; | ||
115 | int ret; | 100 | int ret; |
116 | 101 | ||
102 | prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
117 | ssc = prtd->ssc; | 103 | ssc = prtd->ssc; |
118 | 104 | ||
119 | ret = snd_hwparams_to_dma_slave_config(substream, params, | 105 | ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config); |
120 | &slave_config); | ||
121 | if (ret) { | 106 | if (ret) { |
122 | pr_err("atmel-pcm: hwparams to dma slave configure failed\n"); | 107 | pr_err("atmel-pcm: hwparams to dma slave configure failed\n"); |
123 | return ret; | 108 | return ret; |
124 | } | 109 | } |
125 | 110 | ||
126 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 111 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
127 | slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR; | 112 | slave_config->dst_addr = ssc->phybase + SSC_THR; |
128 | slave_config.dst_maxburst = 1; | 113 | slave_config->dst_maxburst = 1; |
129 | } else { | 114 | } else { |
130 | slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR; | 115 | slave_config->src_addr = ssc->phybase + SSC_RHR; |
131 | slave_config.src_maxburst = 1; | 116 | slave_config->src_maxburst = 1; |
132 | } | ||
133 | |||
134 | dma_chan = snd_dmaengine_pcm_get_chan(substream); | ||
135 | if (dmaengine_slave_config(dma_chan, &slave_config)) { | ||
136 | pr_err("atmel-pcm: failed to configure dma channel\n"); | ||
137 | ret = -EBUSY; | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, | ||
145 | struct snd_pcm_hw_params *params) | ||
146 | { | ||
147 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
148 | struct atmel_pcm_dma_params *prtd; | ||
149 | struct ssc_device *ssc; | ||
150 | struct at_dma_slave *sdata = NULL; | ||
151 | int ret; | ||
152 | |||
153 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
154 | |||
155 | prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
156 | ssc = prtd->ssc; | ||
157 | if (ssc->pdev) | ||
158 | sdata = ssc->pdev->dev.platform_data; | ||
159 | |||
160 | ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata); | ||
161 | if (ret) { | ||
162 | pr_err("atmel-pcm: dmaengine pcm open failed\n"); | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | |||
166 | ret = atmel_pcm_configure_dma(substream, params, prtd); | ||
167 | if (ret) { | ||
168 | pr_err("atmel-pcm: failed to configure dmai\n"); | ||
169 | goto err; | ||
170 | } | 117 | } |
171 | 118 | ||
172 | prtd->dma_intr_handler = atmel_pcm_dma_irq; | 119 | prtd->dma_intr_handler = atmel_pcm_dma_irq; |
173 | 120 | ||
174 | return 0; | 121 | return 0; |
175 | err: | ||
176 | snd_dmaengine_pcm_close_release_chan(substream); | ||
177 | return ret; | ||
178 | } | 122 | } |
179 | 123 | ||
180 | static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) | 124 | static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = { |
181 | { | 125 | .prepare_slave_config = atmel_pcm_configure_dma, |
182 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 126 | .pcm_hardware = &atmel_pcm_dma_hardware, |
183 | struct atmel_pcm_dma_params *prtd; | 127 | .prealloc_buffer_size = ATMEL_SSC_DMABUF_SIZE, |
184 | |||
185 | prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
186 | |||
187 | ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error); | ||
188 | ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int atmel_pcm_open(struct snd_pcm_substream *substream) | ||
194 | { | ||
195 | snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static struct snd_pcm_ops atmel_pcm_ops = { | ||
201 | .open = atmel_pcm_open, | ||
202 | .close = snd_dmaengine_pcm_close_release_chan, | ||
203 | .ioctl = snd_pcm_lib_ioctl, | ||
204 | .hw_params = atmel_pcm_hw_params, | ||
205 | .prepare = atmel_pcm_dma_prepare, | ||
206 | .trigger = snd_dmaengine_pcm_trigger, | ||
207 | .pointer = snd_dmaengine_pcm_pointer_no_residue, | ||
208 | .mmap = atmel_pcm_mmap, | ||
209 | }; | ||
210 | |||
211 | static struct snd_soc_platform_driver atmel_soc_platform = { | ||
212 | .ops = &atmel_pcm_ops, | ||
213 | .pcm_new = atmel_pcm_new, | ||
214 | .pcm_free = atmel_pcm_free, | ||
215 | }; | 128 | }; |
216 | 129 | ||
217 | int atmel_pcm_dma_platform_register(struct device *dev) | 130 | int atmel_pcm_dma_platform_register(struct device *dev) |
218 | { | 131 | { |
219 | return snd_soc_register_platform(dev, &atmel_soc_platform); | 132 | return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config, |
133 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); | ||
220 | } | 134 | } |
221 | EXPORT_SYMBOL(atmel_pcm_dma_platform_register); | 135 | EXPORT_SYMBOL(atmel_pcm_dma_platform_register); |
222 | 136 | ||
223 | void atmel_pcm_dma_platform_unregister(struct device *dev) | 137 | void atmel_pcm_dma_platform_unregister(struct device *dev) |
224 | { | 138 | { |
225 | snd_soc_unregister_platform(dev); | 139 | snd_dmaengine_pcm_unregister(dev); |
226 | } | 140 | } |
227 | EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister); | 141 | EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister); |
228 | 142 | ||
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index f3fdfa07fcb9..bb53dea85b17 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -73,6 +73,7 @@ static struct atmel_ssc_mask ssc_tx_mask = { | |||
73 | .ssc_disable = SSC_BIT(CR_TXDIS), | 73 | .ssc_disable = SSC_BIT(CR_TXDIS), |
74 | .ssc_endx = SSC_BIT(SR_ENDTX), | 74 | .ssc_endx = SSC_BIT(SR_ENDTX), |
75 | .ssc_endbuf = SSC_BIT(SR_TXBUFE), | 75 | .ssc_endbuf = SSC_BIT(SR_TXBUFE), |
76 | .ssc_error = SSC_BIT(SR_OVRUN), | ||
76 | .pdc_enable = ATMEL_PDC_TXTEN, | 77 | .pdc_enable = ATMEL_PDC_TXTEN, |
77 | .pdc_disable = ATMEL_PDC_TXTDIS, | 78 | .pdc_disable = ATMEL_PDC_TXTDIS, |
78 | }; | 79 | }; |
@@ -82,6 +83,7 @@ static struct atmel_ssc_mask ssc_rx_mask = { | |||
82 | .ssc_disable = SSC_BIT(CR_RXDIS), | 83 | .ssc_disable = SSC_BIT(CR_RXDIS), |
83 | .ssc_endx = SSC_BIT(SR_ENDRX), | 84 | .ssc_endx = SSC_BIT(SR_ENDRX), |
84 | .ssc_endbuf = SSC_BIT(SR_RXBUFF), | 85 | .ssc_endbuf = SSC_BIT(SR_RXBUFF), |
86 | .ssc_error = SSC_BIT(SR_OVRUN), | ||
85 | .pdc_enable = ATMEL_PDC_RXTEN, | 87 | .pdc_enable = ATMEL_PDC_RXTEN, |
86 | .pdc_disable = ATMEL_PDC_RXTDIS, | 88 | .pdc_disable = ATMEL_PDC_RXTDIS, |
87 | }; | 89 | }; |
@@ -196,15 +198,27 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, | |||
196 | struct snd_soc_dai *dai) | 198 | struct snd_soc_dai *dai) |
197 | { | 199 | { |
198 | struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; | 200 | struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; |
199 | int dir_mask; | 201 | struct atmel_pcm_dma_params *dma_params; |
202 | int dir, dir_mask; | ||
200 | 203 | ||
201 | pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", | 204 | pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", |
202 | ssc_readl(ssc_p->ssc->regs, SR)); | 205 | ssc_readl(ssc_p->ssc->regs, SR)); |
203 | 206 | ||
204 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 207 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
208 | dir = 0; | ||
205 | dir_mask = SSC_DIR_MASK_PLAYBACK; | 209 | dir_mask = SSC_DIR_MASK_PLAYBACK; |
206 | else | 210 | } else { |
211 | dir = 1; | ||
207 | dir_mask = SSC_DIR_MASK_CAPTURE; | 212 | dir_mask = SSC_DIR_MASK_CAPTURE; |
213 | } | ||
214 | |||
215 | dma_params = &ssc_dma_params[dai->id][dir]; | ||
216 | dma_params->ssc = ssc_p->ssc; | ||
217 | dma_params->substream = substream; | ||
218 | |||
219 | ssc_p->dma_params[dir] = dma_params; | ||
220 | |||
221 | snd_soc_dai_set_dma_data(dai, substream, dma_params); | ||
208 | 222 | ||
209 | spin_lock_irq(&ssc_p->lock); | 223 | spin_lock_irq(&ssc_p->lock); |
210 | if (ssc_p->dir_mask & dir_mask) { | 224 | if (ssc_p->dir_mask & dir_mask) { |
@@ -325,7 +339,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
325 | struct snd_pcm_hw_params *params, | 339 | struct snd_pcm_hw_params *params, |
326 | struct snd_soc_dai *dai) | 340 | struct snd_soc_dai *dai) |
327 | { | 341 | { |
328 | struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); | ||
329 | int id = dai->id; | 342 | int id = dai->id; |
330 | struct atmel_ssc_info *ssc_p = &ssc_info[id]; | 343 | struct atmel_ssc_info *ssc_p = &ssc_info[id]; |
331 | struct atmel_pcm_dma_params *dma_params; | 344 | struct atmel_pcm_dma_params *dma_params; |
@@ -344,19 +357,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
344 | else | 357 | else |
345 | dir = 1; | 358 | dir = 1; |
346 | 359 | ||
347 | dma_params = &ssc_dma_params[id][dir]; | 360 | dma_params = ssc_p->dma_params[dir]; |
348 | dma_params->ssc = ssc_p->ssc; | ||
349 | dma_params->substream = substream; | ||
350 | |||
351 | ssc_p->dma_params[dir] = dma_params; | ||
352 | |||
353 | /* | ||
354 | * The snd_soc_pcm_stream->dma_data field is only used to communicate | ||
355 | * the appropriate DMA parameters to the pcm driver hw_params() | ||
356 | * function. It should not be used for other purposes | ||
357 | * as it is common to all substreams. | ||
358 | */ | ||
359 | snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params); | ||
360 | 361 | ||
361 | channels = params_channels(params); | 362 | channels = params_channels(params); |
362 | 363 | ||
@@ -648,6 +649,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream, | |||
648 | dma_params = ssc_p->dma_params[dir]; | 649 | dma_params = ssc_p->dma_params[dir]; |
649 | 650 | ||
650 | ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); | 651 | ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); |
652 | ssc_writel(ssc_p->ssc->regs, IDR, dma_params->mask->ssc_error); | ||
651 | 653 | ||
652 | pr_debug("%s enabled SSC_SR=0x%08x\n", | 654 | pr_debug("%s enabled SSC_SR=0x%08x\n", |
653 | dir ? "receive" : "transmit", | 655 | dir ? "receive" : "transmit", |
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c new file mode 100644 index 000000000000..7222380131ea --- /dev/null +++ b/sound/soc/atmel/atmel_wm8904.c | |||
@@ -0,0 +1,254 @@ | |||
1 | /* | ||
2 | * atmel_wm8904 - Atmel ASoC driver for boards with WM8904 codec. | ||
3 | * | ||
4 | * Copyright (C) 2012 Atmel | ||
5 | * | ||
6 | * Author: Bo Shen <voice.shen@atmel.com> | ||
7 | * | ||
8 | * GPLv2 or later | ||
9 | */ | ||
10 | |||
11 | #include <linux/clk.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/of.h> | ||
14 | #include <linux/of_device.h> | ||
15 | #include <linux/pinctrl/consumer.h> | ||
16 | |||
17 | #include <sound/soc.h> | ||
18 | |||
19 | #include "../codecs/wm8904.h" | ||
20 | #include "atmel_ssc_dai.h" | ||
21 | |||
22 | #define MCLK_RATE 32768 | ||
23 | |||
24 | static struct clk *mclk; | ||
25 | |||
26 | static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = { | ||
27 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
28 | SND_SOC_DAPM_MIC("Mic", NULL), | ||
29 | SND_SOC_DAPM_LINE("Line In Jack", NULL), | ||
30 | }; | ||
31 | |||
32 | static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream, | ||
33 | struct snd_pcm_hw_params *params) | ||
34 | { | ||
35 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
36 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
37 | int ret; | ||
38 | |||
39 | ret = snd_soc_dai_set_pll(codec_dai, WM8904_FLL_MCLK, WM8904_FLL_MCLK, | ||
40 | 32768, params_rate(params) * 256); | ||
41 | if (ret < 0) { | ||
42 | pr_err("%s - failed to set wm8904 codec PLL.", __func__); | ||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * As here wm8904 use FLL output as its system clock | ||
48 | * so calling set_sysclk won't care freq parameter | ||
49 | * then we pass 0 | ||
50 | */ | ||
51 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8904_CLK_FLL, | ||
52 | 0, SND_SOC_CLOCK_IN); | ||
53 | if (ret < 0) { | ||
54 | pr_err("%s -failed to set wm8904 SYSCLK\n", __func__); | ||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static struct snd_soc_ops atmel_asoc_wm8904_ops = { | ||
62 | .hw_params = atmel_asoc_wm8904_hw_params, | ||
63 | }; | ||
64 | |||
65 | static int atmel_set_bias_level(struct snd_soc_card *card, | ||
66 | struct snd_soc_dapm_context *dapm, | ||
67 | enum snd_soc_bias_level level) | ||
68 | { | ||
69 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { | ||
70 | switch (level) { | ||
71 | case SND_SOC_BIAS_PREPARE: | ||
72 | clk_prepare_enable(mclk); | ||
73 | break; | ||
74 | case SND_SOC_BIAS_OFF: | ||
75 | clk_disable_unprepare(mclk); | ||
76 | break; | ||
77 | default: | ||
78 | break; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | }; | ||
84 | |||
85 | static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = { | ||
86 | .name = "WM8904", | ||
87 | .stream_name = "WM8904 PCM", | ||
88 | .codec_dai_name = "wm8904-hifi", | ||
89 | .dai_fmt = SND_SOC_DAIFMT_I2S | ||
90 | | SND_SOC_DAIFMT_NB_NF | ||
91 | | SND_SOC_DAIFMT_CBM_CFM, | ||
92 | .ops = &atmel_asoc_wm8904_ops, | ||
93 | }; | ||
94 | |||
95 | static struct snd_soc_card atmel_asoc_wm8904_card = { | ||
96 | .name = "atmel_asoc_wm8904", | ||
97 | .owner = THIS_MODULE, | ||
98 | .set_bias_level = atmel_set_bias_level, | ||
99 | .dai_link = &atmel_asoc_wm8904_dailink, | ||
100 | .num_links = 1, | ||
101 | .dapm_widgets = atmel_asoc_wm8904_dapm_widgets, | ||
102 | .num_dapm_widgets = ARRAY_SIZE(atmel_asoc_wm8904_dapm_widgets), | ||
103 | .fully_routed = true, | ||
104 | }; | ||
105 | |||
106 | static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev) | ||
107 | { | ||
108 | struct device_node *np = pdev->dev.of_node; | ||
109 | struct device_node *codec_np, *cpu_np; | ||
110 | struct snd_soc_card *card = &atmel_asoc_wm8904_card; | ||
111 | struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; | ||
112 | int ret; | ||
113 | |||
114 | if (!np) { | ||
115 | dev_err(&pdev->dev, "only device tree supported\n"); | ||
116 | return -EINVAL; | ||
117 | } | ||
118 | |||
119 | ret = snd_soc_of_parse_card_name(card, "atmel,model"); | ||
120 | if (ret) { | ||
121 | dev_err(&pdev->dev, "failed to parse card name\n"); | ||
122 | return ret; | ||
123 | } | ||
124 | |||
125 | ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing"); | ||
126 | if (ret) { | ||
127 | dev_err(&pdev->dev, "failed to parse audio routing\n"); | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); | ||
132 | if (!cpu_np) { | ||
133 | dev_err(&pdev->dev, "failed to get dai and pcm info\n"); | ||
134 | ret = -EINVAL; | ||
135 | return ret; | ||
136 | } | ||
137 | dailink->cpu_of_node = cpu_np; | ||
138 | dailink->platform_of_node = cpu_np; | ||
139 | of_node_put(cpu_np); | ||
140 | |||
141 | codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); | ||
142 | if (!codec_np) { | ||
143 | dev_err(&pdev->dev, "failed to get codec info\n"); | ||
144 | ret = -EINVAL; | ||
145 | return ret; | ||
146 | } | ||
147 | dailink->codec_of_node = codec_np; | ||
148 | of_node_put(codec_np); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int atmel_asoc_wm8904_probe(struct platform_device *pdev) | ||
154 | { | ||
155 | struct snd_soc_card *card = &atmel_asoc_wm8904_card; | ||
156 | struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; | ||
157 | struct clk *clk_src; | ||
158 | struct pinctrl *pinctrl; | ||
159 | int id, ret; | ||
160 | |||
161 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | ||
162 | if (IS_ERR(pinctrl)) { | ||
163 | dev_err(&pdev->dev, "failed to request pinctrl\n"); | ||
164 | return PTR_ERR(pinctrl); | ||
165 | } | ||
166 | |||
167 | card->dev = &pdev->dev; | ||
168 | ret = atmel_asoc_wm8904_dt_init(pdev); | ||
169 | if (ret) { | ||
170 | dev_err(&pdev->dev, "failed to init dt info\n"); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc"); | ||
175 | ret = atmel_ssc_set_audio(id); | ||
176 | if (ret != 0) { | ||
177 | dev_err(&pdev->dev, "failed to set SSC %d for audio\n", id); | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | mclk = clk_get(NULL, "pck0"); | ||
182 | if (IS_ERR(mclk)) { | ||
183 | dev_err(&pdev->dev, "failed to get pck0\n"); | ||
184 | ret = PTR_ERR(mclk); | ||
185 | goto err_set_audio; | ||
186 | } | ||
187 | |||
188 | clk_src = clk_get(NULL, "clk32k"); | ||
189 | if (IS_ERR(clk_src)) { | ||
190 | dev_err(&pdev->dev, "failed to get clk32k\n"); | ||
191 | ret = PTR_ERR(clk_src); | ||
192 | goto err_set_audio; | ||
193 | } | ||
194 | |||
195 | ret = clk_set_parent(mclk, clk_src); | ||
196 | clk_put(clk_src); | ||
197 | if (ret != 0) { | ||
198 | dev_err(&pdev->dev, "failed to set MCLK parent\n"); | ||
199 | goto err_set_audio; | ||
200 | } | ||
201 | |||
202 | dev_info(&pdev->dev, "setting pck0 to %dHz\n", MCLK_RATE); | ||
203 | clk_set_rate(mclk, MCLK_RATE); | ||
204 | |||
205 | ret = snd_soc_register_card(card); | ||
206 | if (ret) { | ||
207 | dev_err(&pdev->dev, "snd_soc_register_card failed\n"); | ||
208 | goto err_set_audio; | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | |||
213 | err_set_audio: | ||
214 | atmel_ssc_put_audio(id); | ||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | static int atmel_asoc_wm8904_remove(struct platform_device *pdev) | ||
219 | { | ||
220 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
221 | struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; | ||
222 | int id; | ||
223 | |||
224 | id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc"); | ||
225 | |||
226 | snd_soc_unregister_card(card); | ||
227 | atmel_ssc_put_audio(id); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | #ifdef CONFIG_OF | ||
233 | static const struct of_device_id atmel_asoc_wm8904_dt_ids[] = { | ||
234 | { .compatible = "atmel,asoc-wm8904", }, | ||
235 | { } | ||
236 | }; | ||
237 | #endif | ||
238 | |||
239 | static struct platform_driver atmel_asoc_wm8904_driver = { | ||
240 | .driver = { | ||
241 | .name = "atmel-wm8904-audio", | ||
242 | .owner = THIS_MODULE, | ||
243 | .of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids), | ||
244 | }, | ||
245 | .probe = atmel_asoc_wm8904_probe, | ||
246 | .remove = atmel_asoc_wm8904_remove, | ||
247 | }; | ||
248 | |||
249 | module_platform_driver(atmel_asoc_wm8904_driver); | ||
250 | |||
251 | /* Module information */ | ||
252 | MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>"); | ||
253 | MODULE_DESCRIPTION("ALSA SoC machine driver for Atmel EK with WM8904 codec"); | ||
254 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c new file mode 100644 index 000000000000..992ae38d5a15 --- /dev/null +++ b/sound/soc/atmel/sam9x5_wm8731.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * sam9x5_wm8731 -- SoC audio for AT91SAM9X5-based boards | ||
3 | * that are using WM8731 as codec. | ||
4 | * | ||
5 | * Copyright (C) 2011 Atmel, | ||
6 | * Nicolas Ferre <nicolas.ferre@atmel.com> | ||
7 | * | ||
8 | * Copyright (C) 2013 Paratronic, | ||
9 | * Richard Genoud <richard.genoud@gmail.com> | ||
10 | * | ||
11 | * Based on sam9g20_wm8731.c by: | ||
12 | * Sedji Gaouaou <sedji.gaouaou@atmel.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify it | ||
15 | * under the terms of the GNU General Public License as published by the | ||
16 | * Free Software Foundation; either version 2 of the License, or (at your | ||
17 | * option) any later version. | ||
18 | * | ||
19 | */ | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/export.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/mod_devicetable.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/device.h> | ||
26 | |||
27 | #include <sound/soc.h> | ||
28 | #include <sound/soc-dai.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | |||
31 | #include "../codecs/wm8731.h" | ||
32 | #include "atmel_ssc_dai.h" | ||
33 | |||
34 | |||
35 | #define MCLK_RATE 12288000 | ||
36 | |||
37 | #define DRV_NAME "sam9x5-snd-wm8731" | ||
38 | |||
39 | struct sam9x5_drvdata { | ||
40 | int ssc_id; | ||
41 | }; | ||
42 | |||
43 | /* | ||
44 | * Logic for a wm8731 as connected on a at91sam9x5ek based board. | ||
45 | */ | ||
46 | static int sam9x5_wm8731_init(struct snd_soc_pcm_runtime *rtd) | ||
47 | { | ||
48 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
49 | struct device *dev = rtd->dev; | ||
50 | int ret; | ||
51 | |||
52 | dev_dbg(dev, "ASoC: %s called\n", __func__); | ||
53 | |||
54 | /* set the codec system clock for DAC and ADC */ | ||
55 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, | ||
56 | MCLK_RATE, SND_SOC_CLOCK_IN); | ||
57 | if (ret < 0) { | ||
58 | dev_err(dev, "ASoC: Failed to set WM8731 SYSCLK: %d\n", ret); | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * Audio paths on at91sam9x5ek board: | ||
67 | * | ||
68 | * |A| ------------> | | ---R----> Headphone Jack | ||
69 | * |T| <----\ | WM | ---L--/ | ||
70 | * |9| ---> CLK <--> | 8731 | <--R----- Line In Jack | ||
71 | * |1| <------------ | | <--L--/ | ||
72 | */ | ||
73 | static const struct snd_soc_dapm_widget sam9x5_dapm_widgets[] = { | ||
74 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
75 | SND_SOC_DAPM_LINE("Line In Jack", NULL), | ||
76 | }; | ||
77 | |||
78 | static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) | ||
79 | { | ||
80 | struct device_node *np = pdev->dev.of_node; | ||
81 | struct device_node *codec_np, *cpu_np; | ||
82 | struct snd_soc_card *card; | ||
83 | struct snd_soc_dai_link *dai; | ||
84 | struct sam9x5_drvdata *priv; | ||
85 | int ret; | ||
86 | |||
87 | if (!np) { | ||
88 | dev_err(&pdev->dev, "No device node supplied\n"); | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | |||
92 | card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL); | ||
93 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
94 | dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL); | ||
95 | if (!dai || !card || !priv) { | ||
96 | ret = -ENOMEM; | ||
97 | goto out; | ||
98 | } | ||
99 | |||
100 | card->dev = &pdev->dev; | ||
101 | card->owner = THIS_MODULE; | ||
102 | card->dai_link = dai; | ||
103 | card->num_links = 1; | ||
104 | card->dapm_widgets = sam9x5_dapm_widgets; | ||
105 | card->num_dapm_widgets = ARRAY_SIZE(sam9x5_dapm_widgets); | ||
106 | dai->name = "WM8731"; | ||
107 | dai->stream_name = "WM8731 PCM"; | ||
108 | dai->codec_dai_name = "wm8731-hifi"; | ||
109 | dai->init = sam9x5_wm8731_init; | ||
110 | dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ||
111 | | SND_SOC_DAIFMT_CBM_CFM; | ||
112 | |||
113 | ret = snd_soc_of_parse_card_name(card, "atmel,model"); | ||
114 | if (ret) { | ||
115 | dev_err(&pdev->dev, "atmel,model node missing\n"); | ||
116 | goto out; | ||
117 | } | ||
118 | |||
119 | ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing"); | ||
120 | if (ret) { | ||
121 | dev_err(&pdev->dev, "atmel,audio-routing node missing\n"); | ||
122 | goto out; | ||
123 | } | ||
124 | |||
125 | codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); | ||
126 | if (!codec_np) { | ||
127 | dev_err(&pdev->dev, "atmel,audio-codec node missing\n"); | ||
128 | ret = -EINVAL; | ||
129 | goto out; | ||
130 | } | ||
131 | |||
132 | dai->codec_of_node = codec_np; | ||
133 | |||
134 | cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); | ||
135 | if (!cpu_np) { | ||
136 | dev_err(&pdev->dev, "atmel,ssc-controller node missing\n"); | ||
137 | ret = -EINVAL; | ||
138 | goto out; | ||
139 | } | ||
140 | dai->cpu_of_node = cpu_np; | ||
141 | dai->platform_of_node = cpu_np; | ||
142 | |||
143 | priv->ssc_id = of_alias_get_id(cpu_np, "ssc"); | ||
144 | |||
145 | ret = atmel_ssc_set_audio(priv->ssc_id); | ||
146 | if (ret != 0) { | ||
147 | dev_err(&pdev->dev, | ||
148 | "ASoC: Failed to set SSC %d for audio: %d\n", | ||
149 | ret, priv->ssc_id); | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | of_node_put(codec_np); | ||
154 | of_node_put(cpu_np); | ||
155 | |||
156 | platform_set_drvdata(pdev, card); | ||
157 | |||
158 | ret = snd_soc_register_card(card); | ||
159 | if (ret) { | ||
160 | dev_err(&pdev->dev, | ||
161 | "ASoC: Platform device allocation failed\n"); | ||
162 | goto out_put_audio; | ||
163 | } | ||
164 | |||
165 | dev_dbg(&pdev->dev, "ASoC: %s ok\n", __func__); | ||
166 | |||
167 | return ret; | ||
168 | |||
169 | out_put_audio: | ||
170 | atmel_ssc_put_audio(priv->ssc_id); | ||
171 | out: | ||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | static int sam9x5_wm8731_driver_remove(struct platform_device *pdev) | ||
176 | { | ||
177 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
178 | struct sam9x5_drvdata *priv = card->drvdata; | ||
179 | |||
180 | snd_soc_unregister_card(card); | ||
181 | atmel_ssc_put_audio(priv->ssc_id); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static const struct of_device_id sam9x5_wm8731_of_match[] = { | ||
187 | { .compatible = "atmel,sam9x5-wm8731-audio", }, | ||
188 | {}, | ||
189 | }; | ||
190 | MODULE_DEVICE_TABLE(of, sam9x5_wm8731_of_match); | ||
191 | |||
192 | static struct platform_driver sam9x5_wm8731_driver = { | ||
193 | .driver = { | ||
194 | .name = DRV_NAME, | ||
195 | .owner = THIS_MODULE, | ||
196 | .of_match_table = of_match_ptr(sam9x5_wm8731_of_match), | ||
197 | }, | ||
198 | .probe = sam9x5_wm8731_driver_probe, | ||
199 | .remove = sam9x5_wm8731_driver_remove, | ||
200 | }; | ||
201 | module_platform_driver(sam9x5_wm8731_driver); | ||
202 | |||
203 | /* Module information */ | ||
204 | MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>"); | ||
205 | MODULE_AUTHOR("Richard Genoud <richard.genoud@gmail.com>"); | ||
206 | MODULE_DESCRIPTION("ALSA SoC machine driver for AT91SAM9x5 - WM8731"); | ||
207 | MODULE_LICENSE("GPL"); | ||
208 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index a497a0cfeba1..decba87a074c 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c | |||
@@ -73,12 +73,14 @@ static struct snd_soc_dai_link db1300_ac97_dai = { | |||
73 | 73 | ||
74 | static struct snd_soc_card db1300_ac97_machine = { | 74 | static struct snd_soc_card db1300_ac97_machine = { |
75 | .name = "DB1300_AC97", | 75 | .name = "DB1300_AC97", |
76 | .owner = THIS_MODULE, | ||
76 | .dai_link = &db1300_ac97_dai, | 77 | .dai_link = &db1300_ac97_dai, |
77 | .num_links = 1, | 78 | .num_links = 1, |
78 | }; | 79 | }; |
79 | 80 | ||
80 | static struct snd_soc_card db1550_ac97_machine = { | 81 | static struct snd_soc_card db1550_ac97_machine = { |
81 | .name = "DB1550_AC97", | 82 | .name = "DB1550_AC97", |
83 | .owner = THIS_MODULE, | ||
82 | .dai_link = &db1200_ac97_dai, | 84 | .dai_link = &db1200_ac97_dai, |
83 | .num_links = 1, | 85 | .num_links = 1, |
84 | }; | 86 | }; |
@@ -145,6 +147,7 @@ static struct snd_soc_dai_link db1300_i2s_dai = { | |||
145 | 147 | ||
146 | static struct snd_soc_card db1300_i2s_machine = { | 148 | static struct snd_soc_card db1300_i2s_machine = { |
147 | .name = "DB1300_I2S", | 149 | .name = "DB1300_I2S", |
150 | .owner = THIS_MODULE, | ||
148 | .dai_link = &db1300_i2s_dai, | 151 | .dai_link = &db1300_i2s_dai, |
149 | .num_links = 1, | 152 | .num_links = 1, |
150 | }; | 153 | }; |
@@ -161,6 +164,7 @@ static struct snd_soc_dai_link db1550_i2s_dai = { | |||
161 | 164 | ||
162 | static struct snd_soc_card db1550_i2s_machine = { | 165 | static struct snd_soc_card db1550_i2s_machine = { |
163 | .name = "DB1550_I2S", | 166 | .name = "DB1550_I2S", |
167 | .owner = THIS_MODULE, | ||
164 | .dai_link = &db1550_i2s_dai, | 168 | .dai_link = &db1550_i2s_dai, |
165 | .num_links = 1, | 169 | .num_links = 1, |
166 | }; | 170 | }; |
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index a822ab822bb7..986dcec79fa0 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c | |||
@@ -379,9 +379,6 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) | |||
379 | mutex_init(&wd->lock); | 379 | mutex_init(&wd->lock); |
380 | 380 | ||
381 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 381 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
382 | if (!iores) | ||
383 | return -ENODEV; | ||
384 | |||
385 | wd->mmio = devm_ioremap_resource(&pdev->dev, iores); | 382 | wd->mmio = devm_ioremap_resource(&pdev->dev, iores); |
386 | if (IS_ERR(wd->mmio)) | 383 | if (IS_ERR(wd->mmio)) |
387 | return PTR_ERR(wd->mmio); | 384 | return PTR_ERR(wd->mmio); |
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h index 0c3e22d90a8d..a680fdc9bb42 100644 --- a/sound/soc/blackfin/bf5xx-ac97.h +++ b/sound/soc/blackfin/bf5xx-ac97.h | |||
@@ -9,7 +9,6 @@ | |||
9 | #ifndef _BF5XX_AC97_H | 9 | #ifndef _BF5XX_AC97_H |
10 | #define _BF5XX_AC97_H | 10 | #define _BF5XX_AC97_H |
11 | 11 | ||
12 | extern struct snd_ac97 *ac97; | ||
13 | /* Frame format in memory, only support stereo currently */ | 12 | /* Frame format in memory, only support stereo currently */ |
14 | struct ac97_frame { | 13 | struct ac97_frame { |
15 | u16 ac97_tag; /* slot 0 */ | 14 | u16 ac97_tag; /* slot 0 */ |
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index 04491f0e8d1b..efa75b5086a4 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c | |||
@@ -363,9 +363,6 @@ static int ep93xx_ac97_probe(struct platform_device *pdev) | |||
363 | return -ENOMEM; | 363 | return -ENOMEM; |
364 | 364 | ||
365 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 365 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
366 | if (!res) | ||
367 | return -ENODEV; | ||
368 | |||
369 | info->regs = devm_ioremap_resource(&pdev->dev, res); | 366 | info->regs = devm_ioremap_resource(&pdev->dev, res); |
370 | if (IS_ERR(info->regs)) | 367 | if (IS_ERR(info->regs)) |
371 | return PTR_ERR(info->regs); | 368 | return PTR_ERR(info->regs); |
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 17ad70bca9fe..f23f331e9a97 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c | |||
@@ -376,9 +376,6 @@ static int ep93xx_i2s_probe(struct platform_device *pdev) | |||
376 | return -ENOMEM; | 376 | return -ENOMEM; |
377 | 377 | ||
378 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 378 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
379 | if (!res) | ||
380 | return -ENODEV; | ||
381 | |||
382 | info->regs = devm_ioremap_resource(&pdev->dev, res); | 379 | info->regs = devm_ioremap_resource(&pdev->dev, res); |
383 | if (IS_ERR(info->regs)) | 380 | if (IS_ERR(info->regs)) |
384 | return PTR_ERR(info->regs); | 381 | return PTR_ERR(info->regs); |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index badb6fbacaa6..15106c045478 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI | |||
10 | 10 | ||
11 | config SND_SOC_ALL_CODECS | 11 | config SND_SOC_ALL_CODECS |
12 | tristate "Build all ASoC CODEC drivers" | 12 | tristate "Build all ASoC CODEC drivers" |
13 | depends on COMPILE_TEST | ||
13 | select SND_SOC_88PM860X if MFD_88PM860X | 14 | select SND_SOC_88PM860X if MFD_88PM860X |
14 | select SND_SOC_L3 | 15 | select SND_SOC_L3 |
15 | select SND_SOC_AB8500_CODEC if ABX500_CORE | 16 | select SND_SOC_AB8500_CODEC if ABX500_CORE |
@@ -20,6 +21,7 @@ config SND_SOC_ALL_CODECS | |||
20 | select SND_SOC_AD73311 | 21 | select SND_SOC_AD73311 |
21 | select SND_SOC_ADAU1373 if I2C | 22 | select SND_SOC_ADAU1373 if I2C |
22 | select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI | 23 | select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI |
24 | select SND_SOC_ADAU1701 if I2C | ||
23 | select SND_SOC_ADS117X | 25 | select SND_SOC_ADS117X |
24 | select SND_SOC_AK4104 if SPI_MASTER | 26 | select SND_SOC_AK4104 if SPI_MASTER |
25 | select SND_SOC_AK4535 if I2C | 27 | select SND_SOC_AK4535 if I2C |
@@ -54,6 +56,8 @@ config SND_SOC_ALL_CODECS | |||
54 | select SND_SOC_MC13783 if MFD_MC13XXX | 56 | select SND_SOC_MC13783 if MFD_MC13XXX |
55 | select SND_SOC_ML26124 if I2C | 57 | select SND_SOC_ML26124 if I2C |
56 | select SND_SOC_HDMI_CODEC | 58 | select SND_SOC_HDMI_CODEC |
59 | select SND_SOC_PCM1681 if I2C | ||
60 | select SND_SOC_PCM1792A if SPI_MASTER | ||
57 | select SND_SOC_PCM3008 | 61 | select SND_SOC_PCM3008 |
58 | select SND_SOC_RT5631 if I2C | 62 | select SND_SOC_RT5631 if I2C |
59 | select SND_SOC_RT5640 if I2C | 63 | select SND_SOC_RT5640 if I2C |
@@ -122,6 +126,7 @@ config SND_SOC_ALL_CODECS | |||
122 | select SND_SOC_WM8994 if MFD_WM8994 | 126 | select SND_SOC_WM8994 if MFD_WM8994 |
123 | select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI | 127 | select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI |
124 | select SND_SOC_WM8996 if I2C | 128 | select SND_SOC_WM8996 if I2C |
129 | select SND_SOC_WM8997 if MFD_WM8997 | ||
125 | select SND_SOC_WM9081 if I2C | 130 | select SND_SOC_WM9081 if I2C |
126 | select SND_SOC_WM9090 if I2C | 131 | select SND_SOC_WM9090 if I2C |
127 | select SND_SOC_WM9705 if SND_SOC_AC97_BUS | 132 | select SND_SOC_WM9705 if SND_SOC_AC97_BUS |
@@ -145,8 +150,10 @@ config SND_SOC_ARIZONA | |||
145 | tristate | 150 | tristate |
146 | default y if SND_SOC_WM5102=y | 151 | default y if SND_SOC_WM5102=y |
147 | default y if SND_SOC_WM5110=y | 152 | default y if SND_SOC_WM5110=y |
153 | default y if SND_SOC_WM8997=y | ||
148 | default m if SND_SOC_WM5102=m | 154 | default m if SND_SOC_WM5102=m |
149 | default m if SND_SOC_WM5110=m | 155 | default m if SND_SOC_WM5110=m |
156 | default m if SND_SOC_WM8997=m | ||
150 | 157 | ||
151 | config SND_SOC_WM_HUBS | 158 | config SND_SOC_WM_HUBS |
152 | tristate | 159 | tristate |
@@ -198,6 +205,9 @@ config SND_SOC_AK4104 | |||
198 | config SND_SOC_AK4535 | 205 | config SND_SOC_AK4535 |
199 | tristate | 206 | tristate |
200 | 207 | ||
208 | config SND_SOC_AK4554 | ||
209 | tristate | ||
210 | |||
201 | config SND_SOC_AK4641 | 211 | config SND_SOC_AK4641 |
202 | tristate | 212 | tristate |
203 | 213 | ||
@@ -292,6 +302,12 @@ config SND_SOC_MAX9850 | |||
292 | config SND_SOC_HDMI_CODEC | 302 | config SND_SOC_HDMI_CODEC |
293 | tristate | 303 | tristate |
294 | 304 | ||
305 | config SND_SOC_PCM1681 | ||
306 | tristate | ||
307 | |||
308 | config SND_SOC_PCM1792A | ||
309 | tristate | ||
310 | |||
295 | config SND_SOC_PCM3008 | 311 | config SND_SOC_PCM3008 |
296 | tristate | 312 | tristate |
297 | 313 | ||
@@ -500,6 +516,9 @@ config SND_SOC_WM8995 | |||
500 | config SND_SOC_WM8996 | 516 | config SND_SOC_WM8996 |
501 | tristate | 517 | tristate |
502 | 518 | ||
519 | config SND_SOC_WM8997 | ||
520 | tristate | ||
521 | |||
503 | config SND_SOC_WM9081 | 522 | config SND_SOC_WM9081 |
504 | tristate | 523 | tristate |
505 | 524 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 70fd8066f546..bc126764a44d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -11,6 +11,7 @@ snd-soc-adav80x-objs := adav80x.o | |||
11 | snd-soc-ads117x-objs := ads117x.o | 11 | snd-soc-ads117x-objs := ads117x.o |
12 | snd-soc-ak4104-objs := ak4104.o | 12 | snd-soc-ak4104-objs := ak4104.o |
13 | snd-soc-ak4535-objs := ak4535.o | 13 | snd-soc-ak4535-objs := ak4535.o |
14 | snd-soc-ak4554-objs := ak4554.o | ||
14 | snd-soc-ak4641-objs := ak4641.o | 15 | snd-soc-ak4641-objs := ak4641.o |
15 | snd-soc-ak4642-objs := ak4642.o | 16 | snd-soc-ak4642-objs := ak4642.o |
16 | snd-soc-ak4671-objs := ak4671.o | 17 | snd-soc-ak4671-objs := ak4671.o |
@@ -42,6 +43,8 @@ snd-soc-max9850-objs := max9850.o | |||
42 | snd-soc-mc13783-objs := mc13783.o | 43 | snd-soc-mc13783-objs := mc13783.o |
43 | snd-soc-ml26124-objs := ml26124.o | 44 | snd-soc-ml26124-objs := ml26124.o |
44 | snd-soc-hdmi-codec-objs := hdmi.o | 45 | snd-soc-hdmi-codec-objs := hdmi.o |
46 | snd-soc-pcm1681-objs := pcm1681.o | ||
47 | snd-soc-pcm1792a-codec-objs := pcm1792a.o | ||
45 | snd-soc-pcm3008-objs := pcm3008.o | 48 | snd-soc-pcm3008-objs := pcm3008.o |
46 | snd-soc-rt5631-objs := rt5631.o | 49 | snd-soc-rt5631-objs := rt5631.o |
47 | snd-soc-rt5640-objs := rt5640.o | 50 | snd-soc-rt5640-objs := rt5640.o |
@@ -114,6 +117,7 @@ snd-soc-wm8991-objs := wm8991.o | |||
114 | snd-soc-wm8993-objs := wm8993.o | 117 | snd-soc-wm8993-objs := wm8993.o |
115 | snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o | 118 | snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o |
116 | snd-soc-wm8995-objs := wm8995.o | 119 | snd-soc-wm8995-objs := wm8995.o |
120 | snd-soc-wm8997-objs := wm8997.o | ||
117 | snd-soc-wm9081-objs := wm9081.o | 121 | snd-soc-wm9081-objs := wm9081.o |
118 | snd-soc-wm9090-objs := wm9090.o | 122 | snd-soc-wm9090-objs := wm9090.o |
119 | snd-soc-wm9705-objs := wm9705.o | 123 | snd-soc-wm9705-objs := wm9705.o |
@@ -138,6 +142,7 @@ obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o | |||
138 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o | 142 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o |
139 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | 143 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o |
140 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 144 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
145 | obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o | ||
141 | obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o | 146 | obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o |
142 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o | 147 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o |
143 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o | 148 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o |
@@ -171,6 +176,8 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o | |||
171 | obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o | 176 | obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o |
172 | obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o | 177 | obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o |
173 | obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o | 178 | obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o |
179 | obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o | ||
180 | obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o | ||
174 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 181 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
175 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | 182 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o |
176 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o | 183 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o |
@@ -239,6 +246,7 @@ obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o | |||
239 | obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o | 246 | obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o |
240 | obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o | 247 | obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o |
241 | obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o | 248 | obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o |
249 | obj-$(CONFIG_SND_SOC_WM8997) += snd-soc-wm8997.o | ||
242 | obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o | 250 | obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o |
243 | obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o | 251 | obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o |
244 | obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o | 252 | obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index ec7351803c24..8d9ba4ba4bfe 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -23,6 +23,16 @@ | |||
23 | #include <sound/initval.h> | 23 | #include <sound/initval.h> |
24 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
25 | 25 | ||
26 | static const struct snd_soc_dapm_widget ac97_widgets[] = { | ||
27 | SND_SOC_DAPM_INPUT("RX"), | ||
28 | SND_SOC_DAPM_OUTPUT("TX"), | ||
29 | }; | ||
30 | |||
31 | static const struct snd_soc_dapm_route ac97_routes[] = { | ||
32 | { "AC97 Capture", NULL, "RX" }, | ||
33 | { "TX", NULL, "AC97 Playback" }, | ||
34 | }; | ||
35 | |||
26 | static int ac97_prepare(struct snd_pcm_substream *substream, | 36 | static int ac97_prepare(struct snd_pcm_substream *substream, |
27 | struct snd_soc_dai *dai) | 37 | struct snd_soc_dai *dai) |
28 | { | 38 | { |
@@ -117,6 +127,11 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = { | |||
117 | .probe = ac97_soc_probe, | 127 | .probe = ac97_soc_probe, |
118 | .suspend = ac97_soc_suspend, | 128 | .suspend = ac97_soc_suspend, |
119 | .resume = ac97_soc_resume, | 129 | .resume = ac97_soc_resume, |
130 | |||
131 | .dapm_widgets = ac97_widgets, | ||
132 | .num_dapm_widgets = ARRAY_SIZE(ac97_widgets), | ||
133 | .dapm_routes = ac97_routes, | ||
134 | .num_dapm_routes = ARRAY_SIZE(ac97_routes), | ||
120 | }; | 135 | }; |
121 | 136 | ||
122 | static int ac97_probe(struct platform_device *pdev) | 137 | static int ac97_probe(struct platform_device *pdev) |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 89fcf7d6e7b8..7257a8885f42 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -96,6 +96,44 @@ SOC_ENUM("Capture Source", ad1980_cap_src), | |||
96 | SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), | 96 | SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), |
97 | }; | 97 | }; |
98 | 98 | ||
99 | static const struct snd_soc_dapm_widget ad1980_dapm_widgets[] = { | ||
100 | SND_SOC_DAPM_INPUT("MIC1"), | ||
101 | SND_SOC_DAPM_INPUT("MIC2"), | ||
102 | SND_SOC_DAPM_INPUT("CD_L"), | ||
103 | SND_SOC_DAPM_INPUT("CD_R"), | ||
104 | SND_SOC_DAPM_INPUT("AUX_L"), | ||
105 | SND_SOC_DAPM_INPUT("AUX_R"), | ||
106 | SND_SOC_DAPM_INPUT("LINE_IN_L"), | ||
107 | SND_SOC_DAPM_INPUT("LINE_IN_R"), | ||
108 | |||
109 | SND_SOC_DAPM_OUTPUT("LFE_OUT"), | ||
110 | SND_SOC_DAPM_OUTPUT("CENTER_OUT"), | ||
111 | SND_SOC_DAPM_OUTPUT("LINE_OUT_L"), | ||
112 | SND_SOC_DAPM_OUTPUT("LINE_OUT_R"), | ||
113 | SND_SOC_DAPM_OUTPUT("MONO_OUT"), | ||
114 | SND_SOC_DAPM_OUTPUT("HP_OUT_L"), | ||
115 | SND_SOC_DAPM_OUTPUT("HP_OUT_R"), | ||
116 | }; | ||
117 | |||
118 | static const struct snd_soc_dapm_route ad1980_dapm_routes[] = { | ||
119 | { "Capture", NULL, "MIC1" }, | ||
120 | { "Capture", NULL, "MIC2" }, | ||
121 | { "Capture", NULL, "CD_L" }, | ||
122 | { "Capture", NULL, "CD_R" }, | ||
123 | { "Capture", NULL, "AUX_L" }, | ||
124 | { "Capture", NULL, "AUX_R" }, | ||
125 | { "Capture", NULL, "LINE_IN_L" }, | ||
126 | { "Capture", NULL, "LINE_IN_R" }, | ||
127 | |||
128 | { "LFE_OUT", NULL, "Playback" }, | ||
129 | { "CENTER_OUT", NULL, "Playback" }, | ||
130 | { "LINE_OUT_L", NULL, "Playback" }, | ||
131 | { "LINE_OUT_R", NULL, "Playback" }, | ||
132 | { "MONO_OUT", NULL, "Playback" }, | ||
133 | { "HP_OUT_L", NULL, "Playback" }, | ||
134 | { "HP_OUT_R", NULL, "Playback" }, | ||
135 | }; | ||
136 | |||
99 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 137 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
100 | unsigned int reg) | 138 | unsigned int reg) |
101 | { | 139 | { |
@@ -253,6 +291,11 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { | |||
253 | .reg_cache_step = 2, | 291 | .reg_cache_step = 2, |
254 | .write = ac97_write, | 292 | .write = ac97_write, |
255 | .read = ac97_read, | 293 | .read = ac97_read, |
294 | |||
295 | .dapm_widgets = ad1980_dapm_widgets, | ||
296 | .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets), | ||
297 | .dapm_routes = ad1980_dapm_routes, | ||
298 | .num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes), | ||
256 | }; | 299 | }; |
257 | 300 | ||
258 | static int ad1980_probe(struct platform_device *pdev) | 301 | static int ad1980_probe(struct platform_device *pdev) |
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index b1f2baf42b48..5fac8adbc136 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c | |||
@@ -23,6 +23,21 @@ | |||
23 | 23 | ||
24 | #include "ad73311.h" | 24 | #include "ad73311.h" |
25 | 25 | ||
26 | static const struct snd_soc_dapm_widget ad73311_dapm_widgets[] = { | ||
27 | SND_SOC_DAPM_INPUT("VINP"), | ||
28 | SND_SOC_DAPM_INPUT("VINN"), | ||
29 | SND_SOC_DAPM_OUTPUT("VOUTN"), | ||
30 | SND_SOC_DAPM_OUTPUT("VOUTP"), | ||
31 | }; | ||
32 | |||
33 | static const struct snd_soc_dapm_route ad73311_dapm_routes[] = { | ||
34 | { "Capture", NULL, "VINP" }, | ||
35 | { "Capture", NULL, "VINN" }, | ||
36 | |||
37 | { "VOUTN", NULL, "Playback" }, | ||
38 | { "VOUTP", NULL, "Playback" }, | ||
39 | }; | ||
40 | |||
26 | static struct snd_soc_dai_driver ad73311_dai = { | 41 | static struct snd_soc_dai_driver ad73311_dai = { |
27 | .name = "ad73311-hifi", | 42 | .name = "ad73311-hifi", |
28 | .playback = { | 43 | .playback = { |
@@ -39,7 +54,12 @@ static struct snd_soc_dai_driver ad73311_dai = { | |||
39 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | 54 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, |
40 | }; | 55 | }; |
41 | 56 | ||
42 | static struct snd_soc_codec_driver soc_codec_dev_ad73311; | 57 | static struct snd_soc_codec_driver soc_codec_dev_ad73311 = { |
58 | .dapm_widgets = ad73311_dapm_widgets, | ||
59 | .num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets), | ||
60 | .dapm_routes = ad73311_dapm_routes, | ||
61 | .num_dapm_routes = ARRAY_SIZE(ad73311_dapm_routes), | ||
62 | }; | ||
43 | 63 | ||
44 | static int ad73311_probe(struct platform_device *pdev) | 64 | static int ad73311_probe(struct platform_device *pdev) |
45 | { | 65 | { |
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index d1124a5b3471..ebff1128be59 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c | |||
@@ -91,7 +91,7 @@ | |||
91 | #define ADAU1701_OSCIPOW_OPD 0x04 | 91 | #define ADAU1701_OSCIPOW_OPD 0x04 |
92 | #define ADAU1701_DACSET_DACINIT 1 | 92 | #define ADAU1701_DACSET_DACINIT 1 |
93 | 93 | ||
94 | #define ADAU1707_CLKDIV_UNSET (-1UL) | 94 | #define ADAU1707_CLKDIV_UNSET (-1U) |
95 | 95 | ||
96 | #define ADAU1701_FIRMWARE "adau1701.bin" | 96 | #define ADAU1701_FIRMWARE "adau1701.bin" |
97 | 97 | ||
@@ -247,21 +247,21 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) | |||
247 | gpio_is_valid(adau1701->gpio_pll_mode[1])) { | 247 | gpio_is_valid(adau1701->gpio_pll_mode[1])) { |
248 | switch (clkdiv) { | 248 | switch (clkdiv) { |
249 | case 64: | 249 | case 64: |
250 | gpio_set_value(adau1701->gpio_pll_mode[0], 0); | 250 | gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0); |
251 | gpio_set_value(adau1701->gpio_pll_mode[1], 0); | 251 | gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0); |
252 | break; | 252 | break; |
253 | case 256: | 253 | case 256: |
254 | gpio_set_value(adau1701->gpio_pll_mode[0], 0); | 254 | gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0); |
255 | gpio_set_value(adau1701->gpio_pll_mode[1], 1); | 255 | gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1); |
256 | break; | 256 | break; |
257 | case 384: | 257 | case 384: |
258 | gpio_set_value(adau1701->gpio_pll_mode[0], 1); | 258 | gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1); |
259 | gpio_set_value(adau1701->gpio_pll_mode[1], 0); | 259 | gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0); |
260 | break; | 260 | break; |
261 | case 0: /* fallback */ | 261 | case 0: /* fallback */ |
262 | case 512: | 262 | case 512: |
263 | gpio_set_value(adau1701->gpio_pll_mode[0], 1); | 263 | gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1); |
264 | gpio_set_value(adau1701->gpio_pll_mode[1], 1); | 264 | gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1); |
265 | break; | 265 | break; |
266 | } | 266 | } |
267 | } | 267 | } |
@@ -269,10 +269,10 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) | |||
269 | adau1701->pll_clkdiv = clkdiv; | 269 | adau1701->pll_clkdiv = clkdiv; |
270 | 270 | ||
271 | if (gpio_is_valid(adau1701->gpio_nreset)) { | 271 | if (gpio_is_valid(adau1701->gpio_nreset)) { |
272 | gpio_set_value(adau1701->gpio_nreset, 0); | 272 | gpio_set_value_cansleep(adau1701->gpio_nreset, 0); |
273 | /* minimum reset time is 20ns */ | 273 | /* minimum reset time is 20ns */ |
274 | udelay(1); | 274 | udelay(1); |
275 | gpio_set_value(adau1701->gpio_nreset, 1); | 275 | gpio_set_value_cansleep(adau1701->gpio_nreset, 1); |
276 | /* power-up time may be as long as 85ms */ | 276 | /* power-up time may be as long as 85ms */ |
277 | mdelay(85); | 277 | mdelay(85); |
278 | } | 278 | } |
@@ -734,7 +734,10 @@ static int adau1701_i2c_remove(struct i2c_client *client) | |||
734 | } | 734 | } |
735 | 735 | ||
736 | static const struct i2c_device_id adau1701_i2c_id[] = { | 736 | static const struct i2c_device_id adau1701_i2c_id[] = { |
737 | { "adau1401", 0 }, | ||
738 | { "adau1401a", 0 }, | ||
737 | { "adau1701", 0 }, | 739 | { "adau1701", 0 }, |
740 | { "adau1702", 0 }, | ||
738 | { } | 741 | { } |
739 | }; | 742 | }; |
740 | MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id); | 743 | MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id); |
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 3c839cc4e00e..15b012d0f226 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c | |||
@@ -868,6 +868,12 @@ static int adav80x_bus_remove(struct device *dev) | |||
868 | } | 868 | } |
869 | 869 | ||
870 | #if defined(CONFIG_SPI_MASTER) | 870 | #if defined(CONFIG_SPI_MASTER) |
871 | static const struct spi_device_id adav80x_spi_id[] = { | ||
872 | { "adav801", 0 }, | ||
873 | { } | ||
874 | }; | ||
875 | MODULE_DEVICE_TABLE(spi, adav80x_spi_id); | ||
876 | |||
871 | static int adav80x_spi_probe(struct spi_device *spi) | 877 | static int adav80x_spi_probe(struct spi_device *spi) |
872 | { | 878 | { |
873 | return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); | 879 | return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); |
@@ -885,15 +891,16 @@ static struct spi_driver adav80x_spi_driver = { | |||
885 | }, | 891 | }, |
886 | .probe = adav80x_spi_probe, | 892 | .probe = adav80x_spi_probe, |
887 | .remove = adav80x_spi_remove, | 893 | .remove = adav80x_spi_remove, |
894 | .id_table = adav80x_spi_id, | ||
888 | }; | 895 | }; |
889 | #endif | 896 | #endif |
890 | 897 | ||
891 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 898 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
892 | static const struct i2c_device_id adav80x_id[] = { | 899 | static const struct i2c_device_id adav80x_i2c_id[] = { |
893 | { "adav803", 0 }, | 900 | { "adav803", 0 }, |
894 | { } | 901 | { } |
895 | }; | 902 | }; |
896 | MODULE_DEVICE_TABLE(i2c, adav80x_id); | 903 | MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id); |
897 | 904 | ||
898 | static int adav80x_i2c_probe(struct i2c_client *client, | 905 | static int adav80x_i2c_probe(struct i2c_client *client, |
899 | const struct i2c_device_id *id) | 906 | const struct i2c_device_id *id) |
@@ -913,7 +920,7 @@ static struct i2c_driver adav80x_i2c_driver = { | |||
913 | }, | 920 | }, |
914 | .probe = adav80x_i2c_probe, | 921 | .probe = adav80x_i2c_probe, |
915 | .remove = adav80x_i2c_remove, | 922 | .remove = adav80x_i2c_remove, |
916 | .id_table = adav80x_id, | 923 | .id_table = adav80x_i2c_id, |
917 | }; | 924 | }; |
918 | #endif | 925 | #endif |
919 | 926 | ||
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c index 506d474c4d22..8f388edff586 100644 --- a/sound/soc/codecs/ads117x.c +++ b/sound/soc/codecs/ads117x.c | |||
@@ -23,6 +23,28 @@ | |||
23 | #define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000) | 23 | #define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000) |
24 | #define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) | 24 | #define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) |
25 | 25 | ||
26 | static const struct snd_soc_dapm_widget ads117x_dapm_widgets[] = { | ||
27 | SND_SOC_DAPM_INPUT("Input1"), | ||
28 | SND_SOC_DAPM_INPUT("Input2"), | ||
29 | SND_SOC_DAPM_INPUT("Input3"), | ||
30 | SND_SOC_DAPM_INPUT("Input4"), | ||
31 | SND_SOC_DAPM_INPUT("Input5"), | ||
32 | SND_SOC_DAPM_INPUT("Input6"), | ||
33 | SND_SOC_DAPM_INPUT("Input7"), | ||
34 | SND_SOC_DAPM_INPUT("Input8"), | ||
35 | }; | ||
36 | |||
37 | static const struct snd_soc_dapm_route ads117x_dapm_routes[] = { | ||
38 | { "Capture", NULL, "Input1" }, | ||
39 | { "Capture", NULL, "Input2" }, | ||
40 | { "Capture", NULL, "Input3" }, | ||
41 | { "Capture", NULL, "Input4" }, | ||
42 | { "Capture", NULL, "Input5" }, | ||
43 | { "Capture", NULL, "Input6" }, | ||
44 | { "Capture", NULL, "Input7" }, | ||
45 | { "Capture", NULL, "Input8" }, | ||
46 | }; | ||
47 | |||
26 | static struct snd_soc_dai_driver ads117x_dai = { | 48 | static struct snd_soc_dai_driver ads117x_dai = { |
27 | /* ADC */ | 49 | /* ADC */ |
28 | .name = "ads117x-hifi", | 50 | .name = "ads117x-hifi", |
@@ -34,7 +56,12 @@ static struct snd_soc_dai_driver ads117x_dai = { | |||
34 | .formats = ADS117X_FORMATS,}, | 56 | .formats = ADS117X_FORMATS,}, |
35 | }; | 57 | }; |
36 | 58 | ||
37 | static struct snd_soc_codec_driver soc_codec_dev_ads117x; | 59 | static struct snd_soc_codec_driver soc_codec_dev_ads117x = { |
60 | .dapm_widgets = ads117x_dapm_widgets, | ||
61 | .num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets), | ||
62 | .dapm_routes = ads117x_dapm_routes, | ||
63 | .num_dapm_routes = ARRAY_SIZE(ads117x_dapm_routes), | ||
64 | }; | ||
38 | 65 | ||
39 | static int ads117x_probe(struct platform_device *pdev) | 66 | static int ads117x_probe(struct platform_device *pdev) |
40 | { | 67 | { |
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index c7cfdf957e4d..71059c07ae7b 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c | |||
@@ -51,6 +51,17 @@ struct ak4104_private { | |||
51 | struct regmap *regmap; | 51 | struct regmap *regmap; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { | ||
55 | SND_SOC_DAPM_PGA("TXE", AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0), | ||
56 | |||
57 | SND_SOC_DAPM_OUTPUT("TX"), | ||
58 | }; | ||
59 | |||
60 | static const struct snd_soc_dapm_route ak4104_dapm_routes[] = { | ||
61 | { "TXE", NULL, "Playback" }, | ||
62 | { "TX", NULL, "TXE" }, | ||
63 | }; | ||
64 | |||
54 | static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, | 65 | static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, |
55 | unsigned int format) | 66 | unsigned int format) |
56 | { | 67 | { |
@@ -138,29 +149,11 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, | |||
138 | if (ret < 0) | 149 | if (ret < 0) |
139 | return ret; | 150 | return ret; |
140 | 151 | ||
141 | /* enable transmitter */ | ||
142 | ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, | ||
143 | AK4104_TX_TXE, AK4104_TX_TXE); | ||
144 | if (ret < 0) | ||
145 | return ret; | ||
146 | |||
147 | return 0; | 152 | return 0; |
148 | } | 153 | } |
149 | 154 | ||
150 | static int ak4104_hw_free(struct snd_pcm_substream *substream, | ||
151 | struct snd_soc_dai *dai) | ||
152 | { | ||
153 | struct snd_soc_codec *codec = dai->codec; | ||
154 | struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); | ||
155 | |||
156 | /* disable transmitter */ | ||
157 | return regmap_update_bits(ak4104->regmap, AK4104_REG_TX, | ||
158 | AK4104_TX_TXE, 0); | ||
159 | } | ||
160 | |||
161 | static const struct snd_soc_dai_ops ak4101_dai_ops = { | 155 | static const struct snd_soc_dai_ops ak4101_dai_ops = { |
162 | .hw_params = ak4104_hw_params, | 156 | .hw_params = ak4104_hw_params, |
163 | .hw_free = ak4104_hw_free, | ||
164 | .set_fmt = ak4104_set_dai_fmt, | 157 | .set_fmt = ak4104_set_dai_fmt, |
165 | }; | 158 | }; |
166 | 159 | ||
@@ -214,6 +207,11 @@ static int ak4104_remove(struct snd_soc_codec *codec) | |||
214 | static struct snd_soc_codec_driver soc_codec_device_ak4104 = { | 207 | static struct snd_soc_codec_driver soc_codec_device_ak4104 = { |
215 | .probe = ak4104_probe, | 208 | .probe = ak4104_probe, |
216 | .remove = ak4104_remove, | 209 | .remove = ak4104_remove, |
210 | |||
211 | .dapm_widgets = ak4104_dapm_widgets, | ||
212 | .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets), | ||
213 | .dapm_routes = ak4104_dapm_routes, | ||
214 | .num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes), | ||
217 | }; | 215 | }; |
218 | 216 | ||
219 | static const struct regmap_config ak4104_regmap = { | 217 | static const struct regmap_config ak4104_regmap = { |
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c new file mode 100644 index 000000000000..79e9555766c0 --- /dev/null +++ b/sound/soc/codecs/ak4554.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * ak4554.c | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <sound/soc.h> | ||
14 | |||
15 | /* | ||
16 | * ak4554 is very simple DA/AD converter which has no setting register. | ||
17 | * | ||
18 | * CAUTION | ||
19 | * | ||
20 | * ak4554 playback format is SND_SOC_DAIFMT_RIGHT_J, | ||
21 | * and, capture format is SND_SOC_DAIFMT_LEFT_J | ||
22 | * on same bit clock, LR clock. | ||
23 | * But, this driver doesn't have snd_soc_dai_ops :: set_fmt | ||
24 | * | ||
25 | * CPU/Codec DAI image | ||
26 | * | ||
27 | * CPU-DAI1 (plaback only fmt = RIGHT_J) --+-- ak4554 | ||
28 | * | | ||
29 | * CPU-DAI2 (capture only fmt = LEFT_J) ---+ | ||
30 | */ | ||
31 | |||
32 | static const struct snd_soc_dapm_widget ak4554_dapm_widgets[] = { | ||
33 | SND_SOC_DAPM_INPUT("AINL"), | ||
34 | SND_SOC_DAPM_INPUT("AINR"), | ||
35 | |||
36 | SND_SOC_DAPM_OUTPUT("AOUTL"), | ||
37 | SND_SOC_DAPM_OUTPUT("AOUTR"), | ||
38 | }; | ||
39 | |||
40 | static const struct snd_soc_dapm_route ak4554_dapm_routes[] = { | ||
41 | { "Capture", NULL, "AINL" }, | ||
42 | { "Capture", NULL, "AINR" }, | ||
43 | |||
44 | { "AOUTL", NULL, "Playback" }, | ||
45 | { "AOUTR", NULL, "Playback" }, | ||
46 | }; | ||
47 | |||
48 | static struct snd_soc_dai_driver ak4554_dai = { | ||
49 | .name = "ak4554-hifi", | ||
50 | .playback = { | ||
51 | .stream_name = "Playback", | ||
52 | .channels_min = 2, | ||
53 | .channels_max = 2, | ||
54 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
55 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
56 | }, | ||
57 | .capture = { | ||
58 | .stream_name = "Capture", | ||
59 | .channels_min = 2, | ||
60 | .channels_max = 2, | ||
61 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
62 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
63 | }, | ||
64 | .symmetric_rates = 1, | ||
65 | }; | ||
66 | |||
67 | static struct snd_soc_codec_driver soc_codec_dev_ak4554 = { | ||
68 | .dapm_widgets = ak4554_dapm_widgets, | ||
69 | .num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets), | ||
70 | .dapm_routes = ak4554_dapm_routes, | ||
71 | .num_dapm_routes = ARRAY_SIZE(ak4554_dapm_routes), | ||
72 | }; | ||
73 | |||
74 | static int ak4554_soc_probe(struct platform_device *pdev) | ||
75 | { | ||
76 | return snd_soc_register_codec(&pdev->dev, | ||
77 | &soc_codec_dev_ak4554, | ||
78 | &ak4554_dai, 1); | ||
79 | } | ||
80 | |||
81 | static int ak4554_soc_remove(struct platform_device *pdev) | ||
82 | { | ||
83 | snd_soc_unregister_codec(&pdev->dev); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static struct of_device_id ak4554_of_match[] = { | ||
88 | { .compatible = "asahi-kasei,ak4554" }, | ||
89 | {}, | ||
90 | }; | ||
91 | MODULE_DEVICE_TABLE(of, ak4554_of_match); | ||
92 | |||
93 | static struct platform_driver ak4554_driver = { | ||
94 | .driver = { | ||
95 | .name = "ak4554-adc-dac", | ||
96 | .owner = THIS_MODULE, | ||
97 | .of_match_table = ak4554_of_match, | ||
98 | }, | ||
99 | .probe = ak4554_soc_probe, | ||
100 | .remove = ak4554_soc_remove, | ||
101 | }; | ||
102 | module_platform_driver(ak4554_driver); | ||
103 | |||
104 | MODULE_LICENSE("GPL"); | ||
105 | MODULE_DESCRIPTION("SoC AK4554 driver"); | ||
106 | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); | ||
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c index 1f303983ae02..72e953b2cb41 100644 --- a/sound/soc/codecs/ak5386.c +++ b/sound/soc/codecs/ak5386.c | |||
@@ -22,7 +22,22 @@ struct ak5386_priv { | |||
22 | int reset_gpio; | 22 | int reset_gpio; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | static struct snd_soc_codec_driver soc_codec_ak5386; | 25 | static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = { |
26 | SND_SOC_DAPM_INPUT("AINL"), | ||
27 | SND_SOC_DAPM_INPUT("AINR"), | ||
28 | }; | ||
29 | |||
30 | static const struct snd_soc_dapm_route ak5386_dapm_routes[] = { | ||
31 | { "Capture", NULL, "AINL" }, | ||
32 | { "Capture", NULL, "AINR" }, | ||
33 | }; | ||
34 | |||
35 | static struct snd_soc_codec_driver soc_codec_ak5386 = { | ||
36 | .dapm_widgets = ak5386_dapm_widgets, | ||
37 | .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets), | ||
38 | .dapm_routes = ak5386_dapm_routes, | ||
39 | .num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes), | ||
40 | }; | ||
26 | 41 | ||
27 | static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai, | 42 | static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai, |
28 | unsigned int format) | 43 | unsigned int format) |
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index de625813c0e6..657808ba1418 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <sound/tlv.h> | 19 | #include <sound/tlv.h> |
20 | 20 | ||
21 | #include <linux/mfd/arizona/core.h> | 21 | #include <linux/mfd/arizona/core.h> |
22 | #include <linux/mfd/arizona/gpio.h> | ||
22 | #include <linux/mfd/arizona/registers.h> | 23 | #include <linux/mfd/arizona/registers.h> |
23 | 24 | ||
24 | #include "arizona.h" | 25 | #include "arizona.h" |
@@ -199,9 +200,16 @@ int arizona_init_spk(struct snd_soc_codec *codec) | |||
199 | if (ret != 0) | 200 | if (ret != 0) |
200 | return ret; | 201 | return ret; |
201 | 202 | ||
202 | ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1); | 203 | switch (arizona->type) { |
203 | if (ret != 0) | 204 | case WM8997: |
204 | return ret; | 205 | break; |
206 | default: | ||
207 | ret = snd_soc_dapm_new_controls(&codec->dapm, | ||
208 | &arizona_spkr, 1); | ||
209 | if (ret != 0) | ||
210 | return ret; | ||
211 | break; | ||
212 | } | ||
205 | 213 | ||
206 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN, | 214 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN, |
207 | "Thermal warning", arizona_thermal_warn, | 215 | "Thermal warning", arizona_thermal_warn, |
@@ -223,6 +231,41 @@ int arizona_init_spk(struct snd_soc_codec *codec) | |||
223 | } | 231 | } |
224 | EXPORT_SYMBOL_GPL(arizona_init_spk); | 232 | EXPORT_SYMBOL_GPL(arizona_init_spk); |
225 | 233 | ||
234 | int arizona_init_gpio(struct snd_soc_codec *codec) | ||
235 | { | ||
236 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
237 | struct arizona *arizona = priv->arizona; | ||
238 | int i; | ||
239 | |||
240 | switch (arizona->type) { | ||
241 | case WM5110: | ||
242 | snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity"); | ||
243 | break; | ||
244 | default: | ||
245 | break; | ||
246 | } | ||
247 | |||
248 | snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity"); | ||
249 | |||
250 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { | ||
251 | switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) { | ||
252 | case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT: | ||
253 | snd_soc_dapm_enable_pin(&codec->dapm, | ||
254 | "DRC1 Signal Activity"); | ||
255 | break; | ||
256 | case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT: | ||
257 | snd_soc_dapm_enable_pin(&codec->dapm, | ||
258 | "DRC2 Signal Activity"); | ||
259 | break; | ||
260 | default: | ||
261 | break; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | EXPORT_SYMBOL_GPL(arizona_init_gpio); | ||
268 | |||
226 | const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { | 269 | const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { |
227 | "None", | 270 | "None", |
228 | "Tone Generator 1", | 271 | "Tone Generator 1", |
@@ -517,6 +560,26 @@ const struct soc_enum arizona_ng_hold = | |||
517 | 4, arizona_ng_hold_text); | 560 | 4, arizona_ng_hold_text); |
518 | EXPORT_SYMBOL_GPL(arizona_ng_hold); | 561 | EXPORT_SYMBOL_GPL(arizona_ng_hold); |
519 | 562 | ||
563 | static const char * const arizona_in_dmic_osr_text[] = { | ||
564 | "1.536MHz", "3.072MHz", "6.144MHz", | ||
565 | }; | ||
566 | |||
567 | const struct soc_enum arizona_in_dmic_osr[] = { | ||
568 | SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT, | ||
569 | ARRAY_SIZE(arizona_in_dmic_osr_text), | ||
570 | arizona_in_dmic_osr_text), | ||
571 | SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT, | ||
572 | ARRAY_SIZE(arizona_in_dmic_osr_text), | ||
573 | arizona_in_dmic_osr_text), | ||
574 | SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT, | ||
575 | ARRAY_SIZE(arizona_in_dmic_osr_text), | ||
576 | arizona_in_dmic_osr_text), | ||
577 | SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT, | ||
578 | ARRAY_SIZE(arizona_in_dmic_osr_text), | ||
579 | arizona_in_dmic_osr_text), | ||
580 | }; | ||
581 | EXPORT_SYMBOL_GPL(arizona_in_dmic_osr); | ||
582 | |||
520 | static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) | 583 | static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) |
521 | { | 584 | { |
522 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 585 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index b60b08ccc1d0..9e81b6392692 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h | |||
@@ -150,7 +150,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; | |||
150 | ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \ | 150 | ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \ |
151 | ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux) | 151 | ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux) |
152 | 152 | ||
153 | #define ARIZONA_MUX_ROUTES(name) \ | 153 | #define ARIZONA_MUX_ROUTES(widget, name) \ |
154 | { widget, NULL, name " Input" }, \ | ||
154 | ARIZONA_MIXER_INPUT_ROUTES(name " Input") | 155 | ARIZONA_MIXER_INPUT_ROUTES(name " Input") |
155 | 156 | ||
156 | #define ARIZONA_MIXER_ROUTES(widget, name) \ | 157 | #define ARIZONA_MIXER_ROUTES(widget, name) \ |
@@ -198,6 +199,7 @@ extern const struct soc_enum arizona_lhpf3_mode; | |||
198 | extern const struct soc_enum arizona_lhpf4_mode; | 199 | extern const struct soc_enum arizona_lhpf4_mode; |
199 | 200 | ||
200 | extern const struct soc_enum arizona_ng_hold; | 201 | extern const struct soc_enum arizona_ng_hold; |
202 | extern const struct soc_enum arizona_in_dmic_osr[]; | ||
201 | 203 | ||
202 | extern int arizona_in_ev(struct snd_soc_dapm_widget *w, | 204 | extern int arizona_in_ev(struct snd_soc_dapm_widget *w, |
203 | struct snd_kcontrol *kcontrol, | 205 | struct snd_kcontrol *kcontrol, |
@@ -242,6 +244,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source, | |||
242 | unsigned int Fref, unsigned int Fout); | 244 | unsigned int Fref, unsigned int Fout); |
243 | 245 | ||
244 | extern int arizona_init_spk(struct snd_soc_codec *codec); | 246 | extern int arizona_init_spk(struct snd_soc_codec *codec); |
247 | extern int arizona_init_gpio(struct snd_soc_codec *codec); | ||
245 | 248 | ||
246 | extern int arizona_init_dai(struct arizona_priv *priv, int dai); | 249 | extern int arizona_init_dai(struct arizona_priv *priv, int dai); |
247 | 250 | ||
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index a081d9fcb166..c4cf0699e77f 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c | |||
@@ -15,15 +15,27 @@ | |||
15 | 15 | ||
16 | #include <sound/soc.h> | 16 | #include <sound/soc.h> |
17 | 17 | ||
18 | static const struct snd_soc_dapm_widget bt_sco_widgets[] = { | ||
19 | SND_SOC_DAPM_INPUT("RX"), | ||
20 | SND_SOC_DAPM_OUTPUT("TX"), | ||
21 | }; | ||
22 | |||
23 | static const struct snd_soc_dapm_route bt_sco_routes[] = { | ||
24 | { "Capture", NULL, "RX" }, | ||
25 | { "TX", NULL, "Playback" }, | ||
26 | }; | ||
27 | |||
18 | static struct snd_soc_dai_driver bt_sco_dai = { | 28 | static struct snd_soc_dai_driver bt_sco_dai = { |
19 | .name = "bt-sco-pcm", | 29 | .name = "bt-sco-pcm", |
20 | .playback = { | 30 | .playback = { |
31 | .stream_name = "Playback", | ||
21 | .channels_min = 1, | 32 | .channels_min = 1, |
22 | .channels_max = 1, | 33 | .channels_max = 1, |
23 | .rates = SNDRV_PCM_RATE_8000, | 34 | .rates = SNDRV_PCM_RATE_8000, |
24 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 35 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
25 | }, | 36 | }, |
26 | .capture = { | 37 | .capture = { |
38 | .stream_name = "Capture", | ||
27 | .channels_min = 1, | 39 | .channels_min = 1, |
28 | .channels_max = 1, | 40 | .channels_max = 1, |
29 | .rates = SNDRV_PCM_RATE_8000, | 41 | .rates = SNDRV_PCM_RATE_8000, |
@@ -31,7 +43,12 @@ static struct snd_soc_dai_driver bt_sco_dai = { | |||
31 | }, | 43 | }, |
32 | }; | 44 | }; |
33 | 45 | ||
34 | static struct snd_soc_codec_driver soc_codec_dev_bt_sco; | 46 | static struct snd_soc_codec_driver soc_codec_dev_bt_sco = { |
47 | .dapm_widgets = bt_sco_widgets, | ||
48 | .num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets), | ||
49 | .dapm_routes = bt_sco_routes, | ||
50 | .num_dapm_routes = ARRAY_SIZE(bt_sco_routes), | ||
51 | }; | ||
35 | 52 | ||
36 | static int bt_sco_probe(struct platform_device *pdev) | 53 | static int bt_sco_probe(struct platform_device *pdev) |
37 | { | 54 | { |
@@ -50,6 +67,9 @@ static struct platform_device_id bt_sco_driver_ids[] = { | |||
50 | { | 67 | { |
51 | .name = "dfbmcs320", | 68 | .name = "dfbmcs320", |
52 | }, | 69 | }, |
70 | { | ||
71 | .name = "bt-sco", | ||
72 | }, | ||
53 | {}, | 73 | {}, |
54 | }; | 74 | }; |
55 | MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids); | 75 | MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids); |
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 8e4779812b96..83c835d9fd88 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -139,6 +139,22 @@ struct cs4270_private { | |||
139 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | 139 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; |
140 | }; | 140 | }; |
141 | 141 | ||
142 | static const struct snd_soc_dapm_widget cs4270_dapm_widgets[] = { | ||
143 | SND_SOC_DAPM_INPUT("AINL"), | ||
144 | SND_SOC_DAPM_INPUT("AINR"), | ||
145 | |||
146 | SND_SOC_DAPM_OUTPUT("AOUTL"), | ||
147 | SND_SOC_DAPM_OUTPUT("AOUTR"), | ||
148 | }; | ||
149 | |||
150 | static const struct snd_soc_dapm_route cs4270_dapm_routes[] = { | ||
151 | { "Capture", NULL, "AINA" }, | ||
152 | { "Capture", NULL, "AINB" }, | ||
153 | |||
154 | { "AOUTA", NULL, "Playback" }, | ||
155 | { "AOUTB", NULL, "Playback" }, | ||
156 | }; | ||
157 | |||
142 | /** | 158 | /** |
143 | * struct cs4270_mode_ratios - clock ratio tables | 159 | * struct cs4270_mode_ratios - clock ratio tables |
144 | * @ratio: the ratio of MCLK to the sample rate | 160 | * @ratio: the ratio of MCLK to the sample rate |
@@ -612,6 +628,10 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { | |||
612 | 628 | ||
613 | .controls = cs4270_snd_controls, | 629 | .controls = cs4270_snd_controls, |
614 | .num_controls = ARRAY_SIZE(cs4270_snd_controls), | 630 | .num_controls = ARRAY_SIZE(cs4270_snd_controls), |
631 | .dapm_widgets = cs4270_dapm_widgets, | ||
632 | .num_dapm_widgets = ARRAY_SIZE(cs4270_dapm_widgets), | ||
633 | .dapm_routes = cs4270_dapm_routes, | ||
634 | .num_dapm_routes = ARRAY_SIZE(cs4270_dapm_routes), | ||
615 | }; | 635 | }; |
616 | 636 | ||
617 | /* | 637 | /* |
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 03036b326732..a20f1bb8f071 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c | |||
@@ -173,6 +173,26 @@ struct cs4271_private { | |||
173 | bool enable_soft_reset; | 173 | bool enable_soft_reset; |
174 | }; | 174 | }; |
175 | 175 | ||
176 | static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = { | ||
177 | SND_SOC_DAPM_INPUT("AINA"), | ||
178 | SND_SOC_DAPM_INPUT("AINB"), | ||
179 | |||
180 | SND_SOC_DAPM_OUTPUT("AOUTA+"), | ||
181 | SND_SOC_DAPM_OUTPUT("AOUTA-"), | ||
182 | SND_SOC_DAPM_OUTPUT("AOUTB+"), | ||
183 | SND_SOC_DAPM_OUTPUT("AOUTB-"), | ||
184 | }; | ||
185 | |||
186 | static const struct snd_soc_dapm_route cs4271_dapm_routes[] = { | ||
187 | { "Capture", NULL, "AINA" }, | ||
188 | { "Capture", NULL, "AINB" }, | ||
189 | |||
190 | { "AOUTA+", NULL, "Playback" }, | ||
191 | { "AOUTA-", NULL, "Playback" }, | ||
192 | { "AOUTB+", NULL, "Playback" }, | ||
193 | { "AOUTB-", NULL, "Playback" }, | ||
194 | }; | ||
195 | |||
176 | /* | 196 | /* |
177 | * @freq is the desired MCLK rate | 197 | * @freq is the desired MCLK rate |
178 | * MCLK rate should (c) be the sample rate, multiplied by one of the | 198 | * MCLK rate should (c) be the sample rate, multiplied by one of the |
@@ -576,8 +596,7 @@ static int cs4271_probe(struct snd_soc_codec *codec) | |||
576 | CS4271_MODE2_MUTECAEQUB, | 596 | CS4271_MODE2_MUTECAEQUB, |
577 | CS4271_MODE2_MUTECAEQUB); | 597 | CS4271_MODE2_MUTECAEQUB); |
578 | 598 | ||
579 | return snd_soc_add_codec_controls(codec, cs4271_snd_controls, | 599 | return 0; |
580 | ARRAY_SIZE(cs4271_snd_controls)); | ||
581 | } | 600 | } |
582 | 601 | ||
583 | static int cs4271_remove(struct snd_soc_codec *codec) | 602 | static int cs4271_remove(struct snd_soc_codec *codec) |
@@ -596,6 +615,13 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { | |||
596 | .remove = cs4271_remove, | 615 | .remove = cs4271_remove, |
597 | .suspend = cs4271_soc_suspend, | 616 | .suspend = cs4271_soc_suspend, |
598 | .resume = cs4271_soc_resume, | 617 | .resume = cs4271_soc_resume, |
618 | |||
619 | .controls = cs4271_snd_controls, | ||
620 | .num_controls = ARRAY_SIZE(cs4271_snd_controls), | ||
621 | .dapm_widgets = cs4271_dapm_widgets, | ||
622 | .num_dapm_widgets = ARRAY_SIZE(cs4271_dapm_widgets), | ||
623 | .dapm_routes = cs4271_dapm_routes, | ||
624 | .num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes), | ||
599 | }; | 625 | }; |
600 | 626 | ||
601 | #if defined(CONFIG_SPI_MASTER) | 627 | #if defined(CONFIG_SPI_MASTER) |
diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 2bcae2b40c92..68342b121c96 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c | |||
@@ -23,11 +23,20 @@ | |||
23 | 23 | ||
24 | #define DRV_NAME "hdmi-audio-codec" | 24 | #define DRV_NAME "hdmi-audio-codec" |
25 | 25 | ||
26 | static struct snd_soc_codec_driver hdmi_codec; | 26 | static const struct snd_soc_dapm_widget hdmi_widgets[] = { |
27 | SND_SOC_DAPM_INPUT("RX"), | ||
28 | SND_SOC_DAPM_OUTPUT("TX"), | ||
29 | }; | ||
30 | |||
31 | static const struct snd_soc_dapm_route hdmi_routes[] = { | ||
32 | { "Capture", NULL, "RX" }, | ||
33 | { "TX", NULL, "Playback" }, | ||
34 | }; | ||
27 | 35 | ||
28 | static struct snd_soc_dai_driver hdmi_codec_dai = { | 36 | static struct snd_soc_dai_driver hdmi_codec_dai = { |
29 | .name = "hdmi-hifi", | 37 | .name = "hdmi-hifi", |
30 | .playback = { | 38 | .playback = { |
39 | .stream_name = "Playback", | ||
31 | .channels_min = 2, | 40 | .channels_min = 2, |
32 | .channels_max = 8, | 41 | .channels_max = 8, |
33 | .rates = SNDRV_PCM_RATE_32000 | | 42 | .rates = SNDRV_PCM_RATE_32000 | |
@@ -37,6 +46,25 @@ static struct snd_soc_dai_driver hdmi_codec_dai = { | |||
37 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 46 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
38 | SNDRV_PCM_FMTBIT_S24_LE, | 47 | SNDRV_PCM_FMTBIT_S24_LE, |
39 | }, | 48 | }, |
49 | .capture = { | ||
50 | .stream_name = "Capture", | ||
51 | .channels_min = 2, | ||
52 | .channels_max = 2, | ||
53 | .rates = SNDRV_PCM_RATE_32000 | | ||
54 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | ||
55 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | | ||
56 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, | ||
57 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
58 | SNDRV_PCM_FMTBIT_S24_LE, | ||
59 | }, | ||
60 | |||
61 | }; | ||
62 | |||
63 | static struct snd_soc_codec_driver hdmi_codec = { | ||
64 | .dapm_widgets = hdmi_widgets, | ||
65 | .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), | ||
66 | .dapm_routes = hdmi_routes, | ||
67 | .num_dapm_routes = ARRAY_SIZE(hdmi_routes), | ||
40 | }; | 68 | }; |
41 | 69 | ||
42 | static int hdmi_codec_probe(struct platform_device *pdev) | 70 | static int hdmi_codec_probe(struct platform_device *pdev) |
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 9f9f59573f72..0e5743ea79df 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/regmap.h> | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | 21 | ||
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
@@ -23,12 +24,15 @@ | |||
23 | #include <sound/tlv.h> | 24 | #include <sound/tlv.h> |
24 | 25 | ||
25 | struct lm4857 { | 26 | struct lm4857 { |
26 | struct i2c_client *i2c; | 27 | struct regmap *regmap; |
27 | uint8_t mode; | 28 | uint8_t mode; |
28 | }; | 29 | }; |
29 | 30 | ||
30 | static const uint8_t lm4857_default_regs[] = { | 31 | static const struct reg_default lm4857_default_regs[] = { |
31 | 0x00, 0x00, 0x00, 0x00, | 32 | { 0x0, 0x00 }, |
33 | { 0x1, 0x00 }, | ||
34 | { 0x2, 0x00 }, | ||
35 | { 0x3, 0x00 }, | ||
32 | }; | 36 | }; |
33 | 37 | ||
34 | /* The register offsets in the cache array */ | 38 | /* The register offsets in the cache array */ |
@@ -42,39 +46,6 @@ static const uint8_t lm4857_default_regs[] = { | |||
42 | #define LM4857_WAKEUP 5 | 46 | #define LM4857_WAKEUP 5 |
43 | #define LM4857_EPGAIN 4 | 47 | #define LM4857_EPGAIN 4 |
44 | 48 | ||
45 | static int lm4857_write(struct snd_soc_codec *codec, unsigned int reg, | ||
46 | unsigned int value) | ||
47 | { | ||
48 | uint8_t data; | ||
49 | int ret; | ||
50 | |||
51 | ret = snd_soc_cache_write(codec, reg, value); | ||
52 | if (ret < 0) | ||
53 | return ret; | ||
54 | |||
55 | data = (reg << 6) | value; | ||
56 | ret = i2c_master_send(codec->control_data, &data, 1); | ||
57 | if (ret != 1) { | ||
58 | dev_err(codec->dev, "Failed to write register: %d\n", ret); | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static unsigned int lm4857_read(struct snd_soc_codec *codec, | ||
66 | unsigned int reg) | ||
67 | { | ||
68 | unsigned int val; | ||
69 | int ret; | ||
70 | |||
71 | ret = snd_soc_cache_read(codec, reg, &val); | ||
72 | if (ret) | ||
73 | return -1; | ||
74 | |||
75 | return val; | ||
76 | } | ||
77 | |||
78 | static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | 49 | static int lm4857_get_mode(struct snd_kcontrol *kcontrol, |
79 | struct snd_ctl_elem_value *ucontrol) | 50 | struct snd_ctl_elem_value *ucontrol) |
80 | { | 51 | { |
@@ -96,7 +67,7 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | |||
96 | lm4857->mode = value; | 67 | lm4857->mode = value; |
97 | 68 | ||
98 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) | 69 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) |
99 | snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, value + 6); | 70 | regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, value + 6); |
100 | 71 | ||
101 | return 1; | 72 | return 1; |
102 | } | 73 | } |
@@ -108,10 +79,11 @@ static int lm4857_set_bias_level(struct snd_soc_codec *codec, | |||
108 | 79 | ||
109 | switch (level) { | 80 | switch (level) { |
110 | case SND_SOC_BIAS_ON: | 81 | case SND_SOC_BIAS_ON: |
111 | snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, lm4857->mode + 6); | 82 | regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, |
83 | lm4857->mode + 6); | ||
112 | break; | 84 | break; |
113 | case SND_SOC_BIAS_STANDBY: | 85 | case SND_SOC_BIAS_STANDBY: |
114 | snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, 0); | 86 | regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, 0); |
115 | break; | 87 | break; |
116 | default: | 88 | default: |
117 | break; | 89 | break; |
@@ -171,49 +143,32 @@ static const struct snd_soc_dapm_route lm4857_routes[] = { | |||
171 | {"EP", NULL, "IN"}, | 143 | {"EP", NULL, "IN"}, |
172 | }; | 144 | }; |
173 | 145 | ||
174 | static int lm4857_probe(struct snd_soc_codec *codec) | 146 | static struct snd_soc_codec_driver soc_codec_dev_lm4857 = { |
175 | { | 147 | .set_bias_level = lm4857_set_bias_level, |
176 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
177 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
178 | int ret; | ||
179 | |||
180 | codec->control_data = lm4857->i2c; | ||
181 | |||
182 | ret = snd_soc_add_codec_controls(codec, lm4857_controls, | ||
183 | ARRAY_SIZE(lm4857_controls)); | ||
184 | if (ret) | ||
185 | return ret; | ||
186 | |||
187 | ret = snd_soc_dapm_new_controls(dapm, lm4857_dapm_widgets, | ||
188 | ARRAY_SIZE(lm4857_dapm_widgets)); | ||
189 | if (ret) | ||
190 | return ret; | ||
191 | 148 | ||
192 | ret = snd_soc_dapm_add_routes(dapm, lm4857_routes, | 149 | .controls = lm4857_controls, |
193 | ARRAY_SIZE(lm4857_routes)); | 150 | .num_controls = ARRAY_SIZE(lm4857_controls), |
194 | if (ret) | 151 | .dapm_widgets = lm4857_dapm_widgets, |
195 | return ret; | 152 | .num_dapm_widgets = ARRAY_SIZE(lm4857_dapm_widgets), |
153 | .dapm_routes = lm4857_routes, | ||
154 | .num_dapm_routes = ARRAY_SIZE(lm4857_routes), | ||
155 | }; | ||
196 | 156 | ||
197 | snd_soc_dapm_new_widgets(dapm); | 157 | static const struct regmap_config lm4857_regmap_config = { |
158 | .val_bits = 6, | ||
159 | .reg_bits = 2, | ||
198 | 160 | ||
199 | return 0; | 161 | .max_register = LM4857_CTRL, |
200 | } | ||
201 | 162 | ||
202 | static struct snd_soc_codec_driver soc_codec_dev_lm4857 = { | 163 | .cache_type = REGCACHE_FLAT, |
203 | .write = lm4857_write, | 164 | .reg_defaults = lm4857_default_regs, |
204 | .read = lm4857_read, | 165 | .num_reg_defaults = ARRAY_SIZE(lm4857_default_regs), |
205 | .probe = lm4857_probe, | ||
206 | .reg_cache_size = ARRAY_SIZE(lm4857_default_regs), | ||
207 | .reg_word_size = sizeof(uint8_t), | ||
208 | .reg_cache_default = lm4857_default_regs, | ||
209 | .set_bias_level = lm4857_set_bias_level, | ||
210 | }; | 166 | }; |
211 | 167 | ||
212 | static int lm4857_i2c_probe(struct i2c_client *i2c, | 168 | static int lm4857_i2c_probe(struct i2c_client *i2c, |
213 | const struct i2c_device_id *id) | 169 | const struct i2c_device_id *id) |
214 | { | 170 | { |
215 | struct lm4857 *lm4857; | 171 | struct lm4857 *lm4857; |
216 | int ret; | ||
217 | 172 | ||
218 | lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL); | 173 | lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL); |
219 | if (!lm4857) | 174 | if (!lm4857) |
@@ -221,11 +176,11 @@ static int lm4857_i2c_probe(struct i2c_client *i2c, | |||
221 | 176 | ||
222 | i2c_set_clientdata(i2c, lm4857); | 177 | i2c_set_clientdata(i2c, lm4857); |
223 | 178 | ||
224 | lm4857->i2c = i2c; | 179 | lm4857->regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config); |
225 | 180 | if (IS_ERR(lm4857->regmap)) | |
226 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0); | 181 | return PTR_ERR(lm4857->regmap); |
227 | 182 | ||
228 | return ret; | 183 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0); |
229 | } | 184 | } |
230 | 185 | ||
231 | static int lm4857_i2c_remove(struct i2c_client *i2c) | 186 | static int lm4857_i2c_remove(struct i2c_client *i2c) |
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index a6ac2313047d..31f91560e9f6 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c | |||
@@ -118,6 +118,18 @@ static const struct snd_kcontrol_new max9768_mute[] = { | |||
118 | SOC_SINGLE_BOOL_EXT("Playback Switch", 0, max9768_get_gpio, max9768_set_gpio), | 118 | SOC_SINGLE_BOOL_EXT("Playback Switch", 0, max9768_get_gpio, max9768_set_gpio), |
119 | }; | 119 | }; |
120 | 120 | ||
121 | static const struct snd_soc_dapm_widget max9768_dapm_widgets[] = { | ||
122 | SND_SOC_DAPM_INPUT("IN"), | ||
123 | |||
124 | SND_SOC_DAPM_OUTPUT("OUT+"), | ||
125 | SND_SOC_DAPM_OUTPUT("OUT-"), | ||
126 | }; | ||
127 | |||
128 | static const struct snd_soc_dapm_route max9768_dapm_routes[] = { | ||
129 | { "OUT+", NULL, "IN" }, | ||
130 | { "OUT-", NULL, "IN" }, | ||
131 | }; | ||
132 | |||
121 | static int max9768_probe(struct snd_soc_codec *codec) | 133 | static int max9768_probe(struct snd_soc_codec *codec) |
122 | { | 134 | { |
123 | struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); | 135 | struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); |
@@ -148,6 +160,10 @@ static struct snd_soc_codec_driver max9768_codec_driver = { | |||
148 | .probe = max9768_probe, | 160 | .probe = max9768_probe, |
149 | .controls = max9768_volume, | 161 | .controls = max9768_volume, |
150 | .num_controls = ARRAY_SIZE(max9768_volume), | 162 | .num_controls = ARRAY_SIZE(max9768_volume), |
163 | .dapm_widgets = max9768_dapm_widgets, | ||
164 | .num_dapm_widgets = ARRAY_SIZE(max9768_dapm_widgets), | ||
165 | .dapm_routes = max9768_dapm_routes, | ||
166 | .num_dapm_routes = ARRAY_SIZE(max9768_dapm_routes), | ||
151 | }; | 167 | }; |
152 | 168 | ||
153 | static const struct regmap_config max9768_i2c_regmap_config = { | 169 | static const struct regmap_config max9768_i2c_regmap_config = { |
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index ad5313f98f28..0569a4c3ae00 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
@@ -2084,8 +2084,9 @@ static irqreturn_t max98090_interrupt(int irq, void *data) | |||
2084 | 2084 | ||
2085 | pm_wakeup_event(codec->dev, 100); | 2085 | pm_wakeup_event(codec->dev, 100); |
2086 | 2086 | ||
2087 | schedule_delayed_work(&max98090->jack_work, | 2087 | queue_delayed_work(system_power_efficient_wq, |
2088 | msecs_to_jiffies(100)); | 2088 | &max98090->jack_work, |
2089 | msecs_to_jiffies(100)); | ||
2089 | } | 2090 | } |
2090 | 2091 | ||
2091 | if (active & M98090_DRCACT_MASK) | 2092 | if (active & M98090_DRCACT_MASK) |
@@ -2132,8 +2133,9 @@ int max98090_mic_detect(struct snd_soc_codec *codec, | |||
2132 | snd_soc_jack_report(max98090->jack, 0, | 2133 | snd_soc_jack_report(max98090->jack, 0, |
2133 | SND_JACK_HEADSET | SND_JACK_BTN_0); | 2134 | SND_JACK_HEADSET | SND_JACK_BTN_0); |
2134 | 2135 | ||
2135 | schedule_delayed_work(&max98090->jack_work, | 2136 | queue_delayed_work(system_power_efficient_wq, |
2136 | msecs_to_jiffies(100)); | 2137 | &max98090->jack_work, |
2138 | msecs_to_jiffies(100)); | ||
2137 | 2139 | ||
2138 | return 0; | 2140 | return 0; |
2139 | } | 2141 | } |
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 6b6c74cd83e2..29549cdbf4c1 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c | |||
@@ -14,170 +14,21 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
17 | #include <linux/regmap.h> | ||
17 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
18 | #include <sound/tlv.h> | 19 | #include <sound/tlv.h> |
19 | 20 | ||
20 | #include "max9877.h" | 21 | #include "max9877.h" |
21 | 22 | ||
22 | static struct i2c_client *i2c; | 23 | static struct regmap *regmap; |
23 | 24 | ||
24 | static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 }; | 25 | static struct reg_default max9877_regs[] = { |
25 | 26 | { 0, 0x40 }, | |
26 | static void max9877_write_regs(void) | 27 | { 1, 0x00 }, |
27 | { | 28 | { 2, 0x00 }, |
28 | unsigned int i; | 29 | { 3, 0x00 }, |
29 | u8 data[6]; | 30 | { 4, 0x49 }, |
30 | 31 | }; | |
31 | data[0] = MAX9877_INPUT_MODE; | ||
32 | for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) | ||
33 | data[i + 1] = max9877_regs[i]; | ||
34 | |||
35 | if (i2c_master_send(i2c, data, 6) != 6) | ||
36 | dev_err(&i2c->dev, "i2c write failed\n"); | ||
37 | } | ||
38 | |||
39 | static int max9877_get_reg(struct snd_kcontrol *kcontrol, | ||
40 | struct snd_ctl_elem_value *ucontrol) | ||
41 | { | ||
42 | struct soc_mixer_control *mc = | ||
43 | (struct soc_mixer_control *)kcontrol->private_value; | ||
44 | unsigned int reg = mc->reg; | ||
45 | unsigned int shift = mc->shift; | ||
46 | unsigned int mask = mc->max; | ||
47 | unsigned int invert = mc->invert; | ||
48 | |||
49 | ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask; | ||
50 | |||
51 | if (invert) | ||
52 | ucontrol->value.integer.value[0] = | ||
53 | mask - ucontrol->value.integer.value[0]; | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int max9877_set_reg(struct snd_kcontrol *kcontrol, | ||
59 | struct snd_ctl_elem_value *ucontrol) | ||
60 | { | ||
61 | struct soc_mixer_control *mc = | ||
62 | (struct soc_mixer_control *)kcontrol->private_value; | ||
63 | unsigned int reg = mc->reg; | ||
64 | unsigned int shift = mc->shift; | ||
65 | unsigned int mask = mc->max; | ||
66 | unsigned int invert = mc->invert; | ||
67 | unsigned int val = (ucontrol->value.integer.value[0] & mask); | ||
68 | |||
69 | if (invert) | ||
70 | val = mask - val; | ||
71 | |||
72 | if (((max9877_regs[reg] >> shift) & mask) == val) | ||
73 | return 0; | ||
74 | |||
75 | max9877_regs[reg] &= ~(mask << shift); | ||
76 | max9877_regs[reg] |= val << shift; | ||
77 | max9877_write_regs(); | ||
78 | |||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | static int max9877_get_2reg(struct snd_kcontrol *kcontrol, | ||
83 | struct snd_ctl_elem_value *ucontrol) | ||
84 | { | ||
85 | struct soc_mixer_control *mc = | ||
86 | (struct soc_mixer_control *)kcontrol->private_value; | ||
87 | unsigned int reg = mc->reg; | ||
88 | unsigned int reg2 = mc->rreg; | ||
89 | unsigned int shift = mc->shift; | ||
90 | unsigned int mask = mc->max; | ||
91 | |||
92 | ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask; | ||
93 | ucontrol->value.integer.value[1] = (max9877_regs[reg2] >> shift) & mask; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int max9877_set_2reg(struct snd_kcontrol *kcontrol, | ||
99 | struct snd_ctl_elem_value *ucontrol) | ||
100 | { | ||
101 | struct soc_mixer_control *mc = | ||
102 | (struct soc_mixer_control *)kcontrol->private_value; | ||
103 | unsigned int reg = mc->reg; | ||
104 | unsigned int reg2 = mc->rreg; | ||
105 | unsigned int shift = mc->shift; | ||
106 | unsigned int mask = mc->max; | ||
107 | unsigned int val = (ucontrol->value.integer.value[0] & mask); | ||
108 | unsigned int val2 = (ucontrol->value.integer.value[1] & mask); | ||
109 | unsigned int change = 0; | ||
110 | |||
111 | if (((max9877_regs[reg] >> shift) & mask) != val) | ||
112 | change = 1; | ||
113 | |||
114 | if (((max9877_regs[reg2] >> shift) & mask) != val2) | ||
115 | change = 1; | ||
116 | |||
117 | if (change) { | ||
118 | max9877_regs[reg] &= ~(mask << shift); | ||
119 | max9877_regs[reg] |= val << shift; | ||
120 | max9877_regs[reg2] &= ~(mask << shift); | ||
121 | max9877_regs[reg2] |= val2 << shift; | ||
122 | max9877_write_regs(); | ||
123 | } | ||
124 | |||
125 | return change; | ||
126 | } | ||
127 | |||
128 | static int max9877_get_out_mode(struct snd_kcontrol *kcontrol, | ||
129 | struct snd_ctl_elem_value *ucontrol) | ||
130 | { | ||
131 | u8 value = max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK; | ||
132 | |||
133 | if (value) | ||
134 | value -= 1; | ||
135 | |||
136 | ucontrol->value.integer.value[0] = value; | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int max9877_set_out_mode(struct snd_kcontrol *kcontrol, | ||
141 | struct snd_ctl_elem_value *ucontrol) | ||
142 | { | ||
143 | u8 value = ucontrol->value.integer.value[0]; | ||
144 | |||
145 | value += 1; | ||
146 | |||
147 | if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK) == value) | ||
148 | return 0; | ||
149 | |||
150 | max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OUTMODE_MASK; | ||
151 | max9877_regs[MAX9877_OUTPUT_MODE] |= value; | ||
152 | max9877_write_regs(); | ||
153 | return 1; | ||
154 | } | ||
155 | |||
156 | static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol, | ||
157 | struct snd_ctl_elem_value *ucontrol) | ||
158 | { | ||
159 | u8 value = (max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK); | ||
160 | |||
161 | value = value >> MAX9877_OSC_OFFSET; | ||
162 | |||
163 | ucontrol->value.integer.value[0] = value; | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol, | ||
168 | struct snd_ctl_elem_value *ucontrol) | ||
169 | { | ||
170 | u8 value = ucontrol->value.integer.value[0]; | ||
171 | |||
172 | value = value << MAX9877_OSC_OFFSET; | ||
173 | if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK) == value) | ||
174 | return 0; | ||
175 | |||
176 | max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OSC_MASK; | ||
177 | max9877_regs[MAX9877_OUTPUT_MODE] |= value; | ||
178 | max9877_write_regs(); | ||
179 | return 1; | ||
180 | } | ||
181 | 32 | ||
182 | static const unsigned int max9877_pgain_tlv[] = { | 33 | static const unsigned int max9877_pgain_tlv[] = { |
183 | TLV_DB_RANGE_HEAD(2), | 34 | TLV_DB_RANGE_HEAD(2), |
@@ -212,65 +63,104 @@ static const char *max9877_osc_mode[] = { | |||
212 | }; | 63 | }; |
213 | 64 | ||
214 | static const struct soc_enum max9877_enum[] = { | 65 | static const struct soc_enum max9877_enum[] = { |
215 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode), | 66 | SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, 0, ARRAY_SIZE(max9877_out_mode), |
216 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode), | 67 | max9877_out_mode), |
68 | SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, MAX9877_OSC_OFFSET, | ||
69 | ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode), | ||
217 | }; | 70 | }; |
218 | 71 | ||
219 | static const struct snd_kcontrol_new max9877_controls[] = { | 72 | static const struct snd_kcontrol_new max9877_controls[] = { |
220 | SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume", | 73 | SOC_SINGLE_TLV("MAX9877 PGAINA Playback Volume", |
221 | MAX9877_INPUT_MODE, 0, 2, 0, | 74 | MAX9877_INPUT_MODE, 0, 2, 0, max9877_pgain_tlv), |
222 | max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), | 75 | SOC_SINGLE_TLV("MAX9877 PGAINB Playback Volume", |
223 | SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume", | 76 | MAX9877_INPUT_MODE, 2, 2, 0, max9877_pgain_tlv), |
224 | MAX9877_INPUT_MODE, 2, 2, 0, | 77 | SOC_SINGLE_TLV("MAX9877 Amp Speaker Playback Volume", |
225 | max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), | 78 | MAX9877_SPK_VOLUME, 0, 31, 0, max9877_output_tlv), |
226 | SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume", | 79 | SOC_DOUBLE_R_TLV("MAX9877 Amp HP Playback Volume", |
227 | MAX9877_SPK_VOLUME, 0, 31, 0, | 80 | MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, |
228 | max9877_get_reg, max9877_set_reg, max9877_output_tlv), | 81 | max9877_output_tlv), |
229 | SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume", | 82 | SOC_SINGLE("MAX9877 INB Stereo Switch", |
230 | MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, | 83 | MAX9877_INPUT_MODE, 4, 1, 1), |
231 | max9877_get_2reg, max9877_set_2reg, max9877_output_tlv), | 84 | SOC_SINGLE("MAX9877 INA Stereo Switch", |
232 | SOC_SINGLE_EXT("MAX9877 INB Stereo Switch", | 85 | MAX9877_INPUT_MODE, 5, 1, 1), |
233 | MAX9877_INPUT_MODE, 4, 1, 1, | 86 | SOC_SINGLE("MAX9877 Zero-crossing detection Switch", |
234 | max9877_get_reg, max9877_set_reg), | 87 | MAX9877_INPUT_MODE, 6, 1, 0), |
235 | SOC_SINGLE_EXT("MAX9877 INA Stereo Switch", | 88 | SOC_SINGLE("MAX9877 Bypass Mode Switch", |
236 | MAX9877_INPUT_MODE, 5, 1, 1, | 89 | MAX9877_OUTPUT_MODE, 6, 1, 0), |
237 | max9877_get_reg, max9877_set_reg), | 90 | SOC_ENUM("MAX9877 Output Mode", max9877_enum[0]), |
238 | SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch", | 91 | SOC_ENUM("MAX9877 Oscillator Mode", max9877_enum[1]), |
239 | MAX9877_INPUT_MODE, 6, 1, 0, | ||
240 | max9877_get_reg, max9877_set_reg), | ||
241 | SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch", | ||
242 | MAX9877_OUTPUT_MODE, 6, 1, 0, | ||
243 | max9877_get_reg, max9877_set_reg), | ||
244 | SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch", | ||
245 | MAX9877_OUTPUT_MODE, 7, 1, 1, | ||
246 | max9877_get_reg, max9877_set_reg), | ||
247 | SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0], | ||
248 | max9877_get_out_mode, max9877_set_out_mode), | ||
249 | SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1], | ||
250 | max9877_get_osc_mode, max9877_set_osc_mode), | ||
251 | }; | 92 | }; |
252 | 93 | ||
253 | /* This function is called from ASoC machine driver */ | 94 | static const struct snd_soc_dapm_widget max9877_dapm_widgets[] = { |
254 | int max9877_add_controls(struct snd_soc_codec *codec) | 95 | SND_SOC_DAPM_INPUT("INA1"), |
255 | { | 96 | SND_SOC_DAPM_INPUT("INA2"), |
256 | return snd_soc_add_codec_controls(codec, max9877_controls, | 97 | SND_SOC_DAPM_INPUT("INB1"), |
257 | ARRAY_SIZE(max9877_controls)); | 98 | SND_SOC_DAPM_INPUT("INB2"), |
258 | } | 99 | SND_SOC_DAPM_INPUT("RXIN+"), |
259 | EXPORT_SYMBOL_GPL(max9877_add_controls); | 100 | SND_SOC_DAPM_INPUT("RXIN-"), |
101 | |||
102 | SND_SOC_DAPM_PGA("SHDN", MAX9877_OUTPUT_MODE, 7, 1, NULL, 0), | ||
103 | |||
104 | SND_SOC_DAPM_OUTPUT("OUT+"), | ||
105 | SND_SOC_DAPM_OUTPUT("OUT-"), | ||
106 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
107 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
108 | }; | ||
109 | |||
110 | static const struct snd_soc_dapm_route max9877_dapm_routes[] = { | ||
111 | { "SHDN", NULL, "INA1" }, | ||
112 | { "SHDN", NULL, "INA2" }, | ||
113 | { "SHDN", NULL, "INB1" }, | ||
114 | { "SHDN", NULL, "INB2" }, | ||
115 | |||
116 | { "OUT+", NULL, "RXIN+" }, | ||
117 | { "OUT+", NULL, "SHDN" }, | ||
118 | |||
119 | { "OUT-", NULL, "SHDN" }, | ||
120 | { "OUT-", NULL, "RXIN-" }, | ||
121 | |||
122 | { "HPL", NULL, "SHDN" }, | ||
123 | { "HPR", NULL, "SHDN" }, | ||
124 | }; | ||
125 | |||
126 | static const struct snd_soc_codec_driver max9877_codec = { | ||
127 | .controls = max9877_controls, | ||
128 | .num_controls = ARRAY_SIZE(max9877_controls), | ||
129 | |||
130 | .dapm_widgets = max9877_dapm_widgets, | ||
131 | .num_dapm_widgets = ARRAY_SIZE(max9877_dapm_widgets), | ||
132 | .dapm_routes = max9877_dapm_routes, | ||
133 | .num_dapm_routes = ARRAY_SIZE(max9877_dapm_routes), | ||
134 | }; | ||
135 | |||
136 | static const struct regmap_config max9877_regmap = { | ||
137 | .reg_bits = 8, | ||
138 | .val_bits = 8, | ||
139 | |||
140 | .reg_defaults = max9877_regs, | ||
141 | .num_reg_defaults = ARRAY_SIZE(max9877_regs), | ||
142 | .cache_type = REGCACHE_RBTREE, | ||
143 | }; | ||
260 | 144 | ||
261 | static int max9877_i2c_probe(struct i2c_client *client, | 145 | static int max9877_i2c_probe(struct i2c_client *client, |
262 | const struct i2c_device_id *id) | 146 | const struct i2c_device_id *id) |
263 | { | 147 | { |
264 | i2c = client; | 148 | int i; |
265 | 149 | ||
266 | max9877_write_regs(); | 150 | regmap = devm_regmap_init_i2c(client, &max9877_regmap); |
151 | if (IS_ERR(regmap)) | ||
152 | return PTR_ERR(regmap); | ||
267 | 153 | ||
268 | return 0; | 154 | /* Ensure the device is in reset state */ |
155 | for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) | ||
156 | regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def); | ||
157 | |||
158 | return snd_soc_register_codec(&client->dev, &max9877_codec, NULL, 0); | ||
269 | } | 159 | } |
270 | 160 | ||
271 | static int max9877_i2c_remove(struct i2c_client *client) | 161 | static int max9877_i2c_remove(struct i2c_client *client) |
272 | { | 162 | { |
273 | i2c = NULL; | 163 | snd_soc_unregister_codec(&client->dev); |
274 | 164 | ||
275 | return 0; | 165 | return 0; |
276 | } | 166 | } |
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 5402dfbbb716..4d3c8fd8c5db 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c | |||
@@ -94,7 +94,6 @@ | |||
94 | #define AUDIO_DAC_CFS_DLY_B (1 << 10) | 94 | #define AUDIO_DAC_CFS_DLY_B (1 << 10) |
95 | 95 | ||
96 | struct mc13783_priv { | 96 | struct mc13783_priv { |
97 | struct snd_soc_codec codec; | ||
98 | struct mc13xxx *mc13xxx; | 97 | struct mc13xxx *mc13xxx; |
99 | 98 | ||
100 | enum mc13783_ssi_port adc_ssi_port; | 99 | enum mc13783_ssi_port adc_ssi_port; |
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c new file mode 100644 index 000000000000..651ce0923675 --- /dev/null +++ b/sound/soc/codecs/pcm1681.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* | ||
2 | * PCM1681 ASoC codec driver | ||
3 | * | ||
4 | * Copyright (c) StreamUnlimited GmbH 2013 | ||
5 | * Marek Belisko <marek.belisko@streamunlimited.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2 | ||
10 | * of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/i2c.h> | ||
23 | #include <linux/regmap.h> | ||
24 | #include <linux/of_device.h> | ||
25 | #include <linux/of_gpio.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/tlv.h> | ||
30 | |||
31 | #define PCM1681_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
32 | SNDRV_PCM_FMTBIT_S24_LE) | ||
33 | |||
34 | #define PCM1681_PCM_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ | ||
35 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
36 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ | ||
37 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) | ||
38 | |||
39 | #define PCM1681_SOFT_MUTE_ALL 0xff | ||
40 | #define PCM1681_DEEMPH_RATE_MASK 0x18 | ||
41 | #define PCM1681_DEEMPH_MASK 0x01 | ||
42 | |||
43 | #define PCM1681_ATT_CONTROL(X) (X <= 6 ? X : X + 9) /* Attenuation level */ | ||
44 | #define PCM1681_SOFT_MUTE 0x07 /* Soft mute control register */ | ||
45 | #define PCM1681_DAC_CONTROL 0x08 /* DAC operation control */ | ||
46 | #define PCM1681_FMT_CONTROL 0x09 /* Audio interface data format */ | ||
47 | #define PCM1681_DEEMPH_CONTROL 0x0a /* De-emphasis control */ | ||
48 | #define PCM1681_ZERO_DETECT_STATUS 0x0e /* Zero detect status reg */ | ||
49 | |||
50 | static const struct reg_default pcm1681_reg_defaults[] = { | ||
51 | { 0x01, 0xff }, | ||
52 | { 0x02, 0xff }, | ||
53 | { 0x03, 0xff }, | ||
54 | { 0x04, 0xff }, | ||
55 | { 0x05, 0xff }, | ||
56 | { 0x06, 0xff }, | ||
57 | { 0x07, 0x00 }, | ||
58 | { 0x08, 0x00 }, | ||
59 | { 0x09, 0x06 }, | ||
60 | { 0x0A, 0x00 }, | ||
61 | { 0x0B, 0xff }, | ||
62 | { 0x0C, 0x0f }, | ||
63 | { 0x0D, 0x00 }, | ||
64 | { 0x10, 0xff }, | ||
65 | { 0x11, 0xff }, | ||
66 | { 0x12, 0x00 }, | ||
67 | { 0x13, 0x00 }, | ||
68 | }; | ||
69 | |||
70 | static bool pcm1681_accessible_reg(struct device *dev, unsigned int reg) | ||
71 | { | ||
72 | return !((reg == 0x00) || (reg == 0x0f)); | ||
73 | } | ||
74 | |||
75 | static bool pcm1681_writeable_reg(struct device *dev, unsigned register reg) | ||
76 | { | ||
77 | return pcm1681_accessible_reg(dev, reg) && | ||
78 | (reg != PCM1681_ZERO_DETECT_STATUS); | ||
79 | } | ||
80 | |||
81 | struct pcm1681_private { | ||
82 | struct regmap *regmap; | ||
83 | unsigned int format; | ||
84 | /* Current deemphasis status */ | ||
85 | unsigned int deemph; | ||
86 | /* Current rate for deemphasis control */ | ||
87 | unsigned int rate; | ||
88 | }; | ||
89 | |||
90 | static const int pcm1681_deemph[] = { 44100, 48000, 32000 }; | ||
91 | |||
92 | static int pcm1681_set_deemph(struct snd_soc_codec *codec) | ||
93 | { | ||
94 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); | ||
95 | int i = 0, val = -1, enable = 0; | ||
96 | |||
97 | if (priv->deemph) | ||
98 | for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) | ||
99 | if (pcm1681_deemph[i] == priv->rate) | ||
100 | val = i; | ||
101 | |||
102 | if (val != -1) { | ||
103 | regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, | ||
104 | PCM1681_DEEMPH_RATE_MASK, val); | ||
105 | enable = 1; | ||
106 | } else | ||
107 | enable = 0; | ||
108 | |||
109 | /* enable/disable deemphasis functionality */ | ||
110 | return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, | ||
111 | PCM1681_DEEMPH_MASK, enable); | ||
112 | } | ||
113 | |||
114 | static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol, | ||
115 | struct snd_ctl_elem_value *ucontrol) | ||
116 | { | ||
117 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
118 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); | ||
119 | |||
120 | ucontrol->value.enumerated.item[0] = priv->deemph; | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol, | ||
126 | struct snd_ctl_elem_value *ucontrol) | ||
127 | { | ||
128 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
129 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); | ||
130 | |||
131 | priv->deemph = ucontrol->value.enumerated.item[0]; | ||
132 | |||
133 | return pcm1681_set_deemph(codec); | ||
134 | } | ||
135 | |||
136 | static int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
137 | unsigned int format) | ||
138 | { | ||
139 | struct snd_soc_codec *codec = codec_dai->codec; | ||
140 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); | ||
141 | |||
142 | /* The PCM1681 can only be slave to all clocks */ | ||
143 | if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { | ||
144 | dev_err(codec->dev, "Invalid clocking mode\n"); | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | |||
148 | priv->format = format; | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int pcm1681_digital_mute(struct snd_soc_dai *dai, int mute) | ||
154 | { | ||
155 | struct snd_soc_codec *codec = dai->codec; | ||
156 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); | ||
157 | int val; | ||
158 | |||
159 | if (mute) | ||
160 | val = PCM1681_SOFT_MUTE_ALL; | ||
161 | else | ||
162 | val = 0; | ||
163 | |||
164 | return regmap_write(priv->regmap, PCM1681_SOFT_MUTE, val); | ||
165 | } | ||
166 | |||
167 | static int pcm1681_hw_params(struct snd_pcm_substream *substream, | ||
168 | struct snd_pcm_hw_params *params, | ||
169 | struct snd_soc_dai *dai) | ||
170 | { | ||
171 | struct snd_soc_codec *codec = dai->codec; | ||
172 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); | ||
173 | int val = 0, ret; | ||
174 | int pcm_format = params_format(params); | ||
175 | |||
176 | priv->rate = params_rate(params); | ||
177 | |||
178 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
179 | case SND_SOC_DAIFMT_RIGHT_J: | ||
180 | if (pcm_format == SNDRV_PCM_FORMAT_S24_LE) | ||
181 | val = 0x00; | ||
182 | else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) | ||
183 | val = 0x03; | ||
184 | break; | ||
185 | case SND_SOC_DAIFMT_I2S: | ||
186 | val = 0x04; | ||
187 | break; | ||
188 | case SND_SOC_DAIFMT_LEFT_J: | ||
189 | val = 0x05; | ||
190 | break; | ||
191 | default: | ||
192 | dev_err(codec->dev, "Invalid DAI format\n"); | ||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | ret = regmap_update_bits(priv->regmap, PCM1681_FMT_CONTROL, 0x0f, val); | ||
197 | if (ret < 0) | ||
198 | return ret; | ||
199 | |||
200 | return pcm1681_set_deemph(codec); | ||
201 | } | ||
202 | |||
203 | static const struct snd_soc_dai_ops pcm1681_dai_ops = { | ||
204 | .set_fmt = pcm1681_set_dai_fmt, | ||
205 | .hw_params = pcm1681_hw_params, | ||
206 | .digital_mute = pcm1681_digital_mute, | ||
207 | }; | ||
208 | |||
209 | static const struct snd_soc_dapm_widget pcm1681_dapm_widgets[] = { | ||
210 | SND_SOC_DAPM_OUTPUT("VOUT1"), | ||
211 | SND_SOC_DAPM_OUTPUT("VOUT2"), | ||
212 | SND_SOC_DAPM_OUTPUT("VOUT3"), | ||
213 | SND_SOC_DAPM_OUTPUT("VOUT4"), | ||
214 | SND_SOC_DAPM_OUTPUT("VOUT5"), | ||
215 | SND_SOC_DAPM_OUTPUT("VOUT6"), | ||
216 | SND_SOC_DAPM_OUTPUT("VOUT7"), | ||
217 | SND_SOC_DAPM_OUTPUT("VOUT8"), | ||
218 | }; | ||
219 | |||
220 | static const struct snd_soc_dapm_route pcm1681_dapm_routes[] = { | ||
221 | { "VOUT1", NULL, "Playback" }, | ||
222 | { "VOUT2", NULL, "Playback" }, | ||
223 | { "VOUT3", NULL, "Playback" }, | ||
224 | { "VOUT4", NULL, "Playback" }, | ||
225 | { "VOUT5", NULL, "Playback" }, | ||
226 | { "VOUT6", NULL, "Playback" }, | ||
227 | { "VOUT7", NULL, "Playback" }, | ||
228 | { "VOUT8", NULL, "Playback" }, | ||
229 | }; | ||
230 | |||
231 | static const DECLARE_TLV_DB_SCALE(pcm1681_dac_tlv, -6350, 50, 1); | ||
232 | |||
233 | static const struct snd_kcontrol_new pcm1681_controls[] = { | ||
234 | SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume", | ||
235 | PCM1681_ATT_CONTROL(1), PCM1681_ATT_CONTROL(2), 0, | ||
236 | 0x7f, 0, pcm1681_dac_tlv), | ||
237 | SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume", | ||
238 | PCM1681_ATT_CONTROL(3), PCM1681_ATT_CONTROL(4), 0, | ||
239 | 0x7f, 0, pcm1681_dac_tlv), | ||
240 | SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume", | ||
241 | PCM1681_ATT_CONTROL(5), PCM1681_ATT_CONTROL(6), 0, | ||
242 | 0x7f, 0, pcm1681_dac_tlv), | ||
243 | SOC_DOUBLE_R_TLV("Channel 7/8 Playback Volume", | ||
244 | PCM1681_ATT_CONTROL(7), PCM1681_ATT_CONTROL(8), 0, | ||
245 | 0x7f, 0, pcm1681_dac_tlv), | ||
246 | SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0, | ||
247 | pcm1681_get_deemph, pcm1681_put_deemph), | ||
248 | }; | ||
249 | |||
250 | static struct snd_soc_dai_driver pcm1681_dai = { | ||
251 | .name = "pcm1681-hifi", | ||
252 | .playback = { | ||
253 | .stream_name = "Playback", | ||
254 | .channels_min = 2, | ||
255 | .channels_max = 8, | ||
256 | .rates = PCM1681_PCM_RATES, | ||
257 | .formats = PCM1681_PCM_FORMATS, | ||
258 | }, | ||
259 | .ops = &pcm1681_dai_ops, | ||
260 | }; | ||
261 | |||
262 | #ifdef CONFIG_OF | ||
263 | static const struct of_device_id pcm1681_dt_ids[] = { | ||
264 | { .compatible = "ti,pcm1681", }, | ||
265 | { } | ||
266 | }; | ||
267 | MODULE_DEVICE_TABLE(of, pcm1681_dt_ids); | ||
268 | #endif | ||
269 | |||
270 | static const struct regmap_config pcm1681_regmap = { | ||
271 | .reg_bits = 8, | ||
272 | .val_bits = 8, | ||
273 | .max_register = ARRAY_SIZE(pcm1681_reg_defaults) + 1, | ||
274 | .reg_defaults = pcm1681_reg_defaults, | ||
275 | .num_reg_defaults = ARRAY_SIZE(pcm1681_reg_defaults), | ||
276 | .writeable_reg = pcm1681_writeable_reg, | ||
277 | .readable_reg = pcm1681_accessible_reg, | ||
278 | }; | ||
279 | |||
280 | static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = { | ||
281 | .controls = pcm1681_controls, | ||
282 | .num_controls = ARRAY_SIZE(pcm1681_controls), | ||
283 | .dapm_widgets = pcm1681_dapm_widgets, | ||
284 | .num_dapm_widgets = ARRAY_SIZE(pcm1681_dapm_widgets), | ||
285 | .dapm_routes = pcm1681_dapm_routes, | ||
286 | .num_dapm_routes = ARRAY_SIZE(pcm1681_dapm_routes), | ||
287 | }; | ||
288 | |||
289 | static const struct i2c_device_id pcm1681_i2c_id[] = { | ||
290 | {"pcm1681", 0}, | ||
291 | {} | ||
292 | }; | ||
293 | MODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id); | ||
294 | |||
295 | static int pcm1681_i2c_probe(struct i2c_client *client, | ||
296 | const struct i2c_device_id *id) | ||
297 | { | ||
298 | int ret; | ||
299 | struct pcm1681_private *priv; | ||
300 | |||
301 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); | ||
302 | if (!priv) | ||
303 | return -ENOMEM; | ||
304 | |||
305 | priv->regmap = devm_regmap_init_i2c(client, &pcm1681_regmap); | ||
306 | if (IS_ERR(priv->regmap)) { | ||
307 | ret = PTR_ERR(priv->regmap); | ||
308 | dev_err(&client->dev, "Failed to create regmap: %d\n", ret); | ||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | i2c_set_clientdata(client, priv); | ||
313 | |||
314 | return snd_soc_register_codec(&client->dev, &soc_codec_dev_pcm1681, | ||
315 | &pcm1681_dai, 1); | ||
316 | } | ||
317 | |||
318 | static int pcm1681_i2c_remove(struct i2c_client *client) | ||
319 | { | ||
320 | snd_soc_unregister_codec(&client->dev); | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static struct i2c_driver pcm1681_i2c_driver = { | ||
325 | .driver = { | ||
326 | .name = "pcm1681", | ||
327 | .owner = THIS_MODULE, | ||
328 | .of_match_table = of_match_ptr(pcm1681_dt_ids), | ||
329 | }, | ||
330 | .id_table = pcm1681_i2c_id, | ||
331 | .probe = pcm1681_i2c_probe, | ||
332 | .remove = pcm1681_i2c_remove, | ||
333 | }; | ||
334 | |||
335 | module_i2c_driver(pcm1681_i2c_driver); | ||
336 | |||
337 | MODULE_DESCRIPTION("Texas Instruments PCM1681 ALSA SoC Codec Driver"); | ||
338 | MODULE_AUTHOR("Marek Belisko <marek.belisko@streamunlimited.com>"); | ||
339 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c new file mode 100644 index 000000000000..2a8eccf64c76 --- /dev/null +++ b/sound/soc/codecs/pcm1792a.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
2 | * PCM1792A ASoC codec driver | ||
3 | * | ||
4 | * Copyright (c) Amarula Solutions B.V. 2013 | ||
5 | * | ||
6 | * Michael Trimarchi <michael@amarulasolutions.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/spi/spi.h> | ||
24 | |||
25 | #include <sound/core.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/initval.h> | ||
29 | #include <sound/soc.h> | ||
30 | #include <sound/tlv.h> | ||
31 | #include <linux/of_device.h> | ||
32 | |||
33 | #include "pcm1792a.h" | ||
34 | |||
35 | #define PCM1792A_DAC_VOL_LEFT 0x10 | ||
36 | #define PCM1792A_DAC_VOL_RIGHT 0x11 | ||
37 | #define PCM1792A_FMT_CONTROL 0x12 | ||
38 | #define PCM1792A_SOFT_MUTE PCM1792A_FMT_CONTROL | ||
39 | |||
40 | #define PCM1792A_FMT_MASK 0x70 | ||
41 | #define PCM1792A_FMT_SHIFT 4 | ||
42 | #define PCM1792A_MUTE_MASK 0x01 | ||
43 | #define PCM1792A_MUTE_SHIFT 0 | ||
44 | #define PCM1792A_ATLD_ENABLE (1 << 7) | ||
45 | |||
46 | static const struct reg_default pcm1792a_reg_defaults[] = { | ||
47 | { 0x10, 0xff }, | ||
48 | { 0x11, 0xff }, | ||
49 | { 0x12, 0x50 }, | ||
50 | { 0x13, 0x00 }, | ||
51 | { 0x14, 0x00 }, | ||
52 | { 0x15, 0x01 }, | ||
53 | { 0x16, 0x00 }, | ||
54 | { 0x17, 0x00 }, | ||
55 | }; | ||
56 | |||
57 | static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg) | ||
58 | { | ||
59 | return reg >= 0x10 && reg <= 0x17; | ||
60 | } | ||
61 | |||
62 | static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg) | ||
63 | { | ||
64 | bool accessible; | ||
65 | |||
66 | accessible = pcm1792a_accessible_reg(dev, reg); | ||
67 | |||
68 | return accessible && reg != 0x16 && reg != 0x17; | ||
69 | } | ||
70 | |||
71 | struct pcm1792a_private { | ||
72 | struct regmap *regmap; | ||
73 | unsigned int format; | ||
74 | unsigned int rate; | ||
75 | }; | ||
76 | |||
77 | static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
78 | unsigned int format) | ||
79 | { | ||
80 | struct snd_soc_codec *codec = codec_dai->codec; | ||
81 | struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); | ||
82 | |||
83 | priv->format = format; | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute) | ||
89 | { | ||
90 | struct snd_soc_codec *codec = dai->codec; | ||
91 | struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); | ||
92 | int ret; | ||
93 | |||
94 | ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE, | ||
95 | PCM1792A_MUTE_MASK, !!mute); | ||
96 | if (ret < 0) | ||
97 | return ret; | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int pcm1792a_hw_params(struct snd_pcm_substream *substream, | ||
103 | struct snd_pcm_hw_params *params, | ||
104 | struct snd_soc_dai *dai) | ||
105 | { | ||
106 | struct snd_soc_codec *codec = dai->codec; | ||
107 | struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); | ||
108 | int val = 0, ret; | ||
109 | int pcm_format = params_format(params); | ||
110 | |||
111 | priv->rate = params_rate(params); | ||
112 | |||
113 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
114 | case SND_SOC_DAIFMT_RIGHT_J: | ||
115 | if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || | ||
116 | pcm_format == SNDRV_PCM_FORMAT_S32_LE) | ||
117 | val = 0x02; | ||
118 | else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) | ||
119 | val = 0x00; | ||
120 | break; | ||
121 | case SND_SOC_DAIFMT_I2S: | ||
122 | if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || | ||
123 | pcm_format == SNDRV_PCM_FORMAT_S32_LE) | ||
124 | val = 0x05; | ||
125 | else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) | ||
126 | val = 0x04; | ||
127 | break; | ||
128 | default: | ||
129 | dev_err(codec->dev, "Invalid DAI format\n"); | ||
130 | return -EINVAL; | ||
131 | } | ||
132 | |||
133 | val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE; | ||
134 | |||
135 | ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL, | ||
136 | PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val); | ||
137 | if (ret < 0) | ||
138 | return ret; | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static const struct snd_soc_dai_ops pcm1792a_dai_ops = { | ||
144 | .set_fmt = pcm1792a_set_dai_fmt, | ||
145 | .hw_params = pcm1792a_hw_params, | ||
146 | .digital_mute = pcm1792a_digital_mute, | ||
147 | }; | ||
148 | |||
149 | static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1); | ||
150 | |||
151 | static const struct snd_kcontrol_new pcm1792a_controls[] = { | ||
152 | SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT, | ||
153 | PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, | ||
154 | pcm1792a_dac_tlv), | ||
155 | }; | ||
156 | |||
157 | static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = { | ||
158 | SND_SOC_DAPM_OUTPUT("IOUTL+"), | ||
159 | SND_SOC_DAPM_OUTPUT("IOUTL-"), | ||
160 | SND_SOC_DAPM_OUTPUT("IOUTR+"), | ||
161 | SND_SOC_DAPM_OUTPUT("IOUTR-"), | ||
162 | }; | ||
163 | |||
164 | static const struct snd_soc_dapm_route pcm1792a_dapm_routes[] = { | ||
165 | { "IOUTL+", NULL, "Playback" }, | ||
166 | { "IOUTL-", NULL, "Playback" }, | ||
167 | { "IOUTR+", NULL, "Playback" }, | ||
168 | { "IOUTR-", NULL, "Playback" }, | ||
169 | }; | ||
170 | |||
171 | static struct snd_soc_dai_driver pcm1792a_dai = { | ||
172 | .name = "pcm1792a-hifi", | ||
173 | .playback = { | ||
174 | .stream_name = "Playback", | ||
175 | .channels_min = 2, | ||
176 | .channels_max = 2, | ||
177 | .rates = PCM1792A_RATES, | ||
178 | .formats = PCM1792A_FORMATS, }, | ||
179 | .ops = &pcm1792a_dai_ops, | ||
180 | }; | ||
181 | |||
182 | static const struct of_device_id pcm1792a_of_match[] = { | ||
183 | { .compatible = "ti,pcm1792a", }, | ||
184 | { } | ||
185 | }; | ||
186 | MODULE_DEVICE_TABLE(of, pcm1792a_of_match); | ||
187 | |||
188 | static const struct regmap_config pcm1792a_regmap = { | ||
189 | .reg_bits = 8, | ||
190 | .val_bits = 8, | ||
191 | .max_register = 24, | ||
192 | .reg_defaults = pcm1792a_reg_defaults, | ||
193 | .num_reg_defaults = ARRAY_SIZE(pcm1792a_reg_defaults), | ||
194 | .writeable_reg = pcm1792a_writeable_reg, | ||
195 | .readable_reg = pcm1792a_accessible_reg, | ||
196 | }; | ||
197 | |||
198 | static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = { | ||
199 | .controls = pcm1792a_controls, | ||
200 | .num_controls = ARRAY_SIZE(pcm1792a_controls), | ||
201 | .dapm_widgets = pcm1792a_dapm_widgets, | ||
202 | .num_dapm_widgets = ARRAY_SIZE(pcm1792a_dapm_widgets), | ||
203 | .dapm_routes = pcm1792a_dapm_routes, | ||
204 | .num_dapm_routes = ARRAY_SIZE(pcm1792a_dapm_routes), | ||
205 | }; | ||
206 | |||
207 | static int pcm1792a_spi_probe(struct spi_device *spi) | ||
208 | { | ||
209 | struct pcm1792a_private *pcm1792a; | ||
210 | int ret; | ||
211 | |||
212 | pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private), | ||
213 | GFP_KERNEL); | ||
214 | if (!pcm1792a) | ||
215 | return -ENOMEM; | ||
216 | |||
217 | spi_set_drvdata(spi, pcm1792a); | ||
218 | |||
219 | pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap); | ||
220 | if (IS_ERR(pcm1792a->regmap)) { | ||
221 | ret = PTR_ERR(pcm1792a->regmap); | ||
222 | dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | return snd_soc_register_codec(&spi->dev, | ||
227 | &soc_codec_dev_pcm1792a, &pcm1792a_dai, 1); | ||
228 | } | ||
229 | |||
230 | static int pcm1792a_spi_remove(struct spi_device *spi) | ||
231 | { | ||
232 | snd_soc_unregister_codec(&spi->dev); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static const struct spi_device_id pcm1792a_spi_ids[] = { | ||
237 | { "pcm1792a", 0 }, | ||
238 | { }, | ||
239 | }; | ||
240 | MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids); | ||
241 | |||
242 | static struct spi_driver pcm1792a_codec_driver = { | ||
243 | .driver = { | ||
244 | .name = "pcm1792a", | ||
245 | .owner = THIS_MODULE, | ||
246 | .of_match_table = of_match_ptr(pcm1792a_of_match), | ||
247 | }, | ||
248 | .id_table = pcm1792a_spi_ids, | ||
249 | .probe = pcm1792a_spi_probe, | ||
250 | .remove = pcm1792a_spi_remove, | ||
251 | }; | ||
252 | |||
253 | module_spi_driver(pcm1792a_codec_driver); | ||
254 | |||
255 | MODULE_DESCRIPTION("ASoC PCM1792A driver"); | ||
256 | MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>"); | ||
257 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm1792a.h new file mode 100644 index 000000000000..7a83d1fc102a --- /dev/null +++ b/sound/soc/codecs/pcm1792a.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * definitions for PCM1792A | ||
3 | * | ||
4 | * Copyright 2013 Amarula Solutions | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version 2 | ||
9 | * of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef __PCM1792A_H__ | ||
18 | #define __PCM1792A_H__ | ||
19 | |||
20 | #define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ | ||
21 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) | ||
22 | |||
23 | #define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
24 | SNDRV_PCM_FMTBIT_S16_LE) | ||
25 | |||
26 | #endif | ||
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index f2a6282b41f4..b6618c4a7597 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c | |||
@@ -28,7 +28,54 @@ | |||
28 | 28 | ||
29 | #include "pcm3008.h" | 29 | #include "pcm3008.h" |
30 | 30 | ||
31 | #define PCM3008_VERSION "0.2" | 31 | static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w, |
32 | struct snd_kcontrol *kcontrol, | ||
33 | int event) | ||
34 | { | ||
35 | struct snd_soc_codec *codec = w->codec; | ||
36 | struct pcm3008_setup_data *setup = codec->dev->platform_data; | ||
37 | |||
38 | gpio_set_value_cansleep(setup->pdda_pin, | ||
39 | SND_SOC_DAPM_EVENT_ON(event)); | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w, | ||
45 | struct snd_kcontrol *kcontrol, | ||
46 | int event) | ||
47 | { | ||
48 | struct snd_soc_codec *codec = w->codec; | ||
49 | struct pcm3008_setup_data *setup = codec->dev->platform_data; | ||
50 | |||
51 | gpio_set_value_cansleep(setup->pdad_pin, | ||
52 | SND_SOC_DAPM_EVENT_ON(event)); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static const struct snd_soc_dapm_widget pcm3008_dapm_widgets[] = { | ||
58 | SND_SOC_DAPM_INPUT("VINL"), | ||
59 | SND_SOC_DAPM_INPUT("VINR"), | ||
60 | |||
61 | SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_dac_ev, | ||
62 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
63 | SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_adc_ev, | ||
64 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
65 | |||
66 | SND_SOC_DAPM_OUTPUT("VOUTL"), | ||
67 | SND_SOC_DAPM_OUTPUT("VOUTR"), | ||
68 | }; | ||
69 | |||
70 | static const struct snd_soc_dapm_route pcm3008_dapm_routes[] = { | ||
71 | { "PCM3008 Capture", NULL, "ADC" }, | ||
72 | { "ADC", NULL, "VINL" }, | ||
73 | { "ADC", NULL, "VINR" }, | ||
74 | |||
75 | { "DAC", NULL, "PCM3008 Playback" }, | ||
76 | { "VOUTL", NULL, "DAC" }, | ||
77 | { "VOUTR", NULL, "DAC" }, | ||
78 | }; | ||
32 | 79 | ||
33 | #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 80 | #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
34 | SNDRV_PCM_RATE_48000) | 81 | SNDRV_PCM_RATE_48000) |
@@ -51,20 +98,20 @@ static struct snd_soc_dai_driver pcm3008_dai = { | |||
51 | }, | 98 | }, |
52 | }; | 99 | }; |
53 | 100 | ||
54 | static void pcm3008_gpio_free(struct pcm3008_setup_data *setup) | 101 | static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = { |
55 | { | 102 | .dapm_widgets = pcm3008_dapm_widgets, |
56 | gpio_free(setup->dem0_pin); | 103 | .num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets), |
57 | gpio_free(setup->dem1_pin); | 104 | .dapm_routes = pcm3008_dapm_routes, |
58 | gpio_free(setup->pdad_pin); | 105 | .num_dapm_routes = ARRAY_SIZE(pcm3008_dapm_routes), |
59 | gpio_free(setup->pdda_pin); | 106 | }; |
60 | } | ||
61 | 107 | ||
62 | static int pcm3008_soc_probe(struct snd_soc_codec *codec) | 108 | static int pcm3008_codec_probe(struct platform_device *pdev) |
63 | { | 109 | { |
64 | struct pcm3008_setup_data *setup = codec->dev->platform_data; | 110 | struct pcm3008_setup_data *setup = pdev->dev.platform_data; |
65 | int ret = 0; | 111 | int ret; |
66 | 112 | ||
67 | printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION); | 113 | if (!setup) |
114 | return -EINVAL; | ||
68 | 115 | ||
69 | /* DEM1 DEM0 DE-EMPHASIS_MODE | 116 | /* DEM1 DEM0 DE-EMPHASIS_MODE |
70 | * Low Low De-emphasis 44.1 kHz ON | 117 | * Low Low De-emphasis 44.1 kHz ON |
@@ -74,83 +121,29 @@ static int pcm3008_soc_probe(struct snd_soc_codec *codec) | |||
74 | */ | 121 | */ |
75 | 122 | ||
76 | /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */ | 123 | /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */ |
77 | ret = gpio_request(setup->dem0_pin, "codec_dem0"); | 124 | ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin, |
78 | if (ret == 0) | 125 | GPIOF_OUT_INIT_HIGH, "codec_dem0"); |
79 | ret = gpio_direction_output(setup->dem0_pin, 1); | ||
80 | if (ret != 0) | 126 | if (ret != 0) |
81 | goto gpio_err; | 127 | return ret; |
82 | 128 | ||
83 | /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */ | 129 | /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */ |
84 | ret = gpio_request(setup->dem1_pin, "codec_dem1"); | 130 | ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin, |
85 | if (ret == 0) | 131 | GPIOF_OUT_INIT_LOW, "codec_dem1"); |
86 | ret = gpio_direction_output(setup->dem1_pin, 0); | ||
87 | if (ret != 0) | 132 | if (ret != 0) |
88 | goto gpio_err; | 133 | return ret; |
89 | 134 | ||
90 | /* Configure PDAD GPIO. */ | 135 | /* Configure PDAD GPIO. */ |
91 | ret = gpio_request(setup->pdad_pin, "codec_pdad"); | 136 | ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin, |
92 | if (ret == 0) | 137 | GPIOF_OUT_INIT_LOW, "codec_pdad"); |
93 | ret = gpio_direction_output(setup->pdad_pin, 1); | ||
94 | if (ret != 0) | 138 | if (ret != 0) |
95 | goto gpio_err; | 139 | return ret; |
96 | 140 | ||
97 | /* Configure PDDA GPIO. */ | 141 | /* Configure PDDA GPIO. */ |
98 | ret = gpio_request(setup->pdda_pin, "codec_pdda"); | 142 | ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin, |
99 | if (ret == 0) | 143 | GPIOF_OUT_INIT_LOW, "codec_pdda"); |
100 | ret = gpio_direction_output(setup->pdda_pin, 1); | ||
101 | if (ret != 0) | 144 | if (ret != 0) |
102 | goto gpio_err; | 145 | return ret; |
103 | |||
104 | return ret; | ||
105 | |||
106 | gpio_err: | ||
107 | pcm3008_gpio_free(setup); | ||
108 | 146 | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int pcm3008_soc_remove(struct snd_soc_codec *codec) | ||
113 | { | ||
114 | struct pcm3008_setup_data *setup = codec->dev->platform_data; | ||
115 | |||
116 | pcm3008_gpio_free(setup); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | #ifdef CONFIG_PM | ||
121 | static int pcm3008_soc_suspend(struct snd_soc_codec *codec) | ||
122 | { | ||
123 | struct pcm3008_setup_data *setup = codec->dev->platform_data; | ||
124 | |||
125 | gpio_set_value(setup->pdad_pin, 0); | ||
126 | gpio_set_value(setup->pdda_pin, 0); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int pcm3008_soc_resume(struct snd_soc_codec *codec) | ||
132 | { | ||
133 | struct pcm3008_setup_data *setup = codec->dev->platform_data; | ||
134 | |||
135 | gpio_set_value(setup->pdad_pin, 1); | ||
136 | gpio_set_value(setup->pdda_pin, 1); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | #else | ||
141 | #define pcm3008_soc_suspend NULL | ||
142 | #define pcm3008_soc_resume NULL | ||
143 | #endif | ||
144 | |||
145 | static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = { | ||
146 | .probe = pcm3008_soc_probe, | ||
147 | .remove = pcm3008_soc_remove, | ||
148 | .suspend = pcm3008_soc_suspend, | ||
149 | .resume = pcm3008_soc_resume, | ||
150 | }; | ||
151 | |||
152 | static int pcm3008_codec_probe(struct platform_device *pdev) | ||
153 | { | ||
154 | return snd_soc_register_codec(&pdev->dev, | 147 | return snd_soc_register_codec(&pdev->dev, |
155 | &soc_codec_dev_pcm3008, &pcm3008_dai, 1); | 148 | &soc_codec_dev_pcm3008, &pcm3008_dai, 1); |
156 | } | 149 | } |
@@ -158,6 +151,7 @@ static int pcm3008_codec_probe(struct platform_device *pdev) | |||
158 | static int pcm3008_codec_remove(struct platform_device *pdev) | 151 | static int pcm3008_codec_remove(struct platform_device *pdev) |
159 | { | 152 | { |
160 | snd_soc_unregister_codec(&pdev->dev); | 153 | snd_soc_unregister_codec(&pdev->dev); |
154 | |||
161 | return 0; | 155 | return 0; |
162 | } | 156 | } |
163 | 157 | ||
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index ce585e37e38a..4db7314baabc 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c | |||
@@ -737,29 +737,6 @@ static const struct snd_kcontrol_new rt5640_mono_mix[] = { | |||
737 | RT5640_M_BST1_MM_SFT, 1, 1), | 737 | RT5640_M_BST1_MM_SFT, 1, 1), |
738 | }; | 738 | }; |
739 | 739 | ||
740 | /* INL/R source */ | ||
741 | static const char * const rt5640_inl_src[] = { | ||
742 | "IN2P", "MONOP" | ||
743 | }; | ||
744 | |||
745 | static const SOC_ENUM_SINGLE_DECL( | ||
746 | rt5640_inl_enum, RT5640_INL_INR_VOL, | ||
747 | RT5640_INL_SEL_SFT, rt5640_inl_src); | ||
748 | |||
749 | static const struct snd_kcontrol_new rt5640_inl_mux = | ||
750 | SOC_DAPM_ENUM("INL source", rt5640_inl_enum); | ||
751 | |||
752 | static const char * const rt5640_inr_src[] = { | ||
753 | "IN2N", "MONON" | ||
754 | }; | ||
755 | |||
756 | static const SOC_ENUM_SINGLE_DECL( | ||
757 | rt5640_inr_enum, RT5640_INL_INR_VOL, | ||
758 | RT5640_INR_SEL_SFT, rt5640_inr_src); | ||
759 | |||
760 | static const struct snd_kcontrol_new rt5640_inr_mux = | ||
761 | SOC_DAPM_ENUM("INR source", rt5640_inr_enum); | ||
762 | |||
763 | /* Stereo ADC source */ | 740 | /* Stereo ADC source */ |
764 | static const char * const rt5640_stereo_adc1_src[] = { | 741 | static const char * const rt5640_stereo_adc1_src[] = { |
765 | "DIG MIX", "ADC" | 742 | "DIG MIX", "ADC" |
@@ -1005,9 +982,6 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { | |||
1005 | RT5640_PWR_IN_L_BIT, 0, NULL, 0), | 982 | RT5640_PWR_IN_L_BIT, 0, NULL, 0), |
1006 | SND_SOC_DAPM_PGA("INR VOL", RT5640_PWR_VOL, | 983 | SND_SOC_DAPM_PGA("INR VOL", RT5640_PWR_VOL, |
1007 | RT5640_PWR_IN_R_BIT, 0, NULL, 0), | 984 | RT5640_PWR_IN_R_BIT, 0, NULL, 0), |
1008 | /* IN Mux */ | ||
1009 | SND_SOC_DAPM_MUX("INL Mux", SND_SOC_NOPM, 0, 0, &rt5640_inl_mux), | ||
1010 | SND_SOC_DAPM_MUX("INR Mux", SND_SOC_NOPM, 0, 0, &rt5640_inr_mux), | ||
1011 | /* REC Mixer */ | 985 | /* REC Mixer */ |
1012 | SND_SOC_DAPM_MIXER("RECMIXL", RT5640_PWR_MIXER, RT5640_PWR_RM_L_BIT, 0, | 986 | SND_SOC_DAPM_MIXER("RECMIXL", RT5640_PWR_MIXER, RT5640_PWR_RM_L_BIT, 0, |
1013 | rt5640_rec_l_mix, ARRAY_SIZE(rt5640_rec_l_mix)), | 987 | rt5640_rec_l_mix, ARRAY_SIZE(rt5640_rec_l_mix)), |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 760e8bfeacaa..1f4093f3f3a1 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -654,16 +654,19 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
654 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | 654 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, |
655 | SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP, | 655 | SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP, |
656 | SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP); | 656 | SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP); |
657 | |||
658 | /* if using pll, clk_ctrl must be set after pll power up */ | ||
659 | snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl); | ||
657 | } else { | 660 | } else { |
661 | /* otherwise, clk_ctrl must be set before pll power down */ | ||
662 | snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl); | ||
663 | |||
658 | /* power down pll */ | 664 | /* power down pll */ |
659 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | 665 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, |
660 | SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP, | 666 | SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP, |
661 | 0); | 667 | 0); |
662 | } | 668 | } |
663 | 669 | ||
664 | /* if using pll, clk_ctrl must be set after pll power up */ | ||
665 | snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl); | ||
666 | |||
667 | return 0; | 670 | return 0; |
668 | } | 671 | } |
669 | 672 | ||
@@ -1480,6 +1483,7 @@ static struct snd_soc_codec_driver sgtl5000_driver = { | |||
1480 | static const struct regmap_config sgtl5000_regmap = { | 1483 | static const struct regmap_config sgtl5000_regmap = { |
1481 | .reg_bits = 16, | 1484 | .reg_bits = 16, |
1482 | .val_bits = 16, | 1485 | .val_bits = 16, |
1486 | .reg_stride = 2, | ||
1483 | 1487 | ||
1484 | .max_register = SGTL5000_MAX_REG_OFFSET, | 1488 | .max_register = SGTL5000_MAX_REG_OFFSET, |
1485 | .volatile_reg = sgtl5000_volatile, | 1489 | .volatile_reg = sgtl5000_volatile, |
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 73e205c892a0..38f3b105c17d 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c | |||
@@ -102,6 +102,16 @@ static int si476x_codec_write(struct snd_soc_codec *codec, | |||
102 | return err; | 102 | return err; |
103 | } | 103 | } |
104 | 104 | ||
105 | static const struct snd_soc_dapm_widget si476x_dapm_widgets[] = { | ||
106 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
107 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
108 | }; | ||
109 | |||
110 | static const struct snd_soc_dapm_route si476x_dapm_routes[] = { | ||
111 | { "Capture", NULL, "LOUT" }, | ||
112 | { "Capture", NULL, "ROUT" }, | ||
113 | }; | ||
114 | |||
105 | static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, | 115 | static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, |
106 | unsigned int fmt) | 116 | unsigned int fmt) |
107 | { | 117 | { |
@@ -260,6 +270,10 @@ static struct snd_soc_codec_driver soc_codec_dev_si476x = { | |||
260 | .probe = si476x_codec_probe, | 270 | .probe = si476x_codec_probe, |
261 | .read = si476x_codec_read, | 271 | .read = si476x_codec_read, |
262 | .write = si476x_codec_write, | 272 | .write = si476x_codec_write, |
273 | .dapm_widgets = si476x_dapm_widgets, | ||
274 | .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets), | ||
275 | .dapm_routes = si476x_dapm_routes, | ||
276 | .num_dapm_routes = ARRAY_SIZE(si476x_dapm_routes), | ||
263 | }; | 277 | }; |
264 | 278 | ||
265 | static int si476x_platform_probe(struct platform_device *pdev) | 279 | static int si476x_platform_probe(struct platform_device *pdev) |
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c index e9d7881ed2c8..e3501f40c7b3 100644 --- a/sound/soc/codecs/spdif_receiver.c +++ b/sound/soc/codecs/spdif_receiver.c | |||
@@ -23,11 +23,26 @@ | |||
23 | #include <sound/initval.h> | 23 | #include <sound/initval.h> |
24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | 25 | ||
26 | static const struct snd_soc_dapm_widget dir_widgets[] = { | ||
27 | SND_SOC_DAPM_INPUT("spdif-in"), | ||
28 | }; | ||
29 | |||
30 | static const struct snd_soc_dapm_route dir_routes[] = { | ||
31 | { "Capture", NULL, "spdif-in" }, | ||
32 | }; | ||
33 | |||
26 | #define STUB_RATES SNDRV_PCM_RATE_8000_192000 | 34 | #define STUB_RATES SNDRV_PCM_RATE_8000_192000 |
27 | #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | 35 | #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
36 | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
37 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
28 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) | 38 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) |
29 | 39 | ||
30 | static struct snd_soc_codec_driver soc_codec_spdif_dir; | 40 | static struct snd_soc_codec_driver soc_codec_spdif_dir = { |
41 | .dapm_widgets = dir_widgets, | ||
42 | .num_dapm_widgets = ARRAY_SIZE(dir_widgets), | ||
43 | .dapm_routes = dir_routes, | ||
44 | .num_dapm_routes = ARRAY_SIZE(dir_routes), | ||
45 | }; | ||
31 | 46 | ||
32 | static struct snd_soc_dai_driver dir_stub_dai = { | 47 | static struct snd_soc_dai_driver dir_stub_dai = { |
33 | .name = "dir-hifi", | 48 | .name = "dir-hifi", |
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c index 18280499fd55..a078aa31052a 100644 --- a/sound/soc/codecs/spdif_transmitter.c +++ b/sound/soc/codecs/spdif_transmitter.c | |||
@@ -25,10 +25,24 @@ | |||
25 | #define DRV_NAME "spdif-dit" | 25 | #define DRV_NAME "spdif-dit" |
26 | 26 | ||
27 | #define STUB_RATES SNDRV_PCM_RATE_8000_96000 | 27 | #define STUB_RATES SNDRV_PCM_RATE_8000_96000 |
28 | #define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE | 28 | #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
29 | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
30 | SNDRV_PCM_FMTBIT_S24_LE) | ||
29 | 31 | ||
32 | static const struct snd_soc_dapm_widget dit_widgets[] = { | ||
33 | SND_SOC_DAPM_OUTPUT("spdif-out"), | ||
34 | }; | ||
35 | |||
36 | static const struct snd_soc_dapm_route dit_routes[] = { | ||
37 | { "spdif-out", NULL, "Playback" }, | ||
38 | }; | ||
30 | 39 | ||
31 | static struct snd_soc_codec_driver soc_codec_spdif_dit; | 40 | static struct snd_soc_codec_driver soc_codec_spdif_dit = { |
41 | .dapm_widgets = dit_widgets, | ||
42 | .num_dapm_widgets = ARRAY_SIZE(dit_widgets), | ||
43 | .dapm_routes = dit_routes, | ||
44 | .num_dapm_routes = ARRAY_SIZE(dit_routes), | ||
45 | }; | ||
32 | 46 | ||
33 | static struct snd_soc_dai_driver dit_stub_dai = { | 47 | static struct snd_soc_dai_driver dit_stub_dai = { |
34 | .name = "dit-hifi", | 48 | .name = "dit-hifi", |
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index cfb55fe35e98..06edb396e733 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c | |||
@@ -363,16 +363,18 @@ static void sta32x_watchdog(struct work_struct *work) | |||
363 | } | 363 | } |
364 | 364 | ||
365 | if (!sta32x->shutdown) | 365 | if (!sta32x->shutdown) |
366 | schedule_delayed_work(&sta32x->watchdog_work, | 366 | queue_delayed_work(system_power_efficient_wq, |
367 | round_jiffies_relative(HZ)); | 367 | &sta32x->watchdog_work, |
368 | round_jiffies_relative(HZ)); | ||
368 | } | 369 | } |
369 | 370 | ||
370 | static void sta32x_watchdog_start(struct sta32x_priv *sta32x) | 371 | static void sta32x_watchdog_start(struct sta32x_priv *sta32x) |
371 | { | 372 | { |
372 | if (sta32x->pdata->needs_esd_watchdog) { | 373 | if (sta32x->pdata->needs_esd_watchdog) { |
373 | sta32x->shutdown = 0; | 374 | sta32x->shutdown = 0; |
374 | schedule_delayed_work(&sta32x->watchdog_work, | 375 | queue_delayed_work(system_power_efficient_wq, |
375 | round_jiffies_relative(HZ)); | 376 | &sta32x->watchdog_work, |
377 | round_jiffies_relative(HZ)); | ||
376 | } | 378 | } |
377 | } | 379 | } |
378 | 380 | ||
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index b1f6982c7c9c..7b8f3d965f43 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c | |||
@@ -29,7 +29,7 @@ MODULE_LICENSE("GPL"); | |||
29 | /* AIC26 driver private data */ | 29 | /* AIC26 driver private data */ |
30 | struct aic26 { | 30 | struct aic26 { |
31 | struct spi_device *spi; | 31 | struct spi_device *spi; |
32 | struct snd_soc_codec codec; | 32 | struct snd_soc_codec *codec; |
33 | int master; | 33 | int master; |
34 | int datfm; | 34 | int datfm; |
35 | int mclk; | 35 | int mclk; |
@@ -119,6 +119,22 @@ static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, | |||
119 | return 0; | 119 | return 0; |
120 | } | 120 | } |
121 | 121 | ||
122 | static const struct snd_soc_dapm_widget tlv320aic26_dapm_widgets[] = { | ||
123 | SND_SOC_DAPM_INPUT("MICIN"), | ||
124 | SND_SOC_DAPM_INPUT("AUX"), | ||
125 | |||
126 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
127 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
128 | }; | ||
129 | |||
130 | static const struct snd_soc_dapm_route tlv320aic26_dapm_routes[] = { | ||
131 | { "Capture", NULL, "MICIN" }, | ||
132 | { "Capture", NULL, "AUX" }, | ||
133 | |||
134 | { "HPL", NULL, "Playback" }, | ||
135 | { "HPR", NULL, "Playback" }, | ||
136 | }; | ||
137 | |||
122 | /* --------------------------------------------------------------------- | 138 | /* --------------------------------------------------------------------- |
123 | * Digital Audio Interface Operations | 139 | * Digital Audio Interface Operations |
124 | */ | 140 | */ |
@@ -174,9 +190,9 @@ static int aic26_hw_params(struct snd_pcm_substream *substream, | |||
174 | dev_dbg(&aic26->spi->dev, "Setting PLLM to %d.%04d\n", jval, dval); | 190 | dev_dbg(&aic26->spi->dev, "Setting PLLM to %d.%04d\n", jval, dval); |
175 | qval = 0; | 191 | qval = 0; |
176 | reg = 0x8000 | qval << 11 | pval << 8 | jval << 2; | 192 | reg = 0x8000 | qval << 11 | pval << 8 | jval << 2; |
177 | aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg); | 193 | snd_soc_write(codec, AIC26_REG_PLL_PROG1, reg); |
178 | reg = dval << 2; | 194 | reg = dval << 2; |
179 | aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg); | 195 | snd_soc_write(codec, AIC26_REG_PLL_PROG2, reg); |
180 | 196 | ||
181 | /* Audio Control 3 (master mode, fsref rate) */ | 197 | /* Audio Control 3 (master mode, fsref rate) */ |
182 | reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3); | 198 | reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3); |
@@ -185,13 +201,13 @@ static int aic26_hw_params(struct snd_pcm_substream *substream, | |||
185 | reg |= 0x0800; | 201 | reg |= 0x0800; |
186 | if (fsref == 48000) | 202 | if (fsref == 48000) |
187 | reg |= 0x2000; | 203 | reg |= 0x2000; |
188 | aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg); | 204 | snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg); |
189 | 205 | ||
190 | /* Audio Control 1 (FSref divisor) */ | 206 | /* Audio Control 1 (FSref divisor) */ |
191 | reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1); | 207 | reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1); |
192 | reg &= ~0x0fff; | 208 | reg &= ~0x0fff; |
193 | reg |= wlen | aic26->datfm | (divisor << 3) | divisor; | 209 | reg |= wlen | aic26->datfm | (divisor << 3) | divisor; |
194 | aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL1, reg); | 210 | snd_soc_write(codec, AIC26_REG_AUDIO_CTRL1, reg); |
195 | 211 | ||
196 | return 0; | 212 | return 0; |
197 | } | 213 | } |
@@ -212,7 +228,7 @@ static int aic26_mute(struct snd_soc_dai *dai, int mute) | |||
212 | reg |= 0x8080; | 228 | reg |= 0x8080; |
213 | else | 229 | else |
214 | reg &= ~0x8080; | 230 | reg &= ~0x8080; |
215 | aic26_reg_write(codec, AIC26_REG_DAC_GAIN, reg); | 231 | snd_soc_write(codec, AIC26_REG_DAC_GAIN, reg); |
216 | 232 | ||
217 | return 0; | 233 | return 0; |
218 | } | 234 | } |
@@ -330,7 +346,7 @@ static ssize_t aic26_keyclick_show(struct device *dev, | |||
330 | struct aic26 *aic26 = dev_get_drvdata(dev); | 346 | struct aic26 *aic26 = dev_get_drvdata(dev); |
331 | int val, amp, freq, len; | 347 | int val, amp, freq, len; |
332 | 348 | ||
333 | val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2); | 349 | val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2); |
334 | amp = (val >> 12) & 0x7; | 350 | amp = (val >> 12) & 0x7; |
335 | freq = (125 << ((val >> 8) & 0x7)) >> 1; | 351 | freq = (125 << ((val >> 8) & 0x7)) >> 1; |
336 | len = 2 * (1 + ((val >> 4) & 0xf)); | 352 | len = 2 * (1 + ((val >> 4) & 0xf)); |
@@ -346,9 +362,9 @@ static ssize_t aic26_keyclick_set(struct device *dev, | |||
346 | struct aic26 *aic26 = dev_get_drvdata(dev); | 362 | struct aic26 *aic26 = dev_get_drvdata(dev); |
347 | int val; | 363 | int val; |
348 | 364 | ||
349 | val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2); | 365 | val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2); |
350 | val |= 0x8000; | 366 | val |= 0x8000; |
351 | aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL2, val); | 367 | snd_soc_write(aic26->codec, AIC26_REG_AUDIO_CTRL2, val); |
352 | 368 | ||
353 | return count; | 369 | return count; |
354 | } | 370 | } |
@@ -360,25 +376,26 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); | |||
360 | */ | 376 | */ |
361 | static int aic26_probe(struct snd_soc_codec *codec) | 377 | static int aic26_probe(struct snd_soc_codec *codec) |
362 | { | 378 | { |
379 | struct aic26 *aic26 = dev_get_drvdata(codec->dev); | ||
363 | int ret, err, i, reg; | 380 | int ret, err, i, reg; |
364 | 381 | ||
365 | dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n"); | 382 | aic26->codec = codec; |
366 | 383 | ||
367 | /* Reset the codec to power on defaults */ | 384 | /* Reset the codec to power on defaults */ |
368 | aic26_reg_write(codec, AIC26_REG_RESET, 0xBB00); | 385 | snd_soc_write(codec, AIC26_REG_RESET, 0xBB00); |
369 | 386 | ||
370 | /* Power up CODEC */ | 387 | /* Power up CODEC */ |
371 | aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0); | 388 | snd_soc_write(codec, AIC26_REG_POWER_CTRL, 0); |
372 | 389 | ||
373 | /* Audio Control 3 (master mode, fsref rate) */ | 390 | /* Audio Control 3 (master mode, fsref rate) */ |
374 | reg = aic26_reg_read(codec, AIC26_REG_AUDIO_CTRL3); | 391 | reg = snd_soc_read(codec, AIC26_REG_AUDIO_CTRL3); |
375 | reg &= ~0xf800; | 392 | reg &= ~0xf800; |
376 | reg |= 0x0800; /* set master mode */ | 393 | reg |= 0x0800; /* set master mode */ |
377 | aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg); | 394 | snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg); |
378 | 395 | ||
379 | /* Fill register cache */ | 396 | /* Fill register cache */ |
380 | for (i = 0; i < codec->driver->reg_cache_size; i++) | 397 | for (i = 0; i < codec->driver->reg_cache_size; i++) |
381 | aic26_reg_read(codec, i); | 398 | snd_soc_read(codec, i); |
382 | 399 | ||
383 | /* Register the sysfs files for debugging */ | 400 | /* Register the sysfs files for debugging */ |
384 | /* Create SysFS files */ | 401 | /* Create SysFS files */ |
@@ -401,6 +418,10 @@ static struct snd_soc_codec_driver aic26_soc_codec_dev = { | |||
401 | .write = aic26_reg_write, | 418 | .write = aic26_reg_write, |
402 | .reg_cache_size = AIC26_NUM_REGS, | 419 | .reg_cache_size = AIC26_NUM_REGS, |
403 | .reg_word_size = sizeof(u16), | 420 | .reg_word_size = sizeof(u16), |
421 | .dapm_widgets = tlv320aic26_dapm_widgets, | ||
422 | .num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets), | ||
423 | .dapm_routes = tlv320aic26_dapm_routes, | ||
424 | .num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes), | ||
404 | }; | 425 | }; |
405 | 426 | ||
406 | /* --------------------------------------------------------------------- | 427 | /* --------------------------------------------------------------------- |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index e5b926883131..6e3f269243e0 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -138,8 +138,7 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { | |||
138 | static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | 138 | static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, |
139 | struct snd_ctl_elem_value *ucontrol) | 139 | struct snd_ctl_elem_value *ucontrol) |
140 | { | 140 | { |
141 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 141 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
142 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
143 | struct soc_mixer_control *mc = | 142 | struct soc_mixer_control *mc = |
144 | (struct soc_mixer_control *)kcontrol->private_value; | 143 | (struct soc_mixer_control *)kcontrol->private_value; |
145 | unsigned int reg = mc->reg; | 144 | unsigned int reg = mc->reg; |
@@ -147,10 +146,9 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
147 | int max = mc->max; | 146 | int max = mc->max; |
148 | unsigned int mask = (1 << fls(max)) - 1; | 147 | unsigned int mask = (1 << fls(max)) - 1; |
149 | unsigned int invert = mc->invert; | 148 | unsigned int invert = mc->invert; |
150 | unsigned short val, val_mask; | 149 | unsigned short val; |
151 | int ret; | 150 | struct snd_soc_dapm_update update; |
152 | struct snd_soc_dapm_path *path; | 151 | int connect, change; |
153 | int found = 0; | ||
154 | 152 | ||
155 | val = (ucontrol->value.integer.value[0] & mask); | 153 | val = (ucontrol->value.integer.value[0] & mask); |
156 | 154 | ||
@@ -158,42 +156,26 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
158 | if (val) | 156 | if (val) |
159 | val = mask; | 157 | val = mask; |
160 | 158 | ||
159 | connect = !!val; | ||
160 | |||
161 | if (invert) | 161 | if (invert) |
162 | val = mask - val; | 162 | val = mask - val; |
163 | val_mask = mask << shift; | ||
164 | val = val << shift; | ||
165 | |||
166 | mutex_lock(&widget->codec->mutex); | ||
167 | 163 | ||
168 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { | 164 | mask <<= shift; |
169 | /* find dapm widget path assoc with kcontrol */ | 165 | val <<= shift; |
170 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | ||
171 | if (path->kcontrol != kcontrol) | ||
172 | continue; | ||
173 | 166 | ||
174 | /* found, now check type */ | 167 | change = snd_soc_test_bits(codec, val, mask, reg); |
175 | found = 1; | 168 | if (change) { |
176 | if (val) | 169 | update.kcontrol = kcontrol; |
177 | /* new connection */ | 170 | update.reg = reg; |
178 | path->connect = invert ? 0 : 1; | 171 | update.mask = mask; |
179 | else | 172 | update.val = val; |
180 | /* old connection must be powered down */ | ||
181 | path->connect = invert ? 1 : 0; | ||
182 | 173 | ||
183 | dapm_mark_dirty(path->source, "tlv320aic3x source"); | 174 | snd_soc_dapm_mixer_update_power(&codec->dapm, kcontrol, connect, |
184 | dapm_mark_dirty(path->sink, "tlv320aic3x sink"); | 175 | &update); |
185 | |||
186 | break; | ||
187 | } | ||
188 | } | 176 | } |
189 | 177 | ||
190 | mutex_unlock(&widget->codec->mutex); | 178 | return change; |
191 | |||
192 | if (found) | ||
193 | snd_soc_dapm_sync(widget->dapm); | ||
194 | |||
195 | ret = snd_soc_update_bits_locked(widget->codec, reg, val_mask, val); | ||
196 | return ret; | ||
197 | } | 179 | } |
198 | 180 | ||
199 | /* | 181 | /* |
@@ -1492,6 +1474,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = { | |||
1492 | { "tlv320aic3x", AIC3X_MODEL_3X }, | 1474 | { "tlv320aic3x", AIC3X_MODEL_3X }, |
1493 | { "tlv320aic33", AIC3X_MODEL_33 }, | 1475 | { "tlv320aic33", AIC3X_MODEL_33 }, |
1494 | { "tlv320aic3007", AIC3X_MODEL_3007 }, | 1476 | { "tlv320aic3007", AIC3X_MODEL_3007 }, |
1477 | { "tlv320aic3106", AIC3X_MODEL_3X }, | ||
1495 | { } | 1478 | { } |
1496 | }; | 1479 | }; |
1497 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); | 1480 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); |
@@ -1582,6 +1565,9 @@ static int aic3x_i2c_remove(struct i2c_client *client) | |||
1582 | #if defined(CONFIG_OF) | 1565 | #if defined(CONFIG_OF) |
1583 | static const struct of_device_id tlv320aic3x_of_match[] = { | 1566 | static const struct of_device_id tlv320aic3x_of_match[] = { |
1584 | { .compatible = "ti,tlv320aic3x", }, | 1567 | { .compatible = "ti,tlv320aic3x", }, |
1568 | { .compatible = "ti,tlv320aic33" }, | ||
1569 | { .compatible = "ti,tlv320aic3007" }, | ||
1570 | { .compatible = "ti,tlv320aic3106" }, | ||
1585 | {}, | 1571 | {}, |
1586 | }; | 1572 | }; |
1587 | MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); | 1573 | MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 8e6e5b016021..1e3884d6b3fb 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -137,8 +137,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | |||
137 | 137 | ||
138 | /* codec private data */ | 138 | /* codec private data */ |
139 | struct twl4030_priv { | 139 | struct twl4030_priv { |
140 | struct snd_soc_codec codec; | ||
141 | |||
142 | unsigned int codec_powered; | 140 | unsigned int codec_powered; |
143 | 141 | ||
144 | /* reference counts of AIF/APLL users */ | 142 | /* reference counts of AIF/APLL users */ |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 44621ddc332d..3c79dbb6c323 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -429,7 +429,8 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data) | |||
429 | struct snd_soc_codec *codec = data; | 429 | struct snd_soc_codec *codec = data; |
430 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | 430 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); |
431 | 431 | ||
432 | schedule_delayed_work(&priv->hs_jack.work, msecs_to_jiffies(200)); | 432 | queue_delayed_work(system_power_efficient_wq, |
433 | &priv->hs_jack.work, msecs_to_jiffies(200)); | ||
433 | 434 | ||
434 | return IRQ_HANDLED; | 435 | return IRQ_HANDLED; |
435 | } | 436 | } |
@@ -437,9 +438,7 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data) | |||
437 | static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol, | 438 | static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol, |
438 | struct snd_ctl_elem_value *ucontrol) | 439 | struct snd_ctl_elem_value *ucontrol) |
439 | { | 440 | { |
440 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 441 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
441 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
442 | struct snd_soc_codec *codec = widget->codec; | ||
443 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 442 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
444 | unsigned int val; | 443 | unsigned int val; |
445 | 444 | ||
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 6d0aa44c3757..c94d4c1e3dac 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -325,7 +325,6 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
325 | static int uda134x_set_bias_level(struct snd_soc_codec *codec, | 325 | static int uda134x_set_bias_level(struct snd_soc_codec *codec, |
326 | enum snd_soc_bias_level level) | 326 | enum snd_soc_bias_level level) |
327 | { | 327 | { |
328 | u8 reg; | ||
329 | struct uda134x_platform_data *pd = codec->control_data; | 328 | struct uda134x_platform_data *pd = codec->control_data; |
330 | int i; | 329 | int i; |
331 | u8 *cache = codec->reg_cache; | 330 | u8 *cache = codec->reg_cache; |
@@ -334,23 +333,6 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec, | |||
334 | 333 | ||
335 | switch (level) { | 334 | switch (level) { |
336 | case SND_SOC_BIAS_ON: | 335 | case SND_SOC_BIAS_ON: |
337 | /* ADC, DAC on */ | ||
338 | switch (pd->model) { | ||
339 | case UDA134X_UDA1340: | ||
340 | case UDA134X_UDA1344: | ||
341 | case UDA134X_UDA1345: | ||
342 | reg = uda134x_read_reg_cache(codec, UDA134X_DATA011); | ||
343 | uda134x_write(codec, UDA134X_DATA011, reg | 0x03); | ||
344 | break; | ||
345 | case UDA134X_UDA1341: | ||
346 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | ||
347 | uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); | ||
348 | break; | ||
349 | default: | ||
350 | printk(KERN_ERR "UDA134X SoC codec: " | ||
351 | "unsupported model %d\n", pd->model); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | break; | 336 | break; |
355 | case SND_SOC_BIAS_PREPARE: | 337 | case SND_SOC_BIAS_PREPARE: |
356 | /* power on */ | 338 | /* power on */ |
@@ -362,23 +344,6 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec, | |||
362 | } | 344 | } |
363 | break; | 345 | break; |
364 | case SND_SOC_BIAS_STANDBY: | 346 | case SND_SOC_BIAS_STANDBY: |
365 | /* ADC, DAC power off */ | ||
366 | switch (pd->model) { | ||
367 | case UDA134X_UDA1340: | ||
368 | case UDA134X_UDA1344: | ||
369 | case UDA134X_UDA1345: | ||
370 | reg = uda134x_read_reg_cache(codec, UDA134X_DATA011); | ||
371 | uda134x_write(codec, UDA134X_DATA011, reg & ~(0x03)); | ||
372 | break; | ||
373 | case UDA134X_UDA1341: | ||
374 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | ||
375 | uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); | ||
376 | break; | ||
377 | default: | ||
378 | printk(KERN_ERR "UDA134X SoC codec: " | ||
379 | "unsupported model %d\n", pd->model); | ||
380 | return -EINVAL; | ||
381 | } | ||
382 | break; | 347 | break; |
383 | case SND_SOC_BIAS_OFF: | 348 | case SND_SOC_BIAS_OFF: |
384 | /* power off */ | 349 | /* power off */ |
@@ -450,6 +415,37 @@ SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), | |||
450 | SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), | 415 | SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), |
451 | }; | 416 | }; |
452 | 417 | ||
418 | /* UDA1341 has the DAC/ADC power down in STATUS1 */ | ||
419 | static const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = { | ||
420 | SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0), | ||
421 | SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0), | ||
422 | }; | ||
423 | |||
424 | /* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */ | ||
425 | static const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = { | ||
426 | SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0), | ||
427 | SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0), | ||
428 | }; | ||
429 | |||
430 | /* Common DAPM widgets */ | ||
431 | static const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = { | ||
432 | SND_SOC_DAPM_INPUT("VINL1"), | ||
433 | SND_SOC_DAPM_INPUT("VINR1"), | ||
434 | SND_SOC_DAPM_INPUT("VINL2"), | ||
435 | SND_SOC_DAPM_INPUT("VINR2"), | ||
436 | SND_SOC_DAPM_OUTPUT("VOUTL"), | ||
437 | SND_SOC_DAPM_OUTPUT("VOUTR"), | ||
438 | }; | ||
439 | |||
440 | static const struct snd_soc_dapm_route uda134x_dapm_routes[] = { | ||
441 | { "ADC", NULL, "VINL1" }, | ||
442 | { "ADC", NULL, "VINR1" }, | ||
443 | { "ADC", NULL, "VINL2" }, | ||
444 | { "ADC", NULL, "VINR2" }, | ||
445 | { "VOUTL", NULL, "DAC" }, | ||
446 | { "VOUTR", NULL, "DAC" }, | ||
447 | }; | ||
448 | |||
453 | static const struct snd_soc_dai_ops uda134x_dai_ops = { | 449 | static const struct snd_soc_dai_ops uda134x_dai_ops = { |
454 | .startup = uda134x_startup, | 450 | .startup = uda134x_startup, |
455 | .shutdown = uda134x_shutdown, | 451 | .shutdown = uda134x_shutdown, |
@@ -485,6 +481,8 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) | |||
485 | { | 481 | { |
486 | struct uda134x_priv *uda134x; | 482 | struct uda134x_priv *uda134x; |
487 | struct uda134x_platform_data *pd = codec->card->dev->platform_data; | 483 | struct uda134x_platform_data *pd = codec->card->dev->platform_data; |
484 | const struct snd_soc_dapm_widget *widgets; | ||
485 | unsigned num_widgets; | ||
488 | 486 | ||
489 | int ret; | 487 | int ret; |
490 | 488 | ||
@@ -526,6 +524,22 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) | |||
526 | else | 524 | else |
527 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 525 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
528 | 526 | ||
527 | if (pd->model == UDA134X_UDA1341) { | ||
528 | widgets = uda1341_dapm_widgets; | ||
529 | num_widgets = ARRAY_SIZE(uda1341_dapm_widgets); | ||
530 | } else { | ||
531 | widgets = uda1340_dapm_widgets; | ||
532 | num_widgets = ARRAY_SIZE(uda1340_dapm_widgets); | ||
533 | } | ||
534 | |||
535 | ret = snd_soc_dapm_new_controls(&codec->dapm, widgets, num_widgets); | ||
536 | if (ret) { | ||
537 | printk(KERN_ERR "%s failed to register dapm controls: %d", | ||
538 | __func__, ret); | ||
539 | kfree(uda134x); | ||
540 | return ret; | ||
541 | } | ||
542 | |||
529 | switch (pd->model) { | 543 | switch (pd->model) { |
530 | case UDA134X_UDA1340: | 544 | case UDA134X_UDA1340: |
531 | case UDA134X_UDA1344: | 545 | case UDA134X_UDA1344: |
@@ -599,6 +613,10 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { | |||
599 | .read = uda134x_read_reg_cache, | 613 | .read = uda134x_read_reg_cache, |
600 | .write = uda134x_write, | 614 | .write = uda134x_write, |
601 | .set_bias_level = uda134x_set_bias_level, | 615 | .set_bias_level = uda134x_set_bias_level, |
616 | .dapm_widgets = uda134x_dapm_widgets, | ||
617 | .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), | ||
618 | .dapm_routes = uda134x_dapm_routes, | ||
619 | .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes), | ||
602 | }; | 620 | }; |
603 | 621 | ||
604 | static int uda134x_codec_probe(struct platform_device *pdev) | 622 | static int uda134x_codec_probe(struct platform_device *pdev) |
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index 54cd3da09abd..b7ab2ef567c8 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c | |||
@@ -290,6 +290,18 @@ static const struct snd_kcontrol_new wl1273_controls[] = { | |||
290 | snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put), | 290 | snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put), |
291 | }; | 291 | }; |
292 | 292 | ||
293 | static const struct snd_soc_dapm_widget wl1273_dapm_widgets[] = { | ||
294 | SND_SOC_DAPM_INPUT("RX"), | ||
295 | |||
296 | SND_SOC_DAPM_OUTPUT("TX"), | ||
297 | }; | ||
298 | |||
299 | static const struct snd_soc_dapm_route wl1273_dapm_routes[] = { | ||
300 | { "Capture", NULL, "RX" }, | ||
301 | |||
302 | { "TX", NULL, "Playback" }, | ||
303 | }; | ||
304 | |||
293 | static int wl1273_startup(struct snd_pcm_substream *substream, | 305 | static int wl1273_startup(struct snd_pcm_substream *substream, |
294 | struct snd_soc_dai *dai) | 306 | struct snd_soc_dai *dai) |
295 | { | 307 | { |
@@ -483,6 +495,11 @@ static int wl1273_remove(struct snd_soc_codec *codec) | |||
483 | static struct snd_soc_codec_driver soc_codec_dev_wl1273 = { | 495 | static struct snd_soc_codec_driver soc_codec_dev_wl1273 = { |
484 | .probe = wl1273_probe, | 496 | .probe = wl1273_probe, |
485 | .remove = wl1273_remove, | 497 | .remove = wl1273_remove, |
498 | |||
499 | .dapm_widgets = wl1273_dapm_widgets, | ||
500 | .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), | ||
501 | .dapm_routes = wl1273_dapm_routes, | ||
502 | .num_dapm_routes = ARRAY_SIZE(wl1273_dapm_routes), | ||
486 | }; | 503 | }; |
487 | 504 | ||
488 | static int wl1273_platform_probe(struct platform_device *pdev) | 505 | static int wl1273_platform_probe(struct platform_device *pdev) |
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 10adc4145d46..d5ebcb00019b 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c | |||
@@ -420,7 +420,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec) | |||
420 | xfer->codec = codec; | 420 | xfer->codec = codec; |
421 | list_add_tail(&xfer->list, &xfer_list); | 421 | list_add_tail(&xfer->list, &xfer_list); |
422 | 422 | ||
423 | out = kzalloc(len, GFP_KERNEL); | 423 | out = kzalloc(len, GFP_KERNEL | GFP_DMA); |
424 | if (!out) { | 424 | if (!out) { |
425 | dev_err(codec->dev, | 425 | dev_err(codec->dev, |
426 | "Failed to allocate RX buffer\n"); | 426 | "Failed to allocate RX buffer\n"); |
@@ -429,7 +429,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec) | |||
429 | } | 429 | } |
430 | xfer->t.rx_buf = out; | 430 | xfer->t.rx_buf = out; |
431 | 431 | ||
432 | img = kzalloc(len, GFP_KERNEL); | 432 | img = kzalloc(len, GFP_KERNEL | GFP_DMA); |
433 | if (!img) { | 433 | if (!img) { |
434 | dev_err(codec->dev, | 434 | dev_err(codec->dev, |
435 | "Failed to allocate image buffer\n"); | 435 | "Failed to allocate image buffer\n"); |
@@ -523,14 +523,14 @@ static int wm0010_stage2_load(struct snd_soc_codec *codec) | |||
523 | dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size); | 523 | dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size); |
524 | 524 | ||
525 | /* Copy to local buffer first as vmalloc causes problems for dma */ | 525 | /* Copy to local buffer first as vmalloc causes problems for dma */ |
526 | img = kzalloc(fw->size, GFP_KERNEL); | 526 | img = kzalloc(fw->size, GFP_KERNEL | GFP_DMA); |
527 | if (!img) { | 527 | if (!img) { |
528 | dev_err(codec->dev, "Failed to allocate image buffer\n"); | 528 | dev_err(codec->dev, "Failed to allocate image buffer\n"); |
529 | ret = -ENOMEM; | 529 | ret = -ENOMEM; |
530 | goto abort2; | 530 | goto abort2; |
531 | } | 531 | } |
532 | 532 | ||
533 | out = kzalloc(fw->size, GFP_KERNEL); | 533 | out = kzalloc(fw->size, GFP_KERNEL | GFP_DMA); |
534 | if (!out) { | 534 | if (!out) { |
535 | dev_err(codec->dev, "Failed to allocate output buffer\n"); | 535 | dev_err(codec->dev, "Failed to allocate output buffer\n"); |
536 | ret = -ENOMEM; | 536 | ret = -ENOMEM; |
@@ -670,14 +670,14 @@ static int wm0010_boot(struct snd_soc_codec *codec) | |||
670 | 670 | ||
671 | ret = -ENOMEM; | 671 | ret = -ENOMEM; |
672 | len = pll_rec.length + 8; | 672 | len = pll_rec.length + 8; |
673 | out = kzalloc(len, GFP_KERNEL); | 673 | out = kzalloc(len, GFP_KERNEL | GFP_DMA); |
674 | if (!out) { | 674 | if (!out) { |
675 | dev_err(codec->dev, | 675 | dev_err(codec->dev, |
676 | "Failed to allocate RX buffer\n"); | 676 | "Failed to allocate RX buffer\n"); |
677 | goto abort; | 677 | goto abort; |
678 | } | 678 | } |
679 | 679 | ||
680 | img_swap = kzalloc(len, GFP_KERNEL); | 680 | img_swap = kzalloc(len, GFP_KERNEL | GFP_DMA); |
681 | if (!img_swap) { | 681 | if (!img_swap) { |
682 | dev_err(codec->dev, | 682 | dev_err(codec->dev, |
683 | "Failed to allocate image buffer\n"); | 683 | "Failed to allocate image buffer\n"); |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 282fd232cdf7..8bbddc151aa8 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
@@ -998,6 +998,8 @@ SND_SOC_DAPM_INPUT("IN2R"), | |||
998 | SND_SOC_DAPM_INPUT("IN3L"), | 998 | SND_SOC_DAPM_INPUT("IN3L"), |
999 | SND_SOC_DAPM_INPUT("IN3R"), | 999 | SND_SOC_DAPM_INPUT("IN3R"), |
1000 | 1000 | ||
1001 | SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), | ||
1002 | |||
1001 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, | 1003 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, |
1002 | 0, NULL, 0, arizona_in_ev, | 1004 | 0, NULL, 0, arizona_in_ev, |
1003 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | | 1005 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | |
@@ -1421,9 +1423,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { | |||
1421 | { "Tone Generator 1", NULL, "TONE" }, | 1423 | { "Tone Generator 1", NULL, "TONE" }, |
1422 | { "Tone Generator 2", NULL, "TONE" }, | 1424 | { "Tone Generator 2", NULL, "TONE" }, |
1423 | 1425 | ||
1424 | { "Mic Mute Mixer", NULL, "Noise Mixer" }, | ||
1425 | { "Mic Mute Mixer", NULL, "Mic Mixer" }, | ||
1426 | |||
1427 | { "AIF1 Capture", NULL, "AIF1TX1" }, | 1426 | { "AIF1 Capture", NULL, "AIF1TX1" }, |
1428 | { "AIF1 Capture", NULL, "AIF1TX2" }, | 1427 | { "AIF1 Capture", NULL, "AIF1TX2" }, |
1429 | { "AIF1 Capture", NULL, "AIF1TX3" }, | 1428 | { "AIF1 Capture", NULL, "AIF1TX3" }, |
@@ -1499,23 +1498,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { | |||
1499 | { "IN3L PGA", NULL, "IN3L" }, | 1498 | { "IN3L PGA", NULL, "IN3L" }, |
1500 | { "IN3R PGA", NULL, "IN3R" }, | 1499 | { "IN3R PGA", NULL, "IN3R" }, |
1501 | 1500 | ||
1502 | { "ASRC1L", NULL, "ASRC1L Input" }, | ||
1503 | { "ASRC1R", NULL, "ASRC1R Input" }, | ||
1504 | { "ASRC2L", NULL, "ASRC2L Input" }, | ||
1505 | { "ASRC2R", NULL, "ASRC2R Input" }, | ||
1506 | |||
1507 | { "ISRC1DEC1", NULL, "ISRC1DEC1 Input" }, | ||
1508 | { "ISRC1DEC2", NULL, "ISRC1DEC2 Input" }, | ||
1509 | |||
1510 | { "ISRC1INT1", NULL, "ISRC1INT1 Input" }, | ||
1511 | { "ISRC1INT2", NULL, "ISRC1INT2 Input" }, | ||
1512 | |||
1513 | { "ISRC2DEC1", NULL, "ISRC2DEC1 Input" }, | ||
1514 | { "ISRC2DEC2", NULL, "ISRC2DEC2 Input" }, | ||
1515 | |||
1516 | { "ISRC2INT1", NULL, "ISRC2INT1 Input" }, | ||
1517 | { "ISRC2INT2", NULL, "ISRC2INT2 Input" }, | ||
1518 | |||
1519 | ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), | 1501 | ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), |
1520 | ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), | 1502 | ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), |
1521 | ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"), | 1503 | ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"), |
@@ -1567,22 +1549,25 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { | |||
1567 | ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), | 1549 | ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), |
1568 | ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), | 1550 | ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), |
1569 | 1551 | ||
1570 | ARIZONA_MUX_ROUTES("ASRC1L"), | 1552 | ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"), |
1571 | ARIZONA_MUX_ROUTES("ASRC1R"), | 1553 | ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"), |
1572 | ARIZONA_MUX_ROUTES("ASRC2L"), | ||
1573 | ARIZONA_MUX_ROUTES("ASRC2R"), | ||
1574 | 1554 | ||
1575 | ARIZONA_MUX_ROUTES("ISRC1INT1"), | 1555 | ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"), |
1576 | ARIZONA_MUX_ROUTES("ISRC1INT2"), | 1556 | ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"), |
1557 | ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"), | ||
1558 | ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"), | ||
1577 | 1559 | ||
1578 | ARIZONA_MUX_ROUTES("ISRC1DEC1"), | 1560 | ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), |
1579 | ARIZONA_MUX_ROUTES("ISRC1DEC2"), | 1561 | ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), |
1580 | 1562 | ||
1581 | ARIZONA_MUX_ROUTES("ISRC2INT1"), | 1563 | ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), |
1582 | ARIZONA_MUX_ROUTES("ISRC2INT2"), | 1564 | ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), |
1583 | 1565 | ||
1584 | ARIZONA_MUX_ROUTES("ISRC2DEC1"), | 1566 | ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), |
1585 | ARIZONA_MUX_ROUTES("ISRC2DEC2"), | 1567 | ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), |
1568 | |||
1569 | ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), | ||
1570 | ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), | ||
1586 | 1571 | ||
1587 | ARIZONA_DSP_ROUTES("DSP1"), | 1572 | ARIZONA_DSP_ROUTES("DSP1"), |
1588 | 1573 | ||
@@ -1614,6 +1599,9 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { | |||
1614 | { "SPKDAT1R", NULL, "OUT5R" }, | 1599 | { "SPKDAT1R", NULL, "OUT5R" }, |
1615 | 1600 | ||
1616 | { "MICSUPP", NULL, "SYSCLK" }, | 1601 | { "MICSUPP", NULL, "SYSCLK" }, |
1602 | |||
1603 | { "DRC1 Signal Activity", NULL, "DRC1L" }, | ||
1604 | { "DRC1 Signal Activity", NULL, "DRC1R" }, | ||
1617 | }; | 1605 | }; |
1618 | 1606 | ||
1619 | static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | 1607 | static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source, |
@@ -1781,6 +1769,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) | |||
1781 | return ret; | 1769 | return ret; |
1782 | 1770 | ||
1783 | arizona_init_spk(codec); | 1771 | arizona_init_spk(codec); |
1772 | arizona_init_gpio(codec); | ||
1784 | 1773 | ||
1785 | snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); | 1774 | snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); |
1786 | 1775 | ||
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 2e7cb4ba161a..bbd64384ca1c 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c | |||
@@ -58,14 +58,10 @@ static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); | |||
58 | SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0) | 58 | SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0) |
59 | 59 | ||
60 | static const struct snd_kcontrol_new wm5110_snd_controls[] = { | 60 | static const struct snd_kcontrol_new wm5110_snd_controls[] = { |
61 | SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL, | 61 | SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]), |
62 | ARIZONA_IN1_OSR_SHIFT, 1, 0), | 62 | SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]), |
63 | SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL, | 63 | SOC_ENUM("IN3 OSR", arizona_in_dmic_osr[2]), |
64 | ARIZONA_IN2_OSR_SHIFT, 1, 0), | 64 | SOC_ENUM("IN4 OSR", arizona_in_dmic_osr[3]), |
65 | SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL, | ||
66 | ARIZONA_IN3_OSR_SHIFT, 1, 0), | ||
67 | SOC_SINGLE("IN4 High Performance Switch", ARIZONA_IN4L_CONTROL, | ||
68 | ARIZONA_IN4_OSR_SHIFT, 1, 0), | ||
69 | 65 | ||
70 | SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL, | 66 | SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL, |
71 | ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | 67 | ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), |
@@ -432,6 +428,9 @@ SND_SOC_DAPM_INPUT("IN3R"), | |||
432 | SND_SOC_DAPM_INPUT("IN4L"), | 428 | SND_SOC_DAPM_INPUT("IN4L"), |
433 | SND_SOC_DAPM_INPUT("IN4R"), | 429 | SND_SOC_DAPM_INPUT("IN4R"), |
434 | 430 | ||
431 | SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), | ||
432 | SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), | ||
433 | |||
435 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, | 434 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, |
436 | 0, NULL, 0, arizona_in_ev, | 435 | 0, NULL, 0, arizona_in_ev, |
437 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | | 436 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | |
@@ -842,9 +841,6 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { | |||
842 | { "Tone Generator 1", NULL, "TONE" }, | 841 | { "Tone Generator 1", NULL, "TONE" }, |
843 | { "Tone Generator 2", NULL, "TONE" }, | 842 | { "Tone Generator 2", NULL, "TONE" }, |
844 | 843 | ||
845 | { "Mic Mute Mixer", NULL, "Noise Mixer" }, | ||
846 | { "Mic Mute Mixer", NULL, "Mic Mixer" }, | ||
847 | |||
848 | { "AIF1 Capture", NULL, "AIF1TX1" }, | 844 | { "AIF1 Capture", NULL, "AIF1TX1" }, |
849 | { "AIF1 Capture", NULL, "AIF1TX2" }, | 845 | { "AIF1 Capture", NULL, "AIF1TX2" }, |
850 | { "AIF1 Capture", NULL, "AIF1TX3" }, | 846 | { "AIF1 Capture", NULL, "AIF1TX3" }, |
@@ -979,10 +975,13 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { | |||
979 | ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), | 975 | ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), |
980 | ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), | 976 | ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), |
981 | 977 | ||
982 | ARIZONA_MUX_ROUTES("ASRC1L"), | 978 | ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"), |
983 | ARIZONA_MUX_ROUTES("ASRC1R"), | 979 | ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"), |
984 | ARIZONA_MUX_ROUTES("ASRC2L"), | 980 | |
985 | ARIZONA_MUX_ROUTES("ASRC2R"), | 981 | ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"), |
982 | ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"), | ||
983 | ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"), | ||
984 | ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"), | ||
986 | 985 | ||
987 | { "HPOUT1L", NULL, "OUT1L" }, | 986 | { "HPOUT1L", NULL, "OUT1L" }, |
988 | { "HPOUT1R", NULL, "OUT1R" }, | 987 | { "HPOUT1R", NULL, "OUT1R" }, |
@@ -1006,6 +1005,11 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { | |||
1006 | { "SPKDAT2R", NULL, "OUT6R" }, | 1005 | { "SPKDAT2R", NULL, "OUT6R" }, |
1007 | 1006 | ||
1008 | { "MICSUPP", NULL, "SYSCLK" }, | 1007 | { "MICSUPP", NULL, "SYSCLK" }, |
1008 | |||
1009 | { "DRC1 Signal Activity", NULL, "DRC1L" }, | ||
1010 | { "DRC1 Signal Activity", NULL, "DRC1R" }, | ||
1011 | { "DRC2 Signal Activity", NULL, "DRC2L" }, | ||
1012 | { "DRC2 Signal Activity", NULL, "DRC2R" }, | ||
1009 | }; | 1013 | }; |
1010 | 1014 | ||
1011 | static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | 1015 | static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, |
@@ -1170,6 +1174,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) | |||
1170 | return ret; | 1174 | return ret; |
1171 | 1175 | ||
1172 | arizona_init_spk(codec); | 1176 | arizona_init_spk(codec); |
1177 | arizona_init_gpio(codec); | ||
1173 | 1178 | ||
1174 | snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); | 1179 | snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); |
1175 | 1180 | ||
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 0e8b3aaf6c8d..af1318ddb062 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -1301,7 +1301,8 @@ static irqreturn_t wm8350_hpl_jack_handler(int irq, void *data) | |||
1301 | if (device_may_wakeup(wm8350->dev)) | 1301 | if (device_may_wakeup(wm8350->dev)) |
1302 | pm_wakeup_event(wm8350->dev, 250); | 1302 | pm_wakeup_event(wm8350->dev, 250); |
1303 | 1303 | ||
1304 | schedule_delayed_work(&priv->hpl.work, msecs_to_jiffies(200)); | 1304 | queue_delayed_work(system_power_efficient_wq, |
1305 | &priv->hpl.work, msecs_to_jiffies(200)); | ||
1305 | 1306 | ||
1306 | return IRQ_HANDLED; | 1307 | return IRQ_HANDLED; |
1307 | } | 1308 | } |
@@ -1318,7 +1319,8 @@ static irqreturn_t wm8350_hpr_jack_handler(int irq, void *data) | |||
1318 | if (device_may_wakeup(wm8350->dev)) | 1319 | if (device_may_wakeup(wm8350->dev)) |
1319 | pm_wakeup_event(wm8350->dev, 250); | 1320 | pm_wakeup_event(wm8350->dev, 250); |
1320 | 1321 | ||
1321 | schedule_delayed_work(&priv->hpr.work, msecs_to_jiffies(200)); | 1322 | queue_delayed_work(system_power_efficient_wq, |
1323 | &priv->hpr.work, msecs_to_jiffies(200)); | ||
1322 | 1324 | ||
1323 | return IRQ_HANDLED; | 1325 | return IRQ_HANDLED; |
1324 | } | 1326 | } |
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c index 462f5e4d5c05..7b1a6d5c11c6 100644 --- a/sound/soc/codecs/wm8727.c +++ b/sound/soc/codecs/wm8727.c | |||
@@ -23,6 +23,16 @@ | |||
23 | #include <sound/initval.h> | 23 | #include <sound/initval.h> |
24 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
25 | 25 | ||
26 | static const struct snd_soc_dapm_widget wm8727_dapm_widgets[] = { | ||
27 | SND_SOC_DAPM_OUTPUT("VOUTL"), | ||
28 | SND_SOC_DAPM_OUTPUT("VOUTR"), | ||
29 | }; | ||
30 | |||
31 | static const struct snd_soc_dapm_route wm8727_dapm_routes[] = { | ||
32 | { "VOUTL", NULL, "Playback" }, | ||
33 | { "VOUTR", NULL, "Playback" }, | ||
34 | }; | ||
35 | |||
26 | /* | 36 | /* |
27 | * Note this is a simple chip with no configuration interface, sample rate is | 37 | * Note this is a simple chip with no configuration interface, sample rate is |
28 | * determined automatically by examining the Master clock and Bit clock ratios | 38 | * determined automatically by examining the Master clock and Bit clock ratios |
@@ -43,7 +53,12 @@ static struct snd_soc_dai_driver wm8727_dai = { | |||
43 | }, | 53 | }, |
44 | }; | 54 | }; |
45 | 55 | ||
46 | static struct snd_soc_codec_driver soc_codec_dev_wm8727; | 56 | static struct snd_soc_codec_driver soc_codec_dev_wm8727 = { |
57 | .dapm_widgets = wm8727_dapm_widgets, | ||
58 | .num_dapm_widgets = ARRAY_SIZE(wm8727_dapm_widgets), | ||
59 | .dapm_routes = wm8727_dapm_routes, | ||
60 | .num_dapm_routes = ARRAY_SIZE(wm8727_dapm_routes), | ||
61 | }; | ||
47 | 62 | ||
48 | static int wm8727_probe(struct platform_device *pdev) | 63 | static int wm8727_probe(struct platform_device *pdev) |
49 | { | 64 | { |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 5276062d6c79..456bb8c6d759 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -45,6 +45,7 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { | |||
45 | struct wm8731_priv { | 45 | struct wm8731_priv { |
46 | struct regmap *regmap; | 46 | struct regmap *regmap; |
47 | struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; | 47 | struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; |
48 | const struct snd_pcm_hw_constraint_list *constraints; | ||
48 | unsigned int sysclk; | 49 | unsigned int sysclk; |
49 | int sysclk_type; | 50 | int sysclk_type; |
50 | int playback_fs; | 51 | int playback_fs; |
@@ -290,6 +291,36 @@ static const struct _coeff_div coeff_div[] = { | |||
290 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, | 291 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, |
291 | }; | 292 | }; |
292 | 293 | ||
294 | /* rates constraints */ | ||
295 | static const unsigned int wm8731_rates_12000000[] = { | ||
296 | 8000, 32000, 44100, 48000, 96000, 88200, | ||
297 | }; | ||
298 | |||
299 | static const unsigned int wm8731_rates_12288000_18432000[] = { | ||
300 | 8000, 32000, 48000, 96000, | ||
301 | }; | ||
302 | |||
303 | static const unsigned int wm8731_rates_11289600_16934400[] = { | ||
304 | 8000, 44100, 88200, | ||
305 | }; | ||
306 | |||
307 | static const struct snd_pcm_hw_constraint_list wm8731_constraints_12000000 = { | ||
308 | .list = wm8731_rates_12000000, | ||
309 | .count = ARRAY_SIZE(wm8731_rates_12000000), | ||
310 | }; | ||
311 | |||
312 | static const | ||
313 | struct snd_pcm_hw_constraint_list wm8731_constraints_12288000_18432000 = { | ||
314 | .list = wm8731_rates_12288000_18432000, | ||
315 | .count = ARRAY_SIZE(wm8731_rates_12288000_18432000), | ||
316 | }; | ||
317 | |||
318 | static const | ||
319 | struct snd_pcm_hw_constraint_list wm8731_constraints_11289600_16934400 = { | ||
320 | .list = wm8731_rates_11289600_16934400, | ||
321 | .count = ARRAY_SIZE(wm8731_rates_11289600_16934400), | ||
322 | }; | ||
323 | |||
293 | static inline int get_coeff(int mclk, int rate) | 324 | static inline int get_coeff(int mclk, int rate) |
294 | { | 325 | { |
295 | int i; | 326 | int i; |
@@ -362,17 +393,26 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
362 | } | 393 | } |
363 | 394 | ||
364 | switch (freq) { | 395 | switch (freq) { |
365 | case 11289600: | 396 | case 0: |
397 | wm8731->constraints = NULL; | ||
398 | break; | ||
366 | case 12000000: | 399 | case 12000000: |
400 | wm8731->constraints = &wm8731_constraints_12000000; | ||
401 | break; | ||
367 | case 12288000: | 402 | case 12288000: |
368 | case 16934400: | ||
369 | case 18432000: | 403 | case 18432000: |
370 | wm8731->sysclk = freq; | 404 | wm8731->constraints = &wm8731_constraints_12288000_18432000; |
405 | break; | ||
406 | case 16934400: | ||
407 | case 11289600: | ||
408 | wm8731->constraints = &wm8731_constraints_11289600_16934400; | ||
371 | break; | 409 | break; |
372 | default: | 410 | default: |
373 | return -EINVAL; | 411 | return -EINVAL; |
374 | } | 412 | } |
375 | 413 | ||
414 | wm8731->sysclk = freq; | ||
415 | |||
376 | snd_soc_dapm_sync(&codec->dapm); | 416 | snd_soc_dapm_sync(&codec->dapm); |
377 | 417 | ||
378 | return 0; | 418 | return 0; |
@@ -475,12 +515,26 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, | |||
475 | return 0; | 515 | return 0; |
476 | } | 516 | } |
477 | 517 | ||
518 | static int wm8731_startup(struct snd_pcm_substream *substream, | ||
519 | struct snd_soc_dai *dai) | ||
520 | { | ||
521 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(dai->codec); | ||
522 | |||
523 | if (wm8731->constraints) | ||
524 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
525 | SNDRV_PCM_HW_PARAM_RATE, | ||
526 | wm8731->constraints); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
478 | #define WM8731_RATES SNDRV_PCM_RATE_8000_96000 | 531 | #define WM8731_RATES SNDRV_PCM_RATE_8000_96000 |
479 | 532 | ||
480 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 533 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
481 | SNDRV_PCM_FMTBIT_S24_LE) | 534 | SNDRV_PCM_FMTBIT_S24_LE) |
482 | 535 | ||
483 | static const struct snd_soc_dai_ops wm8731_dai_ops = { | 536 | static const struct snd_soc_dai_ops wm8731_dai_ops = { |
537 | .startup = wm8731_startup, | ||
484 | .hw_params = wm8731_hw_params, | 538 | .hw_params = wm8731_hw_params, |
485 | .digital_mute = wm8731_mute, | 539 | .digital_mute = wm8731_mute, |
486 | .set_sysclk = wm8731_set_dai_sysclk, | 540 | .set_sysclk = wm8731_set_dai_sysclk, |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 0a4ab4c423d1..d96ebf52d953 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -1456,8 +1456,9 @@ static int wm8753_resume(struct snd_soc_codec *codec) | |||
1456 | if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { | 1456 | if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { |
1457 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 1457 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1458 | codec->dapm.bias_level = SND_SOC_BIAS_ON; | 1458 | codec->dapm.bias_level = SND_SOC_BIAS_ON; |
1459 | schedule_delayed_work(&codec->dapm.delayed_work, | 1459 | queue_delayed_work(system_power_efficient_wq, |
1460 | msecs_to_jiffies(caps_charge)); | 1460 | &codec->dapm.delayed_work, |
1461 | msecs_to_jiffies(caps_charge)); | ||
1461 | } | 1462 | } |
1462 | 1463 | ||
1463 | return 0; | 1464 | return 0; |
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c index f1fdbf63abb4..8092495605ce 100644 --- a/sound/soc/codecs/wm8782.c +++ b/sound/soc/codecs/wm8782.c | |||
@@ -26,6 +26,16 @@ | |||
26 | #include <sound/initval.h> | 26 | #include <sound/initval.h> |
27 | #include <sound/soc.h> | 27 | #include <sound/soc.h> |
28 | 28 | ||
29 | static const struct snd_soc_dapm_widget wm8782_dapm_widgets[] = { | ||
30 | SND_SOC_DAPM_INPUT("AINL"), | ||
31 | SND_SOC_DAPM_INPUT("AINR"), | ||
32 | }; | ||
33 | |||
34 | static const struct snd_soc_dapm_route wm8782_dapm_routes[] = { | ||
35 | { "Capture", NULL, "AINL" }, | ||
36 | { "Capture", NULL, "AINR" }, | ||
37 | }; | ||
38 | |||
29 | static struct snd_soc_dai_driver wm8782_dai = { | 39 | static struct snd_soc_dai_driver wm8782_dai = { |
30 | .name = "wm8782", | 40 | .name = "wm8782", |
31 | .capture = { | 41 | .capture = { |
@@ -40,7 +50,12 @@ static struct snd_soc_dai_driver wm8782_dai = { | |||
40 | }, | 50 | }, |
41 | }; | 51 | }; |
42 | 52 | ||
43 | static struct snd_soc_codec_driver soc_codec_dev_wm8782; | 53 | static struct snd_soc_codec_driver soc_codec_dev_wm8782 = { |
54 | .dapm_widgets = wm8782_dapm_widgets, | ||
55 | .num_dapm_widgets = ARRAY_SIZE(wm8782_dapm_widgets), | ||
56 | .dapm_routes = wm8782_dapm_routes, | ||
57 | .num_dapm_routes = ARRAY_SIZE(wm8782_dapm_routes), | ||
58 | }; | ||
44 | 59 | ||
45 | static int wm8782_probe(struct platform_device *pdev) | 60 | static int wm8782_probe(struct platform_device *pdev) |
46 | { | 61 | { |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index fa24cedee687..eebcb1da3b7b 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -364,9 +364,7 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm, | |||
364 | static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, | 364 | static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, |
365 | struct snd_ctl_elem_value *ucontrol) | 365 | struct snd_ctl_elem_value *ucontrol) |
366 | { | 366 | { |
367 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 367 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
368 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
369 | struct snd_soc_codec *codec = widget->codec; | ||
370 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | 368 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); |
371 | u16 reg; | 369 | u16 reg; |
372 | int ret; | 370 | int ret; |
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 4c9fb142cb2d..91dfbfeda6f8 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -1012,7 +1012,7 @@ static const struct soc_enum liner_enum = | |||
1012 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text); | 1012 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text); |
1013 | 1013 | ||
1014 | static const struct snd_kcontrol_new liner_mux = | 1014 | static const struct snd_kcontrol_new liner_mux = |
1015 | SOC_DAPM_ENUM("LINEL Mux", liner_enum); | 1015 | SOC_DAPM_ENUM("LINER Mux", liner_enum); |
1016 | 1016 | ||
1017 | static const char *sidetone_text[] = { | 1017 | static const char *sidetone_text[] = { |
1018 | "None", "Left", "Right" | 1018 | "None", "Left", "Right" |
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 0a4ffdd1d2a7..f156010e52bc 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -263,8 +263,8 @@ SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0), | |||
263 | SOC_SINGLE("Noise Gate Threshold", WM8960_NOISEG, 3, 31, 0), | 263 | SOC_SINGLE("Noise Gate Threshold", WM8960_NOISEG, 3, 31, 0), |
264 | SOC_SINGLE("Noise Gate Switch", WM8960_NOISEG, 0, 1, 0), | 264 | SOC_SINGLE("Noise Gate Switch", WM8960_NOISEG, 0, 1, 0), |
265 | 265 | ||
266 | SOC_DOUBLE_R("ADC PCM Capture Volume", WM8960_LINPATH, WM8960_RINPATH, | 266 | SOC_DOUBLE_R_TLV("ADC PCM Capture Volume", WM8960_LADC, WM8960_RADC, |
267 | 0, 127, 0), | 267 | 0, 255, 0, adc_tlv), |
268 | 268 | ||
269 | SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume", | 269 | SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume", |
270 | WM8960_BYPASS1, 4, 7, 1, bypass_tlv), | 270 | WM8960_BYPASS1, 4, 7, 1, bypass_tlv), |
@@ -857,9 +857,9 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, | |||
857 | if (pll_div.k) { | 857 | if (pll_div.k) { |
858 | reg |= 0x20; | 858 | reg |= 0x20; |
859 | 859 | ||
860 | snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); | 860 | snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 16) & 0xff); |
861 | snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); | 861 | snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 8) & 0xff); |
862 | snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); | 862 | snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0xff); |
863 | } | 863 | } |
864 | snd_soc_write(codec, WM8960_PLL1, reg); | 864 | snd_soc_write(codec, WM8960_PLL1, reg); |
865 | 865 | ||
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index e2de9ecfd641..36782f067cc5 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -2621,8 +2621,6 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
2621 | 2621 | ||
2622 | wm8962->sysclk_rate = freq; | 2622 | wm8962->sysclk_rate = freq; |
2623 | 2623 | ||
2624 | wm8962_configure_bclk(codec); | ||
2625 | |||
2626 | return 0; | 2624 | return 0; |
2627 | } | 2625 | } |
2628 | 2626 | ||
@@ -3046,8 +3044,9 @@ static irqreturn_t wm8962_irq(int irq, void *data) | |||
3046 | 3044 | ||
3047 | pm_wakeup_event(dev, 300); | 3045 | pm_wakeup_event(dev, 300); |
3048 | 3046 | ||
3049 | schedule_delayed_work(&wm8962->mic_work, | 3047 | queue_delayed_work(system_power_efficient_wq, |
3050 | msecs_to_jiffies(250)); | 3048 | &wm8962->mic_work, |
3049 | msecs_to_jiffies(250)); | ||
3051 | } | 3050 | } |
3052 | 3051 | ||
3053 | return IRQ_HANDLED; | 3052 | return IRQ_HANDLED; |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index ba832b77c543..86426a117b07 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -819,8 +819,9 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, | |||
819 | * don't want false reports. | 819 | * don't want false reports. |
820 | */ | 820 | */ |
821 | if (wm8994->jackdet && !wm8994->clk_has_run) { | 821 | if (wm8994->jackdet && !wm8994->clk_has_run) { |
822 | schedule_delayed_work(&wm8994->jackdet_bootstrap, | 822 | queue_delayed_work(system_power_efficient_wq, |
823 | msecs_to_jiffies(1000)); | 823 | &wm8994->jackdet_bootstrap, |
824 | msecs_to_jiffies(1000)); | ||
824 | wm8994->clk_has_run = true; | 825 | wm8994->clk_has_run = true; |
825 | } | 826 | } |
826 | break; | 827 | break; |
@@ -1432,14 +1433,12 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, | |||
1432 | 1433 | ||
1433 | #define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \ | 1434 | #define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \ |
1434 | SOC_SINGLE_EXT(xname, reg, shift, max, invert, \ | 1435 | SOC_SINGLE_EXT(xname, reg, shift, max, invert, \ |
1435 | snd_soc_get_volsw, wm8994_put_class_w) | 1436 | snd_soc_dapm_get_volsw, wm8994_put_class_w) |
1436 | 1437 | ||
1437 | static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, | 1438 | static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, |
1438 | struct snd_ctl_elem_value *ucontrol) | 1439 | struct snd_ctl_elem_value *ucontrol) |
1439 | { | 1440 | { |
1440 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 1441 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
1441 | struct snd_soc_dapm_widget *w = wlist->widgets[0]; | ||
1442 | struct snd_soc_codec *codec = w->codec; | ||
1443 | int ret; | 1442 | int ret; |
1444 | 1443 | ||
1445 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); | 1444 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); |
@@ -3487,7 +3486,8 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data) | |||
3487 | 3486 | ||
3488 | pm_wakeup_event(codec->dev, 300); | 3487 | pm_wakeup_event(codec->dev, 300); |
3489 | 3488 | ||
3490 | schedule_delayed_work(&priv->mic_work, msecs_to_jiffies(250)); | 3489 | queue_delayed_work(system_power_efficient_wq, |
3490 | &priv->mic_work, msecs_to_jiffies(250)); | ||
3491 | 3491 | ||
3492 | return IRQ_HANDLED; | 3492 | return IRQ_HANDLED; |
3493 | } | 3493 | } |
@@ -3575,8 +3575,9 @@ static void wm8958_mic_id(void *data, u16 status) | |||
3575 | /* If nothing present then clear our statuses */ | 3575 | /* If nothing present then clear our statuses */ |
3576 | dev_dbg(codec->dev, "Detected open circuit\n"); | 3576 | dev_dbg(codec->dev, "Detected open circuit\n"); |
3577 | 3577 | ||
3578 | schedule_delayed_work(&wm8994->open_circuit_work, | 3578 | queue_delayed_work(system_power_efficient_wq, |
3579 | msecs_to_jiffies(2500)); | 3579 | &wm8994->open_circuit_work, |
3580 | msecs_to_jiffies(2500)); | ||
3580 | return; | 3581 | return; |
3581 | } | 3582 | } |
3582 | 3583 | ||
@@ -3690,8 +3691,9 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) | |||
3690 | WM1811_JACKDET_DB, 0); | 3691 | WM1811_JACKDET_DB, 0); |
3691 | 3692 | ||
3692 | delay = control->pdata.micdet_delay; | 3693 | delay = control->pdata.micdet_delay; |
3693 | schedule_delayed_work(&wm8994->mic_work, | 3694 | queue_delayed_work(system_power_efficient_wq, |
3694 | msecs_to_jiffies(delay)); | 3695 | &wm8994->mic_work, |
3696 | msecs_to_jiffies(delay)); | ||
3695 | } else { | 3697 | } else { |
3696 | dev_dbg(codec->dev, "Jack not detected\n"); | 3698 | dev_dbg(codec->dev, "Jack not detected\n"); |
3697 | 3699 | ||
@@ -3936,8 +3938,9 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) | |||
3936 | id_delay = wm8994->wm8994->pdata.mic_id_delay; | 3938 | id_delay = wm8994->wm8994->pdata.mic_id_delay; |
3937 | 3939 | ||
3938 | if (wm8994->mic_detecting) | 3940 | if (wm8994->mic_detecting) |
3939 | schedule_delayed_work(&wm8994->mic_complete_work, | 3941 | queue_delayed_work(system_power_efficient_wq, |
3940 | msecs_to_jiffies(id_delay)); | 3942 | &wm8994->mic_complete_work, |
3943 | msecs_to_jiffies(id_delay)); | ||
3941 | else | 3944 | else |
3942 | wm8958_button_det(codec, reg); | 3945 | wm8958_button_det(codec, reg); |
3943 | 3946 | ||
@@ -4010,9 +4013,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
4010 | 4013 | ||
4011 | wm8994->micdet_irq = control->pdata.micdet_irq; | 4014 | wm8994->micdet_irq = control->pdata.micdet_irq; |
4012 | 4015 | ||
4013 | pm_runtime_enable(codec->dev); | ||
4014 | pm_runtime_idle(codec->dev); | ||
4015 | |||
4016 | /* By default use idle_bias_off, will override for WM8994 */ | 4016 | /* By default use idle_bias_off, will override for WM8994 */ |
4017 | codec->dapm.idle_bias_off = 1; | 4017 | codec->dapm.idle_bias_off = 1; |
4018 | 4018 | ||
@@ -4385,8 +4385,6 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) | |||
4385 | 4385 | ||
4386 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); | 4386 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); |
4387 | 4387 | ||
4388 | pm_runtime_disable(codec->dev); | ||
4389 | |||
4390 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) | 4388 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) |
4391 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i, | 4389 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i, |
4392 | &wm8994->fll_locked[i]); | 4390 | &wm8994->fll_locked[i]); |
@@ -4445,6 +4443,9 @@ static int wm8994_probe(struct platform_device *pdev) | |||
4445 | 4443 | ||
4446 | wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); | 4444 | wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); |
4447 | 4445 | ||
4446 | pm_runtime_enable(&pdev->dev); | ||
4447 | pm_runtime_idle(&pdev->dev); | ||
4448 | |||
4448 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994, | 4449 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994, |
4449 | wm8994_dai, ARRAY_SIZE(wm8994_dai)); | 4450 | wm8994_dai, ARRAY_SIZE(wm8994_dai)); |
4450 | } | 4451 | } |
@@ -4452,6 +4453,8 @@ static int wm8994_probe(struct platform_device *pdev) | |||
4452 | static int wm8994_remove(struct platform_device *pdev) | 4453 | static int wm8994_remove(struct platform_device *pdev) |
4453 | { | 4454 | { |
4454 | snd_soc_unregister_codec(&pdev->dev); | 4455 | snd_soc_unregister_codec(&pdev->dev); |
4456 | pm_runtime_disable(&pdev->dev); | ||
4457 | |||
4455 | return 0; | 4458 | return 0; |
4456 | } | 4459 | } |
4457 | 4460 | ||
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 90a65c427541..da2899e6c401 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c | |||
@@ -549,12 +549,9 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source, | |||
549 | static int wm8995_put_class_w(struct snd_kcontrol *kcontrol, | 549 | static int wm8995_put_class_w(struct snd_kcontrol *kcontrol, |
550 | struct snd_ctl_elem_value *ucontrol) | 550 | struct snd_ctl_elem_value *ucontrol) |
551 | { | 551 | { |
552 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 552 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
553 | struct snd_soc_dapm_widget *w = wlist->widgets[0]; | ||
554 | struct snd_soc_codec *codec; | ||
555 | int ret; | 553 | int ret; |
556 | 554 | ||
557 | codec = w->codec; | ||
558 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); | 555 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); |
559 | wm8995_update_class_w(codec); | 556 | wm8995_update_class_w(codec); |
560 | return ret; | 557 | return ret; |
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c new file mode 100644 index 000000000000..6ec3de3efa4f --- /dev/null +++ b/sound/soc/codecs/wm8997.c | |||
@@ -0,0 +1,1175 @@ | |||
1 | /* | ||
2 | * wm8997.c -- WM8997 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2012 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Charles Keepax <ckeepax@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 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/pm_runtime.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/jack.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/tlv.h> | ||
28 | |||
29 | #include <linux/mfd/arizona/core.h> | ||
30 | #include <linux/mfd/arizona/registers.h> | ||
31 | |||
32 | #include "arizona.h" | ||
33 | #include "wm8997.h" | ||
34 | |||
35 | struct wm8997_priv { | ||
36 | struct arizona_priv core; | ||
37 | struct arizona_fll fll[2]; | ||
38 | }; | ||
39 | |||
40 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); | ||
41 | static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | ||
42 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); | ||
43 | static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0); | ||
44 | static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); | ||
45 | |||
46 | static const struct reg_default wm8997_sysclk_reva_patch[] = { | ||
47 | { 0x301D, 0x7B15 }, | ||
48 | { 0x301B, 0x0050 }, | ||
49 | { 0x305D, 0x7B17 }, | ||
50 | { 0x305B, 0x0050 }, | ||
51 | { 0x3001, 0x08FE }, | ||
52 | { 0x3003, 0x00F4 }, | ||
53 | { 0x3041, 0x08FF }, | ||
54 | { 0x3043, 0x0005 }, | ||
55 | { 0x3020, 0x0225 }, | ||
56 | { 0x3021, 0x0A00 }, | ||
57 | { 0x3022, 0xE24D }, | ||
58 | { 0x3023, 0x0800 }, | ||
59 | { 0x3024, 0xE24D }, | ||
60 | { 0x3025, 0xF000 }, | ||
61 | { 0x3060, 0x0226 }, | ||
62 | { 0x3061, 0x0A00 }, | ||
63 | { 0x3062, 0xE252 }, | ||
64 | { 0x3063, 0x0800 }, | ||
65 | { 0x3064, 0xE252 }, | ||
66 | { 0x3065, 0xF000 }, | ||
67 | { 0x3116, 0x022B }, | ||
68 | { 0x3117, 0xFA00 }, | ||
69 | { 0x3110, 0x246C }, | ||
70 | { 0x3111, 0x0A03 }, | ||
71 | { 0x3112, 0x246E }, | ||
72 | { 0x3113, 0x0A03 }, | ||
73 | { 0x3114, 0x2470 }, | ||
74 | { 0x3115, 0x0A03 }, | ||
75 | { 0x3126, 0x246C }, | ||
76 | { 0x3127, 0x0A02 }, | ||
77 | { 0x3128, 0x246E }, | ||
78 | { 0x3129, 0x0A02 }, | ||
79 | { 0x312A, 0x2470 }, | ||
80 | { 0x312B, 0xFA02 }, | ||
81 | { 0x3125, 0x0800 }, | ||
82 | }; | ||
83 | |||
84 | static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w, | ||
85 | struct snd_kcontrol *kcontrol, int event) | ||
86 | { | ||
87 | struct snd_soc_codec *codec = w->codec; | ||
88 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | ||
89 | struct regmap *regmap = codec->control_data; | ||
90 | const struct reg_default *patch = NULL; | ||
91 | int i, patch_size; | ||
92 | |||
93 | switch (arizona->rev) { | ||
94 | case 0: | ||
95 | patch = wm8997_sysclk_reva_patch; | ||
96 | patch_size = ARRAY_SIZE(wm8997_sysclk_reva_patch); | ||
97 | break; | ||
98 | default: | ||
99 | break; | ||
100 | } | ||
101 | |||
102 | switch (event) { | ||
103 | case SND_SOC_DAPM_POST_PMU: | ||
104 | if (patch) | ||
105 | for (i = 0; i < patch_size; i++) | ||
106 | regmap_write(regmap, patch[i].reg, | ||
107 | patch[i].def); | ||
108 | break; | ||
109 | default: | ||
110 | break; | ||
111 | } | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static const char *wm8997_osr_text[] = { | ||
117 | "Low power", "Normal", "High performance", | ||
118 | }; | ||
119 | |||
120 | static const unsigned int wm8997_osr_val[] = { | ||
121 | 0x0, 0x3, 0x5, | ||
122 | }; | ||
123 | |||
124 | static const struct soc_enum wm8997_hpout_osr[] = { | ||
125 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, | ||
126 | ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, | ||
127 | wm8997_osr_text, wm8997_osr_val), | ||
128 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, | ||
129 | ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, | ||
130 | wm8997_osr_text, wm8997_osr_val), | ||
131 | }; | ||
132 | |||
133 | #define WM8997_NG_SRC(name, base) \ | ||
134 | SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ | ||
135 | SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ | ||
136 | SOC_SINGLE(name " NG EPOUT Switch", base, 4, 1, 0), \ | ||
137 | SOC_SINGLE(name " NG SPKOUT Switch", base, 6, 1, 0), \ | ||
138 | SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \ | ||
139 | SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0) | ||
140 | |||
141 | static const struct snd_kcontrol_new wm8997_snd_controls[] = { | ||
142 | SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL, | ||
143 | ARIZONA_IN1_OSR_SHIFT, 1, 0), | ||
144 | SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL, | ||
145 | ARIZONA_IN2_OSR_SHIFT, 1, 0), | ||
146 | |||
147 | SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL, | ||
148 | ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
149 | SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL, | ||
150 | ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
151 | SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL, | ||
152 | ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
153 | SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL, | ||
154 | ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
155 | |||
156 | SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, | ||
157 | ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), | ||
158 | SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, | ||
159 | ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), | ||
160 | SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L, | ||
161 | ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), | ||
162 | SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R, | ||
163 | ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), | ||
164 | |||
165 | SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp), | ||
166 | SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp), | ||
167 | |||
168 | ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), | ||
169 | ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), | ||
170 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), | ||
171 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), | ||
172 | |||
173 | SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21, | ||
174 | ARIZONA_EQ1_ENA_MASK), | ||
175 | SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21, | ||
176 | ARIZONA_EQ2_ENA_MASK), | ||
177 | SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21, | ||
178 | ARIZONA_EQ3_ENA_MASK), | ||
179 | SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21, | ||
180 | ARIZONA_EQ4_ENA_MASK), | ||
181 | |||
182 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, | ||
183 | 24, 0, eq_tlv), | ||
184 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, | ||
185 | 24, 0, eq_tlv), | ||
186 | SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT, | ||
187 | 24, 0, eq_tlv), | ||
188 | SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, | ||
189 | 24, 0, eq_tlv), | ||
190 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, | ||
191 | 24, 0, eq_tlv), | ||
192 | |||
193 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, | ||
194 | 24, 0, eq_tlv), | ||
195 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, | ||
196 | 24, 0, eq_tlv), | ||
197 | SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT, | ||
198 | 24, 0, eq_tlv), | ||
199 | SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, | ||
200 | 24, 0, eq_tlv), | ||
201 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, | ||
202 | 24, 0, eq_tlv), | ||
203 | |||
204 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, | ||
205 | 24, 0, eq_tlv), | ||
206 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, | ||
207 | 24, 0, eq_tlv), | ||
208 | SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT, | ||
209 | 24, 0, eq_tlv), | ||
210 | SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, | ||
211 | 24, 0, eq_tlv), | ||
212 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, | ||
213 | 24, 0, eq_tlv), | ||
214 | |||
215 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, | ||
216 | 24, 0, eq_tlv), | ||
217 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, | ||
218 | 24, 0, eq_tlv), | ||
219 | SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT, | ||
220 | 24, 0, eq_tlv), | ||
221 | SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT, | ||
222 | 24, 0, eq_tlv), | ||
223 | SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT, | ||
224 | 24, 0, eq_tlv), | ||
225 | |||
226 | ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE), | ||
227 | ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE), | ||
228 | |||
229 | SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5, | ||
230 | ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA), | ||
231 | |||
232 | ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE), | ||
233 | ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), | ||
234 | ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), | ||
235 | ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), | ||
236 | |||
237 | SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), | ||
238 | SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), | ||
239 | SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), | ||
240 | SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), | ||
241 | |||
242 | SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), | ||
243 | SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), | ||
244 | SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), | ||
245 | SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), | ||
246 | |||
247 | SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), | ||
248 | SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), | ||
249 | |||
250 | ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), | ||
251 | ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), | ||
252 | |||
253 | SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR, | ||
254 | ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv), | ||
255 | |||
256 | ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE), | ||
257 | ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE), | ||
258 | ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE), | ||
259 | ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE), | ||
260 | ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE), | ||
261 | ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE), | ||
262 | |||
263 | SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L, | ||
264 | ARIZONA_OUT4_OSR_SHIFT, 1, 0), | ||
265 | SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, | ||
266 | ARIZONA_OUT5_OSR_SHIFT, 1, 0), | ||
267 | |||
268 | SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L, | ||
269 | ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1), | ||
270 | SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L, | ||
271 | ARIZONA_OUT3L_MUTE_SHIFT, 1, 1), | ||
272 | SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L, | ||
273 | ARIZONA_OUT4L_MUTE_SHIFT, 1, 1), | ||
274 | SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L, | ||
275 | ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1), | ||
276 | |||
277 | SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L, | ||
278 | ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT, | ||
279 | 0xbf, 0, digital_tlv), | ||
280 | SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L, | ||
281 | ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv), | ||
282 | SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L, | ||
283 | ARIZONA_OUT4L_VOL_SHIFT, 0xbf, 0, digital_tlv), | ||
284 | SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, | ||
285 | ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, | ||
286 | 0xbf, 0, digital_tlv), | ||
287 | |||
288 | SOC_VALUE_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]), | ||
289 | SOC_VALUE_ENUM("EPOUT OSR", wm8997_hpout_osr[1]), | ||
290 | |||
291 | SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), | ||
292 | SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), | ||
293 | |||
294 | SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, | ||
295 | ARIZONA_SPK1R_MUTE_SHIFT, 1, 1), | ||
296 | |||
297 | SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL, | ||
298 | ARIZONA_NGATE_ENA_SHIFT, 1, 0), | ||
299 | SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL, | ||
300 | ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv), | ||
301 | SOC_ENUM("Noise Gate Hold", arizona_ng_hold), | ||
302 | |||
303 | WM8997_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L), | ||
304 | WM8997_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R), | ||
305 | WM8997_NG_SRC("EPOUT", ARIZONA_NOISE_GATE_SELECT_3L), | ||
306 | WM8997_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L), | ||
307 | WM8997_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L), | ||
308 | WM8997_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R), | ||
309 | |||
310 | ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE), | ||
311 | ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE), | ||
312 | ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE), | ||
313 | ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE), | ||
314 | ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE), | ||
315 | ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE), | ||
316 | ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE), | ||
317 | ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE), | ||
318 | |||
319 | ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE), | ||
320 | ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE), | ||
321 | |||
322 | ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE), | ||
323 | ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE), | ||
324 | ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE), | ||
325 | ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE), | ||
326 | ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE), | ||
327 | ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE), | ||
328 | ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE), | ||
329 | ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE), | ||
330 | }; | ||
331 | |||
332 | ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); | ||
333 | ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); | ||
334 | ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE); | ||
335 | ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE); | ||
336 | |||
337 | ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE); | ||
338 | ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE); | ||
339 | |||
340 | ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE); | ||
341 | ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE); | ||
342 | ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE); | ||
343 | ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE); | ||
344 | |||
345 | ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE); | ||
346 | ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE); | ||
347 | |||
348 | ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE); | ||
349 | ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE); | ||
350 | |||
351 | ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE); | ||
352 | ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE); | ||
353 | ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE); | ||
354 | ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE); | ||
355 | ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE); | ||
356 | ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE); | ||
357 | |||
358 | ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE); | ||
359 | ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE); | ||
360 | ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE); | ||
361 | ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE); | ||
362 | ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE); | ||
363 | ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE); | ||
364 | ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE); | ||
365 | ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE); | ||
366 | |||
367 | ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE); | ||
368 | ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); | ||
369 | |||
370 | ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE); | ||
371 | ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE); | ||
372 | ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE); | ||
373 | ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE); | ||
374 | ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE); | ||
375 | ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE); | ||
376 | ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE); | ||
377 | ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE); | ||
378 | |||
379 | ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE); | ||
380 | ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE); | ||
381 | |||
382 | ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE); | ||
383 | ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE); | ||
384 | |||
385 | ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE); | ||
386 | ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE); | ||
387 | |||
388 | ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE); | ||
389 | ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE); | ||
390 | |||
391 | static const char *wm8997_aec_loopback_texts[] = { | ||
392 | "HPOUT1L", "HPOUT1R", "EPOUT", "SPKOUT", "SPKDAT1L", "SPKDAT1R", | ||
393 | }; | ||
394 | |||
395 | static const unsigned int wm8997_aec_loopback_values[] = { | ||
396 | 0, 1, 4, 6, 8, 9, | ||
397 | }; | ||
398 | |||
399 | static const struct soc_enum wm8997_aec_loopback = | ||
400 | SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1, | ||
401 | ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, | ||
402 | ARRAY_SIZE(wm8997_aec_loopback_texts), | ||
403 | wm8997_aec_loopback_texts, | ||
404 | wm8997_aec_loopback_values); | ||
405 | |||
406 | static const struct snd_kcontrol_new wm8997_aec_loopback_mux = | ||
407 | SOC_DAPM_VALUE_ENUM("AEC Loopback", wm8997_aec_loopback); | ||
408 | |||
409 | static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = { | ||
410 | SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, | ||
411 | 0, wm8997_sysclk_ev, SND_SOC_DAPM_POST_PMU), | ||
412 | SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, | ||
413 | ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), | ||
414 | SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, | ||
415 | ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), | ||
416 | SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, | ||
417 | ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0), | ||
418 | |||
419 | SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0), | ||
420 | SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0), | ||
421 | SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS), | ||
422 | SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0), | ||
423 | |||
424 | SND_SOC_DAPM_SIGGEN("TONE"), | ||
425 | SND_SOC_DAPM_SIGGEN("NOISE"), | ||
426 | SND_SOC_DAPM_SIGGEN("HAPTICS"), | ||
427 | |||
428 | SND_SOC_DAPM_INPUT("IN1L"), | ||
429 | SND_SOC_DAPM_INPUT("IN1R"), | ||
430 | SND_SOC_DAPM_INPUT("IN2L"), | ||
431 | SND_SOC_DAPM_INPUT("IN2R"), | ||
432 | |||
433 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, | ||
434 | 0, NULL, 0, arizona_in_ev, | ||
435 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | | ||
436 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), | ||
437 | SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, | ||
438 | 0, NULL, 0, arizona_in_ev, | ||
439 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | | ||
440 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), | ||
441 | SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, | ||
442 | 0, NULL, 0, arizona_in_ev, | ||
443 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | | ||
444 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), | ||
445 | SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, | ||
446 | 0, NULL, 0, arizona_in_ev, | ||
447 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | | ||
448 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), | ||
449 | |||
450 | SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, | ||
451 | ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), | ||
452 | SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2, | ||
453 | ARIZONA_MICB2_ENA_SHIFT, 0, NULL, 0), | ||
454 | SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3, | ||
455 | ARIZONA_MICB3_ENA_SHIFT, 0, NULL, 0), | ||
456 | |||
457 | SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR, | ||
458 | ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), | ||
459 | |||
460 | SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1, | ||
461 | ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0), | ||
462 | SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1, | ||
463 | ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0), | ||
464 | |||
465 | SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1, | ||
466 | ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0), | ||
467 | |||
468 | SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0), | ||
469 | SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0), | ||
470 | SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0), | ||
471 | SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0), | ||
472 | |||
473 | SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0, | ||
474 | NULL, 0), | ||
475 | SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0, | ||
476 | NULL, 0), | ||
477 | |||
478 | SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0, | ||
479 | NULL, 0), | ||
480 | SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0, | ||
481 | NULL, 0), | ||
482 | SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0, | ||
483 | NULL, 0), | ||
484 | SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0, | ||
485 | NULL, 0), | ||
486 | |||
487 | SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT, | ||
488 | 0, NULL, 0), | ||
489 | SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT, | ||
490 | 0, NULL, 0), | ||
491 | |||
492 | SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3, | ||
493 | ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0), | ||
494 | SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3, | ||
495 | ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0), | ||
496 | |||
497 | SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3, | ||
498 | ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0), | ||
499 | SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3, | ||
500 | ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0), | ||
501 | |||
502 | SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3, | ||
503 | ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0), | ||
504 | SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3, | ||
505 | ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0), | ||
506 | |||
507 | SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3, | ||
508 | ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0), | ||
509 | SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3, | ||
510 | ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0), | ||
511 | |||
512 | SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, | ||
513 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), | ||
514 | SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, | ||
515 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), | ||
516 | SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, | ||
517 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), | ||
518 | SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, | ||
519 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), | ||
520 | SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, | ||
521 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), | ||
522 | SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, | ||
523 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), | ||
524 | SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, | ||
525 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), | ||
526 | SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, | ||
527 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), | ||
528 | |||
529 | SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, | ||
530 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), | ||
531 | SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, | ||
532 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), | ||
533 | SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, | ||
534 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), | ||
535 | SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, | ||
536 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), | ||
537 | SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, | ||
538 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), | ||
539 | SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, | ||
540 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), | ||
541 | SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, | ||
542 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), | ||
543 | SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, | ||
544 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), | ||
545 | |||
546 | SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, | ||
547 | ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), | ||
548 | SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, | ||
549 | ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), | ||
550 | |||
551 | SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, | ||
552 | ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), | ||
553 | SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, | ||
554 | ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), | ||
555 | |||
556 | SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, | ||
557 | ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, | ||
558 | ARIZONA_SLIMTX1_ENA_SHIFT, 0), | ||
559 | SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, | ||
560 | ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, | ||
561 | ARIZONA_SLIMTX2_ENA_SHIFT, 0), | ||
562 | SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, | ||
563 | ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, | ||
564 | ARIZONA_SLIMTX3_ENA_SHIFT, 0), | ||
565 | SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, | ||
566 | ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, | ||
567 | ARIZONA_SLIMTX4_ENA_SHIFT, 0), | ||
568 | SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, | ||
569 | ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, | ||
570 | ARIZONA_SLIMTX5_ENA_SHIFT, 0), | ||
571 | SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, | ||
572 | ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, | ||
573 | ARIZONA_SLIMTX6_ENA_SHIFT, 0), | ||
574 | SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0, | ||
575 | ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, | ||
576 | ARIZONA_SLIMTX7_ENA_SHIFT, 0), | ||
577 | SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0, | ||
578 | ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, | ||
579 | ARIZONA_SLIMTX8_ENA_SHIFT, 0), | ||
580 | |||
581 | SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, | ||
582 | ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, | ||
583 | ARIZONA_SLIMRX1_ENA_SHIFT, 0), | ||
584 | SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, | ||
585 | ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, | ||
586 | ARIZONA_SLIMRX2_ENA_SHIFT, 0), | ||
587 | SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, | ||
588 | ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, | ||
589 | ARIZONA_SLIMRX3_ENA_SHIFT, 0), | ||
590 | SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, | ||
591 | ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, | ||
592 | ARIZONA_SLIMRX4_ENA_SHIFT, 0), | ||
593 | SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0, | ||
594 | ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, | ||
595 | ARIZONA_SLIMRX5_ENA_SHIFT, 0), | ||
596 | SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0, | ||
597 | ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, | ||
598 | ARIZONA_SLIMRX6_ENA_SHIFT, 0), | ||
599 | SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0, | ||
600 | ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, | ||
601 | ARIZONA_SLIMRX7_ENA_SHIFT, 0), | ||
602 | SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, | ||
603 | ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, | ||
604 | ARIZONA_SLIMRX8_ENA_SHIFT, 0), | ||
605 | |||
606 | SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, | ||
607 | ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, | ||
608 | &wm8997_aec_loopback_mux), | ||
609 | |||
610 | SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, | ||
611 | ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, | ||
612 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
613 | SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, | ||
614 | ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, | ||
615 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
616 | SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, | ||
617 | ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
618 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
619 | SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, | ||
620 | ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
621 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
622 | SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1, | ||
623 | ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
624 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
625 | |||
626 | ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"), | ||
627 | ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"), | ||
628 | ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"), | ||
629 | ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"), | ||
630 | |||
631 | ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"), | ||
632 | ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"), | ||
633 | |||
634 | ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"), | ||
635 | ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"), | ||
636 | ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"), | ||
637 | ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"), | ||
638 | |||
639 | ARIZONA_MIXER_WIDGETS(Mic, "Mic"), | ||
640 | ARIZONA_MIXER_WIDGETS(Noise, "Noise"), | ||
641 | |||
642 | ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"), | ||
643 | ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"), | ||
644 | |||
645 | ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"), | ||
646 | ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"), | ||
647 | ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"), | ||
648 | ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"), | ||
649 | ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"), | ||
650 | ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"), | ||
651 | |||
652 | ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), | ||
653 | ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), | ||
654 | ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), | ||
655 | ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), | ||
656 | ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), | ||
657 | ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), | ||
658 | ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"), | ||
659 | ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"), | ||
660 | |||
661 | ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), | ||
662 | ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), | ||
663 | |||
664 | ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"), | ||
665 | ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"), | ||
666 | ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"), | ||
667 | ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"), | ||
668 | ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"), | ||
669 | ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"), | ||
670 | ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"), | ||
671 | ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"), | ||
672 | |||
673 | ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"), | ||
674 | ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"), | ||
675 | |||
676 | ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"), | ||
677 | ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"), | ||
678 | |||
679 | ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"), | ||
680 | ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), | ||
681 | |||
682 | ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), | ||
683 | ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), | ||
684 | |||
685 | SND_SOC_DAPM_OUTPUT("HPOUT1L"), | ||
686 | SND_SOC_DAPM_OUTPUT("HPOUT1R"), | ||
687 | SND_SOC_DAPM_OUTPUT("EPOUTN"), | ||
688 | SND_SOC_DAPM_OUTPUT("EPOUTP"), | ||
689 | SND_SOC_DAPM_OUTPUT("SPKOUTN"), | ||
690 | SND_SOC_DAPM_OUTPUT("SPKOUTP"), | ||
691 | SND_SOC_DAPM_OUTPUT("SPKDAT1L"), | ||
692 | SND_SOC_DAPM_OUTPUT("SPKDAT1R"), | ||
693 | |||
694 | SND_SOC_DAPM_OUTPUT("MICSUPP"), | ||
695 | }; | ||
696 | |||
697 | #define ARIZONA_MIXER_INPUT_ROUTES(name) \ | ||
698 | { name, "Noise Generator", "Noise Generator" }, \ | ||
699 | { name, "Tone Generator 1", "Tone Generator 1" }, \ | ||
700 | { name, "Tone Generator 2", "Tone Generator 2" }, \ | ||
701 | { name, "Haptics", "HAPTICS" }, \ | ||
702 | { name, "AEC", "AEC Loopback" }, \ | ||
703 | { name, "IN1L", "IN1L PGA" }, \ | ||
704 | { name, "IN1R", "IN1R PGA" }, \ | ||
705 | { name, "IN2L", "IN2L PGA" }, \ | ||
706 | { name, "IN2R", "IN2R PGA" }, \ | ||
707 | { name, "Mic Mute Mixer", "Mic Mute Mixer" }, \ | ||
708 | { name, "AIF1RX1", "AIF1RX1" }, \ | ||
709 | { name, "AIF1RX2", "AIF1RX2" }, \ | ||
710 | { name, "AIF1RX3", "AIF1RX3" }, \ | ||
711 | { name, "AIF1RX4", "AIF1RX4" }, \ | ||
712 | { name, "AIF1RX5", "AIF1RX5" }, \ | ||
713 | { name, "AIF1RX6", "AIF1RX6" }, \ | ||
714 | { name, "AIF1RX7", "AIF1RX7" }, \ | ||
715 | { name, "AIF1RX8", "AIF1RX8" }, \ | ||
716 | { name, "AIF2RX1", "AIF2RX1" }, \ | ||
717 | { name, "AIF2RX2", "AIF2RX2" }, \ | ||
718 | { name, "SLIMRX1", "SLIMRX1" }, \ | ||
719 | { name, "SLIMRX2", "SLIMRX2" }, \ | ||
720 | { name, "SLIMRX3", "SLIMRX3" }, \ | ||
721 | { name, "SLIMRX4", "SLIMRX4" }, \ | ||
722 | { name, "SLIMRX5", "SLIMRX5" }, \ | ||
723 | { name, "SLIMRX6", "SLIMRX6" }, \ | ||
724 | { name, "SLIMRX7", "SLIMRX7" }, \ | ||
725 | { name, "SLIMRX8", "SLIMRX8" }, \ | ||
726 | { name, "EQ1", "EQ1" }, \ | ||
727 | { name, "EQ2", "EQ2" }, \ | ||
728 | { name, "EQ3", "EQ3" }, \ | ||
729 | { name, "EQ4", "EQ4" }, \ | ||
730 | { name, "DRC1L", "DRC1L" }, \ | ||
731 | { name, "DRC1R", "DRC1R" }, \ | ||
732 | { name, "LHPF1", "LHPF1" }, \ | ||
733 | { name, "LHPF2", "LHPF2" }, \ | ||
734 | { name, "LHPF3", "LHPF3" }, \ | ||
735 | { name, "LHPF4", "LHPF4" }, \ | ||
736 | { name, "ISRC1DEC1", "ISRC1DEC1" }, \ | ||
737 | { name, "ISRC1DEC2", "ISRC1DEC2" }, \ | ||
738 | { name, "ISRC1INT1", "ISRC1INT1" }, \ | ||
739 | { name, "ISRC1INT2", "ISRC1INT2" }, \ | ||
740 | { name, "ISRC2DEC1", "ISRC2DEC1" }, \ | ||
741 | { name, "ISRC2DEC2", "ISRC2DEC2" }, \ | ||
742 | { name, "ISRC2INT1", "ISRC2INT1" }, \ | ||
743 | { name, "ISRC2INT2", "ISRC2INT2" } | ||
744 | |||
745 | static const struct snd_soc_dapm_route wm8997_dapm_routes[] = { | ||
746 | { "AIF2 Capture", NULL, "DBVDD2" }, | ||
747 | { "AIF2 Playback", NULL, "DBVDD2" }, | ||
748 | |||
749 | { "OUT1L", NULL, "CPVDD" }, | ||
750 | { "OUT1R", NULL, "CPVDD" }, | ||
751 | { "OUT3L", NULL, "CPVDD" }, | ||
752 | |||
753 | { "OUT4L", NULL, "SPKVDD" }, | ||
754 | |||
755 | { "OUT1L", NULL, "SYSCLK" }, | ||
756 | { "OUT1R", NULL, "SYSCLK" }, | ||
757 | { "OUT3L", NULL, "SYSCLK" }, | ||
758 | { "OUT4L", NULL, "SYSCLK" }, | ||
759 | |||
760 | { "IN1L", NULL, "SYSCLK" }, | ||
761 | { "IN1R", NULL, "SYSCLK" }, | ||
762 | { "IN2L", NULL, "SYSCLK" }, | ||
763 | { "IN2R", NULL, "SYSCLK" }, | ||
764 | |||
765 | { "MICBIAS1", NULL, "MICVDD" }, | ||
766 | { "MICBIAS2", NULL, "MICVDD" }, | ||
767 | { "MICBIAS3", NULL, "MICVDD" }, | ||
768 | |||
769 | { "Noise Generator", NULL, "SYSCLK" }, | ||
770 | { "Tone Generator 1", NULL, "SYSCLK" }, | ||
771 | { "Tone Generator 2", NULL, "SYSCLK" }, | ||
772 | |||
773 | { "Noise Generator", NULL, "NOISE" }, | ||
774 | { "Tone Generator 1", NULL, "TONE" }, | ||
775 | { "Tone Generator 2", NULL, "TONE" }, | ||
776 | |||
777 | { "AIF1 Capture", NULL, "AIF1TX1" }, | ||
778 | { "AIF1 Capture", NULL, "AIF1TX2" }, | ||
779 | { "AIF1 Capture", NULL, "AIF1TX3" }, | ||
780 | { "AIF1 Capture", NULL, "AIF1TX4" }, | ||
781 | { "AIF1 Capture", NULL, "AIF1TX5" }, | ||
782 | { "AIF1 Capture", NULL, "AIF1TX6" }, | ||
783 | { "AIF1 Capture", NULL, "AIF1TX7" }, | ||
784 | { "AIF1 Capture", NULL, "AIF1TX8" }, | ||
785 | |||
786 | { "AIF1RX1", NULL, "AIF1 Playback" }, | ||
787 | { "AIF1RX2", NULL, "AIF1 Playback" }, | ||
788 | { "AIF1RX3", NULL, "AIF1 Playback" }, | ||
789 | { "AIF1RX4", NULL, "AIF1 Playback" }, | ||
790 | { "AIF1RX5", NULL, "AIF1 Playback" }, | ||
791 | { "AIF1RX6", NULL, "AIF1 Playback" }, | ||
792 | { "AIF1RX7", NULL, "AIF1 Playback" }, | ||
793 | { "AIF1RX8", NULL, "AIF1 Playback" }, | ||
794 | |||
795 | { "AIF2 Capture", NULL, "AIF2TX1" }, | ||
796 | { "AIF2 Capture", NULL, "AIF2TX2" }, | ||
797 | |||
798 | { "AIF2RX1", NULL, "AIF2 Playback" }, | ||
799 | { "AIF2RX2", NULL, "AIF2 Playback" }, | ||
800 | |||
801 | { "Slim1 Capture", NULL, "SLIMTX1" }, | ||
802 | { "Slim1 Capture", NULL, "SLIMTX2" }, | ||
803 | { "Slim1 Capture", NULL, "SLIMTX3" }, | ||
804 | { "Slim1 Capture", NULL, "SLIMTX4" }, | ||
805 | |||
806 | { "SLIMRX1", NULL, "Slim1 Playback" }, | ||
807 | { "SLIMRX2", NULL, "Slim1 Playback" }, | ||
808 | { "SLIMRX3", NULL, "Slim1 Playback" }, | ||
809 | { "SLIMRX4", NULL, "Slim1 Playback" }, | ||
810 | |||
811 | { "Slim2 Capture", NULL, "SLIMTX5" }, | ||
812 | { "Slim2 Capture", NULL, "SLIMTX6" }, | ||
813 | |||
814 | { "SLIMRX5", NULL, "Slim2 Playback" }, | ||
815 | { "SLIMRX6", NULL, "Slim2 Playback" }, | ||
816 | |||
817 | { "Slim3 Capture", NULL, "SLIMTX7" }, | ||
818 | { "Slim3 Capture", NULL, "SLIMTX8" }, | ||
819 | |||
820 | { "SLIMRX7", NULL, "Slim3 Playback" }, | ||
821 | { "SLIMRX8", NULL, "Slim3 Playback" }, | ||
822 | |||
823 | { "AIF1 Playback", NULL, "SYSCLK" }, | ||
824 | { "AIF2 Playback", NULL, "SYSCLK" }, | ||
825 | { "Slim1 Playback", NULL, "SYSCLK" }, | ||
826 | { "Slim2 Playback", NULL, "SYSCLK" }, | ||
827 | { "Slim3 Playback", NULL, "SYSCLK" }, | ||
828 | |||
829 | { "AIF1 Capture", NULL, "SYSCLK" }, | ||
830 | { "AIF2 Capture", NULL, "SYSCLK" }, | ||
831 | { "Slim1 Capture", NULL, "SYSCLK" }, | ||
832 | { "Slim2 Capture", NULL, "SYSCLK" }, | ||
833 | { "Slim3 Capture", NULL, "SYSCLK" }, | ||
834 | |||
835 | { "IN1L PGA", NULL, "IN1L" }, | ||
836 | { "IN1R PGA", NULL, "IN1R" }, | ||
837 | |||
838 | { "IN2L PGA", NULL, "IN2L" }, | ||
839 | { "IN2R PGA", NULL, "IN2R" }, | ||
840 | |||
841 | ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), | ||
842 | ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), | ||
843 | ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"), | ||
844 | |||
845 | ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"), | ||
846 | ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"), | ||
847 | ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"), | ||
848 | |||
849 | ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"), | ||
850 | ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"), | ||
851 | |||
852 | ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), | ||
853 | ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), | ||
854 | ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), | ||
855 | ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), | ||
856 | ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), | ||
857 | ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), | ||
858 | ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"), | ||
859 | ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"), | ||
860 | |||
861 | ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), | ||
862 | ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), | ||
863 | |||
864 | ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"), | ||
865 | ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"), | ||
866 | ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"), | ||
867 | ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"), | ||
868 | ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"), | ||
869 | ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"), | ||
870 | ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"), | ||
871 | ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"), | ||
872 | |||
873 | ARIZONA_MIXER_ROUTES("EQ1", "EQ1"), | ||
874 | ARIZONA_MIXER_ROUTES("EQ2", "EQ2"), | ||
875 | ARIZONA_MIXER_ROUTES("EQ3", "EQ3"), | ||
876 | ARIZONA_MIXER_ROUTES("EQ4", "EQ4"), | ||
877 | |||
878 | ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"), | ||
879 | ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"), | ||
880 | |||
881 | ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"), | ||
882 | ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"), | ||
883 | ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), | ||
884 | ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), | ||
885 | |||
886 | ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"), | ||
887 | ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"), | ||
888 | |||
889 | ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), | ||
890 | ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC2INT2"), | ||
891 | |||
892 | ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), | ||
893 | ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), | ||
894 | |||
895 | ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), | ||
896 | ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), | ||
897 | |||
898 | ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), | ||
899 | ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), | ||
900 | |||
901 | { "AEC Loopback", "HPOUT1L", "OUT1L" }, | ||
902 | { "AEC Loopback", "HPOUT1R", "OUT1R" }, | ||
903 | { "HPOUT1L", NULL, "OUT1L" }, | ||
904 | { "HPOUT1R", NULL, "OUT1R" }, | ||
905 | |||
906 | { "AEC Loopback", "EPOUT", "OUT3L" }, | ||
907 | { "EPOUTN", NULL, "OUT3L" }, | ||
908 | { "EPOUTP", NULL, "OUT3L" }, | ||
909 | |||
910 | { "AEC Loopback", "SPKOUT", "OUT4L" }, | ||
911 | { "SPKOUTN", NULL, "OUT4L" }, | ||
912 | { "SPKOUTP", NULL, "OUT4L" }, | ||
913 | |||
914 | { "AEC Loopback", "SPKDAT1L", "OUT5L" }, | ||
915 | { "AEC Loopback", "SPKDAT1R", "OUT5R" }, | ||
916 | { "SPKDAT1L", NULL, "OUT5L" }, | ||
917 | { "SPKDAT1R", NULL, "OUT5R" }, | ||
918 | |||
919 | { "MICSUPP", NULL, "SYSCLK" }, | ||
920 | }; | ||
921 | |||
922 | static int wm8997_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | ||
923 | unsigned int Fref, unsigned int Fout) | ||
924 | { | ||
925 | struct wm8997_priv *wm8997 = snd_soc_codec_get_drvdata(codec); | ||
926 | |||
927 | switch (fll_id) { | ||
928 | case WM8997_FLL1: | ||
929 | return arizona_set_fll(&wm8997->fll[0], source, Fref, Fout); | ||
930 | case WM8997_FLL2: | ||
931 | return arizona_set_fll(&wm8997->fll[1], source, Fref, Fout); | ||
932 | case WM8997_FLL1_REFCLK: | ||
933 | return arizona_set_fll_refclk(&wm8997->fll[0], source, Fref, | ||
934 | Fout); | ||
935 | case WM8997_FLL2_REFCLK: | ||
936 | return arizona_set_fll_refclk(&wm8997->fll[1], source, Fref, | ||
937 | Fout); | ||
938 | default: | ||
939 | return -EINVAL; | ||
940 | } | ||
941 | } | ||
942 | |||
943 | #define WM8997_RATES SNDRV_PCM_RATE_8000_192000 | ||
944 | |||
945 | #define WM8997_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
946 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
947 | |||
948 | static struct snd_soc_dai_driver wm8997_dai[] = { | ||
949 | { | ||
950 | .name = "wm8997-aif1", | ||
951 | .id = 1, | ||
952 | .base = ARIZONA_AIF1_BCLK_CTRL, | ||
953 | .playback = { | ||
954 | .stream_name = "AIF1 Playback", | ||
955 | .channels_min = 1, | ||
956 | .channels_max = 8, | ||
957 | .rates = WM8997_RATES, | ||
958 | .formats = WM8997_FORMATS, | ||
959 | }, | ||
960 | .capture = { | ||
961 | .stream_name = "AIF1 Capture", | ||
962 | .channels_min = 1, | ||
963 | .channels_max = 8, | ||
964 | .rates = WM8997_RATES, | ||
965 | .formats = WM8997_FORMATS, | ||
966 | }, | ||
967 | .ops = &arizona_dai_ops, | ||
968 | .symmetric_rates = 1, | ||
969 | }, | ||
970 | { | ||
971 | .name = "wm8997-aif2", | ||
972 | .id = 2, | ||
973 | .base = ARIZONA_AIF2_BCLK_CTRL, | ||
974 | .playback = { | ||
975 | .stream_name = "AIF2 Playback", | ||
976 | .channels_min = 1, | ||
977 | .channels_max = 2, | ||
978 | .rates = WM8997_RATES, | ||
979 | .formats = WM8997_FORMATS, | ||
980 | }, | ||
981 | .capture = { | ||
982 | .stream_name = "AIF2 Capture", | ||
983 | .channels_min = 1, | ||
984 | .channels_max = 2, | ||
985 | .rates = WM8997_RATES, | ||
986 | .formats = WM8997_FORMATS, | ||
987 | }, | ||
988 | .ops = &arizona_dai_ops, | ||
989 | .symmetric_rates = 1, | ||
990 | }, | ||
991 | { | ||
992 | .name = "wm8997-slim1", | ||
993 | .id = 3, | ||
994 | .playback = { | ||
995 | .stream_name = "Slim1 Playback", | ||
996 | .channels_min = 1, | ||
997 | .channels_max = 4, | ||
998 | .rates = WM8997_RATES, | ||
999 | .formats = WM8997_FORMATS, | ||
1000 | }, | ||
1001 | .capture = { | ||
1002 | .stream_name = "Slim1 Capture", | ||
1003 | .channels_min = 1, | ||
1004 | .channels_max = 4, | ||
1005 | .rates = WM8997_RATES, | ||
1006 | .formats = WM8997_FORMATS, | ||
1007 | }, | ||
1008 | .ops = &arizona_simple_dai_ops, | ||
1009 | }, | ||
1010 | { | ||
1011 | .name = "wm8997-slim2", | ||
1012 | .id = 4, | ||
1013 | .playback = { | ||
1014 | .stream_name = "Slim2 Playback", | ||
1015 | .channels_min = 1, | ||
1016 | .channels_max = 2, | ||
1017 | .rates = WM8997_RATES, | ||
1018 | .formats = WM8997_FORMATS, | ||
1019 | }, | ||
1020 | .capture = { | ||
1021 | .stream_name = "Slim2 Capture", | ||
1022 | .channels_min = 1, | ||
1023 | .channels_max = 2, | ||
1024 | .rates = WM8997_RATES, | ||
1025 | .formats = WM8997_FORMATS, | ||
1026 | }, | ||
1027 | .ops = &arizona_simple_dai_ops, | ||
1028 | }, | ||
1029 | { | ||
1030 | .name = "wm8997-slim3", | ||
1031 | .id = 5, | ||
1032 | .playback = { | ||
1033 | .stream_name = "Slim3 Playback", | ||
1034 | .channels_min = 1, | ||
1035 | .channels_max = 2, | ||
1036 | .rates = WM8997_RATES, | ||
1037 | .formats = WM8997_FORMATS, | ||
1038 | }, | ||
1039 | .capture = { | ||
1040 | .stream_name = "Slim3 Capture", | ||
1041 | .channels_min = 1, | ||
1042 | .channels_max = 2, | ||
1043 | .rates = WM8997_RATES, | ||
1044 | .formats = WM8997_FORMATS, | ||
1045 | }, | ||
1046 | .ops = &arizona_simple_dai_ops, | ||
1047 | }, | ||
1048 | }; | ||
1049 | |||
1050 | static int wm8997_codec_probe(struct snd_soc_codec *codec) | ||
1051 | { | ||
1052 | struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
1053 | int ret; | ||
1054 | |||
1055 | codec->control_data = priv->core.arizona->regmap; | ||
1056 | |||
1057 | ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); | ||
1058 | if (ret != 0) | ||
1059 | return ret; | ||
1060 | |||
1061 | arizona_init_spk(codec); | ||
1062 | |||
1063 | snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); | ||
1064 | |||
1065 | priv->core.arizona->dapm = &codec->dapm; | ||
1066 | |||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | static int wm8997_codec_remove(struct snd_soc_codec *codec) | ||
1071 | { | ||
1072 | struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
1073 | |||
1074 | priv->core.arizona->dapm = NULL; | ||
1075 | |||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | #define WM8997_DIG_VU 0x0200 | ||
1080 | |||
1081 | static unsigned int wm8997_digital_vu[] = { | ||
1082 | ARIZONA_DAC_DIGITAL_VOLUME_1L, | ||
1083 | ARIZONA_DAC_DIGITAL_VOLUME_1R, | ||
1084 | ARIZONA_DAC_DIGITAL_VOLUME_3L, | ||
1085 | ARIZONA_DAC_DIGITAL_VOLUME_4L, | ||
1086 | ARIZONA_DAC_DIGITAL_VOLUME_5L, | ||
1087 | ARIZONA_DAC_DIGITAL_VOLUME_5R, | ||
1088 | }; | ||
1089 | |||
1090 | static struct snd_soc_codec_driver soc_codec_dev_wm8997 = { | ||
1091 | .probe = wm8997_codec_probe, | ||
1092 | .remove = wm8997_codec_remove, | ||
1093 | |||
1094 | .idle_bias_off = true, | ||
1095 | |||
1096 | .set_sysclk = arizona_set_sysclk, | ||
1097 | .set_pll = wm8997_set_fll, | ||
1098 | |||
1099 | .controls = wm8997_snd_controls, | ||
1100 | .num_controls = ARRAY_SIZE(wm8997_snd_controls), | ||
1101 | .dapm_widgets = wm8997_dapm_widgets, | ||
1102 | .num_dapm_widgets = ARRAY_SIZE(wm8997_dapm_widgets), | ||
1103 | .dapm_routes = wm8997_dapm_routes, | ||
1104 | .num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes), | ||
1105 | }; | ||
1106 | |||
1107 | static int wm8997_probe(struct platform_device *pdev) | ||
1108 | { | ||
1109 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | ||
1110 | struct wm8997_priv *wm8997; | ||
1111 | int i; | ||
1112 | |||
1113 | wm8997 = devm_kzalloc(&pdev->dev, sizeof(struct wm8997_priv), | ||
1114 | GFP_KERNEL); | ||
1115 | if (wm8997 == NULL) | ||
1116 | return -ENOMEM; | ||
1117 | platform_set_drvdata(pdev, wm8997); | ||
1118 | |||
1119 | wm8997->core.arizona = arizona; | ||
1120 | wm8997->core.num_inputs = 4; | ||
1121 | |||
1122 | for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++) | ||
1123 | wm8997->fll[i].vco_mult = 1; | ||
1124 | |||
1125 | arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1, | ||
1126 | ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK, | ||
1127 | &wm8997->fll[0]); | ||
1128 | arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1, | ||
1129 | ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK, | ||
1130 | &wm8997->fll[1]); | ||
1131 | |||
1132 | /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */ | ||
1133 | regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2, | ||
1134 | ARIZONA_SAMPLE_RATE_2_MASK, 0x11); | ||
1135 | regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3, | ||
1136 | ARIZONA_SAMPLE_RATE_3_MASK, 0x12); | ||
1137 | |||
1138 | for (i = 0; i < ARRAY_SIZE(wm8997_dai); i++) | ||
1139 | arizona_init_dai(&wm8997->core, i); | ||
1140 | |||
1141 | /* Latch volume update bits */ | ||
1142 | for (i = 0; i < ARRAY_SIZE(wm8997_digital_vu); i++) | ||
1143 | regmap_update_bits(arizona->regmap, wm8997_digital_vu[i], | ||
1144 | WM8997_DIG_VU, WM8997_DIG_VU); | ||
1145 | |||
1146 | pm_runtime_enable(&pdev->dev); | ||
1147 | pm_runtime_idle(&pdev->dev); | ||
1148 | |||
1149 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997, | ||
1150 | wm8997_dai, ARRAY_SIZE(wm8997_dai)); | ||
1151 | } | ||
1152 | |||
1153 | static int wm8997_remove(struct platform_device *pdev) | ||
1154 | { | ||
1155 | snd_soc_unregister_codec(&pdev->dev); | ||
1156 | pm_runtime_disable(&pdev->dev); | ||
1157 | |||
1158 | return 0; | ||
1159 | } | ||
1160 | |||
1161 | static struct platform_driver wm8997_codec_driver = { | ||
1162 | .driver = { | ||
1163 | .name = "wm8997-codec", | ||
1164 | .owner = THIS_MODULE, | ||
1165 | }, | ||
1166 | .probe = wm8997_probe, | ||
1167 | .remove = wm8997_remove, | ||
1168 | }; | ||
1169 | |||
1170 | module_platform_driver(wm8997_codec_driver); | ||
1171 | |||
1172 | MODULE_DESCRIPTION("ASoC WM8997 driver"); | ||
1173 | MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>"); | ||
1174 | MODULE_LICENSE("GPL"); | ||
1175 | MODULE_ALIAS("platform:wm8997-codec"); | ||
diff --git a/sound/soc/codecs/wm8997.h b/sound/soc/codecs/wm8997.h new file mode 100644 index 000000000000..5e91c6a7d567 --- /dev/null +++ b/sound/soc/codecs/wm8997.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * wm8997.h -- WM8997 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2012 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 | |||
13 | #ifndef _WM8997_H | ||
14 | #define _WM8997_H | ||
15 | |||
16 | #include "arizona.h" | ||
17 | |||
18 | #define WM8997_FLL1 1 | ||
19 | #define WM8997_FLL2 2 | ||
20 | #define WM8997_FLL1_REFCLK 3 | ||
21 | #define WM8997_FLL2_REFCLK 4 | ||
22 | |||
23 | #endif | ||
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 05252ac936a3..b38f3506418f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -225,15 +225,8 @@ struct wm_coeff_ctl_ops { | |||
225 | struct snd_ctl_elem_info *uinfo); | 225 | struct snd_ctl_elem_info *uinfo); |
226 | }; | 226 | }; |
227 | 227 | ||
228 | struct wm_coeff { | ||
229 | struct device *dev; | ||
230 | struct list_head ctl_list; | ||
231 | struct regmap *regmap; | ||
232 | }; | ||
233 | |||
234 | struct wm_coeff_ctl { | 228 | struct wm_coeff_ctl { |
235 | const char *name; | 229 | const char *name; |
236 | struct snd_card *card; | ||
237 | struct wm_adsp_alg_region region; | 230 | struct wm_adsp_alg_region region; |
238 | struct wm_coeff_ctl_ops ops; | 231 | struct wm_coeff_ctl_ops ops; |
239 | struct wm_adsp *adsp; | 232 | struct wm_adsp *adsp; |
@@ -378,7 +371,6 @@ static int wm_coeff_info(struct snd_kcontrol *kcontrol, | |||
378 | static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, | 371 | static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, |
379 | const void *buf, size_t len) | 372 | const void *buf, size_t len) |
380 | { | 373 | { |
381 | struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol); | ||
382 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | 374 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; |
383 | struct wm_adsp_alg_region *region = &ctl->region; | 375 | struct wm_adsp_alg_region *region = &ctl->region; |
384 | const struct wm_adsp_region *mem; | 376 | const struct wm_adsp_region *mem; |
@@ -401,7 +393,7 @@ static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, | |||
401 | if (!scratch) | 393 | if (!scratch) |
402 | return -ENOMEM; | 394 | return -ENOMEM; |
403 | 395 | ||
404 | ret = regmap_raw_write(wm_coeff->regmap, reg, scratch, | 396 | ret = regmap_raw_write(adsp->regmap, reg, scratch, |
405 | ctl->len); | 397 | ctl->len); |
406 | if (ret) { | 398 | if (ret) { |
407 | adsp_err(adsp, "Failed to write %zu bytes to %x\n", | 399 | adsp_err(adsp, "Failed to write %zu bytes to %x\n", |
@@ -434,7 +426,6 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol, | |||
434 | static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, | 426 | static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, |
435 | void *buf, size_t len) | 427 | void *buf, size_t len) |
436 | { | 428 | { |
437 | struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol); | ||
438 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | 429 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; |
439 | struct wm_adsp_alg_region *region = &ctl->region; | 430 | struct wm_adsp_alg_region *region = &ctl->region; |
440 | const struct wm_adsp_region *mem; | 431 | const struct wm_adsp_region *mem; |
@@ -457,7 +448,7 @@ static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, | |||
457 | if (!scratch) | 448 | if (!scratch) |
458 | return -ENOMEM; | 449 | return -ENOMEM; |
459 | 450 | ||
460 | ret = regmap_raw_read(wm_coeff->regmap, reg, scratch, ctl->len); | 451 | ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len); |
461 | if (ret) { | 452 | if (ret) { |
462 | adsp_err(adsp, "Failed to read %zu bytes from %x\n", | 453 | adsp_err(adsp, "Failed to read %zu bytes from %x\n", |
463 | ctl->len, reg); | 454 | ctl->len, reg); |
@@ -481,37 +472,18 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol, | |||
481 | return 0; | 472 | return 0; |
482 | } | 473 | } |
483 | 474 | ||
484 | static int wm_coeff_add_kcontrol(struct wm_coeff *wm_coeff, | ||
485 | struct wm_coeff_ctl *ctl, | ||
486 | const struct snd_kcontrol_new *kctl) | ||
487 | { | ||
488 | int ret; | ||
489 | struct snd_kcontrol *kcontrol; | ||
490 | |||
491 | kcontrol = snd_ctl_new1(kctl, wm_coeff); | ||
492 | ret = snd_ctl_add(ctl->card, kcontrol); | ||
493 | if (ret < 0) { | ||
494 | dev_err(wm_coeff->dev, "Failed to add %s: %d\n", | ||
495 | kctl->name, ret); | ||
496 | return ret; | ||
497 | } | ||
498 | ctl->kcontrol = kcontrol; | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | struct wmfw_ctl_work { | 475 | struct wmfw_ctl_work { |
503 | struct wm_coeff *wm_coeff; | 476 | struct wm_adsp *adsp; |
504 | struct wm_coeff_ctl *ctl; | 477 | struct wm_coeff_ctl *ctl; |
505 | struct work_struct work; | 478 | struct work_struct work; |
506 | }; | 479 | }; |
507 | 480 | ||
508 | static int wmfw_add_ctl(struct wm_coeff *wm_coeff, | 481 | static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl) |
509 | struct wm_coeff_ctl *ctl) | ||
510 | { | 482 | { |
511 | struct snd_kcontrol_new *kcontrol; | 483 | struct snd_kcontrol_new *kcontrol; |
512 | int ret; | 484 | int ret; |
513 | 485 | ||
514 | if (!wm_coeff || !ctl || !ctl->name || !ctl->card) | 486 | if (!ctl || !ctl->name) |
515 | return -EINVAL; | 487 | return -EINVAL; |
516 | 488 | ||
517 | kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); | 489 | kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); |
@@ -525,14 +497,17 @@ static int wmfw_add_ctl(struct wm_coeff *wm_coeff, | |||
525 | kcontrol->put = wm_coeff_put; | 497 | kcontrol->put = wm_coeff_put; |
526 | kcontrol->private_value = (unsigned long)ctl; | 498 | kcontrol->private_value = (unsigned long)ctl; |
527 | 499 | ||
528 | ret = wm_coeff_add_kcontrol(wm_coeff, | 500 | ret = snd_soc_add_card_controls(adsp->card, |
529 | ctl, kcontrol); | 501 | kcontrol, 1); |
530 | if (ret < 0) | 502 | if (ret < 0) |
531 | goto err_kcontrol; | 503 | goto err_kcontrol; |
532 | 504 | ||
533 | kfree(kcontrol); | 505 | kfree(kcontrol); |
534 | 506 | ||
535 | list_add(&ctl->list, &wm_coeff->ctl_list); | 507 | ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card, |
508 | ctl->name); | ||
509 | |||
510 | list_add(&ctl->list, &adsp->ctl_list); | ||
536 | return 0; | 511 | return 0; |
537 | 512 | ||
538 | err_kcontrol: | 513 | err_kcontrol: |
@@ -753,13 +728,12 @@ out: | |||
753 | return ret; | 728 | return ret; |
754 | } | 729 | } |
755 | 730 | ||
756 | static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff) | 731 | static int wm_coeff_init_control_caches(struct wm_adsp *adsp) |
757 | { | 732 | { |
758 | struct wm_coeff_ctl *ctl; | 733 | struct wm_coeff_ctl *ctl; |
759 | int ret; | 734 | int ret; |
760 | 735 | ||
761 | list_for_each_entry(ctl, &wm_coeff->ctl_list, | 736 | list_for_each_entry(ctl, &adsp->ctl_list, list) { |
762 | list) { | ||
763 | if (!ctl->enabled || ctl->set) | 737 | if (!ctl->enabled || ctl->set) |
764 | continue; | 738 | continue; |
765 | ret = wm_coeff_read_control(ctl->kcontrol, | 739 | ret = wm_coeff_read_control(ctl->kcontrol, |
@@ -772,13 +746,12 @@ static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff) | |||
772 | return 0; | 746 | return 0; |
773 | } | 747 | } |
774 | 748 | ||
775 | static int wm_coeff_sync_controls(struct wm_coeff *wm_coeff) | 749 | static int wm_coeff_sync_controls(struct wm_adsp *adsp) |
776 | { | 750 | { |
777 | struct wm_coeff_ctl *ctl; | 751 | struct wm_coeff_ctl *ctl; |
778 | int ret; | 752 | int ret; |
779 | 753 | ||
780 | list_for_each_entry(ctl, &wm_coeff->ctl_list, | 754 | list_for_each_entry(ctl, &adsp->ctl_list, list) { |
781 | list) { | ||
782 | if (!ctl->enabled) | 755 | if (!ctl->enabled) |
783 | continue; | 756 | continue; |
784 | if (ctl->set) { | 757 | if (ctl->set) { |
@@ -799,15 +772,14 @@ static void wm_adsp_ctl_work(struct work_struct *work) | |||
799 | struct wmfw_ctl_work, | 772 | struct wmfw_ctl_work, |
800 | work); | 773 | work); |
801 | 774 | ||
802 | wmfw_add_ctl(ctl_work->wm_coeff, ctl_work->ctl); | 775 | wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl); |
803 | kfree(ctl_work); | 776 | kfree(ctl_work); |
804 | } | 777 | } |
805 | 778 | ||
806 | static int wm_adsp_create_control(struct snd_soc_codec *codec, | 779 | static int wm_adsp_create_control(struct wm_adsp *dsp, |
807 | const struct wm_adsp_alg_region *region) | 780 | const struct wm_adsp_alg_region *region) |
808 | 781 | ||
809 | { | 782 | { |
810 | struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); | ||
811 | struct wm_coeff_ctl *ctl; | 783 | struct wm_coeff_ctl *ctl; |
812 | struct wmfw_ctl_work *ctl_work; | 784 | struct wmfw_ctl_work *ctl_work; |
813 | char *name; | 785 | char *name; |
@@ -842,7 +814,7 @@ static int wm_adsp_create_control(struct snd_soc_codec *codec, | |||
842 | snprintf(name, PAGE_SIZE, "DSP%d %s %x", | 814 | snprintf(name, PAGE_SIZE, "DSP%d %s %x", |
843 | dsp->num, region_name, region->alg); | 815 | dsp->num, region_name, region->alg); |
844 | 816 | ||
845 | list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list, | 817 | list_for_each_entry(ctl, &dsp->ctl_list, |
846 | list) { | 818 | list) { |
847 | if (!strcmp(ctl->name, name)) { | 819 | if (!strcmp(ctl->name, name)) { |
848 | if (!ctl->enabled) | 820 | if (!ctl->enabled) |
@@ -866,7 +838,6 @@ static int wm_adsp_create_control(struct snd_soc_codec *codec, | |||
866 | ctl->set = 0; | 838 | ctl->set = 0; |
867 | ctl->ops.xget = wm_coeff_get; | 839 | ctl->ops.xget = wm_coeff_get; |
868 | ctl->ops.xput = wm_coeff_put; | 840 | ctl->ops.xput = wm_coeff_put; |
869 | ctl->card = codec->card->snd_card; | ||
870 | ctl->adsp = dsp; | 841 | ctl->adsp = dsp; |
871 | 842 | ||
872 | ctl->len = region->len; | 843 | ctl->len = region->len; |
@@ -882,7 +853,7 @@ static int wm_adsp_create_control(struct snd_soc_codec *codec, | |||
882 | goto err_ctl_cache; | 853 | goto err_ctl_cache; |
883 | } | 854 | } |
884 | 855 | ||
885 | ctl_work->wm_coeff = dsp->wm_coeff; | 856 | ctl_work->adsp = dsp; |
886 | ctl_work->ctl = ctl; | 857 | ctl_work->ctl = ctl; |
887 | INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); | 858 | INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); |
888 | schedule_work(&ctl_work->work); | 859 | schedule_work(&ctl_work->work); |
@@ -903,7 +874,7 @@ err_name: | |||
903 | return ret; | 874 | return ret; |
904 | } | 875 | } |
905 | 876 | ||
906 | static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec) | 877 | static int wm_adsp_setup_algs(struct wm_adsp *dsp) |
907 | { | 878 | { |
908 | struct regmap *regmap = dsp->regmap; | 879 | struct regmap *regmap = dsp->regmap; |
909 | struct wmfw_adsp1_id_hdr adsp1_id; | 880 | struct wmfw_adsp1_id_hdr adsp1_id; |
@@ -1091,7 +1062,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec) | |||
1091 | if (i + 1 < algs) { | 1062 | if (i + 1 < algs) { |
1092 | region->len = be32_to_cpu(adsp1_alg[i + 1].dm); | 1063 | region->len = be32_to_cpu(adsp1_alg[i + 1].dm); |
1093 | region->len -= be32_to_cpu(adsp1_alg[i].dm); | 1064 | region->len -= be32_to_cpu(adsp1_alg[i].dm); |
1094 | wm_adsp_create_control(codec, region); | 1065 | wm_adsp_create_control(dsp, region); |
1095 | } else { | 1066 | } else { |
1096 | adsp_warn(dsp, "Missing length info for region DM with ID %x\n", | 1067 | adsp_warn(dsp, "Missing length info for region DM with ID %x\n", |
1097 | be32_to_cpu(adsp1_alg[i].alg.id)); | 1068 | be32_to_cpu(adsp1_alg[i].alg.id)); |
@@ -1108,7 +1079,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec) | |||
1108 | if (i + 1 < algs) { | 1079 | if (i + 1 < algs) { |
1109 | region->len = be32_to_cpu(adsp1_alg[i + 1].zm); | 1080 | region->len = be32_to_cpu(adsp1_alg[i + 1].zm); |
1110 | region->len -= be32_to_cpu(adsp1_alg[i].zm); | 1081 | region->len -= be32_to_cpu(adsp1_alg[i].zm); |
1111 | wm_adsp_create_control(codec, region); | 1082 | wm_adsp_create_control(dsp, region); |
1112 | } else { | 1083 | } else { |
1113 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", | 1084 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", |
1114 | be32_to_cpu(adsp1_alg[i].alg.id)); | 1085 | be32_to_cpu(adsp1_alg[i].alg.id)); |
@@ -1137,7 +1108,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec) | |||
1137 | if (i + 1 < algs) { | 1108 | if (i + 1 < algs) { |
1138 | region->len = be32_to_cpu(adsp2_alg[i + 1].xm); | 1109 | region->len = be32_to_cpu(adsp2_alg[i + 1].xm); |
1139 | region->len -= be32_to_cpu(adsp2_alg[i].xm); | 1110 | region->len -= be32_to_cpu(adsp2_alg[i].xm); |
1140 | wm_adsp_create_control(codec, region); | 1111 | wm_adsp_create_control(dsp, region); |
1141 | } else { | 1112 | } else { |
1142 | adsp_warn(dsp, "Missing length info for region XM with ID %x\n", | 1113 | adsp_warn(dsp, "Missing length info for region XM with ID %x\n", |
1143 | be32_to_cpu(adsp2_alg[i].alg.id)); | 1114 | be32_to_cpu(adsp2_alg[i].alg.id)); |
@@ -1154,7 +1125,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec) | |||
1154 | if (i + 1 < algs) { | 1125 | if (i + 1 < algs) { |
1155 | region->len = be32_to_cpu(adsp2_alg[i + 1].ym); | 1126 | region->len = be32_to_cpu(adsp2_alg[i + 1].ym); |
1156 | region->len -= be32_to_cpu(adsp2_alg[i].ym); | 1127 | region->len -= be32_to_cpu(adsp2_alg[i].ym); |
1157 | wm_adsp_create_control(codec, region); | 1128 | wm_adsp_create_control(dsp, region); |
1158 | } else { | 1129 | } else { |
1159 | adsp_warn(dsp, "Missing length info for region YM with ID %x\n", | 1130 | adsp_warn(dsp, "Missing length info for region YM with ID %x\n", |
1160 | be32_to_cpu(adsp2_alg[i].alg.id)); | 1131 | be32_to_cpu(adsp2_alg[i].alg.id)); |
@@ -1171,7 +1142,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec) | |||
1171 | if (i + 1 < algs) { | 1142 | if (i + 1 < algs) { |
1172 | region->len = be32_to_cpu(adsp2_alg[i + 1].zm); | 1143 | region->len = be32_to_cpu(adsp2_alg[i + 1].zm); |
1173 | region->len -= be32_to_cpu(adsp2_alg[i].zm); | 1144 | region->len -= be32_to_cpu(adsp2_alg[i].zm); |
1174 | wm_adsp_create_control(codec, region); | 1145 | wm_adsp_create_control(dsp, region); |
1175 | } else { | 1146 | } else { |
1176 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", | 1147 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", |
1177 | be32_to_cpu(adsp2_alg[i].alg.id)); | 1148 | be32_to_cpu(adsp2_alg[i].alg.id)); |
@@ -1391,6 +1362,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1391 | int ret; | 1362 | int ret; |
1392 | int val; | 1363 | int val; |
1393 | 1364 | ||
1365 | dsp->card = codec->card; | ||
1366 | |||
1394 | switch (event) { | 1367 | switch (event) { |
1395 | case SND_SOC_DAPM_POST_PMU: | 1368 | case SND_SOC_DAPM_POST_PMU: |
1396 | regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, | 1369 | regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, |
@@ -1425,7 +1398,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1425 | if (ret != 0) | 1398 | if (ret != 0) |
1426 | goto err; | 1399 | goto err; |
1427 | 1400 | ||
1428 | ret = wm_adsp_setup_algs(dsp, codec); | 1401 | ret = wm_adsp_setup_algs(dsp); |
1429 | if (ret != 0) | 1402 | if (ret != 0) |
1430 | goto err; | 1403 | goto err; |
1431 | 1404 | ||
@@ -1434,12 +1407,12 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1434 | goto err; | 1407 | goto err; |
1435 | 1408 | ||
1436 | /* Initialize caches for enabled and unset controls */ | 1409 | /* Initialize caches for enabled and unset controls */ |
1437 | ret = wm_coeff_init_control_caches(dsp->wm_coeff); | 1410 | ret = wm_coeff_init_control_caches(dsp); |
1438 | if (ret != 0) | 1411 | if (ret != 0) |
1439 | goto err; | 1412 | goto err; |
1440 | 1413 | ||
1441 | /* Sync set controls */ | 1414 | /* Sync set controls */ |
1442 | ret = wm_coeff_sync_controls(dsp->wm_coeff); | 1415 | ret = wm_coeff_sync_controls(dsp); |
1443 | if (ret != 0) | 1416 | if (ret != 0) |
1444 | goto err; | 1417 | goto err; |
1445 | 1418 | ||
@@ -1460,10 +1433,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1460 | regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, | 1433 | regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, |
1461 | ADSP1_SYS_ENA, 0); | 1434 | ADSP1_SYS_ENA, 0); |
1462 | 1435 | ||
1463 | list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list, | 1436 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
1464 | list) { | ||
1465 | ctl->enabled = 0; | 1437 | ctl->enabled = 0; |
1466 | } | ||
1467 | break; | 1438 | break; |
1468 | 1439 | ||
1469 | default: | 1440 | default: |
@@ -1520,6 +1491,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1520 | unsigned int val; | 1491 | unsigned int val; |
1521 | int ret; | 1492 | int ret; |
1522 | 1493 | ||
1494 | dsp->card = codec->card; | ||
1495 | |||
1523 | switch (event) { | 1496 | switch (event) { |
1524 | case SND_SOC_DAPM_POST_PMU: | 1497 | case SND_SOC_DAPM_POST_PMU: |
1525 | /* | 1498 | /* |
@@ -1582,7 +1555,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1582 | if (ret != 0) | 1555 | if (ret != 0) |
1583 | goto err; | 1556 | goto err; |
1584 | 1557 | ||
1585 | ret = wm_adsp_setup_algs(dsp, codec); | 1558 | ret = wm_adsp_setup_algs(dsp); |
1586 | if (ret != 0) | 1559 | if (ret != 0) |
1587 | goto err; | 1560 | goto err; |
1588 | 1561 | ||
@@ -1591,12 +1564,12 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1591 | goto err; | 1564 | goto err; |
1592 | 1565 | ||
1593 | /* Initialize caches for enabled and unset controls */ | 1566 | /* Initialize caches for enabled and unset controls */ |
1594 | ret = wm_coeff_init_control_caches(dsp->wm_coeff); | 1567 | ret = wm_coeff_init_control_caches(dsp); |
1595 | if (ret != 0) | 1568 | if (ret != 0) |
1596 | goto err; | 1569 | goto err; |
1597 | 1570 | ||
1598 | /* Sync set controls */ | 1571 | /* Sync set controls */ |
1599 | ret = wm_coeff_sync_controls(dsp->wm_coeff); | 1572 | ret = wm_coeff_sync_controls(dsp); |
1600 | if (ret != 0) | 1573 | if (ret != 0) |
1601 | goto err; | 1574 | goto err; |
1602 | 1575 | ||
@@ -1637,10 +1610,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1637 | ret); | 1610 | ret); |
1638 | } | 1611 | } |
1639 | 1612 | ||
1640 | list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list, | 1613 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
1641 | list) { | ||
1642 | ctl->enabled = 0; | 1614 | ctl->enabled = 0; |
1643 | } | ||
1644 | 1615 | ||
1645 | while (!list_empty(&dsp->alg_regions)) { | 1616 | while (!list_empty(&dsp->alg_regions)) { |
1646 | alg_region = list_first_entry(&dsp->alg_regions, | 1617 | alg_region = list_first_entry(&dsp->alg_regions, |
@@ -1679,49 +1650,38 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) | |||
1679 | } | 1650 | } |
1680 | 1651 | ||
1681 | INIT_LIST_HEAD(&adsp->alg_regions); | 1652 | INIT_LIST_HEAD(&adsp->alg_regions); |
1682 | 1653 | INIT_LIST_HEAD(&adsp->ctl_list); | |
1683 | adsp->wm_coeff = kzalloc(sizeof(*adsp->wm_coeff), | ||
1684 | GFP_KERNEL); | ||
1685 | if (!adsp->wm_coeff) | ||
1686 | return -ENOMEM; | ||
1687 | adsp->wm_coeff->regmap = adsp->regmap; | ||
1688 | adsp->wm_coeff->dev = adsp->dev; | ||
1689 | INIT_LIST_HEAD(&adsp->wm_coeff->ctl_list); | ||
1690 | 1654 | ||
1691 | if (dvfs) { | 1655 | if (dvfs) { |
1692 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); | 1656 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); |
1693 | if (IS_ERR(adsp->dvfs)) { | 1657 | if (IS_ERR(adsp->dvfs)) { |
1694 | ret = PTR_ERR(adsp->dvfs); | 1658 | ret = PTR_ERR(adsp->dvfs); |
1695 | dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret); | 1659 | dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret); |
1696 | goto out_coeff; | 1660 | return ret; |
1697 | } | 1661 | } |
1698 | 1662 | ||
1699 | ret = regulator_enable(adsp->dvfs); | 1663 | ret = regulator_enable(adsp->dvfs); |
1700 | if (ret != 0) { | 1664 | if (ret != 0) { |
1701 | dev_err(adsp->dev, "Failed to enable DCVDD: %d\n", | 1665 | dev_err(adsp->dev, "Failed to enable DCVDD: %d\n", |
1702 | ret); | 1666 | ret); |
1703 | goto out_coeff; | 1667 | return ret; |
1704 | } | 1668 | } |
1705 | 1669 | ||
1706 | ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); | 1670 | ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); |
1707 | if (ret != 0) { | 1671 | if (ret != 0) { |
1708 | dev_err(adsp->dev, "Failed to initialise DVFS: %d\n", | 1672 | dev_err(adsp->dev, "Failed to initialise DVFS: %d\n", |
1709 | ret); | 1673 | ret); |
1710 | goto out_coeff; | 1674 | return ret; |
1711 | } | 1675 | } |
1712 | 1676 | ||
1713 | ret = regulator_disable(adsp->dvfs); | 1677 | ret = regulator_disable(adsp->dvfs); |
1714 | if (ret != 0) { | 1678 | if (ret != 0) { |
1715 | dev_err(adsp->dev, "Failed to disable DCVDD: %d\n", | 1679 | dev_err(adsp->dev, "Failed to disable DCVDD: %d\n", |
1716 | ret); | 1680 | ret); |
1717 | goto out_coeff; | 1681 | return ret; |
1718 | } | 1682 | } |
1719 | } | 1683 | } |
1720 | 1684 | ||
1721 | return 0; | 1685 | return 0; |
1722 | |||
1723 | out_coeff: | ||
1724 | kfree(adsp->wm_coeff); | ||
1725 | return ret; | ||
1726 | } | 1686 | } |
1727 | EXPORT_SYMBOL_GPL(wm_adsp2_init); | 1687 | EXPORT_SYMBOL_GPL(wm_adsp2_init); |
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 9f922c82536c..d018dea6254d 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h | |||
@@ -39,6 +39,7 @@ struct wm_adsp { | |||
39 | int type; | 39 | int type; |
40 | struct device *dev; | 40 | struct device *dev; |
41 | struct regmap *regmap; | 41 | struct regmap *regmap; |
42 | struct snd_soc_card *card; | ||
42 | 43 | ||
43 | int base; | 44 | int base; |
44 | int sysclk_reg; | 45 | int sysclk_reg; |
@@ -57,7 +58,7 @@ struct wm_adsp { | |||
57 | 58 | ||
58 | struct regulator *dvfs; | 59 | struct regulator *dvfs; |
59 | 60 | ||
60 | struct wm_coeff *wm_coeff; | 61 | struct list_head ctl_list; |
61 | }; | 62 | }; |
62 | 63 | ||
63 | #define WM_ADSP1(wname, num) \ | 64 | #define WM_ADSP1(wname, num) \ |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 2d9e099415a5..8b50e5958de5 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -699,9 +699,7 @@ EXPORT_SYMBOL_GPL(wm_hubs_update_class_w); | |||
699 | static int class_w_put_volsw(struct snd_kcontrol *kcontrol, | 699 | static int class_w_put_volsw(struct snd_kcontrol *kcontrol, |
700 | struct snd_ctl_elem_value *ucontrol) | 700 | struct snd_ctl_elem_value *ucontrol) |
701 | { | 701 | { |
702 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 702 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
703 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
704 | struct snd_soc_codec *codec = widget->codec; | ||
705 | int ret; | 703 | int ret; |
706 | 704 | ||
707 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); | 705 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); |
@@ -721,9 +719,7 @@ static int class_w_put_volsw(struct snd_kcontrol *kcontrol, | |||
721 | static int class_w_put_double(struct snd_kcontrol *kcontrol, | 719 | static int class_w_put_double(struct snd_kcontrol *kcontrol, |
722 | struct snd_ctl_elem_value *ucontrol) | 720 | struct snd_ctl_elem_value *ucontrol) |
723 | { | 721 | { |
724 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 722 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
725 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
726 | struct snd_soc_codec *codec = widget->codec; | ||
727 | int ret; | 723 | int ret; |
728 | 724 | ||
729 | ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); | 725 | ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index aa438546c912..cd088cc8c866 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -1,6 +1,9 @@ | |||
1 | config SND_SOC_FSL_SSI | 1 | config SND_SOC_FSL_SSI |
2 | tristate | 2 | tristate |
3 | 3 | ||
4 | config SND_SOC_FSL_SPDIF | ||
5 | tristate | ||
6 | |||
4 | config SND_SOC_FSL_UTILS | 7 | config SND_SOC_FSL_UTILS |
5 | tristate | 8 | tristate |
6 | 9 | ||
@@ -98,7 +101,7 @@ endif # SND_POWERPC_SOC | |||
98 | 101 | ||
99 | menuconfig SND_IMX_SOC | 102 | menuconfig SND_IMX_SOC |
100 | tristate "SoC Audio for Freescale i.MX CPUs" | 103 | tristate "SoC Audio for Freescale i.MX CPUs" |
101 | depends on ARCH_MXC | 104 | depends on ARCH_MXC || COMPILE_TEST |
102 | help | 105 | help |
103 | Say Y or M if you want to add support for codecs attached to | 106 | Say Y or M if you want to add support for codecs attached to |
104 | the i.MX CPUs. | 107 | the i.MX CPUs. |
@@ -109,11 +112,11 @@ config SND_SOC_IMX_SSI | |||
109 | tristate | 112 | tristate |
110 | 113 | ||
111 | config SND_SOC_IMX_PCM_FIQ | 114 | config SND_SOC_IMX_PCM_FIQ |
112 | bool | 115 | tristate |
113 | select FIQ | 116 | select FIQ |
114 | 117 | ||
115 | config SND_SOC_IMX_PCM_DMA | 118 | config SND_SOC_IMX_PCM_DMA |
116 | bool | 119 | tristate |
117 | select SND_SOC_GENERIC_DMAENGINE_PCM | 120 | select SND_SOC_GENERIC_DMAENGINE_PCM |
118 | 121 | ||
119 | config SND_SOC_IMX_AUDMUX | 122 | config SND_SOC_IMX_AUDMUX |
@@ -175,7 +178,6 @@ config SND_SOC_IMX_WM8962 | |||
175 | select SND_SOC_IMX_PCM_DMA | 178 | select SND_SOC_IMX_PCM_DMA |
176 | select SND_SOC_IMX_AUDMUX | 179 | select SND_SOC_IMX_AUDMUX |
177 | select SND_SOC_FSL_SSI | 180 | select SND_SOC_FSL_SSI |
178 | select SND_SOC_FSL_UTILS | ||
179 | help | 181 | help |
180 | Say Y if you want to add support for SoC audio on an i.MX board with | 182 | Say Y if you want to add support for SoC audio on an i.MX board with |
181 | a wm8962 codec. | 183 | a wm8962 codec. |
@@ -187,14 +189,13 @@ config SND_SOC_IMX_SGTL5000 | |||
187 | select SND_SOC_IMX_PCM_DMA | 189 | select SND_SOC_IMX_PCM_DMA |
188 | select SND_SOC_IMX_AUDMUX | 190 | select SND_SOC_IMX_AUDMUX |
189 | select SND_SOC_FSL_SSI | 191 | select SND_SOC_FSL_SSI |
190 | select SND_SOC_FSL_UTILS | ||
191 | help | 192 | help |
192 | Say Y if you want to add support for SoC audio on an i.MX board with | 193 | Say Y if you want to add support for SoC audio on an i.MX board with |
193 | a sgtl5000 codec. | 194 | a sgtl5000 codec. |
194 | 195 | ||
195 | config SND_SOC_IMX_MC13783 | 196 | config SND_SOC_IMX_MC13783 |
196 | tristate "SoC Audio support for I.MX boards with mc13783" | 197 | tristate "SoC Audio support for I.MX boards with mc13783" |
197 | depends on MFD_MC13783 | 198 | depends on MFD_MC13783 && ARM |
198 | select SND_SOC_IMX_SSI | 199 | select SND_SOC_IMX_SSI |
199 | select SND_SOC_IMX_AUDMUX | 200 | select SND_SOC_IMX_AUDMUX |
200 | select SND_SOC_MC13783 | 201 | select SND_SOC_MC13783 |
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index d4b4aa8b5649..4b5970e014dd 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile | |||
@@ -12,9 +12,11 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o | |||
12 | 12 | ||
13 | # Freescale PowerPC SSI/DMA Platform Support | 13 | # Freescale PowerPC SSI/DMA Platform Support |
14 | snd-soc-fsl-ssi-objs := fsl_ssi.o | 14 | snd-soc-fsl-ssi-objs := fsl_ssi.o |
15 | snd-soc-fsl-spdif-objs := fsl_spdif.o | ||
15 | snd-soc-fsl-utils-objs := fsl_utils.o | 16 | snd-soc-fsl-utils-objs := fsl_utils.o |
16 | snd-soc-fsl-dma-objs := fsl_dma.o | 17 | snd-soc-fsl-dma-objs := fsl_dma.o |
17 | obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o | 18 | obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o |
19 | obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o | ||
18 | obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o | 20 | obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o |
19 | obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o | 21 | obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o |
20 | 22 | ||
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c new file mode 100644 index 000000000000..42a43820d993 --- /dev/null +++ b/sound/soc/fsl/fsl_spdif.c | |||
@@ -0,0 +1,1236 @@ | |||
1 | /* | ||
2 | * Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Based on stmp3xxx_spdif_dai.c | ||
7 | * Vladimir Barinov <vbarinov@embeddedalley.com> | ||
8 | * Copyright 2008 SigmaTel, Inc | ||
9 | * Copyright 2008 Embedded Alley Solutions, Inc | ||
10 | * | ||
11 | * This file is licensed under the terms of the GNU General Public License | ||
12 | * version 2. This program is licensed "as is" without any warranty of any | ||
13 | * kind, whether express or implied. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/clk.h> | ||
18 | #include <linux/clk-private.h> | ||
19 | #include <linux/bitrev.h> | ||
20 | #include <linux/regmap.h> | ||
21 | #include <linux/of_address.h> | ||
22 | #include <linux/of_device.h> | ||
23 | #include <linux/of_irq.h> | ||
24 | |||
25 | #include <sound/asoundef.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/dmaengine_pcm.h> | ||
28 | |||
29 | #include "fsl_spdif.h" | ||
30 | #include "imx-pcm.h" | ||
31 | |||
32 | #define FSL_SPDIF_TXFIFO_WML 0x8 | ||
33 | #define FSL_SPDIF_RXFIFO_WML 0x8 | ||
34 | |||
35 | #define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC) | ||
36 | #define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL | INT_URX_OV|\ | ||
37 | INT_QRX_FUL | INT_QRX_OV | INT_UQ_SYNC | INT_UQ_ERR |\ | ||
38 | INT_RXFIFO_RESYNC | INT_LOSS_LOCK | INT_DPLL_LOCKED) | ||
39 | |||
40 | /* Index list for the values that has if (DPLL Locked) condition */ | ||
41 | static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; | ||
42 | #define SRPC_NODPLL_START1 0x5 | ||
43 | #define SRPC_NODPLL_START2 0xc | ||
44 | |||
45 | #define DEFAULT_RXCLK_SRC 1 | ||
46 | |||
47 | /* | ||
48 | * SPDIF control structure | ||
49 | * Defines channel status, subcode and Q sub | ||
50 | */ | ||
51 | struct spdif_mixer_control { | ||
52 | /* spinlock to access control data */ | ||
53 | spinlock_t ctl_lock; | ||
54 | |||
55 | /* IEC958 channel tx status bit */ | ||
56 | unsigned char ch_status[4]; | ||
57 | |||
58 | /* User bits */ | ||
59 | unsigned char subcode[2 * SPDIF_UBITS_SIZE]; | ||
60 | |||
61 | /* Q subcode part of user bits */ | ||
62 | unsigned char qsub[2 * SPDIF_QSUB_SIZE]; | ||
63 | |||
64 | /* Buffer offset for U/Q */ | ||
65 | u32 upos; | ||
66 | u32 qpos; | ||
67 | |||
68 | /* Ready buffer index of the two buffers */ | ||
69 | u32 ready_buf; | ||
70 | }; | ||
71 | |||
72 | struct fsl_spdif_priv { | ||
73 | struct spdif_mixer_control fsl_spdif_control; | ||
74 | struct snd_soc_dai_driver cpu_dai_drv; | ||
75 | struct platform_device *pdev; | ||
76 | struct regmap *regmap; | ||
77 | bool dpll_locked; | ||
78 | u8 txclk_div[SPDIF_TXRATE_MAX]; | ||
79 | u8 txclk_src[SPDIF_TXRATE_MAX]; | ||
80 | u8 rxclk_src; | ||
81 | struct clk *txclk[SPDIF_TXRATE_MAX]; | ||
82 | struct clk *rxclk; | ||
83 | struct snd_dmaengine_dai_dma_data dma_params_tx; | ||
84 | struct snd_dmaengine_dai_dma_data dma_params_rx; | ||
85 | |||
86 | /* The name space will be allocated dynamically */ | ||
87 | char name[0]; | ||
88 | }; | ||
89 | |||
90 | |||
91 | /* DPLL locked and lock loss interrupt handler */ | ||
92 | static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) | ||
93 | { | ||
94 | struct regmap *regmap = spdif_priv->regmap; | ||
95 | struct platform_device *pdev = spdif_priv->pdev; | ||
96 | u32 locked; | ||
97 | |||
98 | regmap_read(regmap, REG_SPDIF_SRPC, &locked); | ||
99 | locked &= SRPC_DPLL_LOCKED; | ||
100 | |||
101 | dev_dbg(&pdev->dev, "isr: Rx dpll %s \n", | ||
102 | locked ? "locked" : "loss lock"); | ||
103 | |||
104 | spdif_priv->dpll_locked = locked ? true : false; | ||
105 | } | ||
106 | |||
107 | /* Receiver found illegal symbol interrupt handler */ | ||
108 | static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv) | ||
109 | { | ||
110 | struct regmap *regmap = spdif_priv->regmap; | ||
111 | struct platform_device *pdev = spdif_priv->pdev; | ||
112 | |||
113 | dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n"); | ||
114 | |||
115 | if (!spdif_priv->dpll_locked) { | ||
116 | /* DPLL unlocked seems no audio stream */ | ||
117 | regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /* U/Q Channel receive register full */ | ||
122 | static void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char name) | ||
123 | { | ||
124 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
125 | struct regmap *regmap = spdif_priv->regmap; | ||
126 | struct platform_device *pdev = spdif_priv->pdev; | ||
127 | u32 *pos, size, val, reg; | ||
128 | |||
129 | switch (name) { | ||
130 | case 'U': | ||
131 | pos = &ctrl->upos; | ||
132 | size = SPDIF_UBITS_SIZE; | ||
133 | reg = REG_SPDIF_SRU; | ||
134 | break; | ||
135 | case 'Q': | ||
136 | pos = &ctrl->qpos; | ||
137 | size = SPDIF_QSUB_SIZE; | ||
138 | reg = REG_SPDIF_SRQ; | ||
139 | break; | ||
140 | default: | ||
141 | dev_err(&pdev->dev, "unsupported channel name\n"); | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | dev_dbg(&pdev->dev, "isr: %c Channel receive register full\n", name); | ||
146 | |||
147 | if (*pos >= size * 2) { | ||
148 | *pos = 0; | ||
149 | } else if (unlikely((*pos % size) + 3 > size)) { | ||
150 | dev_err(&pdev->dev, "User bit receivce buffer overflow\n"); | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | regmap_read(regmap, reg, &val); | ||
155 | ctrl->subcode[*pos++] = val >> 16; | ||
156 | ctrl->subcode[*pos++] = val >> 8; | ||
157 | ctrl->subcode[*pos++] = val; | ||
158 | } | ||
159 | |||
160 | /* U/Q Channel sync found */ | ||
161 | static void spdif_irq_uq_sync(struct fsl_spdif_priv *spdif_priv) | ||
162 | { | ||
163 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
164 | struct platform_device *pdev = spdif_priv->pdev; | ||
165 | |||
166 | dev_dbg(&pdev->dev, "isr: U/Q Channel sync found\n"); | ||
167 | |||
168 | /* U/Q buffer reset */ | ||
169 | if (ctrl->qpos == 0) | ||
170 | return; | ||
171 | |||
172 | /* Set ready to this buffer */ | ||
173 | ctrl->ready_buf = (ctrl->qpos - 1) / SPDIF_QSUB_SIZE + 1; | ||
174 | } | ||
175 | |||
176 | /* U/Q Channel framing error */ | ||
177 | static void spdif_irq_uq_err(struct fsl_spdif_priv *spdif_priv) | ||
178 | { | ||
179 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
180 | struct regmap *regmap = spdif_priv->regmap; | ||
181 | struct platform_device *pdev = spdif_priv->pdev; | ||
182 | u32 val; | ||
183 | |||
184 | dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n"); | ||
185 | |||
186 | /* Read U/Q data to clear the irq and do buffer reset */ | ||
187 | regmap_read(regmap, REG_SPDIF_SRU, &val); | ||
188 | regmap_read(regmap, REG_SPDIF_SRQ, &val); | ||
189 | |||
190 | /* Drop this U/Q buffer */ | ||
191 | ctrl->ready_buf = 0; | ||
192 | ctrl->upos = 0; | ||
193 | ctrl->qpos = 0; | ||
194 | } | ||
195 | |||
196 | /* Get spdif interrupt status and clear the interrupt */ | ||
197 | static u32 spdif_intr_status_clear(struct fsl_spdif_priv *spdif_priv) | ||
198 | { | ||
199 | struct regmap *regmap = spdif_priv->regmap; | ||
200 | u32 val, val2; | ||
201 | |||
202 | regmap_read(regmap, REG_SPDIF_SIS, &val); | ||
203 | regmap_read(regmap, REG_SPDIF_SIE, &val2); | ||
204 | |||
205 | regmap_write(regmap, REG_SPDIF_SIC, val & val2); | ||
206 | |||
207 | return val; | ||
208 | } | ||
209 | |||
210 | static irqreturn_t spdif_isr(int irq, void *devid) | ||
211 | { | ||
212 | struct fsl_spdif_priv *spdif_priv = (struct fsl_spdif_priv *)devid; | ||
213 | struct platform_device *pdev = spdif_priv->pdev; | ||
214 | u32 sis; | ||
215 | |||
216 | sis = spdif_intr_status_clear(spdif_priv); | ||
217 | |||
218 | if (sis & INT_DPLL_LOCKED) | ||
219 | spdif_irq_dpll_lock(spdif_priv); | ||
220 | |||
221 | if (sis & INT_TXFIFO_UNOV) | ||
222 | dev_dbg(&pdev->dev, "isr: Tx FIFO under/overrun\n"); | ||
223 | |||
224 | if (sis & INT_TXFIFO_RESYNC) | ||
225 | dev_dbg(&pdev->dev, "isr: Tx FIFO resync\n"); | ||
226 | |||
227 | if (sis & INT_CNEW) | ||
228 | dev_dbg(&pdev->dev, "isr: cstatus new\n"); | ||
229 | |||
230 | if (sis & INT_VAL_NOGOOD) | ||
231 | dev_dbg(&pdev->dev, "isr: validity flag no good\n"); | ||
232 | |||
233 | if (sis & INT_SYM_ERR) | ||
234 | spdif_irq_sym_error(spdif_priv); | ||
235 | |||
236 | if (sis & INT_BIT_ERR) | ||
237 | dev_dbg(&pdev->dev, "isr: receiver found parity bit error\n"); | ||
238 | |||
239 | if (sis & INT_URX_FUL) | ||
240 | spdif_irq_uqrx_full(spdif_priv, 'U'); | ||
241 | |||
242 | if (sis & INT_URX_OV) | ||
243 | dev_dbg(&pdev->dev, "isr: U Channel receive register overrun\n"); | ||
244 | |||
245 | if (sis & INT_QRX_FUL) | ||
246 | spdif_irq_uqrx_full(spdif_priv, 'Q'); | ||
247 | |||
248 | if (sis & INT_QRX_OV) | ||
249 | dev_dbg(&pdev->dev, "isr: Q Channel receive register overrun\n"); | ||
250 | |||
251 | if (sis & INT_UQ_SYNC) | ||
252 | spdif_irq_uq_sync(spdif_priv); | ||
253 | |||
254 | if (sis & INT_UQ_ERR) | ||
255 | spdif_irq_uq_err(spdif_priv); | ||
256 | |||
257 | if (sis & INT_RXFIFO_UNOV) | ||
258 | dev_dbg(&pdev->dev, "isr: Rx FIFO under/overrun\n"); | ||
259 | |||
260 | if (sis & INT_RXFIFO_RESYNC) | ||
261 | dev_dbg(&pdev->dev, "isr: Rx FIFO resync\n"); | ||
262 | |||
263 | if (sis & INT_LOSS_LOCK) | ||
264 | spdif_irq_dpll_lock(spdif_priv); | ||
265 | |||
266 | /* FIXME: Write Tx FIFO to clear TxEm */ | ||
267 | if (sis & INT_TX_EM) | ||
268 | dev_dbg(&pdev->dev, "isr: Tx FIFO empty\n"); | ||
269 | |||
270 | /* FIXME: Read Rx FIFO to clear RxFIFOFul */ | ||
271 | if (sis & INT_RXFIFO_FUL) | ||
272 | dev_dbg(&pdev->dev, "isr: Rx FIFO full\n"); | ||
273 | |||
274 | return IRQ_HANDLED; | ||
275 | } | ||
276 | |||
277 | static int spdif_softreset(struct fsl_spdif_priv *spdif_priv) | ||
278 | { | ||
279 | struct regmap *regmap = spdif_priv->regmap; | ||
280 | u32 val, cycle = 1000; | ||
281 | |||
282 | regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET); | ||
283 | |||
284 | /* | ||
285 | * RESET bit would be cleared after finishing its reset procedure, | ||
286 | * which typically lasts 8 cycles. 1000 cycles will keep it safe. | ||
287 | */ | ||
288 | do { | ||
289 | regmap_read(regmap, REG_SPDIF_SCR, &val); | ||
290 | } while ((val & SCR_SOFT_RESET) && cycle--); | ||
291 | |||
292 | if (cycle) | ||
293 | return 0; | ||
294 | else | ||
295 | return -EBUSY; | ||
296 | } | ||
297 | |||
298 | static void spdif_set_cstatus(struct spdif_mixer_control *ctrl, | ||
299 | u8 mask, u8 cstatus) | ||
300 | { | ||
301 | ctrl->ch_status[3] &= ~mask; | ||
302 | ctrl->ch_status[3] |= cstatus & mask; | ||
303 | } | ||
304 | |||
305 | static void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv) | ||
306 | { | ||
307 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
308 | struct regmap *regmap = spdif_priv->regmap; | ||
309 | struct platform_device *pdev = spdif_priv->pdev; | ||
310 | u32 ch_status; | ||
311 | |||
312 | ch_status = (bitrev8(ctrl->ch_status[0]) << 16) | | ||
313 | (bitrev8(ctrl->ch_status[1]) << 8) | | ||
314 | bitrev8(ctrl->ch_status[2]); | ||
315 | regmap_write(regmap, REG_SPDIF_STCSCH, ch_status); | ||
316 | |||
317 | dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status); | ||
318 | |||
319 | ch_status = bitrev8(ctrl->ch_status[3]) << 16; | ||
320 | regmap_write(regmap, REG_SPDIF_STCSCL, ch_status); | ||
321 | |||
322 | dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", ch_status); | ||
323 | } | ||
324 | |||
325 | /* Set SPDIF PhaseConfig register for rx clock */ | ||
326 | static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv, | ||
327 | enum spdif_gainsel gainsel, int dpll_locked) | ||
328 | { | ||
329 | struct regmap *regmap = spdif_priv->regmap; | ||
330 | u8 clksrc = spdif_priv->rxclk_src; | ||
331 | |||
332 | if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX) | ||
333 | return -EINVAL; | ||
334 | |||
335 | regmap_update_bits(regmap, REG_SPDIF_SRPC, | ||
336 | SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, | ||
337 | SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel)); | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int spdif_set_sample_rate(struct snd_pcm_substream *substream, | ||
343 | int sample_rate) | ||
344 | { | ||
345 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
346 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
347 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
348 | struct regmap *regmap = spdif_priv->regmap; | ||
349 | struct platform_device *pdev = spdif_priv->pdev; | ||
350 | unsigned long csfs = 0; | ||
351 | u32 stc, mask, rate; | ||
352 | u8 clk, div; | ||
353 | int ret; | ||
354 | |||
355 | switch (sample_rate) { | ||
356 | case 32000: | ||
357 | rate = SPDIF_TXRATE_32000; | ||
358 | csfs = IEC958_AES3_CON_FS_32000; | ||
359 | break; | ||
360 | case 44100: | ||
361 | rate = SPDIF_TXRATE_44100; | ||
362 | csfs = IEC958_AES3_CON_FS_44100; | ||
363 | break; | ||
364 | case 48000: | ||
365 | rate = SPDIF_TXRATE_48000; | ||
366 | csfs = IEC958_AES3_CON_FS_48000; | ||
367 | break; | ||
368 | default: | ||
369 | dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate); | ||
370 | return -EINVAL; | ||
371 | } | ||
372 | |||
373 | clk = spdif_priv->txclk_src[rate]; | ||
374 | if (clk >= STC_TXCLK_SRC_MAX) { | ||
375 | dev_err(&pdev->dev, "tx clock source is out of range\n"); | ||
376 | return -EINVAL; | ||
377 | } | ||
378 | |||
379 | div = spdif_priv->txclk_div[rate]; | ||
380 | if (div == 0) { | ||
381 | dev_err(&pdev->dev, "the divisor can't be zero\n"); | ||
382 | return -EINVAL; | ||
383 | } | ||
384 | |||
385 | /* | ||
386 | * The S/PDIF block needs a clock of 64 * fs * div. The S/PDIF block | ||
387 | * will divide by (div). So request 64 * fs * (div+1) which will | ||
388 | * get rounded. | ||
389 | */ | ||
390 | ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (div + 1)); | ||
391 | if (ret) { | ||
392 | dev_err(&pdev->dev, "failed to set tx clock rate\n"); | ||
393 | return ret; | ||
394 | } | ||
395 | |||
396 | dev_dbg(&pdev->dev, "expected clock rate = %d\n", | ||
397 | (64 * sample_rate * div)); | ||
398 | dev_dbg(&pdev->dev, "actual clock rate = %ld\n", | ||
399 | clk_get_rate(spdif_priv->txclk[rate])); | ||
400 | |||
401 | /* set fs field in consumer channel status */ | ||
402 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs); | ||
403 | |||
404 | /* select clock source and divisor */ | ||
405 | stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DIV(div); | ||
406 | mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MASK; | ||
407 | regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc); | ||
408 | |||
409 | dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | int fsl_spdif_startup(struct snd_pcm_substream *substream, | ||
415 | struct snd_soc_dai *cpu_dai) | ||
416 | { | ||
417 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
418 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
419 | struct platform_device *pdev = spdif_priv->pdev; | ||
420 | struct regmap *regmap = spdif_priv->regmap; | ||
421 | u32 scr, mask, i; | ||
422 | int ret; | ||
423 | |||
424 | /* Reset module and interrupts only for first initialization */ | ||
425 | if (!cpu_dai->active) { | ||
426 | ret = spdif_softreset(spdif_priv); | ||
427 | if (ret) { | ||
428 | dev_err(&pdev->dev, "failed to soft reset\n"); | ||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | /* Disable all the interrupts */ | ||
433 | regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0); | ||
434 | } | ||
435 | |||
436 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
437 | scr = SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL | | ||
438 | SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP | | ||
439 | SCR_TXFIFO_FSEL_IF8; | ||
440 | mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | | ||
441 | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | | ||
442 | SCR_TXFIFO_FSEL_MASK; | ||
443 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) | ||
444 | clk_prepare_enable(spdif_priv->txclk[i]); | ||
445 | } else { | ||
446 | scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC; | ||
447 | mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| | ||
448 | SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; | ||
449 | clk_prepare_enable(spdif_priv->rxclk); | ||
450 | } | ||
451 | regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); | ||
452 | |||
453 | /* Power up SPDIF module */ | ||
454 | regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, | ||
460 | struct snd_soc_dai *cpu_dai) | ||
461 | { | ||
462 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
463 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
464 | struct regmap *regmap = spdif_priv->regmap; | ||
465 | u32 scr, mask, i; | ||
466 | |||
467 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
468 | scr = 0; | ||
469 | mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | | ||
470 | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | | ||
471 | SCR_TXFIFO_FSEL_MASK; | ||
472 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) | ||
473 | clk_disable_unprepare(spdif_priv->txclk[i]); | ||
474 | } else { | ||
475 | scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO; | ||
476 | mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| | ||
477 | SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; | ||
478 | clk_disable_unprepare(spdif_priv->rxclk); | ||
479 | } | ||
480 | regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); | ||
481 | |||
482 | /* Power down SPDIF module only if tx&rx are both inactive */ | ||
483 | if (!cpu_dai->active) { | ||
484 | spdif_intr_status_clear(spdif_priv); | ||
485 | regmap_update_bits(regmap, REG_SPDIF_SCR, | ||
486 | SCR_LOW_POWER, SCR_LOW_POWER); | ||
487 | } | ||
488 | } | ||
489 | |||
490 | static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, | ||
491 | struct snd_pcm_hw_params *params, | ||
492 | struct snd_soc_dai *dai) | ||
493 | { | ||
494 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
495 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
496 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
497 | struct platform_device *pdev = spdif_priv->pdev; | ||
498 | u32 sample_rate = params_rate(params); | ||
499 | int ret = 0; | ||
500 | |||
501 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
502 | ret = spdif_set_sample_rate(substream, sample_rate); | ||
503 | if (ret) { | ||
504 | dev_err(&pdev->dev, "%s: set sample rate failed: %d\n", | ||
505 | __func__, sample_rate); | ||
506 | return ret; | ||
507 | } | ||
508 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK, | ||
509 | IEC958_AES3_CON_CLOCK_1000PPM); | ||
510 | spdif_write_channel_status(spdif_priv); | ||
511 | } else { | ||
512 | /* Setup rx clock source */ | ||
513 | ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1); | ||
514 | } | ||
515 | |||
516 | return ret; | ||
517 | } | ||
518 | |||
519 | static int fsl_spdif_trigger(struct snd_pcm_substream *substream, | ||
520 | int cmd, struct snd_soc_dai *dai) | ||
521 | { | ||
522 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
523 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
524 | struct regmap *regmap = spdif_priv->regmap; | ||
525 | int is_playack = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
526 | u32 intr = is_playack ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE; | ||
527 | u32 dmaen = is_playack ? SCR_DMA_TX_EN : SCR_DMA_RX_EN;; | ||
528 | |||
529 | switch (cmd) { | ||
530 | case SNDRV_PCM_TRIGGER_START: | ||
531 | case SNDRV_PCM_TRIGGER_RESUME: | ||
532 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
533 | regmap_update_bits(regmap, REG_SPDIF_SIE, intr, intr); | ||
534 | regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, dmaen); | ||
535 | break; | ||
536 | case SNDRV_PCM_TRIGGER_STOP: | ||
537 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
538 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
539 | regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0); | ||
540 | regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0); | ||
541 | break; | ||
542 | default: | ||
543 | return -EINVAL; | ||
544 | } | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | struct snd_soc_dai_ops fsl_spdif_dai_ops = { | ||
550 | .startup = fsl_spdif_startup, | ||
551 | .hw_params = fsl_spdif_hw_params, | ||
552 | .trigger = fsl_spdif_trigger, | ||
553 | .shutdown = fsl_spdif_shutdown, | ||
554 | }; | ||
555 | |||
556 | |||
557 | /* | ||
558 | * ============================================ | ||
559 | * FSL SPDIF IEC958 controller(mixer) functions | ||
560 | * | ||
561 | * Channel status get/put control | ||
562 | * User bit value get/put control | ||
563 | * Valid bit value get control | ||
564 | * DPLL lock status get control | ||
565 | * User bit sync mode selection control | ||
566 | * ============================================ | ||
567 | */ | ||
568 | |||
569 | static int fsl_spdif_info(struct snd_kcontrol *kcontrol, | ||
570 | struct snd_ctl_elem_info *uinfo) | ||
571 | { | ||
572 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
573 | uinfo->count = 1; | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static int fsl_spdif_pb_get(struct snd_kcontrol *kcontrol, | ||
579 | struct snd_ctl_elem_value *uvalue) | ||
580 | { | ||
581 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
582 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
583 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
584 | |||
585 | uvalue->value.iec958.status[0] = ctrl->ch_status[0]; | ||
586 | uvalue->value.iec958.status[1] = ctrl->ch_status[1]; | ||
587 | uvalue->value.iec958.status[2] = ctrl->ch_status[2]; | ||
588 | uvalue->value.iec958.status[3] = ctrl->ch_status[3]; | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static int fsl_spdif_pb_put(struct snd_kcontrol *kcontrol, | ||
594 | struct snd_ctl_elem_value *uvalue) | ||
595 | { | ||
596 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
597 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
598 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
599 | |||
600 | ctrl->ch_status[0] = uvalue->value.iec958.status[0]; | ||
601 | ctrl->ch_status[1] = uvalue->value.iec958.status[1]; | ||
602 | ctrl->ch_status[2] = uvalue->value.iec958.status[2]; | ||
603 | ctrl->ch_status[3] = uvalue->value.iec958.status[3]; | ||
604 | |||
605 | spdif_write_channel_status(spdif_priv); | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | /* Get channel status from SPDIF_RX_CCHAN register */ | ||
611 | static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol, | ||
612 | struct snd_ctl_elem_value *ucontrol) | ||
613 | { | ||
614 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
615 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
616 | struct regmap *regmap = spdif_priv->regmap; | ||
617 | u32 cstatus, val; | ||
618 | |||
619 | regmap_read(regmap, REG_SPDIF_SIS, &val); | ||
620 | if (!(val & INT_CNEW)) { | ||
621 | return -EAGAIN; | ||
622 | } | ||
623 | |||
624 | regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus); | ||
625 | ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF; | ||
626 | ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF; | ||
627 | ucontrol->value.iec958.status[2] = cstatus & 0xFF; | ||
628 | |||
629 | regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus); | ||
630 | ucontrol->value.iec958.status[3] = (cstatus >> 16) & 0xFF; | ||
631 | ucontrol->value.iec958.status[4] = (cstatus >> 8) & 0xFF; | ||
632 | ucontrol->value.iec958.status[5] = cstatus & 0xFF; | ||
633 | |||
634 | /* Clear intr */ | ||
635 | regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW); | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * Get User bits (subcode) from chip value which readed out | ||
642 | * in UChannel register. | ||
643 | */ | ||
644 | static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol, | ||
645 | struct snd_ctl_elem_value *ucontrol) | ||
646 | { | ||
647 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
648 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
649 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
650 | unsigned long flags; | ||
651 | int ret = 0; | ||
652 | |||
653 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | ||
654 | if (ctrl->ready_buf) { | ||
655 | int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE; | ||
656 | memcpy(&ucontrol->value.iec958.subcode[0], | ||
657 | &ctrl->subcode[idx], SPDIF_UBITS_SIZE); | ||
658 | } else { | ||
659 | ret = -EAGAIN; | ||
660 | } | ||
661 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | ||
662 | |||
663 | return ret; | ||
664 | } | ||
665 | |||
666 | /* Q-subcode infomation. The byte size is SPDIF_UBITS_SIZE/8 */ | ||
667 | static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol, | ||
668 | struct snd_ctl_elem_info *uinfo) | ||
669 | { | ||
670 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
671 | uinfo->count = SPDIF_QSUB_SIZE; | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | /* Get Q subcode from chip value which readed out in QChannel register */ | ||
677 | static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, | ||
678 | struct snd_ctl_elem_value *ucontrol) | ||
679 | { | ||
680 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
681 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
682 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
683 | unsigned long flags; | ||
684 | int ret = 0; | ||
685 | |||
686 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | ||
687 | if (ctrl->ready_buf) { | ||
688 | int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE; | ||
689 | memcpy(&ucontrol->value.bytes.data[0], | ||
690 | &ctrl->qsub[idx], SPDIF_QSUB_SIZE); | ||
691 | } else { | ||
692 | ret = -EAGAIN; | ||
693 | } | ||
694 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | ||
695 | |||
696 | return ret; | ||
697 | } | ||
698 | |||
699 | /* Valid bit infomation */ | ||
700 | static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol, | ||
701 | struct snd_ctl_elem_info *uinfo) | ||
702 | { | ||
703 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
704 | uinfo->count = 1; | ||
705 | uinfo->value.integer.min = 0; | ||
706 | uinfo->value.integer.max = 1; | ||
707 | |||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | /* Get valid good bit from interrupt status register */ | ||
712 | static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, | ||
713 | struct snd_ctl_elem_value *ucontrol) | ||
714 | { | ||
715 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
716 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
717 | struct regmap *regmap = spdif_priv->regmap; | ||
718 | u32 val; | ||
719 | |||
720 | val = regmap_read(regmap, REG_SPDIF_SIS, &val); | ||
721 | ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; | ||
722 | regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | /* DPLL lock infomation */ | ||
728 | static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, | ||
729 | struct snd_ctl_elem_info *uinfo) | ||
730 | { | ||
731 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
732 | uinfo->count = 1; | ||
733 | uinfo->value.integer.min = 16000; | ||
734 | uinfo->value.integer.max = 96000; | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static u32 gainsel_multi[GAINSEL_MULTI_MAX] = { | ||
740 | 24, 16, 12, 8, 6, 4, 3, | ||
741 | }; | ||
742 | |||
743 | /* Get RX data clock rate given the SPDIF bus_clk */ | ||
744 | static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv, | ||
745 | enum spdif_gainsel gainsel) | ||
746 | { | ||
747 | struct regmap *regmap = spdif_priv->regmap; | ||
748 | struct platform_device *pdev = spdif_priv->pdev; | ||
749 | u64 tmpval64, busclk_freq = 0; | ||
750 | u32 freqmeas, phaseconf; | ||
751 | u8 clksrc; | ||
752 | |||
753 | regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas); | ||
754 | regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf); | ||
755 | |||
756 | clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf; | ||
757 | if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) { | ||
758 | /* Get bus clock from system */ | ||
759 | busclk_freq = clk_get_rate(spdif_priv->rxclk); | ||
760 | } | ||
761 | |||
762 | /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */ | ||
763 | tmpval64 = (u64) busclk_freq * freqmeas; | ||
764 | do_div(tmpval64, gainsel_multi[gainsel] * 1024); | ||
765 | do_div(tmpval64, 128 * 1024); | ||
766 | |||
767 | dev_dbg(&pdev->dev, "FreqMeas: %d\n", freqmeas); | ||
768 | dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq); | ||
769 | dev_dbg(&pdev->dev, "RxRate: %lld\n", tmpval64); | ||
770 | |||
771 | return (int)tmpval64; | ||
772 | } | ||
773 | |||
774 | /* | ||
775 | * Get DPLL lock or not info from stable interrupt status register. | ||
776 | * User application must use this control to get locked, | ||
777 | * then can do next PCM operation | ||
778 | */ | ||
779 | static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol, | ||
780 | struct snd_ctl_elem_value *ucontrol) | ||
781 | { | ||
782 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
783 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
784 | int rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL); | ||
785 | |||
786 | if (spdif_priv->dpll_locked) | ||
787 | ucontrol->value.integer.value[0] = rate; | ||
788 | else | ||
789 | ucontrol->value.integer.value[0] = 0; | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | /* User bit sync mode info */ | ||
795 | static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol, | ||
796 | struct snd_ctl_elem_info *uinfo) | ||
797 | { | ||
798 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
799 | uinfo->count = 1; | ||
800 | uinfo->value.integer.min = 0; | ||
801 | uinfo->value.integer.max = 1; | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | /* | ||
807 | * User bit sync mode: | ||
808 | * 1 CD User channel subcode | ||
809 | * 0 Non-CD data | ||
810 | */ | ||
811 | static int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol, | ||
812 | struct snd_ctl_elem_value *ucontrol) | ||
813 | { | ||
814 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
815 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
816 | struct regmap *regmap = spdif_priv->regmap; | ||
817 | u32 val; | ||
818 | |||
819 | regmap_read(regmap, REG_SPDIF_SRCD, &val); | ||
820 | ucontrol->value.integer.value[0] = (val & SRCD_CD_USER) != 0; | ||
821 | |||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | /* | ||
826 | * User bit sync mode: | ||
827 | * 1 CD User channel subcode | ||
828 | * 0 Non-CD data | ||
829 | */ | ||
830 | static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol, | ||
831 | struct snd_ctl_elem_value *ucontrol) | ||
832 | { | ||
833 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
834 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
835 | struct regmap *regmap = spdif_priv->regmap; | ||
836 | u32 val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET; | ||
837 | |||
838 | regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val); | ||
839 | |||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | /* FSL SPDIF IEC958 controller defines */ | ||
844 | static struct snd_kcontrol_new fsl_spdif_ctrls[] = { | ||
845 | /* Status cchanel controller */ | ||
846 | { | ||
847 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
848 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | ||
849 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
850 | SNDRV_CTL_ELEM_ACCESS_WRITE | | ||
851 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
852 | .info = fsl_spdif_info, | ||
853 | .get = fsl_spdif_pb_get, | ||
854 | .put = fsl_spdif_pb_put, | ||
855 | }, | ||
856 | { | ||
857 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
858 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | ||
859 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
860 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
861 | .info = fsl_spdif_info, | ||
862 | .get = fsl_spdif_capture_get, | ||
863 | }, | ||
864 | /* User bits controller */ | ||
865 | { | ||
866 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
867 | .name = "IEC958 Subcode Capture Default", | ||
868 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
869 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
870 | .info = fsl_spdif_info, | ||
871 | .get = fsl_spdif_subcode_get, | ||
872 | }, | ||
873 | { | ||
874 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
875 | .name = "IEC958 Q-subcode Capture Default", | ||
876 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
877 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
878 | .info = fsl_spdif_qinfo, | ||
879 | .get = fsl_spdif_qget, | ||
880 | }, | ||
881 | /* Valid bit error controller */ | ||
882 | { | ||
883 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
884 | .name = "IEC958 V-Bit Errors", | ||
885 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
886 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
887 | .info = fsl_spdif_vbit_info, | ||
888 | .get = fsl_spdif_vbit_get, | ||
889 | }, | ||
890 | /* DPLL lock info get controller */ | ||
891 | { | ||
892 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
893 | .name = "RX Sample Rate", | ||
894 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
895 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
896 | .info = fsl_spdif_rxrate_info, | ||
897 | .get = fsl_spdif_rxrate_get, | ||
898 | }, | ||
899 | /* User bit sync mode set/get controller */ | ||
900 | { | ||
901 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
902 | .name = "IEC958 USyncMode CDText", | ||
903 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
904 | SNDRV_CTL_ELEM_ACCESS_WRITE | | ||
905 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
906 | .info = fsl_spdif_usync_info, | ||
907 | .get = fsl_spdif_usync_get, | ||
908 | .put = fsl_spdif_usync_put, | ||
909 | }, | ||
910 | }; | ||
911 | |||
912 | static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) | ||
913 | { | ||
914 | struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); | ||
915 | |||
916 | dai->playback_dma_data = &spdif_private->dma_params_tx; | ||
917 | dai->capture_dma_data = &spdif_private->dma_params_rx; | ||
918 | |||
919 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); | ||
920 | |||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | struct snd_soc_dai_driver fsl_spdif_dai = { | ||
925 | .probe = &fsl_spdif_dai_probe, | ||
926 | .playback = { | ||
927 | .channels_min = 2, | ||
928 | .channels_max = 2, | ||
929 | .rates = FSL_SPDIF_RATES_PLAYBACK, | ||
930 | .formats = FSL_SPDIF_FORMATS_PLAYBACK, | ||
931 | }, | ||
932 | .capture = { | ||
933 | .channels_min = 2, | ||
934 | .channels_max = 2, | ||
935 | .rates = FSL_SPDIF_RATES_CAPTURE, | ||
936 | .formats = FSL_SPDIF_FORMATS_CAPTURE, | ||
937 | }, | ||
938 | .ops = &fsl_spdif_dai_ops, | ||
939 | }; | ||
940 | |||
941 | static const struct snd_soc_component_driver fsl_spdif_component = { | ||
942 | .name = "fsl-spdif", | ||
943 | }; | ||
944 | |||
945 | /* | ||
946 | * ================ | ||
947 | * FSL SPDIF REGMAP | ||
948 | * ================ | ||
949 | */ | ||
950 | |||
951 | static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg) | ||
952 | { | ||
953 | switch (reg) { | ||
954 | case REG_SPDIF_SCR: | ||
955 | case REG_SPDIF_SRCD: | ||
956 | case REG_SPDIF_SRPC: | ||
957 | case REG_SPDIF_SIE: | ||
958 | case REG_SPDIF_SIS: | ||
959 | case REG_SPDIF_SRL: | ||
960 | case REG_SPDIF_SRR: | ||
961 | case REG_SPDIF_SRCSH: | ||
962 | case REG_SPDIF_SRCSL: | ||
963 | case REG_SPDIF_SRU: | ||
964 | case REG_SPDIF_SRQ: | ||
965 | case REG_SPDIF_STCSCH: | ||
966 | case REG_SPDIF_STCSCL: | ||
967 | case REG_SPDIF_SRFM: | ||
968 | case REG_SPDIF_STC: | ||
969 | return true; | ||
970 | default: | ||
971 | return false; | ||
972 | }; | ||
973 | } | ||
974 | |||
975 | static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) | ||
976 | { | ||
977 | switch (reg) { | ||
978 | case REG_SPDIF_SCR: | ||
979 | case REG_SPDIF_SRCD: | ||
980 | case REG_SPDIF_SRPC: | ||
981 | case REG_SPDIF_SIE: | ||
982 | case REG_SPDIF_SIC: | ||
983 | case REG_SPDIF_STL: | ||
984 | case REG_SPDIF_STR: | ||
985 | case REG_SPDIF_STCSCH: | ||
986 | case REG_SPDIF_STCSCL: | ||
987 | case REG_SPDIF_STC: | ||
988 | return true; | ||
989 | default: | ||
990 | return false; | ||
991 | }; | ||
992 | } | ||
993 | |||
994 | static const struct regmap_config fsl_spdif_regmap_config = { | ||
995 | .reg_bits = 32, | ||
996 | .reg_stride = 4, | ||
997 | .val_bits = 32, | ||
998 | |||
999 | .max_register = REG_SPDIF_STC, | ||
1000 | .readable_reg = fsl_spdif_readable_reg, | ||
1001 | .writeable_reg = fsl_spdif_writeable_reg, | ||
1002 | }; | ||
1003 | |||
1004 | static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, | ||
1005 | struct clk *clk, u64 savesub, | ||
1006 | enum spdif_txrate index) | ||
1007 | { | ||
1008 | const u32 rate[] = { 32000, 44100, 48000 }; | ||
1009 | u64 rate_ideal, rate_actual, sub; | ||
1010 | u32 div, arate; | ||
1011 | |||
1012 | for (div = 1; div <= 128; div++) { | ||
1013 | rate_ideal = rate[index] * (div + 1) * 64; | ||
1014 | rate_actual = clk_round_rate(clk, rate_ideal); | ||
1015 | |||
1016 | arate = rate_actual / 64; | ||
1017 | arate /= div; | ||
1018 | |||
1019 | if (arate == rate[index]) { | ||
1020 | /* We are lucky */ | ||
1021 | savesub = 0; | ||
1022 | spdif_priv->txclk_div[index] = div; | ||
1023 | break; | ||
1024 | } else if (arate / rate[index] == 1) { | ||
1025 | /* A little bigger than expect */ | ||
1026 | sub = (arate - rate[index]) * 100000; | ||
1027 | do_div(sub, rate[index]); | ||
1028 | if (sub < savesub) { | ||
1029 | savesub = sub; | ||
1030 | spdif_priv->txclk_div[index] = div; | ||
1031 | } | ||
1032 | } else if (rate[index] / arate == 1) { | ||
1033 | /* A little smaller than expect */ | ||
1034 | sub = (rate[index] - arate) * 100000; | ||
1035 | do_div(sub, rate[index]); | ||
1036 | if (sub < savesub) { | ||
1037 | savesub = sub; | ||
1038 | spdif_priv->txclk_div[index] = div; | ||
1039 | } | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | return savesub; | ||
1044 | } | ||
1045 | |||
1046 | static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, | ||
1047 | enum spdif_txrate index) | ||
1048 | { | ||
1049 | const u32 rate[] = { 32000, 44100, 48000 }; | ||
1050 | struct platform_device *pdev = spdif_priv->pdev; | ||
1051 | struct device *dev = &pdev->dev; | ||
1052 | u64 savesub = 100000, ret; | ||
1053 | struct clk *clk; | ||
1054 | char tmp[16]; | ||
1055 | int i; | ||
1056 | |||
1057 | for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { | ||
1058 | sprintf(tmp, "rxtx%d", i); | ||
1059 | clk = devm_clk_get(&pdev->dev, tmp); | ||
1060 | if (IS_ERR(clk)) { | ||
1061 | dev_err(dev, "no rxtx%d clock in devicetree\n", i); | ||
1062 | return PTR_ERR(clk); | ||
1063 | } | ||
1064 | if (!clk_get_rate(clk)) | ||
1065 | continue; | ||
1066 | |||
1067 | ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index); | ||
1068 | if (savesub == ret) | ||
1069 | continue; | ||
1070 | |||
1071 | savesub = ret; | ||
1072 | spdif_priv->txclk[index] = clk; | ||
1073 | spdif_priv->txclk_src[index] = i; | ||
1074 | |||
1075 | /* To quick catch a divisor, we allow a 0.1% deviation */ | ||
1076 | if (savesub < 100) | ||
1077 | break; | ||
1078 | } | ||
1079 | |||
1080 | dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate", | ||
1081 | spdif_priv->txclk_src[index], rate[index]); | ||
1082 | dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate", | ||
1083 | spdif_priv->txclk_div[index], rate[index]); | ||
1084 | |||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | static int fsl_spdif_probe(struct platform_device *pdev) | ||
1089 | { | ||
1090 | struct device_node *np = pdev->dev.of_node; | ||
1091 | struct fsl_spdif_priv *spdif_priv; | ||
1092 | struct spdif_mixer_control *ctrl; | ||
1093 | struct resource *res; | ||
1094 | void __iomem *regs; | ||
1095 | int irq, ret, i; | ||
1096 | |||
1097 | if (!np) | ||
1098 | return -ENODEV; | ||
1099 | |||
1100 | spdif_priv = devm_kzalloc(&pdev->dev, | ||
1101 | sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1, | ||
1102 | GFP_KERNEL); | ||
1103 | if (!spdif_priv) | ||
1104 | return -ENOMEM; | ||
1105 | |||
1106 | strcpy(spdif_priv->name, np->name); | ||
1107 | |||
1108 | spdif_priv->pdev = pdev; | ||
1109 | |||
1110 | /* Initialize this copy of the CPU DAI driver structure */ | ||
1111 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); | ||
1112 | spdif_priv->cpu_dai_drv.name = spdif_priv->name; | ||
1113 | |||
1114 | /* Get the addresses and IRQ */ | ||
1115 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1116 | if (IS_ERR(res)) { | ||
1117 | dev_err(&pdev->dev, "could not determine device resources\n"); | ||
1118 | return PTR_ERR(res); | ||
1119 | } | ||
1120 | |||
1121 | regs = devm_ioremap_resource(&pdev->dev, res); | ||
1122 | if (IS_ERR(regs)) { | ||
1123 | dev_err(&pdev->dev, "could not map device resources\n"); | ||
1124 | return PTR_ERR(regs); | ||
1125 | } | ||
1126 | |||
1127 | spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, | ||
1128 | "core", regs, &fsl_spdif_regmap_config); | ||
1129 | if (IS_ERR(spdif_priv->regmap)) { | ||
1130 | dev_err(&pdev->dev, "regmap init failed\n"); | ||
1131 | return PTR_ERR(spdif_priv->regmap); | ||
1132 | } | ||
1133 | |||
1134 | irq = platform_get_irq(pdev, 0); | ||
1135 | if (irq < 0) { | ||
1136 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); | ||
1137 | return irq; | ||
1138 | } | ||
1139 | |||
1140 | ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, | ||
1141 | spdif_priv->name, spdif_priv); | ||
1142 | if (ret) { | ||
1143 | dev_err(&pdev->dev, "could not claim irq %u\n", irq); | ||
1144 | return ret; | ||
1145 | } | ||
1146 | |||
1147 | /* Select clock source for rx/tx clock */ | ||
1148 | spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1"); | ||
1149 | if (IS_ERR(spdif_priv->rxclk)) { | ||
1150 | dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n"); | ||
1151 | return PTR_ERR(spdif_priv->rxclk); | ||
1152 | } | ||
1153 | spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC; | ||
1154 | |||
1155 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) { | ||
1156 | ret = fsl_spdif_probe_txclk(spdif_priv, i); | ||
1157 | if (ret) | ||
1158 | return ret; | ||
1159 | } | ||
1160 | |||
1161 | /* Initial spinlock for control data */ | ||
1162 | ctrl = &spdif_priv->fsl_spdif_control; | ||
1163 | spin_lock_init(&ctrl->ctl_lock); | ||
1164 | |||
1165 | /* Init tx channel status default value */ | ||
1166 | ctrl->ch_status[0] = | ||
1167 | IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_5015; | ||
1168 | ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID; | ||
1169 | ctrl->ch_status[2] = 0x00; | ||
1170 | ctrl->ch_status[3] = | ||
1171 | IEC958_AES3_CON_FS_44100 | IEC958_AES3_CON_CLOCK_1000PPM; | ||
1172 | |||
1173 | spdif_priv->dpll_locked = false; | ||
1174 | |||
1175 | spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML; | ||
1176 | spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML; | ||
1177 | spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL; | ||
1178 | spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL; | ||
1179 | |||
1180 | /* Register with ASoC */ | ||
1181 | dev_set_drvdata(&pdev->dev, spdif_priv); | ||
1182 | |||
1183 | ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component, | ||
1184 | &spdif_priv->cpu_dai_drv, 1); | ||
1185 | if (ret) { | ||
1186 | dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); | ||
1187 | goto error_dev; | ||
1188 | } | ||
1189 | |||
1190 | ret = imx_pcm_dma_init(pdev); | ||
1191 | if (ret) { | ||
1192 | dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); | ||
1193 | goto error_component; | ||
1194 | } | ||
1195 | |||
1196 | return ret; | ||
1197 | |||
1198 | error_component: | ||
1199 | snd_soc_unregister_component(&pdev->dev); | ||
1200 | error_dev: | ||
1201 | dev_set_drvdata(&pdev->dev, NULL); | ||
1202 | |||
1203 | return ret; | ||
1204 | } | ||
1205 | |||
1206 | static int fsl_spdif_remove(struct platform_device *pdev) | ||
1207 | { | ||
1208 | imx_pcm_dma_exit(pdev); | ||
1209 | snd_soc_unregister_component(&pdev->dev); | ||
1210 | dev_set_drvdata(&pdev->dev, NULL); | ||
1211 | |||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | static const struct of_device_id fsl_spdif_dt_ids[] = { | ||
1216 | { .compatible = "fsl,imx35-spdif", }, | ||
1217 | {} | ||
1218 | }; | ||
1219 | MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); | ||
1220 | |||
1221 | static struct platform_driver fsl_spdif_driver = { | ||
1222 | .driver = { | ||
1223 | .name = "fsl-spdif-dai", | ||
1224 | .owner = THIS_MODULE, | ||
1225 | .of_match_table = fsl_spdif_dt_ids, | ||
1226 | }, | ||
1227 | .probe = fsl_spdif_probe, | ||
1228 | .remove = fsl_spdif_remove, | ||
1229 | }; | ||
1230 | |||
1231 | module_platform_driver(fsl_spdif_driver); | ||
1232 | |||
1233 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
1234 | MODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver"); | ||
1235 | MODULE_LICENSE("GPL v2"); | ||
1236 | MODULE_ALIAS("platform:fsl-spdif-dai"); | ||
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h new file mode 100644 index 000000000000..b1266790d117 --- /dev/null +++ b/sound/soc/fsl/fsl_spdif.h | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * fsl_spdif.h - ALSA S/PDIF interface for the Freescale i.MX SoC | ||
3 | * | ||
4 | * Copyright (C) 2013 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Author: Nicolin Chen <b42378@freescale.com> | ||
7 | * | ||
8 | * Based on fsl_ssi.h | ||
9 | * Author: Timur Tabi <timur@freescale.com> | ||
10 | * Copyright 2007-2008 Freescale Semiconductor, Inc. | ||
11 | * | ||
12 | * This file is licensed under the terms of the GNU General Public License | ||
13 | * version 2. This program is licensed "as is" without any warranty of any | ||
14 | * kind, whether express or implied. | ||
15 | */ | ||
16 | |||
17 | #ifndef _FSL_SPDIF_DAI_H | ||
18 | #define _FSL_SPDIF_DAI_H | ||
19 | |||
20 | /* S/PDIF Register Map */ | ||
21 | #define REG_SPDIF_SCR 0x0 /* SPDIF Configuration Register */ | ||
22 | #define REG_SPDIF_SRCD 0x4 /* CDText Control Register */ | ||
23 | #define REG_SPDIF_SRPC 0x8 /* PhaseConfig Register */ | ||
24 | #define REG_SPDIF_SIE 0xc /* InterruptEn Register */ | ||
25 | #define REG_SPDIF_SIS 0x10 /* InterruptStat Register */ | ||
26 | #define REG_SPDIF_SIC 0x10 /* InterruptClear Register */ | ||
27 | #define REG_SPDIF_SRL 0x14 /* SPDIFRxLeft Register */ | ||
28 | #define REG_SPDIF_SRR 0x18 /* SPDIFRxRight Register */ | ||
29 | #define REG_SPDIF_SRCSH 0x1c /* SPDIFRxCChannel_h Register */ | ||
30 | #define REG_SPDIF_SRCSL 0x20 /* SPDIFRxCChannel_l Register */ | ||
31 | #define REG_SPDIF_SRU 0x24 /* UchannelRx Register */ | ||
32 | #define REG_SPDIF_SRQ 0x28 /* QchannelRx Register */ | ||
33 | #define REG_SPDIF_STL 0x2C /* SPDIFTxLeft Register */ | ||
34 | #define REG_SPDIF_STR 0x30 /* SPDIFTxRight Register */ | ||
35 | #define REG_SPDIF_STCSCH 0x34 /* SPDIFTxCChannelCons_h Register */ | ||
36 | #define REG_SPDIF_STCSCL 0x38 /* SPDIFTxCChannelCons_l Register */ | ||
37 | #define REG_SPDIF_SRFM 0x44 /* FreqMeas Register */ | ||
38 | #define REG_SPDIF_STC 0x50 /* SPDIFTxClk Register */ | ||
39 | |||
40 | |||
41 | /* SPDIF Configuration register */ | ||
42 | #define SCR_RXFIFO_CTL_OFFSET 23 | ||
43 | #define SCR_RXFIFO_CTL_MASK (1 << SCR_RXFIFO_CTL_OFFSET) | ||
44 | #define SCR_RXFIFO_CTL_ZERO (1 << SCR_RXFIFO_CTL_OFFSET) | ||
45 | #define SCR_RXFIFO_OFF_OFFSET 22 | ||
46 | #define SCR_RXFIFO_OFF_MASK (1 << SCR_RXFIFO_OFF_OFFSET) | ||
47 | #define SCR_RXFIFO_OFF (1 << SCR_RXFIFO_OFF_OFFSET) | ||
48 | #define SCR_RXFIFO_RST_OFFSET 21 | ||
49 | #define SCR_RXFIFO_RST_MASK (1 << SCR_RXFIFO_RST_OFFSET) | ||
50 | #define SCR_RXFIFO_RST (1 << SCR_RXFIFO_RST_OFFSET) | ||
51 | #define SCR_RXFIFO_FSEL_OFFSET 19 | ||
52 | #define SCR_RXFIFO_FSEL_MASK (0x3 << SCR_RXFIFO_FSEL_OFFSET) | ||
53 | #define SCR_RXFIFO_FSEL_IF0 (0x0 << SCR_RXFIFO_FSEL_OFFSET) | ||
54 | #define SCR_RXFIFO_FSEL_IF4 (0x1 << SCR_RXFIFO_FSEL_OFFSET) | ||
55 | #define SCR_RXFIFO_FSEL_IF8 (0x2 << SCR_RXFIFO_FSEL_OFFSET) | ||
56 | #define SCR_RXFIFO_FSEL_IF12 (0x3 << SCR_RXFIFO_FSEL_OFFSET) | ||
57 | #define SCR_RXFIFO_AUTOSYNC_OFFSET 18 | ||
58 | #define SCR_RXFIFO_AUTOSYNC_MASK (1 << SCR_RXFIFO_AUTOSYNC_OFFSET) | ||
59 | #define SCR_RXFIFO_AUTOSYNC (1 << SCR_RXFIFO_AUTOSYNC_OFFSET) | ||
60 | #define SCR_TXFIFO_AUTOSYNC_OFFSET 17 | ||
61 | #define SCR_TXFIFO_AUTOSYNC_MASK (1 << SCR_TXFIFO_AUTOSYNC_OFFSET) | ||
62 | #define SCR_TXFIFO_AUTOSYNC (1 << SCR_TXFIFO_AUTOSYNC_OFFSET) | ||
63 | #define SCR_TXFIFO_FSEL_OFFSET 15 | ||
64 | #define SCR_TXFIFO_FSEL_MASK (0x3 << SCR_TXFIFO_FSEL_OFFSET) | ||
65 | #define SCR_TXFIFO_FSEL_IF0 (0x0 << SCR_TXFIFO_FSEL_OFFSET) | ||
66 | #define SCR_TXFIFO_FSEL_IF4 (0x1 << SCR_TXFIFO_FSEL_OFFSET) | ||
67 | #define SCR_TXFIFO_FSEL_IF8 (0x2 << SCR_TXFIFO_FSEL_OFFSET) | ||
68 | #define SCR_TXFIFO_FSEL_IF12 (0x3 << SCR_TXFIFO_FSEL_OFFSET) | ||
69 | #define SCR_LOW_POWER (1 << 13) | ||
70 | #define SCR_SOFT_RESET (1 << 12) | ||
71 | #define SCR_TXFIFO_CTRL_OFFSET 10 | ||
72 | #define SCR_TXFIFO_CTRL_MASK (0x3 << SCR_TXFIFO_CTRL_OFFSET) | ||
73 | #define SCR_TXFIFO_CTRL_ZERO (0x0 << SCR_TXFIFO_CTRL_OFFSET) | ||
74 | #define SCR_TXFIFO_CTRL_NORMAL (0x1 << SCR_TXFIFO_CTRL_OFFSET) | ||
75 | #define SCR_TXFIFO_CTRL_ONESAMPLE (0x2 << SCR_TXFIFO_CTRL_OFFSET) | ||
76 | #define SCR_DMA_RX_EN_OFFSET 9 | ||
77 | #define SCR_DMA_RX_EN_MASK (1 << SCR_DMA_RX_EN_OFFSET) | ||
78 | #define SCR_DMA_RX_EN (1 << SCR_DMA_RX_EN_OFFSET) | ||
79 | #define SCR_DMA_TX_EN_OFFSET 8 | ||
80 | #define SCR_DMA_TX_EN_MASK (1 << SCR_DMA_TX_EN_OFFSET) | ||
81 | #define SCR_DMA_TX_EN (1 << SCR_DMA_TX_EN_OFFSET) | ||
82 | #define SCR_VAL_OFFSET 5 | ||
83 | #define SCR_VAL_MASK (1 << SCR_VAL_OFFSET) | ||
84 | #define SCR_VAL_CLEAR (1 << SCR_VAL_OFFSET) | ||
85 | #define SCR_TXSEL_OFFSET 2 | ||
86 | #define SCR_TXSEL_MASK (0x7 << SCR_TXSEL_OFFSET) | ||
87 | #define SCR_TXSEL_OFF (0 << SCR_TXSEL_OFFSET) | ||
88 | #define SCR_TXSEL_RX (1 << SCR_TXSEL_OFFSET) | ||
89 | #define SCR_TXSEL_NORMAL (0x5 << SCR_TXSEL_OFFSET) | ||
90 | #define SCR_USRC_SEL_OFFSET 0x0 | ||
91 | #define SCR_USRC_SEL_MASK (0x3 << SCR_USRC_SEL_OFFSET) | ||
92 | #define SCR_USRC_SEL_NONE (0x0 << SCR_USRC_SEL_OFFSET) | ||
93 | #define SCR_USRC_SEL_RECV (0x1 << SCR_USRC_SEL_OFFSET) | ||
94 | #define SCR_USRC_SEL_CHIP (0x3 << SCR_USRC_SEL_OFFSET) | ||
95 | |||
96 | /* SPDIF CDText control */ | ||
97 | #define SRCD_CD_USER_OFFSET 1 | ||
98 | #define SRCD_CD_USER (1 << SRCD_CD_USER_OFFSET) | ||
99 | |||
100 | /* SPDIF Phase Configuration register */ | ||
101 | #define SRPC_DPLL_LOCKED (1 << 6) | ||
102 | #define SRPC_CLKSRC_SEL_OFFSET 7 | ||
103 | #define SRPC_CLKSRC_SEL_MASK (0xf << SRPC_CLKSRC_SEL_OFFSET) | ||
104 | #define SRPC_CLKSRC_SEL_SET(x) ((x << SRPC_CLKSRC_SEL_OFFSET) & SRPC_CLKSRC_SEL_MASK) | ||
105 | #define SRPC_CLKSRC_SEL_LOCKED_OFFSET1 5 | ||
106 | #define SRPC_CLKSRC_SEL_LOCKED_OFFSET2 2 | ||
107 | #define SRPC_GAINSEL_OFFSET 3 | ||
108 | #define SRPC_GAINSEL_MASK (0x7 << SRPC_GAINSEL_OFFSET) | ||
109 | #define SRPC_GAINSEL_SET(x) ((x << SRPC_GAINSEL_OFFSET) & SRPC_GAINSEL_MASK) | ||
110 | |||
111 | #define SRPC_CLKSRC_MAX 16 | ||
112 | |||
113 | enum spdif_gainsel { | ||
114 | GAINSEL_MULTI_24 = 0, | ||
115 | GAINSEL_MULTI_16, | ||
116 | GAINSEL_MULTI_12, | ||
117 | GAINSEL_MULTI_8, | ||
118 | GAINSEL_MULTI_6, | ||
119 | GAINSEL_MULTI_4, | ||
120 | GAINSEL_MULTI_3, | ||
121 | }; | ||
122 | #define GAINSEL_MULTI_MAX (GAINSEL_MULTI_3 + 1) | ||
123 | #define SPDIF_DEFAULT_GAINSEL GAINSEL_MULTI_8 | ||
124 | |||
125 | /* SPDIF interrupt mask define */ | ||
126 | #define INT_DPLL_LOCKED (1 << 20) | ||
127 | #define INT_TXFIFO_UNOV (1 << 19) | ||
128 | #define INT_TXFIFO_RESYNC (1 << 18) | ||
129 | #define INT_CNEW (1 << 17) | ||
130 | #define INT_VAL_NOGOOD (1 << 16) | ||
131 | #define INT_SYM_ERR (1 << 15) | ||
132 | #define INT_BIT_ERR (1 << 14) | ||
133 | #define INT_URX_FUL (1 << 10) | ||
134 | #define INT_URX_OV (1 << 9) | ||
135 | #define INT_QRX_FUL (1 << 8) | ||
136 | #define INT_QRX_OV (1 << 7) | ||
137 | #define INT_UQ_SYNC (1 << 6) | ||
138 | #define INT_UQ_ERR (1 << 5) | ||
139 | #define INT_RXFIFO_UNOV (1 << 4) | ||
140 | #define INT_RXFIFO_RESYNC (1 << 3) | ||
141 | #define INT_LOSS_LOCK (1 << 2) | ||
142 | #define INT_TX_EM (1 << 1) | ||
143 | #define INT_RXFIFO_FUL (1 << 0) | ||
144 | |||
145 | /* SPDIF Clock register */ | ||
146 | #define STC_SYSCLK_DIV_OFFSET 11 | ||
147 | #define STC_SYSCLK_DIV_MASK (0x1ff << STC_TXCLK_SRC_OFFSET) | ||
148 | #define STC_SYSCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK) | ||
149 | #define STC_TXCLK_SRC_OFFSET 8 | ||
150 | #define STC_TXCLK_SRC_MASK (0x7 << STC_TXCLK_SRC_OFFSET) | ||
151 | #define STC_TXCLK_SRC_SET(x) ((x << STC_TXCLK_SRC_OFFSET) & STC_TXCLK_SRC_MASK) | ||
152 | #define STC_TXCLK_ALL_EN_OFFSET 7 | ||
153 | #define STC_TXCLK_ALL_EN_MASK (1 << STC_TXCLK_ALL_EN_OFFSET) | ||
154 | #define STC_TXCLK_ALL_EN (1 << STC_TXCLK_ALL_EN_OFFSET) | ||
155 | #define STC_TXCLK_DIV_OFFSET 0 | ||
156 | #define STC_TXCLK_DIV_MASK (0x7ff << STC_TXCLK_DIV_OFFSET) | ||
157 | #define STC_TXCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_TXCLK_DIV_MASK) | ||
158 | #define STC_TXCLK_SRC_MAX 8 | ||
159 | |||
160 | /* SPDIF tx rate */ | ||
161 | enum spdif_txrate { | ||
162 | SPDIF_TXRATE_32000 = 0, | ||
163 | SPDIF_TXRATE_44100, | ||
164 | SPDIF_TXRATE_48000, | ||
165 | }; | ||
166 | #define SPDIF_TXRATE_MAX (SPDIF_TXRATE_48000 + 1) | ||
167 | |||
168 | |||
169 | #define SPDIF_CSTATUS_BYTE 6 | ||
170 | #define SPDIF_UBITS_SIZE 96 | ||
171 | #define SPDIF_QSUB_SIZE (SPDIF_UBITS_SIZE / 8) | ||
172 | |||
173 | |||
174 | #define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \ | ||
175 | SNDRV_PCM_RATE_44100 | \ | ||
176 | SNDRV_PCM_RATE_48000) | ||
177 | |||
178 | #define FSL_SPDIF_RATES_CAPTURE (SNDRV_PCM_RATE_16000 | \ | ||
179 | SNDRV_PCM_RATE_32000 | \ | ||
180 | SNDRV_PCM_RATE_44100 | \ | ||
181 | SNDRV_PCM_RATE_48000 | \ | ||
182 | SNDRV_PCM_RATE_64000 | \ | ||
183 | SNDRV_PCM_RATE_96000) | ||
184 | |||
185 | #define FSL_SPDIF_FORMATS_PLAYBACK (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
186 | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
187 | SNDRV_PCM_FMTBIT_S24_LE) | ||
188 | |||
189 | #define FSL_SPDIF_FORMATS_CAPTURE (SNDRV_PCM_FMTBIT_S24_LE) | ||
190 | |||
191 | #endif /* _FSL_SPDIF_DAI_H */ | ||
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 2f2d837df07f..5cf626c4dc96 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -8,6 +8,26 @@ | |||
8 | * This file is licensed under the terms of the GNU General Public License | 8 | * This file is licensed under the terms of the GNU General Public License |
9 | * version 2. This program is licensed "as is" without any warranty of any | 9 | * version 2. This program is licensed "as is" without any warranty of any |
10 | * kind, whether express or implied. | 10 | * kind, whether express or implied. |
11 | * | ||
12 | * | ||
13 | * Some notes why imx-pcm-fiq is used instead of DMA on some boards: | ||
14 | * | ||
15 | * The i.MX SSI core has some nasty limitations in AC97 mode. While most | ||
16 | * sane processor vendors have a FIFO per AC97 slot, the i.MX has only | ||
17 | * one FIFO which combines all valid receive slots. We cannot even select | ||
18 | * which slots we want to receive. The WM9712 with which this driver | ||
19 | * was developed with always sends GPIO status data in slot 12 which | ||
20 | * we receive in our (PCM-) data stream. The only chance we have is to | ||
21 | * manually skip this data in the FIQ handler. With sampling rates different | ||
22 | * from 48000Hz not every frame has valid receive data, so the ratio | ||
23 | * between pcm data and GPIO status data changes. Our FIQ handler is not | ||
24 | * able to handle this, hence this driver only works with 48000Hz sampling | ||
25 | * rate. | ||
26 | * Reading and writing AC97 registers is another challenge. The core | ||
27 | * provides us status bits when the read register is updated with *another* | ||
28 | * value. When we read the same register two times (and the register still | ||
29 | * contains the same value) these status bits are not set. We work | ||
30 | * around this by not polling these bits but only wait a fixed delay. | ||
11 | */ | 31 | */ |
12 | 32 | ||
13 | #include <linux/init.h> | 33 | #include <linux/init.h> |
@@ -36,7 +56,7 @@ | |||
36 | #define read_ssi(addr) in_be32(addr) | 56 | #define read_ssi(addr) in_be32(addr) |
37 | #define write_ssi(val, addr) out_be32(addr, val) | 57 | #define write_ssi(val, addr) out_be32(addr, val) |
38 | #define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set) | 58 | #define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set) |
39 | #elif defined ARM | 59 | #else |
40 | #define read_ssi(addr) readl(addr) | 60 | #define read_ssi(addr) readl(addr) |
41 | #define write_ssi(val, addr) writel(val, addr) | 61 | #define write_ssi(val, addr) writel(val, addr) |
42 | /* | 62 | /* |
@@ -121,11 +141,14 @@ struct fsl_ssi_private { | |||
121 | 141 | ||
122 | bool new_binding; | 142 | bool new_binding; |
123 | bool ssi_on_imx; | 143 | bool ssi_on_imx; |
144 | bool imx_ac97; | ||
145 | bool use_dma; | ||
124 | struct clk *clk; | 146 | struct clk *clk; |
125 | struct snd_dmaengine_dai_dma_data dma_params_tx; | 147 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
126 | struct snd_dmaengine_dai_dma_data dma_params_rx; | 148 | struct snd_dmaengine_dai_dma_data dma_params_rx; |
127 | struct imx_dma_data filter_data_tx; | 149 | struct imx_dma_data filter_data_tx; |
128 | struct imx_dma_data filter_data_rx; | 150 | struct imx_dma_data filter_data_rx; |
151 | struct imx_pcm_fiq_params fiq_params; | ||
129 | 152 | ||
130 | struct { | 153 | struct { |
131 | unsigned int rfrc; | 154 | unsigned int rfrc; |
@@ -298,6 +321,102 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) | |||
298 | return ret; | 321 | return ret; |
299 | } | 322 | } |
300 | 323 | ||
324 | static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) | ||
325 | { | ||
326 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
327 | u8 i2s_mode; | ||
328 | u8 wm; | ||
329 | int synchronous = ssi_private->cpu_dai_drv.symmetric_rates; | ||
330 | |||
331 | if (ssi_private->imx_ac97) | ||
332 | i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET; | ||
333 | else | ||
334 | i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE; | ||
335 | |||
336 | /* | ||
337 | * Section 16.5 of the MPC8610 reference manual says that the SSI needs | ||
338 | * to be disabled before updating the registers we set here. | ||
339 | */ | ||
340 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); | ||
341 | |||
342 | /* | ||
343 | * Program the SSI into I2S Slave Non-Network Synchronous mode. Also | ||
344 | * enable the transmit and receive FIFO. | ||
345 | * | ||
346 | * FIXME: Little-endian samples require a different shift dir | ||
347 | */ | ||
348 | write_ssi_mask(&ssi->scr, | ||
349 | CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, | ||
350 | CCSR_SSI_SCR_TFR_CLK_DIS | | ||
351 | i2s_mode | | ||
352 | (synchronous ? CCSR_SSI_SCR_SYN : 0)); | ||
353 | |||
354 | write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | | ||
355 | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS | | ||
356 | CCSR_SSI_STCR_TSCKP, &ssi->stcr); | ||
357 | |||
358 | write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 | | ||
359 | CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS | | ||
360 | CCSR_SSI_SRCR_RSCKP, &ssi->srcr); | ||
361 | /* | ||
362 | * The DC and PM bits are only used if the SSI is the clock master. | ||
363 | */ | ||
364 | |||
365 | /* | ||
366 | * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't | ||
367 | * use FIFO 1. We program the transmit water to signal a DMA transfer | ||
368 | * if there are only two (or fewer) elements left in the FIFO. Two | ||
369 | * elements equals one frame (left channel, right channel). This value, | ||
370 | * however, depends on the depth of the transmit buffer. | ||
371 | * | ||
372 | * We set the watermark on the same level as the DMA burstsize. For | ||
373 | * fiq it is probably better to use the biggest possible watermark | ||
374 | * size. | ||
375 | */ | ||
376 | if (ssi_private->use_dma) | ||
377 | wm = ssi_private->fifo_depth - 2; | ||
378 | else | ||
379 | wm = ssi_private->fifo_depth; | ||
380 | |||
381 | write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) | | ||
382 | CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm), | ||
383 | &ssi->sfcsr); | ||
384 | |||
385 | /* | ||
386 | * For ac97 interrupts are enabled with the startup of the substream | ||
387 | * because it is also running without an active substream. Normally SSI | ||
388 | * is only enabled when there is a substream. | ||
389 | */ | ||
390 | if (ssi_private->imx_ac97) { | ||
391 | /* | ||
392 | * Setup the clock control register | ||
393 | */ | ||
394 | write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13), | ||
395 | &ssi->stccr); | ||
396 | write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13), | ||
397 | &ssi->srccr); | ||
398 | |||
399 | /* | ||
400 | * Enable AC97 mode and startup the SSI | ||
401 | */ | ||
402 | write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV, | ||
403 | &ssi->sacnt); | ||
404 | write_ssi(0xff, &ssi->saccdis); | ||
405 | write_ssi(0x300, &ssi->saccen); | ||
406 | |||
407 | /* | ||
408 | * Enable SSI, Transmit and Receive | ||
409 | */ | ||
410 | write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN | | ||
411 | CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE); | ||
412 | |||
413 | write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor); | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | |||
301 | /** | 420 | /** |
302 | * fsl_ssi_startup: create a new substream | 421 | * fsl_ssi_startup: create a new substream |
303 | * | 422 | * |
@@ -319,70 +438,14 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
319 | * and initialize the SSI registers. | 438 | * and initialize the SSI registers. |
320 | */ | 439 | */ |
321 | if (!ssi_private->first_stream) { | 440 | if (!ssi_private->first_stream) { |
322 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
323 | |||
324 | ssi_private->first_stream = substream; | 441 | ssi_private->first_stream = substream; |
325 | 442 | ||
326 | /* | 443 | /* |
327 | * Section 16.5 of the MPC8610 reference manual says that the | 444 | * fsl_ssi_setup was already called by ac97_init earlier if |
328 | * SSI needs to be disabled before updating the registers we set | 445 | * the driver is in ac97 mode. |
329 | * here. | ||
330 | */ | ||
331 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); | ||
332 | |||
333 | /* | ||
334 | * Program the SSI into I2S Slave Non-Network Synchronous mode. | ||
335 | * Also enable the transmit and receive FIFO. | ||
336 | * | ||
337 | * FIXME: Little-endian samples require a different shift dir | ||
338 | */ | ||
339 | write_ssi_mask(&ssi->scr, | ||
340 | CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, | ||
341 | CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE | ||
342 | | (synchronous ? CCSR_SSI_SCR_SYN : 0)); | ||
343 | |||
344 | write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | | ||
345 | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS | | ||
346 | CCSR_SSI_STCR_TSCKP, &ssi->stcr); | ||
347 | |||
348 | write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 | | ||
349 | CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS | | ||
350 | CCSR_SSI_SRCR_RSCKP, &ssi->srcr); | ||
351 | |||
352 | /* | ||
353 | * The DC and PM bits are only used if the SSI is the clock | ||
354 | * master. | ||
355 | */ | ||
356 | |||
357 | /* Enable the interrupts and DMA requests */ | ||
358 | write_ssi(SIER_FLAGS, &ssi->sier); | ||
359 | |||
360 | /* | ||
361 | * Set the watermark for transmit FIFI 0 and receive FIFO 0. We | ||
362 | * don't use FIFO 1. We program the transmit water to signal a | ||
363 | * DMA transfer if there are only two (or fewer) elements left | ||
364 | * in the FIFO. Two elements equals one frame (left channel, | ||
365 | * right channel). This value, however, depends on the depth of | ||
366 | * the transmit buffer. | ||
367 | * | ||
368 | * We program the receive FIFO to notify us if at least two | ||
369 | * elements (one frame) have been written to the FIFO. We could | ||
370 | * make this value larger (and maybe we should), but this way | ||
371 | * data will be written to memory as soon as it's available. | ||
372 | */ | ||
373 | write_ssi(CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) | | ||
374 | CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2), | ||
375 | &ssi->sfcsr); | ||
376 | |||
377 | /* | ||
378 | * We keep the SSI disabled because if we enable it, then the | ||
379 | * DMA controller will start. It's not supposed to start until | ||
380 | * the SCR.TE (or SCR.RE) bit is set, but it does anyway. The | ||
381 | * DMA controller will transfer one "BWC" of data (i.e. the | ||
382 | * amount of data that the MR.BWC bits are set to). The reason | ||
383 | * this is bad is because at this point, the PCM driver has not | ||
384 | * finished initializing the DMA controller. | ||
385 | */ | 446 | */ |
447 | if (!ssi_private->imx_ac97) | ||
448 | fsl_ssi_setup(ssi_private); | ||
386 | } else { | 449 | } else { |
387 | if (synchronous) { | 450 | if (synchronous) { |
388 | struct snd_pcm_runtime *first_runtime = | 451 | struct snd_pcm_runtime *first_runtime = |
@@ -492,6 +555,27 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, | |||
492 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 555 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
493 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); | 556 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
494 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | 557 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
558 | unsigned int sier_bits; | ||
559 | |||
560 | /* | ||
561 | * Enable only the interrupts and DMA requests | ||
562 | * that are needed for the channel. As the fiq | ||
563 | * is polling for this bits, we have to ensure | ||
564 | * that this are aligned with the preallocated | ||
565 | * buffers | ||
566 | */ | ||
567 | |||
568 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
569 | if (ssi_private->use_dma) | ||
570 | sier_bits = SIER_FLAGS; | ||
571 | else | ||
572 | sier_bits = CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TFE0_EN; | ||
573 | } else { | ||
574 | if (ssi_private->use_dma) | ||
575 | sier_bits = SIER_FLAGS; | ||
576 | else | ||
577 | sier_bits = CCSR_SSI_SIER_RIE | CCSR_SSI_SIER_RFF0_EN; | ||
578 | } | ||
495 | 579 | ||
496 | switch (cmd) { | 580 | switch (cmd) { |
497 | case SNDRV_PCM_TRIGGER_START: | 581 | case SNDRV_PCM_TRIGGER_START: |
@@ -510,12 +594,18 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, | |||
510 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0); | 594 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0); |
511 | else | 595 | else |
512 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0); | 596 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0); |
597 | |||
598 | if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) & | ||
599 | (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) | ||
600 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); | ||
513 | break; | 601 | break; |
514 | 602 | ||
515 | default: | 603 | default: |
516 | return -EINVAL; | 604 | return -EINVAL; |
517 | } | 605 | } |
518 | 606 | ||
607 | write_ssi(sier_bits, &ssi->sier); | ||
608 | |||
519 | return 0; | 609 | return 0; |
520 | } | 610 | } |
521 | 611 | ||
@@ -534,22 +624,13 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, | |||
534 | ssi_private->first_stream = ssi_private->second_stream; | 624 | ssi_private->first_stream = ssi_private->second_stream; |
535 | 625 | ||
536 | ssi_private->second_stream = NULL; | 626 | ssi_private->second_stream = NULL; |
537 | |||
538 | /* | ||
539 | * If this is the last active substream, disable the SSI. | ||
540 | */ | ||
541 | if (!ssi_private->first_stream) { | ||
542 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
543 | |||
544 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); | ||
545 | } | ||
546 | } | 627 | } |
547 | 628 | ||
548 | static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) | 629 | static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) |
549 | { | 630 | { |
550 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai); | 631 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai); |
551 | 632 | ||
552 | if (ssi_private->ssi_on_imx) { | 633 | if (ssi_private->ssi_on_imx && ssi_private->use_dma) { |
553 | dai->playback_dma_data = &ssi_private->dma_params_tx; | 634 | dai->playback_dma_data = &ssi_private->dma_params_tx; |
554 | dai->capture_dma_data = &ssi_private->dma_params_rx; | 635 | dai->capture_dma_data = &ssi_private->dma_params_rx; |
555 | } | 636 | } |
@@ -587,6 +668,133 @@ static const struct snd_soc_component_driver fsl_ssi_component = { | |||
587 | .name = "fsl-ssi", | 668 | .name = "fsl-ssi", |
588 | }; | 669 | }; |
589 | 670 | ||
671 | /** | ||
672 | * fsl_ssi_ac97_trigger: start and stop the AC97 receive/transmit. | ||
673 | * | ||
674 | * This function is called by ALSA to start, stop, pause, and resume the | ||
675 | * transfer of data. | ||
676 | */ | ||
677 | static int fsl_ssi_ac97_trigger(struct snd_pcm_substream *substream, int cmd, | ||
678 | struct snd_soc_dai *dai) | ||
679 | { | ||
680 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
681 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata( | ||
682 | rtd->cpu_dai); | ||
683 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
684 | |||
685 | switch (cmd) { | ||
686 | case SNDRV_PCM_TRIGGER_START: | ||
687 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
688 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
689 | write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_TIE | | ||
690 | CCSR_SSI_SIER_TFE0_EN); | ||
691 | else | ||
692 | write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_RIE | | ||
693 | CCSR_SSI_SIER_RFF0_EN); | ||
694 | break; | ||
695 | |||
696 | case SNDRV_PCM_TRIGGER_STOP: | ||
697 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
698 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
699 | write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_TIE | | ||
700 | CCSR_SSI_SIER_TFE0_EN, 0); | ||
701 | else | ||
702 | write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_RIE | | ||
703 | CCSR_SSI_SIER_RFF0_EN, 0); | ||
704 | break; | ||
705 | |||
706 | default: | ||
707 | return -EINVAL; | ||
708 | } | ||
709 | |||
710 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
711 | write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor); | ||
712 | else | ||
713 | write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor); | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | static const struct snd_soc_dai_ops fsl_ssi_ac97_dai_ops = { | ||
719 | .startup = fsl_ssi_startup, | ||
720 | .shutdown = fsl_ssi_shutdown, | ||
721 | .trigger = fsl_ssi_ac97_trigger, | ||
722 | }; | ||
723 | |||
724 | static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { | ||
725 | .ac97_control = 1, | ||
726 | .playback = { | ||
727 | .stream_name = "AC97 Playback", | ||
728 | .channels_min = 2, | ||
729 | .channels_max = 2, | ||
730 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
731 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
732 | }, | ||
733 | .capture = { | ||
734 | .stream_name = "AC97 Capture", | ||
735 | .channels_min = 2, | ||
736 | .channels_max = 2, | ||
737 | .rates = SNDRV_PCM_RATE_48000, | ||
738 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
739 | }, | ||
740 | .ops = &fsl_ssi_ac97_dai_ops, | ||
741 | }; | ||
742 | |||
743 | |||
744 | static struct fsl_ssi_private *fsl_ac97_data; | ||
745 | |||
746 | static void fsl_ssi_ac97_init(void) | ||
747 | { | ||
748 | fsl_ssi_setup(fsl_ac97_data); | ||
749 | } | ||
750 | |||
751 | void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
752 | unsigned short val) | ||
753 | { | ||
754 | struct ccsr_ssi *ssi = fsl_ac97_data->ssi; | ||
755 | unsigned int lreg; | ||
756 | unsigned int lval; | ||
757 | |||
758 | if (reg > 0x7f) | ||
759 | return; | ||
760 | |||
761 | |||
762 | lreg = reg << 12; | ||
763 | write_ssi(lreg, &ssi->sacadd); | ||
764 | |||
765 | lval = val << 4; | ||
766 | write_ssi(lval , &ssi->sacdat); | ||
767 | |||
768 | write_ssi_mask(&ssi->sacnt, CCSR_SSI_SACNT_RDWR_MASK, | ||
769 | CCSR_SSI_SACNT_WR); | ||
770 | udelay(100); | ||
771 | } | ||
772 | |||
773 | unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, | ||
774 | unsigned short reg) | ||
775 | { | ||
776 | struct ccsr_ssi *ssi = fsl_ac97_data->ssi; | ||
777 | |||
778 | unsigned short val = -1; | ||
779 | unsigned int lreg; | ||
780 | |||
781 | lreg = (reg & 0x7f) << 12; | ||
782 | write_ssi(lreg, &ssi->sacadd); | ||
783 | write_ssi_mask(&ssi->sacnt, CCSR_SSI_SACNT_RDWR_MASK, | ||
784 | CCSR_SSI_SACNT_RD); | ||
785 | |||
786 | udelay(100); | ||
787 | |||
788 | val = (read_ssi(&ssi->sacdat) >> 4) & 0xffff; | ||
789 | |||
790 | return val; | ||
791 | } | ||
792 | |||
793 | static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = { | ||
794 | .read = fsl_ssi_ac97_read, | ||
795 | .write = fsl_ssi_ac97_write, | ||
796 | }; | ||
797 | |||
590 | /* Show the statistics of a flag only if its interrupt is enabled. The | 798 | /* Show the statistics of a flag only if its interrupt is enabled. The |
591 | * compiler will optimze this code to a no-op if the interrupt is not | 799 | * compiler will optimze this code to a no-op if the interrupt is not |
592 | * enabled. | 800 | * enabled. |
@@ -663,6 +871,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
663 | struct resource res; | 871 | struct resource res; |
664 | char name[64]; | 872 | char name[64]; |
665 | bool shared; | 873 | bool shared; |
874 | bool ac97 = false; | ||
666 | 875 | ||
667 | /* SSIs that are not connected on the board should have a | 876 | /* SSIs that are not connected on the board should have a |
668 | * status = "disabled" | 877 | * status = "disabled" |
@@ -673,14 +882,20 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
673 | 882 | ||
674 | /* We only support the SSI in "I2S Slave" mode */ | 883 | /* We only support the SSI in "I2S Slave" mode */ |
675 | sprop = of_get_property(np, "fsl,mode", NULL); | 884 | sprop = of_get_property(np, "fsl,mode", NULL); |
676 | if (!sprop || strcmp(sprop, "i2s-slave")) { | 885 | if (!sprop) { |
886 | dev_err(&pdev->dev, "fsl,mode property is necessary\n"); | ||
887 | return -EINVAL; | ||
888 | } | ||
889 | if (!strcmp(sprop, "ac97-slave")) { | ||
890 | ac97 = true; | ||
891 | } else if (strcmp(sprop, "i2s-slave")) { | ||
677 | dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop); | 892 | dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop); |
678 | return -ENODEV; | 893 | return -ENODEV; |
679 | } | 894 | } |
680 | 895 | ||
681 | /* The DAI name is the last part of the full name of the node. */ | 896 | /* The DAI name is the last part of the full name of the node. */ |
682 | p = strrchr(np->full_name, '/') + 1; | 897 | p = strrchr(np->full_name, '/') + 1; |
683 | ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p), | 898 | ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private) + strlen(p), |
684 | GFP_KERNEL); | 899 | GFP_KERNEL); |
685 | if (!ssi_private) { | 900 | if (!ssi_private) { |
686 | dev_err(&pdev->dev, "could not allocate DAI object\n"); | 901 | dev_err(&pdev->dev, "could not allocate DAI object\n"); |
@@ -689,38 +904,41 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
689 | 904 | ||
690 | strcpy(ssi_private->name, p); | 905 | strcpy(ssi_private->name, p); |
691 | 906 | ||
692 | /* Initialize this copy of the CPU DAI driver structure */ | 907 | ssi_private->use_dma = !of_property_read_bool(np, |
693 | memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template, | 908 | "fsl,fiq-stream-filter"); |
694 | sizeof(fsl_ssi_dai_template)); | 909 | |
910 | if (ac97) { | ||
911 | memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_ac97_dai, | ||
912 | sizeof(fsl_ssi_ac97_dai)); | ||
913 | |||
914 | fsl_ac97_data = ssi_private; | ||
915 | ssi_private->imx_ac97 = true; | ||
916 | |||
917 | snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev); | ||
918 | } else { | ||
919 | /* Initialize this copy of the CPU DAI driver structure */ | ||
920 | memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template, | ||
921 | sizeof(fsl_ssi_dai_template)); | ||
922 | } | ||
695 | ssi_private->cpu_dai_drv.name = ssi_private->name; | 923 | ssi_private->cpu_dai_drv.name = ssi_private->name; |
696 | 924 | ||
697 | /* Get the addresses and IRQ */ | 925 | /* Get the addresses and IRQ */ |
698 | ret = of_address_to_resource(np, 0, &res); | 926 | ret = of_address_to_resource(np, 0, &res); |
699 | if (ret) { | 927 | if (ret) { |
700 | dev_err(&pdev->dev, "could not determine device resources\n"); | 928 | dev_err(&pdev->dev, "could not determine device resources\n"); |
701 | goto error_kmalloc; | 929 | return ret; |
702 | } | 930 | } |
703 | ssi_private->ssi = of_iomap(np, 0); | 931 | ssi_private->ssi = of_iomap(np, 0); |
704 | if (!ssi_private->ssi) { | 932 | if (!ssi_private->ssi) { |
705 | dev_err(&pdev->dev, "could not map device resources\n"); | 933 | dev_err(&pdev->dev, "could not map device resources\n"); |
706 | ret = -ENOMEM; | 934 | return -ENOMEM; |
707 | goto error_kmalloc; | ||
708 | } | 935 | } |
709 | ssi_private->ssi_phys = res.start; | 936 | ssi_private->ssi_phys = res.start; |
710 | 937 | ||
711 | ssi_private->irq = irq_of_parse_and_map(np, 0); | 938 | ssi_private->irq = irq_of_parse_and_map(np, 0); |
712 | if (ssi_private->irq == NO_IRQ) { | 939 | if (ssi_private->irq == NO_IRQ) { |
713 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); | 940 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); |
714 | ret = -ENXIO; | 941 | return -ENXIO; |
715 | goto error_iomap; | ||
716 | } | ||
717 | |||
718 | /* The 'name' should not have any slashes in it. */ | ||
719 | ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, ssi_private->name, | ||
720 | ssi_private); | ||
721 | if (ret < 0) { | ||
722 | dev_err(&pdev->dev, "could not claim irq %u\n", ssi_private->irq); | ||
723 | goto error_irqmap; | ||
724 | } | 942 | } |
725 | 943 | ||
726 | /* Are the RX and the TX clocks locked? */ | 944 | /* Are the RX and the TX clocks locked? */ |
@@ -739,13 +957,18 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
739 | u32 dma_events[2]; | 957 | u32 dma_events[2]; |
740 | ssi_private->ssi_on_imx = true; | 958 | ssi_private->ssi_on_imx = true; |
741 | 959 | ||
742 | ssi_private->clk = clk_get(&pdev->dev, NULL); | 960 | ssi_private->clk = devm_clk_get(&pdev->dev, NULL); |
743 | if (IS_ERR(ssi_private->clk)) { | 961 | if (IS_ERR(ssi_private->clk)) { |
744 | ret = PTR_ERR(ssi_private->clk); | 962 | ret = PTR_ERR(ssi_private->clk); |
745 | dev_err(&pdev->dev, "could not get clock: %d\n", ret); | 963 | dev_err(&pdev->dev, "could not get clock: %d\n", ret); |
746 | goto error_irq; | 964 | goto error_irqmap; |
965 | } | ||
966 | ret = clk_prepare_enable(ssi_private->clk); | ||
967 | if (ret) { | ||
968 | dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", | ||
969 | ret); | ||
970 | goto error_irqmap; | ||
747 | } | 971 | } |
748 | clk_prepare_enable(ssi_private->clk); | ||
749 | 972 | ||
750 | /* | 973 | /* |
751 | * We have burstsize be "fifo_depth - 2" to match the SSI | 974 | * We have burstsize be "fifo_depth - 2" to match the SSI |
@@ -763,24 +986,38 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
763 | &ssi_private->filter_data_tx; | 986 | &ssi_private->filter_data_tx; |
764 | ssi_private->dma_params_rx.filter_data = | 987 | ssi_private->dma_params_rx.filter_data = |
765 | &ssi_private->filter_data_rx; | 988 | &ssi_private->filter_data_rx; |
766 | /* | 989 | if (!of_property_read_bool(pdev->dev.of_node, "dmas") && |
767 | * TODO: This is a temporary solution and should be changed | 990 | ssi_private->use_dma) { |
768 | * to use generic DMA binding later when the helplers get in. | 991 | /* |
769 | */ | 992 | * FIXME: This is a temporary solution until all |
770 | ret = of_property_read_u32_array(pdev->dev.of_node, | 993 | * necessary dma drivers support the generic dma |
994 | * bindings. | ||
995 | */ | ||
996 | ret = of_property_read_u32_array(pdev->dev.of_node, | ||
771 | "fsl,ssi-dma-events", dma_events, 2); | 997 | "fsl,ssi-dma-events", dma_events, 2); |
772 | if (ret) { | 998 | if (ret && ssi_private->use_dma) { |
773 | dev_err(&pdev->dev, "could not get dma events\n"); | 999 | dev_err(&pdev->dev, "could not get dma events but fsl-ssi is configured to use DMA\n"); |
774 | goto error_clk; | 1000 | goto error_clk; |
1001 | } | ||
775 | } | 1002 | } |
776 | 1003 | ||
777 | shared = of_device_is_compatible(of_get_parent(np), | 1004 | shared = of_device_is_compatible(of_get_parent(np), |
778 | "fsl,spba-bus"); | 1005 | "fsl,spba-bus"); |
779 | 1006 | ||
780 | imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx, | 1007 | imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx, |
781 | dma_events[0], shared); | 1008 | dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI); |
782 | imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx, | 1009 | imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx, |
783 | dma_events[1], shared); | 1010 | dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI); |
1011 | } else if (ssi_private->use_dma) { | ||
1012 | /* The 'name' should not have any slashes in it. */ | ||
1013 | ret = devm_request_irq(&pdev->dev, ssi_private->irq, | ||
1014 | fsl_ssi_isr, 0, ssi_private->name, | ||
1015 | ssi_private); | ||
1016 | if (ret < 0) { | ||
1017 | dev_err(&pdev->dev, "could not claim irq %u\n", | ||
1018 | ssi_private->irq); | ||
1019 | goto error_irqmap; | ||
1020 | } | ||
784 | } | 1021 | } |
785 | 1022 | ||
786 | /* Initialize the the device_attribute structure */ | 1023 | /* Initialize the the device_attribute structure */ |
@@ -794,7 +1031,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
794 | if (ret) { | 1031 | if (ret) { |
795 | dev_err(&pdev->dev, "could not create sysfs %s file\n", | 1032 | dev_err(&pdev->dev, "could not create sysfs %s file\n", |
796 | ssi_private->dev_attr.attr.name); | 1033 | ssi_private->dev_attr.attr.name); |
797 | goto error_irq; | 1034 | goto error_clk; |
798 | } | 1035 | } |
799 | 1036 | ||
800 | /* Register with ASoC */ | 1037 | /* Register with ASoC */ |
@@ -808,9 +1045,30 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
808 | } | 1045 | } |
809 | 1046 | ||
810 | if (ssi_private->ssi_on_imx) { | 1047 | if (ssi_private->ssi_on_imx) { |
811 | ret = imx_pcm_dma_init(pdev); | 1048 | if (!ssi_private->use_dma) { |
812 | if (ret) | 1049 | |
813 | goto error_dev; | 1050 | /* |
1051 | * Some boards use an incompatible codec. To get it | ||
1052 | * working, we are using imx-fiq-pcm-audio, that | ||
1053 | * can handle those codecs. DMA is not possible in this | ||
1054 | * situation. | ||
1055 | */ | ||
1056 | |||
1057 | ssi_private->fiq_params.irq = ssi_private->irq; | ||
1058 | ssi_private->fiq_params.base = ssi_private->ssi; | ||
1059 | ssi_private->fiq_params.dma_params_rx = | ||
1060 | &ssi_private->dma_params_rx; | ||
1061 | ssi_private->fiq_params.dma_params_tx = | ||
1062 | &ssi_private->dma_params_tx; | ||
1063 | |||
1064 | ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params); | ||
1065 | if (ret) | ||
1066 | goto error_dev; | ||
1067 | } else { | ||
1068 | ret = imx_pcm_dma_init(pdev); | ||
1069 | if (ret) | ||
1070 | goto error_dev; | ||
1071 | } | ||
814 | } | 1072 | } |
815 | 1073 | ||
816 | /* | 1074 | /* |
@@ -845,6 +1103,9 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
845 | } | 1103 | } |
846 | 1104 | ||
847 | done: | 1105 | done: |
1106 | if (ssi_private->imx_ac97) | ||
1107 | fsl_ssi_ac97_init(); | ||
1108 | |||
848 | return 0; | 1109 | return 0; |
849 | 1110 | ||
850 | error_dai: | 1111 | error_dai: |
@@ -857,23 +1118,12 @@ error_dev: | |||
857 | device_remove_file(&pdev->dev, dev_attr); | 1118 | device_remove_file(&pdev->dev, dev_attr); |
858 | 1119 | ||
859 | error_clk: | 1120 | error_clk: |
860 | if (ssi_private->ssi_on_imx) { | 1121 | if (ssi_private->ssi_on_imx) |
861 | clk_disable_unprepare(ssi_private->clk); | 1122 | clk_disable_unprepare(ssi_private->clk); |
862 | clk_put(ssi_private->clk); | ||
863 | } | ||
864 | |||
865 | error_irq: | ||
866 | free_irq(ssi_private->irq, ssi_private); | ||
867 | 1123 | ||
868 | error_irqmap: | 1124 | error_irqmap: |
869 | irq_dispose_mapping(ssi_private->irq); | 1125 | irq_dispose_mapping(ssi_private->irq); |
870 | 1126 | ||
871 | error_iomap: | ||
872 | iounmap(ssi_private->ssi); | ||
873 | |||
874 | error_kmalloc: | ||
875 | kfree(ssi_private); | ||
876 | |||
877 | return ret; | 1127 | return ret; |
878 | } | 1128 | } |
879 | 1129 | ||
@@ -883,20 +1133,15 @@ static int fsl_ssi_remove(struct platform_device *pdev) | |||
883 | 1133 | ||
884 | if (!ssi_private->new_binding) | 1134 | if (!ssi_private->new_binding) |
885 | platform_device_unregister(ssi_private->pdev); | 1135 | platform_device_unregister(ssi_private->pdev); |
886 | if (ssi_private->ssi_on_imx) { | 1136 | if (ssi_private->ssi_on_imx) |
887 | imx_pcm_dma_exit(pdev); | 1137 | imx_pcm_dma_exit(pdev); |
888 | clk_disable_unprepare(ssi_private->clk); | ||
889 | clk_put(ssi_private->clk); | ||
890 | } | ||
891 | snd_soc_unregister_component(&pdev->dev); | 1138 | snd_soc_unregister_component(&pdev->dev); |
1139 | dev_set_drvdata(&pdev->dev, NULL); | ||
892 | device_remove_file(&pdev->dev, &ssi_private->dev_attr); | 1140 | device_remove_file(&pdev->dev, &ssi_private->dev_attr); |
893 | 1141 | if (ssi_private->ssi_on_imx) | |
894 | free_irq(ssi_private->irq, ssi_private); | 1142 | clk_disable_unprepare(ssi_private->clk); |
895 | irq_dispose_mapping(ssi_private->irq); | 1143 | irq_dispose_mapping(ssi_private->irq); |
896 | 1144 | ||
897 | kfree(ssi_private); | ||
898 | dev_set_drvdata(&pdev->dev, NULL); | ||
899 | |||
900 | return 0; | 1145 | return 0; |
901 | } | 1146 | } |
902 | 1147 | ||
@@ -919,6 +1164,7 @@ static struct platform_driver fsl_ssi_driver = { | |||
919 | 1164 | ||
920 | module_platform_driver(fsl_ssi_driver); | 1165 | module_platform_driver(fsl_ssi_driver); |
921 | 1166 | ||
1167 | MODULE_ALIAS("platform:fsl-ssi-dai"); | ||
922 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | 1168 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); |
923 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); | 1169 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); |
924 | MODULE_LICENSE("GPL v2"); | 1170 | MODULE_LICENSE("GPL v2"); |
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index e260f1f899db..ab17381cc981 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c | |||
@@ -73,8 +73,11 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, | |||
73 | if (!buf) | 73 | if (!buf) |
74 | return -ENOMEM; | 74 | return -ENOMEM; |
75 | 75 | ||
76 | if (audmux_clk) | 76 | if (audmux_clk) { |
77 | clk_prepare_enable(audmux_clk); | 77 | ret = clk_prepare_enable(audmux_clk); |
78 | if (ret) | ||
79 | return ret; | ||
80 | } | ||
78 | 81 | ||
79 | ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port)); | 82 | ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port)); |
80 | pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port)); | 83 | pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port)); |
@@ -224,14 +227,19 @@ EXPORT_SYMBOL_GPL(imx_audmux_v1_configure_port); | |||
224 | int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, | 227 | int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, |
225 | unsigned int pdcr) | 228 | unsigned int pdcr) |
226 | { | 229 | { |
230 | int ret; | ||
231 | |||
227 | if (audmux_type != IMX31_AUDMUX) | 232 | if (audmux_type != IMX31_AUDMUX) |
228 | return -EINVAL; | 233 | return -EINVAL; |
229 | 234 | ||
230 | if (!audmux_base) | 235 | if (!audmux_base) |
231 | return -ENOSYS; | 236 | return -ENOSYS; |
232 | 237 | ||
233 | if (audmux_clk) | 238 | if (audmux_clk) { |
234 | clk_prepare_enable(audmux_clk); | 239 | ret = clk_prepare_enable(audmux_clk); |
240 | if (ret) | ||
241 | return ret; | ||
242 | } | ||
235 | 243 | ||
236 | writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); | 244 | writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); |
237 | writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); | 245 | writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); |
@@ -243,6 +251,66 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, | |||
243 | } | 251 | } |
244 | EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port); | 252 | EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port); |
245 | 253 | ||
254 | static int imx_audmux_parse_dt_defaults(struct platform_device *pdev, | ||
255 | struct device_node *of_node) | ||
256 | { | ||
257 | struct device_node *child; | ||
258 | |||
259 | for_each_available_child_of_node(of_node, child) { | ||
260 | unsigned int port; | ||
261 | unsigned int ptcr = 0; | ||
262 | unsigned int pdcr = 0; | ||
263 | unsigned int pcr = 0; | ||
264 | unsigned int val; | ||
265 | int ret; | ||
266 | int i = 0; | ||
267 | |||
268 | ret = of_property_read_u32(child, "fsl,audmux-port", &port); | ||
269 | if (ret) { | ||
270 | dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%s\"\n", | ||
271 | child->full_name); | ||
272 | continue; | ||
273 | } | ||
274 | if (!of_property_read_bool(child, "fsl,port-config")) { | ||
275 | dev_warn(&pdev->dev, "child node \"%s\" does not have property fsl,port-config\n", | ||
276 | child->full_name); | ||
277 | continue; | ||
278 | } | ||
279 | |||
280 | for (i = 0; (ret = of_property_read_u32_index(child, | ||
281 | "fsl,port-config", i, &val)) == 0; | ||
282 | ++i) { | ||
283 | if (audmux_type == IMX31_AUDMUX) { | ||
284 | if (i % 2) | ||
285 | pdcr |= val; | ||
286 | else | ||
287 | ptcr |= val; | ||
288 | } else { | ||
289 | pcr |= val; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | if (ret != -EOVERFLOW) { | ||
294 | dev_err(&pdev->dev, "Failed to read u32 at index %d of child %s\n", | ||
295 | i, child->full_name); | ||
296 | continue; | ||
297 | } | ||
298 | |||
299 | if (audmux_type == IMX31_AUDMUX) { | ||
300 | if (i % 2) { | ||
301 | dev_err(&pdev->dev, "One pdcr value is missing in child node %s\n", | ||
302 | child->full_name); | ||
303 | continue; | ||
304 | } | ||
305 | imx_audmux_v2_configure_port(port, ptcr, pdcr); | ||
306 | } else { | ||
307 | imx_audmux_v1_configure_port(port, pcr); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
246 | static int imx_audmux_probe(struct platform_device *pdev) | 314 | static int imx_audmux_probe(struct platform_device *pdev) |
247 | { | 315 | { |
248 | struct resource *res; | 316 | struct resource *res; |
@@ -267,6 +335,8 @@ static int imx_audmux_probe(struct platform_device *pdev) | |||
267 | if (audmux_type == IMX31_AUDMUX) | 335 | if (audmux_type == IMX31_AUDMUX) |
268 | audmux_debugfs_init(); | 336 | audmux_debugfs_init(); |
269 | 337 | ||
338 | imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node); | ||
339 | |||
270 | return 0; | 340 | return 0; |
271 | } | 341 | } |
272 | 342 | ||
diff --git a/sound/soc/fsl/imx-audmux.h b/sound/soc/fsl/imx-audmux.h index b8ff44b9dafa..38a4209af7c6 100644 --- a/sound/soc/fsl/imx-audmux.h +++ b/sound/soc/fsl/imx-audmux.h | |||
@@ -1,57 +1,7 @@ | |||
1 | #ifndef __IMX_AUDMUX_H | 1 | #ifndef __IMX_AUDMUX_H |
2 | #define __IMX_AUDMUX_H | 2 | #define __IMX_AUDMUX_H |
3 | 3 | ||
4 | #define MX27_AUDMUX_HPCR1_SSI0 0 | 4 | #include <dt-bindings/sound/fsl-imx-audmux.h> |
5 | #define MX27_AUDMUX_HPCR2_SSI1 1 | ||
6 | #define MX27_AUDMUX_HPCR3_SSI_PINS_4 2 | ||
7 | #define MX27_AUDMUX_PPCR1_SSI_PINS_1 3 | ||
8 | #define MX27_AUDMUX_PPCR2_SSI_PINS_2 4 | ||
9 | #define MX27_AUDMUX_PPCR3_SSI_PINS_3 5 | ||
10 | |||
11 | #define MX31_AUDMUX_PORT1_SSI0 0 | ||
12 | #define MX31_AUDMUX_PORT2_SSI1 1 | ||
13 | #define MX31_AUDMUX_PORT3_SSI_PINS_3 2 | ||
14 | #define MX31_AUDMUX_PORT4_SSI_PINS_4 3 | ||
15 | #define MX31_AUDMUX_PORT5_SSI_PINS_5 4 | ||
16 | #define MX31_AUDMUX_PORT6_SSI_PINS_6 5 | ||
17 | #define MX31_AUDMUX_PORT7_SSI_PINS_7 6 | ||
18 | |||
19 | #define MX51_AUDMUX_PORT1_SSI0 0 | ||
20 | #define MX51_AUDMUX_PORT2_SSI1 1 | ||
21 | #define MX51_AUDMUX_PORT3 2 | ||
22 | #define MX51_AUDMUX_PORT4 3 | ||
23 | #define MX51_AUDMUX_PORT5 4 | ||
24 | #define MX51_AUDMUX_PORT6 5 | ||
25 | #define MX51_AUDMUX_PORT7 6 | ||
26 | |||
27 | /* Register definitions for the i.MX21/27 Digital Audio Multiplexer */ | ||
28 | #define IMX_AUDMUX_V1_PCR_INMMASK(x) ((x) & 0xff) | ||
29 | #define IMX_AUDMUX_V1_PCR_INMEN (1 << 8) | ||
30 | #define IMX_AUDMUX_V1_PCR_TXRXEN (1 << 10) | ||
31 | #define IMX_AUDMUX_V1_PCR_SYN (1 << 12) | ||
32 | #define IMX_AUDMUX_V1_PCR_RXDSEL(x) (((x) & 0x7) << 13) | ||
33 | #define IMX_AUDMUX_V1_PCR_RFCSEL(x) (((x) & 0xf) << 20) | ||
34 | #define IMX_AUDMUX_V1_PCR_RCLKDIR (1 << 24) | ||
35 | #define IMX_AUDMUX_V1_PCR_RFSDIR (1 << 25) | ||
36 | #define IMX_AUDMUX_V1_PCR_TFCSEL(x) (((x) & 0xf) << 26) | ||
37 | #define IMX_AUDMUX_V1_PCR_TCLKDIR (1 << 30) | ||
38 | #define IMX_AUDMUX_V1_PCR_TFSDIR (1 << 31) | ||
39 | |||
40 | /* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */ | ||
41 | #define IMX_AUDMUX_V2_PTCR_TFSDIR (1 << 31) | ||
42 | #define IMX_AUDMUX_V2_PTCR_TFSEL(x) (((x) & 0xf) << 27) | ||
43 | #define IMX_AUDMUX_V2_PTCR_TCLKDIR (1 << 26) | ||
44 | #define IMX_AUDMUX_V2_PTCR_TCSEL(x) (((x) & 0xf) << 22) | ||
45 | #define IMX_AUDMUX_V2_PTCR_RFSDIR (1 << 21) | ||
46 | #define IMX_AUDMUX_V2_PTCR_RFSEL(x) (((x) & 0xf) << 17) | ||
47 | #define IMX_AUDMUX_V2_PTCR_RCLKDIR (1 << 16) | ||
48 | #define IMX_AUDMUX_V2_PTCR_RCSEL(x) (((x) & 0xf) << 12) | ||
49 | #define IMX_AUDMUX_V2_PTCR_SYN (1 << 11) | ||
50 | |||
51 | #define IMX_AUDMUX_V2_PDCR_RXDSEL(x) (((x) & 0x7) << 13) | ||
52 | #define IMX_AUDMUX_V2_PDCR_TXRXEN (1 << 12) | ||
53 | #define IMX_AUDMUX_V2_PDCR_MODE(x) (((x) & 0x3) << 8) | ||
54 | #define IMX_AUDMUX_V2_PDCR_INMMASK(x) ((x) & 0xff) | ||
55 | 5 | ||
56 | int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr); | 6 | int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr); |
57 | 7 | ||
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index 9df173c091a6..a3d60d4bea4c 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c | |||
@@ -90,6 +90,7 @@ static const struct snd_soc_dapm_route imx_mc13783_routes[] = { | |||
90 | 90 | ||
91 | static struct snd_soc_card imx_mc13783 = { | 91 | static struct snd_soc_card imx_mc13783 = { |
92 | .name = "imx_mc13783", | 92 | .name = "imx_mc13783", |
93 | .owner = THIS_MODULE, | ||
93 | .dai_link = imx_mc13783_dai_mc13783, | 94 | .dai_link = imx_mc13783_dai_mc13783, |
94 | .num_links = ARRAY_SIZE(imx_mc13783_dai_mc13783), | 95 | .num_links = ARRAY_SIZE(imx_mc13783_dai_mc13783), |
95 | .dapm_widgets = imx_mc13783_widget, | 96 | .dapm_widgets = imx_mc13783_widget, |
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index fde4d2ea68c8..4dc1296688e9 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/dmaengine.h> | 15 | #include <linux/dmaengine.h> |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/module.h> | ||
17 | 18 | ||
18 | #include <sound/core.h> | 19 | #include <sound/core.h> |
19 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
@@ -64,7 +65,6 @@ int imx_pcm_dma_init(struct platform_device *pdev) | |||
64 | { | 65 | { |
65 | return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config, | 66 | return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config, |
66 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | | 67 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | |
67 | SND_DMAENGINE_PCM_FLAG_NO_DT | | ||
68 | SND_DMAENGINE_PCM_FLAG_COMPAT); | 68 | SND_DMAENGINE_PCM_FLAG_COMPAT); |
69 | } | 69 | } |
70 | EXPORT_SYMBOL_GPL(imx_pcm_dma_init); | 70 | EXPORT_SYMBOL_GPL(imx_pcm_dma_init); |
@@ -74,3 +74,5 @@ void imx_pcm_dma_exit(struct platform_device *pdev) | |||
74 | snd_dmaengine_pcm_unregister(&pdev->dev); | 74 | snd_dmaengine_pcm_unregister(&pdev->dev); |
75 | } | 75 | } |
76 | EXPORT_SYMBOL_GPL(imx_pcm_dma_exit); | 76 | EXPORT_SYMBOL_GPL(imx_pcm_dma_exit); |
77 | |||
78 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 310d90290320..34043c55f2a6 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | 23 | ||
24 | #include <sound/core.h> | 24 | #include <sound/core.h> |
25 | #include <sound/dmaengine_pcm.h> | ||
25 | #include <sound/initval.h> | 26 | #include <sound/initval.h> |
26 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
27 | #include <sound/pcm_params.h> | 28 | #include <sound/pcm_params.h> |
@@ -32,6 +33,7 @@ | |||
32 | #include <linux/platform_data/asoc-imx-ssi.h> | 33 | #include <linux/platform_data/asoc-imx-ssi.h> |
33 | 34 | ||
34 | #include "imx-ssi.h" | 35 | #include "imx-ssi.h" |
36 | #include "imx-pcm.h" | ||
35 | 37 | ||
36 | struct imx_pcm_runtime_data { | 38 | struct imx_pcm_runtime_data { |
37 | unsigned int period; | 39 | unsigned int period; |
@@ -366,9 +368,9 @@ static struct snd_soc_platform_driver imx_soc_platform_fiq = { | |||
366 | .pcm_free = imx_pcm_fiq_free, | 368 | .pcm_free = imx_pcm_fiq_free, |
367 | }; | 369 | }; |
368 | 370 | ||
369 | int imx_pcm_fiq_init(struct platform_device *pdev) | 371 | int imx_pcm_fiq_init(struct platform_device *pdev, |
372 | struct imx_pcm_fiq_params *params) | ||
370 | { | 373 | { |
371 | struct imx_ssi *ssi = platform_get_drvdata(pdev); | ||
372 | int ret; | 374 | int ret; |
373 | 375 | ||
374 | ret = claim_fiq(&fh); | 376 | ret = claim_fiq(&fh); |
@@ -377,15 +379,15 @@ int imx_pcm_fiq_init(struct platform_device *pdev) | |||
377 | return ret; | 379 | return ret; |
378 | } | 380 | } |
379 | 381 | ||
380 | mxc_set_irq_fiq(ssi->irq, 1); | 382 | mxc_set_irq_fiq(params->irq, 1); |
381 | ssi_irq = ssi->irq; | 383 | ssi_irq = params->irq; |
382 | 384 | ||
383 | imx_pcm_fiq = ssi->irq; | 385 | imx_pcm_fiq = params->irq; |
384 | 386 | ||
385 | imx_ssi_fiq_base = (unsigned long)ssi->base; | 387 | imx_ssi_fiq_base = (unsigned long)params->base; |
386 | 388 | ||
387 | ssi->dma_params_tx.maxburst = 4; | 389 | params->dma_params_tx->maxburst = 4; |
388 | ssi->dma_params_rx.maxburst = 6; | 390 | params->dma_params_rx->maxburst = 6; |
389 | 391 | ||
390 | ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq); | 392 | ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq); |
391 | if (ret) | 393 | if (ret) |
@@ -406,3 +408,5 @@ void imx_pcm_fiq_exit(struct platform_device *pdev) | |||
406 | snd_soc_unregister_platform(&pdev->dev); | 408 | snd_soc_unregister_platform(&pdev->dev); |
407 | } | 409 | } |
408 | EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit); | 410 | EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit); |
411 | |||
412 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index 67f656c7c320..5d5b73303e11 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h | |||
@@ -22,17 +22,23 @@ | |||
22 | 22 | ||
23 | static inline void | 23 | static inline void |
24 | imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data, | 24 | imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data, |
25 | int dma, bool shared) | 25 | int dma, enum sdma_peripheral_type peripheral_type) |
26 | { | 26 | { |
27 | dma_data->dma_request = dma; | 27 | dma_data->dma_request = dma; |
28 | dma_data->priority = DMA_PRIO_HIGH; | 28 | dma_data->priority = DMA_PRIO_HIGH; |
29 | if (shared) | 29 | dma_data->peripheral_type = peripheral_type; |
30 | dma_data->peripheral_type = IMX_DMATYPE_SSI_SP; | ||
31 | else | ||
32 | dma_data->peripheral_type = IMX_DMATYPE_SSI; | ||
33 | } | 30 | } |
34 | 31 | ||
35 | #ifdef CONFIG_SND_SOC_IMX_PCM_DMA | 32 | struct imx_pcm_fiq_params { |
33 | int irq; | ||
34 | void __iomem *base; | ||
35 | |||
36 | /* Pointer to original ssi driver to setup tx rx sizes */ | ||
37 | struct snd_dmaengine_dai_dma_data *dma_params_rx; | ||
38 | struct snd_dmaengine_dai_dma_data *dma_params_tx; | ||
39 | }; | ||
40 | |||
41 | #if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA) | ||
36 | int imx_pcm_dma_init(struct platform_device *pdev); | 42 | int imx_pcm_dma_init(struct platform_device *pdev); |
37 | void imx_pcm_dma_exit(struct platform_device *pdev); | 43 | void imx_pcm_dma_exit(struct platform_device *pdev); |
38 | #else | 44 | #else |
@@ -46,11 +52,13 @@ static inline void imx_pcm_dma_exit(struct platform_device *pdev) | |||
46 | } | 52 | } |
47 | #endif | 53 | #endif |
48 | 54 | ||
49 | #ifdef CONFIG_SND_SOC_IMX_PCM_FIQ | 55 | #if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_FIQ) |
50 | int imx_pcm_fiq_init(struct platform_device *pdev); | 56 | int imx_pcm_fiq_init(struct platform_device *pdev, |
57 | struct imx_pcm_fiq_params *params); | ||
51 | void imx_pcm_fiq_exit(struct platform_device *pdev); | 58 | void imx_pcm_fiq_exit(struct platform_device *pdev); |
52 | #else | 59 | #else |
53 | static inline int imx_pcm_fiq_init(struct platform_device *pdev) | 60 | static inline int imx_pcm_fiq_init(struct platform_device *pdev, |
61 | struct imx_pcm_fiq_params *params) | ||
54 | { | 62 | { |
55 | return -ENODEV; | 63 | return -ENODEV; |
56 | } | 64 | } |
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 3f726e4f88db..389cbfa6dca7 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c | |||
@@ -129,8 +129,10 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) | |||
129 | } | 129 | } |
130 | 130 | ||
131 | data->codec_clk = devm_clk_get(&codec_dev->dev, NULL); | 131 | data->codec_clk = devm_clk_get(&codec_dev->dev, NULL); |
132 | if (IS_ERR(data->codec_clk)) | 132 | if (IS_ERR(data->codec_clk)) { |
133 | ret = PTR_ERR(data->codec_clk); | ||
133 | goto fail; | 134 | goto fail; |
135 | } | ||
134 | 136 | ||
135 | data->clk_frequency = clk_get_rate(data->codec_clk); | 137 | data->clk_frequency = clk_get_rate(data->codec_clk); |
136 | 138 | ||
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 51be3772cba9..f58bcd85c07f 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c | |||
@@ -571,13 +571,13 @@ static int imx_ssi_probe(struct platform_device *pdev) | |||
571 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); | 571 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); |
572 | if (res) { | 572 | if (res) { |
573 | imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start, | 573 | imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start, |
574 | false); | 574 | IMX_DMATYPE_SSI); |
575 | } | 575 | } |
576 | 576 | ||
577 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0"); | 577 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0"); |
578 | if (res) { | 578 | if (res) { |
579 | imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start, | 579 | imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start, |
580 | false); | 580 | IMX_DMATYPE_SSI); |
581 | } | 581 | } |
582 | 582 | ||
583 | platform_set_drvdata(pdev, ssi); | 583 | platform_set_drvdata(pdev, ssi); |
@@ -595,7 +595,12 @@ static int imx_ssi_probe(struct platform_device *pdev) | |||
595 | goto failed_register; | 595 | goto failed_register; |
596 | } | 596 | } |
597 | 597 | ||
598 | ret = imx_pcm_fiq_init(pdev); | 598 | ssi->fiq_params.irq = ssi->irq; |
599 | ssi->fiq_params.base = ssi->base; | ||
600 | ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx; | ||
601 | ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx; | ||
602 | |||
603 | ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params); | ||
599 | if (ret) | 604 | if (ret) |
600 | goto failed_pcm_fiq; | 605 | goto failed_pcm_fiq; |
601 | 606 | ||
diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h index d5003cefca8d..fb1616ba8c59 100644 --- a/sound/soc/fsl/imx-ssi.h +++ b/sound/soc/fsl/imx-ssi.h | |||
@@ -209,6 +209,7 @@ struct imx_ssi { | |||
209 | struct snd_dmaengine_dai_dma_data dma_params_tx; | 209 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
210 | struct imx_dma_data filter_data_tx; | 210 | struct imx_dma_data filter_data_tx; |
211 | struct imx_dma_data filter_data_rx; | 211 | struct imx_dma_data filter_data_rx; |
212 | struct imx_pcm_fiq_params fiq_params; | ||
212 | 213 | ||
213 | int enabled; | 214 | int enabled; |
214 | }; | 215 | }; |
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 52a36a90f4f4..1d70e278e915 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c | |||
@@ -217,7 +217,8 @@ static int imx_wm8962_probe(struct platform_device *pdev) | |||
217 | codec_dev = of_find_i2c_device_by_node(codec_np); | 217 | codec_dev = of_find_i2c_device_by_node(codec_np); |
218 | if (!codec_dev || !codec_dev->driver) { | 218 | if (!codec_dev || !codec_dev->driver) { |
219 | dev_err(&pdev->dev, "failed to find codec platform device\n"); | 219 | dev_err(&pdev->dev, "failed to find codec platform device\n"); |
220 | return -EINVAL; | 220 | ret = -EINVAL; |
221 | goto fail; | ||
221 | } | 222 | } |
222 | 223 | ||
223 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | 224 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); |
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig index c62d715235e2..9e1970c44e86 100644 --- a/sound/soc/kirkwood/Kconfig +++ b/sound/soc/kirkwood/Kconfig | |||
@@ -1,19 +1,15 @@ | |||
1 | config SND_KIRKWOOD_SOC | 1 | config SND_KIRKWOOD_SOC |
2 | tristate "SoC Audio for the Marvell Kirkwood chip" | 2 | tristate "SoC Audio for the Marvell Kirkwood chip" |
3 | depends on ARCH_KIRKWOOD | 3 | depends on ARCH_KIRKWOOD || COMPILE_TEST |
4 | help | 4 | help |
5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
6 | the Kirkwood I2S interface. You will also need to select the | 6 | the Kirkwood I2S interface. You will also need to select the |
7 | audio interfaces to support below. | 7 | audio interfaces to support below. |
8 | 8 | ||
9 | config SND_KIRKWOOD_SOC_I2S | ||
10 | tristate | ||
11 | |||
12 | config SND_KIRKWOOD_SOC_OPENRD | 9 | config SND_KIRKWOOD_SOC_OPENRD |
13 | tristate "SoC Audio support for Kirkwood Openrd Client" | 10 | tristate "SoC Audio support for Kirkwood Openrd Client" |
14 | depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE) | 11 | depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE || COMPILE_TEST) |
15 | depends on I2C | 12 | depends on I2C |
16 | select SND_KIRKWOOD_SOC_I2S | ||
17 | select SND_SOC_CS42L51 | 13 | select SND_SOC_CS42L51 |
18 | help | 14 | help |
19 | Say Y if you want to add support for SoC audio on | 15 | Say Y if you want to add support for SoC audio on |
@@ -21,8 +17,7 @@ config SND_KIRKWOOD_SOC_OPENRD | |||
21 | 17 | ||
22 | config SND_KIRKWOOD_SOC_T5325 | 18 | config SND_KIRKWOOD_SOC_T5325 |
23 | tristate "SoC Audio support for HP t5325" | 19 | tristate "SoC Audio support for HP t5325" |
24 | depends on SND_KIRKWOOD_SOC && MACH_T5325 && I2C | 20 | depends on SND_KIRKWOOD_SOC && (MACH_T5325 || COMPILE_TEST) && I2C |
25 | select SND_KIRKWOOD_SOC_I2S | ||
26 | select SND_SOC_ALC5623 | 21 | select SND_SOC_ALC5623 |
27 | help | 22 | help |
28 | Say Y if you want to add support for SoC audio on | 23 | Say Y if you want to add support for SoC audio on |
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile index 3e62ae9e7bbe..9e781385cb88 100644 --- a/sound/soc/kirkwood/Makefile +++ b/sound/soc/kirkwood/Makefile | |||
@@ -1,8 +1,6 @@ | |||
1 | snd-soc-kirkwood-objs := kirkwood-dma.o | 1 | snd-soc-kirkwood-objs := kirkwood-dma.o kirkwood-i2s.o |
2 | snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o | ||
3 | 2 | ||
4 | obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o | 3 | obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o |
5 | obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o | ||
6 | 4 | ||
7 | snd-soc-openrd-objs := kirkwood-openrd.o | 5 | snd-soc-openrd-objs := kirkwood-openrd.o |
8 | snd-soc-t5325-objs := kirkwood-t5325.o | 6 | snd-soc-t5325-objs := kirkwood-t5325.o |
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index a9f14530c3db..b238434f92b0 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c | |||
@@ -33,11 +33,11 @@ | |||
33 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \ | 33 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \ |
34 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE) | 34 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE) |
35 | 35 | ||
36 | struct kirkwood_dma_priv { | 36 | static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs) |
37 | struct snd_pcm_substream *play_stream; | 37 | { |
38 | struct snd_pcm_substream *rec_stream; | 38 | struct snd_soc_pcm_runtime *soc_runtime = subs->private_data; |
39 | struct kirkwood_dma_data *data; | 39 | return snd_soc_dai_get_drvdata(soc_runtime->cpu_dai); |
40 | }; | 40 | } |
41 | 41 | ||
42 | static struct snd_pcm_hardware kirkwood_dma_snd_hw = { | 42 | static struct snd_pcm_hardware kirkwood_dma_snd_hw = { |
43 | .info = (SNDRV_PCM_INFO_INTERLEAVED | | 43 | .info = (SNDRV_PCM_INFO_INTERLEAVED | |
@@ -51,7 +51,7 @@ static struct snd_pcm_hardware kirkwood_dma_snd_hw = { | |||
51 | .rate_max = 384000, | 51 | .rate_max = 384000, |
52 | .channels_min = 1, | 52 | .channels_min = 1, |
53 | .channels_max = 8, | 53 | .channels_max = 8, |
54 | .buffer_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS, | 54 | .buffer_bytes_max = KIRKWOOD_SND_MAX_BUFFER_BYTES, |
55 | .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, | 55 | .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, |
56 | .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, | 56 | .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, |
57 | .periods_min = KIRKWOOD_SND_MIN_PERIODS, | 57 | .periods_min = KIRKWOOD_SND_MIN_PERIODS, |
@@ -63,8 +63,7 @@ static u64 kirkwood_dma_dmamask = DMA_BIT_MASK(32); | |||
63 | 63 | ||
64 | static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id) | 64 | static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id) |
65 | { | 65 | { |
66 | struct kirkwood_dma_priv *prdata = dev_id; | 66 | struct kirkwood_dma_data *priv = dev_id; |
67 | struct kirkwood_dma_data *priv = prdata->data; | ||
68 | unsigned long mask, status, cause; | 67 | unsigned long mask, status, cause; |
69 | 68 | ||
70 | mask = readl(priv->io + KIRKWOOD_INT_MASK); | 69 | mask = readl(priv->io + KIRKWOOD_INT_MASK); |
@@ -89,10 +88,10 @@ static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id) | |||
89 | writel(status, priv->io + KIRKWOOD_INT_CAUSE); | 88 | writel(status, priv->io + KIRKWOOD_INT_CAUSE); |
90 | 89 | ||
91 | if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES) | 90 | if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES) |
92 | snd_pcm_period_elapsed(prdata->play_stream); | 91 | snd_pcm_period_elapsed(priv->substream_play); |
93 | 92 | ||
94 | if (status & KIRKWOOD_INT_CAUSE_REC_BYTES) | 93 | if (status & KIRKWOOD_INT_CAUSE_REC_BYTES) |
95 | snd_pcm_period_elapsed(prdata->rec_stream); | 94 | snd_pcm_period_elapsed(priv->substream_rec); |
96 | 95 | ||
97 | return IRQ_HANDLED; | 96 | return IRQ_HANDLED; |
98 | } | 97 | } |
@@ -126,15 +125,10 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) | |||
126 | { | 125 | { |
127 | int err; | 126 | int err; |
128 | struct snd_pcm_runtime *runtime = substream->runtime; | 127 | struct snd_pcm_runtime *runtime = substream->runtime; |
129 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 128 | struct kirkwood_dma_data *priv = kirkwood_priv(substream); |
130 | struct snd_soc_platform *platform = soc_runtime->platform; | ||
131 | struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; | ||
132 | struct kirkwood_dma_data *priv; | ||
133 | struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform); | ||
134 | const struct mbus_dram_target_info *dram; | 129 | const struct mbus_dram_target_info *dram; |
135 | unsigned long addr; | 130 | unsigned long addr; |
136 | 131 | ||
137 | priv = snd_soc_dai_get_dma_data(cpu_dai, substream); | ||
138 | snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw); | 132 | snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw); |
139 | 133 | ||
140 | /* Ensure that all constraints linked to dma burst are fulfilled */ | 134 | /* Ensure that all constraints linked to dma burst are fulfilled */ |
@@ -157,21 +151,11 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) | |||
157 | if (err < 0) | 151 | if (err < 0) |
158 | return err; | 152 | return err; |
159 | 153 | ||
160 | if (prdata == NULL) { | 154 | if (!priv->substream_play && !priv->substream_rec) { |
161 | prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL); | ||
162 | if (prdata == NULL) | ||
163 | return -ENOMEM; | ||
164 | |||
165 | prdata->data = priv; | ||
166 | |||
167 | err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED, | 155 | err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED, |
168 | "kirkwood-i2s", prdata); | 156 | "kirkwood-i2s", priv); |
169 | if (err) { | 157 | if (err) |
170 | kfree(prdata); | ||
171 | return -EBUSY; | 158 | return -EBUSY; |
172 | } | ||
173 | |||
174 | snd_soc_platform_set_drvdata(platform, prdata); | ||
175 | 159 | ||
176 | /* | 160 | /* |
177 | * Enable Error interrupts. We're only ack'ing them but | 161 | * Enable Error interrupts. We're only ack'ing them but |
@@ -183,11 +167,11 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) | |||
183 | dram = mv_mbus_dram_info(); | 167 | dram = mv_mbus_dram_info(); |
184 | addr = substream->dma_buffer.addr; | 168 | addr = substream->dma_buffer.addr; |
185 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 169 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
186 | prdata->play_stream = substream; | 170 | priv->substream_play = substream; |
187 | kirkwood_dma_conf_mbus_windows(priv->io, | 171 | kirkwood_dma_conf_mbus_windows(priv->io, |
188 | KIRKWOOD_PLAYBACK_WIN, addr, dram); | 172 | KIRKWOOD_PLAYBACK_WIN, addr, dram); |
189 | } else { | 173 | } else { |
190 | prdata->rec_stream = substream; | 174 | priv->substream_rec = substream; |
191 | kirkwood_dma_conf_mbus_windows(priv->io, | 175 | kirkwood_dma_conf_mbus_windows(priv->io, |
192 | KIRKWOOD_RECORD_WIN, addr, dram); | 176 | KIRKWOOD_RECORD_WIN, addr, dram); |
193 | } | 177 | } |
@@ -197,27 +181,19 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) | |||
197 | 181 | ||
198 | static int kirkwood_dma_close(struct snd_pcm_substream *substream) | 182 | static int kirkwood_dma_close(struct snd_pcm_substream *substream) |
199 | { | 183 | { |
200 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 184 | struct kirkwood_dma_data *priv = kirkwood_priv(substream); |
201 | struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; | ||
202 | struct snd_soc_platform *platform = soc_runtime->platform; | ||
203 | struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform); | ||
204 | struct kirkwood_dma_data *priv; | ||
205 | |||
206 | priv = snd_soc_dai_get_dma_data(cpu_dai, substream); | ||
207 | 185 | ||
208 | if (!prdata || !priv) | 186 | if (!priv) |
209 | return 0; | 187 | return 0; |
210 | 188 | ||
211 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 189 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
212 | prdata->play_stream = NULL; | 190 | priv->substream_play = NULL; |
213 | else | 191 | else |
214 | prdata->rec_stream = NULL; | 192 | priv->substream_rec = NULL; |
215 | 193 | ||
216 | if (!prdata->play_stream && !prdata->rec_stream) { | 194 | if (!priv->substream_play && !priv->substream_rec) { |
217 | writel(0, priv->io + KIRKWOOD_ERR_MASK); | 195 | writel(0, priv->io + KIRKWOOD_ERR_MASK); |
218 | free_irq(priv->irq, prdata); | 196 | free_irq(priv->irq, priv); |
219 | kfree(prdata); | ||
220 | snd_soc_platform_set_drvdata(platform, NULL); | ||
221 | } | 197 | } |
222 | 198 | ||
223 | return 0; | 199 | return 0; |
@@ -243,13 +219,9 @@ static int kirkwood_dma_hw_free(struct snd_pcm_substream *substream) | |||
243 | static int kirkwood_dma_prepare(struct snd_pcm_substream *substream) | 219 | static int kirkwood_dma_prepare(struct snd_pcm_substream *substream) |
244 | { | 220 | { |
245 | struct snd_pcm_runtime *runtime = substream->runtime; | 221 | struct snd_pcm_runtime *runtime = substream->runtime; |
246 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 222 | struct kirkwood_dma_data *priv = kirkwood_priv(substream); |
247 | struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; | ||
248 | struct kirkwood_dma_data *priv; | ||
249 | unsigned long size, count; | 223 | unsigned long size, count; |
250 | 224 | ||
251 | priv = snd_soc_dai_get_dma_data(cpu_dai, substream); | ||
252 | |||
253 | /* compute buffer size in term of "words" as requested in specs */ | 225 | /* compute buffer size in term of "words" as requested in specs */ |
254 | size = frames_to_bytes(runtime, runtime->buffer_size); | 226 | size = frames_to_bytes(runtime, runtime->buffer_size); |
255 | size = (size>>2)-1; | 227 | size = (size>>2)-1; |
@@ -272,13 +244,9 @@ static int kirkwood_dma_prepare(struct snd_pcm_substream *substream) | |||
272 | static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream | 244 | static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream |
273 | *substream) | 245 | *substream) |
274 | { | 246 | { |
275 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 247 | struct kirkwood_dma_data *priv = kirkwood_priv(substream); |
276 | struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; | ||
277 | struct kirkwood_dma_data *priv; | ||
278 | snd_pcm_uframes_t count; | 248 | snd_pcm_uframes_t count; |
279 | 249 | ||
280 | priv = snd_soc_dai_get_dma_data(cpu_dai, substream); | ||
281 | |||
282 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 250 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
283 | count = bytes_to_frames(substream->runtime, | 251 | count = bytes_to_frames(substream->runtime, |
284 | readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT)); | 252 | readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT)); |
@@ -366,36 +334,8 @@ static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm) | |||
366 | } | 334 | } |
367 | } | 335 | } |
368 | 336 | ||
369 | static struct snd_soc_platform_driver kirkwood_soc_platform = { | 337 | struct snd_soc_platform_driver kirkwood_soc_platform = { |
370 | .ops = &kirkwood_dma_ops, | 338 | .ops = &kirkwood_dma_ops, |
371 | .pcm_new = kirkwood_dma_new, | 339 | .pcm_new = kirkwood_dma_new, |
372 | .pcm_free = kirkwood_dma_free_dma_buffers, | 340 | .pcm_free = kirkwood_dma_free_dma_buffers, |
373 | }; | 341 | }; |
374 | |||
375 | static int kirkwood_soc_platform_probe(struct platform_device *pdev) | ||
376 | { | ||
377 | return snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform); | ||
378 | } | ||
379 | |||
380 | static int kirkwood_soc_platform_remove(struct platform_device *pdev) | ||
381 | { | ||
382 | snd_soc_unregister_platform(&pdev->dev); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static struct platform_driver kirkwood_pcm_driver = { | ||
387 | .driver = { | ||
388 | .name = "kirkwood-pcm-audio", | ||
389 | .owner = THIS_MODULE, | ||
390 | }, | ||
391 | |||
392 | .probe = kirkwood_soc_platform_probe, | ||
393 | .remove = kirkwood_soc_platform_remove, | ||
394 | }; | ||
395 | |||
396 | module_platform_driver(kirkwood_pcm_driver); | ||
397 | |||
398 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); | ||
399 | MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module"); | ||
400 | MODULE_LICENSE("GPL"); | ||
401 | MODULE_ALIAS("platform:kirkwood-pcm-audio"); | ||
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 4c9dad3263c5..e5f3f7a9ea26 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c | |||
@@ -24,11 +24,8 @@ | |||
24 | #include <linux/platform_data/asoc-kirkwood.h> | 24 | #include <linux/platform_data/asoc-kirkwood.h> |
25 | #include "kirkwood.h" | 25 | #include "kirkwood.h" |
26 | 26 | ||
27 | #define DRV_NAME "kirkwood-i2s" | 27 | #define DRV_NAME "mvebu-audio" |
28 | 28 | ||
29 | #define KIRKWOOD_I2S_RATES \ | ||
30 | (SNDRV_PCM_RATE_44100 | \ | ||
31 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | ||
32 | #define KIRKWOOD_I2S_FORMATS \ | 29 | #define KIRKWOOD_I2S_FORMATS \ |
33 | (SNDRV_PCM_FMTBIT_S16_LE | \ | 30 | (SNDRV_PCM_FMTBIT_S16_LE | \ |
34 | SNDRV_PCM_FMTBIT_S24_LE | \ | 31 | SNDRV_PCM_FMTBIT_S24_LE | \ |
@@ -105,14 +102,16 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai, | |||
105 | uint32_t clks_ctrl; | 102 | uint32_t clks_ctrl; |
106 | 103 | ||
107 | if (rate == 44100 || rate == 48000 || rate == 96000) { | 104 | if (rate == 44100 || rate == 48000 || rate == 96000) { |
108 | /* use internal dco for supported rates */ | 105 | /* use internal dco for the supported rates |
106 | * defined in kirkwood_i2s_dai */ | ||
109 | dev_dbg(dai->dev, "%s: dco set rate = %lu\n", | 107 | dev_dbg(dai->dev, "%s: dco set rate = %lu\n", |
110 | __func__, rate); | 108 | __func__, rate); |
111 | kirkwood_set_dco(priv->io, rate); | 109 | kirkwood_set_dco(priv->io, rate); |
112 | 110 | ||
113 | clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO; | 111 | clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO; |
114 | } else if (!IS_ERR(priv->extclk)) { | 112 | } else { |
115 | /* use optional external clk for other rates */ | 113 | /* use the external clock for the other rates |
114 | * defined in kirkwood_i2s_dai_extclk */ | ||
116 | dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n", | 115 | dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n", |
117 | __func__, rate, 256 * rate); | 116 | __func__, rate, 256 * rate); |
118 | clk_set_rate(priv->extclk, 256 * rate); | 117 | clk_set_rate(priv->extclk, 256 * rate); |
@@ -199,8 +198,7 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
199 | ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF; | 198 | ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF; |
200 | 199 | ||
201 | priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK | | 200 | priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK | |
202 | KIRKWOOD_PLAYCTL_I2S_EN | | 201 | KIRKWOOD_PLAYCTL_ENABLE_MASK | |
203 | KIRKWOOD_PLAYCTL_SPDIF_EN | | ||
204 | KIRKWOOD_PLAYCTL_SIZE_MASK); | 202 | KIRKWOOD_PLAYCTL_SIZE_MASK); |
205 | priv->ctl_play |= ctl_play; | 203 | priv->ctl_play |= ctl_play; |
206 | } else { | 204 | } else { |
@@ -244,8 +242,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
244 | case SNDRV_PCM_TRIGGER_START: | 242 | case SNDRV_PCM_TRIGGER_START: |
245 | /* configure */ | 243 | /* configure */ |
246 | ctl = priv->ctl_play; | 244 | ctl = priv->ctl_play; |
247 | value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN | | 245 | value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK; |
248 | KIRKWOOD_PLAYCTL_SPDIF_EN); | ||
249 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | 246 | writel(value, priv->io + KIRKWOOD_PLAYCTL); |
250 | 247 | ||
251 | /* enable interrupts */ | 248 | /* enable interrupts */ |
@@ -267,7 +264,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
267 | writel(value, priv->io + KIRKWOOD_INT_MASK); | 264 | writel(value, priv->io + KIRKWOOD_INT_MASK); |
268 | 265 | ||
269 | /* disable all playbacks */ | 266 | /* disable all playbacks */ |
270 | ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); | 267 | ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK; |
271 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 268 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
272 | break; | 269 | break; |
273 | 270 | ||
@@ -387,7 +384,7 @@ static int kirkwood_i2s_probe(struct snd_soc_dai *dai) | |||
387 | 384 | ||
388 | /* disable playback/record */ | 385 | /* disable playback/record */ |
389 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | 386 | value = readl(priv->io + KIRKWOOD_PLAYCTL); |
390 | value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN); | 387 | value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK; |
391 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | 388 | writel(value, priv->io + KIRKWOOD_PLAYCTL); |
392 | 389 | ||
393 | value = readl(priv->io + KIRKWOOD_RECCTL); | 390 | value = readl(priv->io + KIRKWOOD_RECCTL); |
@@ -398,11 +395,6 @@ static int kirkwood_i2s_probe(struct snd_soc_dai *dai) | |||
398 | 395 | ||
399 | } | 396 | } |
400 | 397 | ||
401 | static int kirkwood_i2s_remove(struct snd_soc_dai *dai) | ||
402 | { | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { | 398 | static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { |
407 | .startup = kirkwood_i2s_startup, | 399 | .startup = kirkwood_i2s_startup, |
408 | .trigger = kirkwood_i2s_trigger, | 400 | .trigger = kirkwood_i2s_trigger, |
@@ -413,17 +405,18 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { | |||
413 | 405 | ||
414 | static struct snd_soc_dai_driver kirkwood_i2s_dai = { | 406 | static struct snd_soc_dai_driver kirkwood_i2s_dai = { |
415 | .probe = kirkwood_i2s_probe, | 407 | .probe = kirkwood_i2s_probe, |
416 | .remove = kirkwood_i2s_remove, | ||
417 | .playback = { | 408 | .playback = { |
418 | .channels_min = 1, | 409 | .channels_min = 1, |
419 | .channels_max = 2, | 410 | .channels_max = 2, |
420 | .rates = KIRKWOOD_I2S_RATES, | 411 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | |
412 | SNDRV_PCM_RATE_96000, | ||
421 | .formats = KIRKWOOD_I2S_FORMATS, | 413 | .formats = KIRKWOOD_I2S_FORMATS, |
422 | }, | 414 | }, |
423 | .capture = { | 415 | .capture = { |
424 | .channels_min = 1, | 416 | .channels_min = 1, |
425 | .channels_max = 2, | 417 | .channels_max = 2, |
426 | .rates = KIRKWOOD_I2S_RATES, | 418 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | |
419 | SNDRV_PCM_RATE_96000, | ||
427 | .formats = KIRKWOOD_I2S_FORMATS, | 420 | .formats = KIRKWOOD_I2S_FORMATS, |
428 | }, | 421 | }, |
429 | .ops = &kirkwood_i2s_dai_ops, | 422 | .ops = &kirkwood_i2s_dai_ops, |
@@ -431,7 +424,6 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = { | |||
431 | 424 | ||
432 | static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { | 425 | static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { |
433 | .probe = kirkwood_i2s_probe, | 426 | .probe = kirkwood_i2s_probe, |
434 | .remove = kirkwood_i2s_remove, | ||
435 | .playback = { | 427 | .playback = { |
436 | .channels_min = 1, | 428 | .channels_min = 1, |
437 | .channels_max = 2, | 429 | .channels_max = 2, |
@@ -498,10 +490,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
498 | if (err < 0) | 490 | if (err < 0) |
499 | return err; | 491 | return err; |
500 | 492 | ||
501 | priv->extclk = clk_get(&pdev->dev, "extclk"); | 493 | priv->extclk = devm_clk_get(&pdev->dev, "extclk"); |
502 | if (!IS_ERR(priv->extclk)) { | 494 | if (!IS_ERR(priv->extclk)) { |
503 | if (priv->extclk == priv->clk) { | 495 | if (priv->extclk == priv->clk) { |
504 | clk_put(priv->extclk); | 496 | devm_clk_put(&pdev->dev, priv->extclk); |
505 | priv->extclk = ERR_PTR(-EINVAL); | 497 | priv->extclk = ERR_PTR(-EINVAL); |
506 | } else { | 498 | } else { |
507 | dev_info(&pdev->dev, "found external clock\n"); | 499 | dev_info(&pdev->dev, "found external clock\n"); |
@@ -525,14 +517,22 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
525 | 517 | ||
526 | err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, | 518 | err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, |
527 | soc_dai, 1); | 519 | soc_dai, 1); |
528 | if (!err) | 520 | if (err) { |
529 | return 0; | 521 | dev_err(&pdev->dev, "snd_soc_register_component failed\n"); |
530 | dev_err(&pdev->dev, "snd_soc_register_component failed\n"); | 522 | goto err_component; |
523 | } | ||
531 | 524 | ||
532 | if (!IS_ERR(priv->extclk)) { | 525 | err = snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform); |
533 | clk_disable_unprepare(priv->extclk); | 526 | if (err) { |
534 | clk_put(priv->extclk); | 527 | dev_err(&pdev->dev, "snd_soc_register_platform failed\n"); |
528 | goto err_platform; | ||
535 | } | 529 | } |
530 | return 0; | ||
531 | err_platform: | ||
532 | snd_soc_unregister_component(&pdev->dev); | ||
533 | err_component: | ||
534 | if (!IS_ERR(priv->extclk)) | ||
535 | clk_disable_unprepare(priv->extclk); | ||
536 | clk_disable_unprepare(priv->clk); | 536 | clk_disable_unprepare(priv->clk); |
537 | 537 | ||
538 | return err; | 538 | return err; |
@@ -542,12 +542,11 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev) | |||
542 | { | 542 | { |
543 | struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); | 543 | struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); |
544 | 544 | ||
545 | snd_soc_unregister_platform(&pdev->dev); | ||
545 | snd_soc_unregister_component(&pdev->dev); | 546 | snd_soc_unregister_component(&pdev->dev); |
546 | 547 | ||
547 | if (!IS_ERR(priv->extclk)) { | 548 | if (!IS_ERR(priv->extclk)) |
548 | clk_disable_unprepare(priv->extclk); | 549 | clk_disable_unprepare(priv->extclk); |
549 | clk_put(priv->extclk); | ||
550 | } | ||
551 | clk_disable_unprepare(priv->clk); | 550 | clk_disable_unprepare(priv->clk); |
552 | 551 | ||
553 | return 0; | 552 | return 0; |
@@ -568,4 +567,4 @@ module_platform_driver(kirkwood_i2s_driver); | |||
568 | MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>"); | 567 | MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>"); |
569 | MODULE_DESCRIPTION("Kirkwood I2S SoC Interface"); | 568 | MODULE_DESCRIPTION("Kirkwood I2S SoC Interface"); |
570 | MODULE_LICENSE("GPL"); | 569 | MODULE_LICENSE("GPL"); |
571 | MODULE_ALIAS("platform:kirkwood-i2s"); | 570 | MODULE_ALIAS("platform:mvebu-audio"); |
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c index b979c7154715..025be0e97164 100644 --- a/sound/soc/kirkwood/kirkwood-openrd.c +++ b/sound/soc/kirkwood/kirkwood-openrd.c | |||
@@ -16,9 +16,7 @@ | |||
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
19 | #include <mach/kirkwood.h> | ||
20 | #include <linux/platform_data/asoc-kirkwood.h> | 19 | #include <linux/platform_data/asoc-kirkwood.h> |
21 | #include <asm/mach-types.h> | ||
22 | #include "../codecs/cs42l51.h" | 20 | #include "../codecs/cs42l51.h" |
23 | 21 | ||
24 | static int openrd_client_hw_params(struct snd_pcm_substream *substream, | 22 | static int openrd_client_hw_params(struct snd_pcm_substream *substream, |
@@ -54,8 +52,8 @@ static struct snd_soc_dai_link openrd_client_dai[] = { | |||
54 | { | 52 | { |
55 | .name = "CS42L51", | 53 | .name = "CS42L51", |
56 | .stream_name = "CS42L51 HiFi", | 54 | .stream_name = "CS42L51 HiFi", |
57 | .cpu_dai_name = "kirkwood-i2s", | 55 | .cpu_dai_name = "mvebu-audio", |
58 | .platform_name = "kirkwood-pcm-audio", | 56 | .platform_name = "mvebu-audio", |
59 | .codec_dai_name = "cs42l51-hifi", | 57 | .codec_dai_name = "cs42l51-hifi", |
60 | .codec_name = "cs42l51-codec.0-004a", | 58 | .codec_name = "cs42l51-codec.0-004a", |
61 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, | 59 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, |
diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c index 1d0ed6f8add7..27545b0c4856 100644 --- a/sound/soc/kirkwood/kirkwood-t5325.c +++ b/sound/soc/kirkwood/kirkwood-t5325.c | |||
@@ -15,9 +15,7 @@ | |||
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <sound/soc.h> | 17 | #include <sound/soc.h> |
18 | #include <mach/kirkwood.h> | ||
19 | #include <linux/platform_data/asoc-kirkwood.h> | 18 | #include <linux/platform_data/asoc-kirkwood.h> |
20 | #include <asm/mach-types.h> | ||
21 | #include "../codecs/alc5623.h" | 19 | #include "../codecs/alc5623.h" |
22 | 20 | ||
23 | static int t5325_hw_params(struct snd_pcm_substream *substream, | 21 | static int t5325_hw_params(struct snd_pcm_substream *substream, |
@@ -70,8 +68,8 @@ static struct snd_soc_dai_link t5325_dai[] = { | |||
70 | { | 68 | { |
71 | .name = "ALC5621", | 69 | .name = "ALC5621", |
72 | .stream_name = "ALC5621 HiFi", | 70 | .stream_name = "ALC5621 HiFi", |
73 | .cpu_dai_name = "kirkwood-i2s", | 71 | .cpu_dai_name = "mvebu-audio", |
74 | .platform_name = "kirkwood-pcm-audio", | 72 | .platform_name = "mvebu-audio", |
75 | .codec_dai_name = "alc5621-hifi", | 73 | .codec_dai_name = "alc5621-hifi", |
76 | .codec_name = "alc562x-codec.0-001a", | 74 | .codec_name = "alc562x-codec.0-001a", |
77 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, | 75 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, |
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h index 4d92637ddb3f..f8e1ccc1c58c 100644 --- a/sound/soc/kirkwood/kirkwood.h +++ b/sound/soc/kirkwood/kirkwood.h | |||
@@ -54,7 +54,7 @@ | |||
54 | #define KIRKWOOD_PLAYCTL_MONO_OFF (0<<5) | 54 | #define KIRKWOOD_PLAYCTL_MONO_OFF (0<<5) |
55 | #define KIRKWOOD_PLAYCTL_I2S_MUTE (1<<7) | 55 | #define KIRKWOOD_PLAYCTL_I2S_MUTE (1<<7) |
56 | #define KIRKWOOD_PLAYCTL_SPDIF_EN (1<<4) | 56 | #define KIRKWOOD_PLAYCTL_SPDIF_EN (1<<4) |
57 | #define KIRKWOOD_PLAYCTL_I2S_EN (1<<3) | 57 | #define KIRKWOOD_PLAYCTL_I2S_EN (1<<3) |
58 | #define KIRKWOOD_PLAYCTL_SIZE_MASK (7<<0) | 58 | #define KIRKWOOD_PLAYCTL_SIZE_MASK (7<<0) |
59 | #define KIRKWOOD_PLAYCTL_SIZE_16 (7<<0) | 59 | #define KIRKWOOD_PLAYCTL_SIZE_16 (7<<0) |
60 | #define KIRKWOOD_PLAYCTL_SIZE_16_C (3<<0) | 60 | #define KIRKWOOD_PLAYCTL_SIZE_16_C (3<<0) |
@@ -62,6 +62,9 @@ | |||
62 | #define KIRKWOOD_PLAYCTL_SIZE_24 (1<<0) | 62 | #define KIRKWOOD_PLAYCTL_SIZE_24 (1<<0) |
63 | #define KIRKWOOD_PLAYCTL_SIZE_32 (0<<0) | 63 | #define KIRKWOOD_PLAYCTL_SIZE_32 (0<<0) |
64 | 64 | ||
65 | #define KIRKWOOD_PLAYCTL_ENABLE_MASK (KIRKWOOD_PLAYCTL_SPDIF_EN | \ | ||
66 | KIRKWOOD_PLAYCTL_I2S_EN) | ||
67 | |||
65 | #define KIRKWOOD_PLAY_BUF_ADDR 0x1104 | 68 | #define KIRKWOOD_PLAY_BUF_ADDR 0x1104 |
66 | #define KIRKWOOD_PLAY_BUF_SIZE 0x1108 | 69 | #define KIRKWOOD_PLAY_BUF_SIZE 0x1108 |
67 | #define KIRKWOOD_PLAY_BYTE_COUNT 0x110C | 70 | #define KIRKWOOD_PLAY_BYTE_COUNT 0x110C |
@@ -122,6 +125,8 @@ | |||
122 | #define KIRKWOOD_SND_MAX_PERIODS 16 | 125 | #define KIRKWOOD_SND_MAX_PERIODS 16 |
123 | #define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000 | 126 | #define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000 |
124 | #define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000 | 127 | #define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000 |
128 | #define KIRKWOOD_SND_MAX_BUFFER_BYTES (KIRKWOOD_SND_MAX_PERIOD_BYTES \ | ||
129 | * KIRKWOOD_SND_MAX_PERIODS) | ||
125 | 130 | ||
126 | struct kirkwood_dma_data { | 131 | struct kirkwood_dma_data { |
127 | void __iomem *io; | 132 | void __iomem *io; |
@@ -129,8 +134,12 @@ struct kirkwood_dma_data { | |||
129 | struct clk *extclk; | 134 | struct clk *extclk; |
130 | uint32_t ctl_play; | 135 | uint32_t ctl_play; |
131 | uint32_t ctl_rec; | 136 | uint32_t ctl_rec; |
137 | struct snd_pcm_substream *substream_play; | ||
138 | struct snd_pcm_substream *substream_rec; | ||
132 | int irq; | 139 | int irq; |
133 | int burst; | 140 | int burst; |
134 | }; | 141 | }; |
135 | 142 | ||
143 | extern struct snd_soc_platform_driver kirkwood_soc_platform; | ||
144 | |||
136 | #endif | 145 | #endif |
diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig index 78d321cbe8b4..219235c02212 100644 --- a/sound/soc/mxs/Kconfig +++ b/sound/soc/mxs/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | menuconfig SND_MXS_SOC | 1 | menuconfig SND_MXS_SOC |
2 | tristate "SoC Audio for Freescale MXS CPUs" | 2 | tristate "SoC Audio for Freescale MXS CPUs" |
3 | depends on ARCH_MXS | 3 | depends on ARCH_MXS || COMPILE_TEST |
4 | depends on COMMON_CLK | ||
4 | select SND_SOC_GENERIC_DMAENGINE_PCM | 5 | select SND_SOC_GENERIC_DMAENGINE_PCM |
5 | help | 6 | help |
6 | Say Y or M if you want to add support for codecs attached to | 7 | Say Y or M if you want to add support for codecs attached to |
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 54511c5e6a7c..b56b8a0e8deb 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
32 | #include <sound/pcm_params.h> | 32 | #include <sound/pcm_params.h> |
33 | #include <sound/soc.h> | 33 | #include <sound/soc.h> |
34 | #include <asm/mach-types.h> | ||
35 | 34 | ||
36 | #include "mxs-saif.h" | 35 | #include "mxs-saif.h" |
37 | 36 | ||
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 1b134d72f120..ce084eb10c49 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/jack.h> | 26 | #include <sound/jack.h> |
27 | #include <sound/soc-dapm.h> | 27 | #include <sound/soc-dapm.h> |
28 | #include <asm/mach-types.h> | ||
29 | 28 | ||
30 | #include "../codecs/sgtl5000.h" | 29 | #include "../codecs/sgtl5000.h" |
31 | #include "mxs-saif.h" | 30 | #include "mxs-saif.h" |
@@ -51,18 +50,27 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream, | |||
51 | } | 50 | } |
52 | 51 | ||
53 | /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */ | 52 | /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */ |
54 | if (mclk < 8000000 || mclk > 27000000) | 53 | if (mclk < 8000000 || mclk > 27000000) { |
54 | dev_err(codec_dai->dev, "Invalid mclk frequency: %u.%03uMHz\n", | ||
55 | mclk / 1000000, mclk / 1000 % 1000); | ||
55 | return -EINVAL; | 56 | return -EINVAL; |
57 | } | ||
56 | 58 | ||
57 | /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */ | 59 | /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */ |
58 | ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0); | 60 | ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0); |
59 | if (ret) | 61 | if (ret) { |
62 | dev_err(codec_dai->dev, "Failed to set sysclk to %u.%03uMHz\n", | ||
63 | mclk / 1000000, mclk / 1000 % 1000); | ||
60 | return ret; | 64 | return ret; |
65 | } | ||
61 | 66 | ||
62 | /* The SAIF MCLK should be the same as SGTL5000_SYSCLK */ | 67 | /* The SAIF MCLK should be the same as SGTL5000_SYSCLK */ |
63 | ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_MCLK, mclk, 0); | 68 | ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_MCLK, mclk, 0); |
64 | if (ret) | 69 | if (ret) { |
70 | dev_err(cpu_dai->dev, "Failed to set sysclk to %u.%03uMHz\n", | ||
71 | mclk / 1000000, mclk / 1000 % 1000); | ||
65 | return ret; | 72 | return ret; |
73 | } | ||
66 | 74 | ||
67 | /* set codec to slave mode */ | 75 | /* set codec to slave mode */ |
68 | dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 76 | dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
@@ -70,13 +78,19 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream, | |||
70 | 78 | ||
71 | /* set codec DAI configuration */ | 79 | /* set codec DAI configuration */ |
72 | ret = snd_soc_dai_set_fmt(codec_dai, dai_format); | 80 | ret = snd_soc_dai_set_fmt(codec_dai, dai_format); |
73 | if (ret) | 81 | if (ret) { |
82 | dev_err(codec_dai->dev, "Failed to set dai format to %08x\n", | ||
83 | dai_format); | ||
74 | return ret; | 84 | return ret; |
85 | } | ||
75 | 86 | ||
76 | /* set cpu DAI configuration */ | 87 | /* set cpu DAI configuration */ |
77 | ret = snd_soc_dai_set_fmt(cpu_dai, dai_format); | 88 | ret = snd_soc_dai_set_fmt(cpu_dai, dai_format); |
78 | if (ret) | 89 | if (ret) { |
90 | dev_err(cpu_dai->dev, "Failed to set dai format to %08x\n", | ||
91 | dai_format); | ||
79 | return ret; | 92 | return ret; |
93 | } | ||
80 | 94 | ||
81 | return 0; | 95 | return 0; |
82 | } | 96 | } |
@@ -154,8 +168,10 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) | |||
154 | * should be >= 8MHz and <= 27M. | 168 | * should be >= 8MHz and <= 27M. |
155 | */ | 169 | */ |
156 | ret = mxs_saif_get_mclk(0, 44100 * 256, 44100); | 170 | ret = mxs_saif_get_mclk(0, 44100 * 256, 44100); |
157 | if (ret) | 171 | if (ret) { |
172 | dev_err(&pdev->dev, "failed to get mclk\n"); | ||
158 | return ret; | 173 | return ret; |
174 | } | ||
159 | 175 | ||
160 | card->dev = &pdev->dev; | 176 | card->dev = &pdev->dev; |
161 | platform_set_drvdata(pdev, card); | 177 | platform_set_drvdata(pdev, card); |
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index f4c2417a8730..8987bf987e58 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c | |||
@@ -333,9 +333,6 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev) | |||
333 | spin_lock_init(&nuc900_audio->lock); | 333 | spin_lock_init(&nuc900_audio->lock); |
334 | 334 | ||
335 | nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 335 | nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
336 | if (!nuc900_audio->res) | ||
337 | return ret; | ||
338 | |||
339 | nuc900_audio->mmio = devm_ioremap_resource(&pdev->dev, | 336 | nuc900_audio->mmio = devm_ioremap_resource(&pdev->dev, |
340 | nuc900_audio->res); | 337 | nuc900_audio->res); |
341 | if (IS_ERR(nuc900_audio->mmio)) | 338 | if (IS_ERR(nuc900_audio->mmio)) |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 9f5d55e6b17a..daa78a0095fa 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | config SND_OMAP_SOC | 1 | config SND_OMAP_SOC |
2 | tristate "SoC Audio for the Texas Instruments OMAP chips" | 2 | tristate "SoC Audio for the Texas Instruments OMAP chips" |
3 | depends on ARCH_OMAP && DMA_OMAP | 3 | depends on (ARCH_OMAP && DMA_OMAP) || (ARCH_ARM && COMPILE_TEST) |
4 | select SND_SOC_DMAENGINE_PCM | 4 | select SND_DMAENGINE_PCM |
5 | 5 | ||
6 | config SND_OMAP_SOC_DMIC | 6 | config SND_OMAP_SOC_DMIC |
7 | tristate | 7 | tristate |
@@ -26,7 +26,7 @@ config SND_OMAP_SOC_N810 | |||
26 | 26 | ||
27 | config SND_OMAP_SOC_RX51 | 27 | config SND_OMAP_SOC_RX51 |
28 | tristate "SoC Audio support for Nokia RX-51" | 28 | tristate "SoC Audio support for Nokia RX-51" |
29 | depends on SND_OMAP_SOC && MACH_NOKIA_RX51 | 29 | depends on SND_OMAP_SOC && ARCH_ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) |
30 | select SND_OMAP_SOC_MCBSP | 30 | select SND_OMAP_SOC_MCBSP |
31 | select SND_SOC_TLV320AIC3X | 31 | select SND_SOC_TLV320AIC3X |
32 | select SND_SOC_TPA6130A2 | 32 | select SND_SOC_TPA6130A2 |
@@ -87,7 +87,7 @@ config SND_OMAP_SOC_OMAP_TWL4030 | |||
87 | 87 | ||
88 | config SND_OMAP_SOC_OMAP_ABE_TWL6040 | 88 | config SND_OMAP_SOC_OMAP_ABE_TWL6040 |
89 | tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" | 89 | tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" |
90 | depends on TWL6040_CORE && SND_OMAP_SOC && ARCH_OMAP4 | 90 | depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST) |
91 | select SND_OMAP_SOC_DMIC | 91 | select SND_OMAP_SOC_DMIC |
92 | select SND_OMAP_SOC_MCPDM | 92 | select SND_OMAP_SOC_MCPDM |
93 | select SND_SOC_TWL6040 | 93 | select SND_SOC_TWL6040 |
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 70cd5c7b2e14..ebb13906b3a0 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/mfd/twl6040.h> | 25 | #include <linux/mfd/twl6040.h> |
26 | #include <linux/platform_data/omap-abe-twl6040.h> | ||
27 | #include <linux/module.h> | 26 | #include <linux/module.h> |
28 | #include <linux/of.h> | 27 | #include <linux/of.h> |
29 | 28 | ||
@@ -166,19 +165,10 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
166 | {"AFMR", NULL, "Line In"}, | 165 | {"AFMR", NULL, "Line In"}, |
167 | }; | 166 | }; |
168 | 167 | ||
169 | static inline void twl6040_disconnect_pin(struct snd_soc_dapm_context *dapm, | ||
170 | int connected, char *pin) | ||
171 | { | ||
172 | if (!connected) | ||
173 | snd_soc_dapm_disable_pin(dapm, pin); | ||
174 | } | ||
175 | |||
176 | static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) | 168 | static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) |
177 | { | 169 | { |
178 | struct snd_soc_codec *codec = rtd->codec; | 170 | struct snd_soc_codec *codec = rtd->codec; |
179 | struct snd_soc_card *card = codec->card; | 171 | struct snd_soc_card *card = codec->card; |
180 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
181 | struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev); | ||
182 | struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); | 172 | struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); |
183 | int hs_trim; | 173 | int hs_trim; |
184 | int ret = 0; | 174 | int ret = 0; |
@@ -203,24 +193,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) | |||
203 | twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); | 193 | twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); |
204 | } | 194 | } |
205 | 195 | ||
206 | /* | ||
207 | * NULL pdata means we booted with DT. In this case the routing is | ||
208 | * provided and the card is fully routed, no need to mark pins. | ||
209 | */ | ||
210 | if (!pdata) | ||
211 | return ret; | ||
212 | |||
213 | /* Disable not connected paths if not used */ | ||
214 | twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); | ||
215 | twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); | ||
216 | twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); | ||
217 | twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); | ||
218 | twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vibrator"); | ||
219 | twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); | ||
220 | twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); | ||
221 | twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); | ||
222 | twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); | ||
223 | |||
224 | return ret; | 196 | return ret; |
225 | } | 197 | } |
226 | 198 | ||
@@ -274,13 +246,18 @@ static struct snd_soc_card omap_abe_card = { | |||
274 | 246 | ||
275 | static int omap_abe_probe(struct platform_device *pdev) | 247 | static int omap_abe_probe(struct platform_device *pdev) |
276 | { | 248 | { |
277 | struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); | ||
278 | struct device_node *node = pdev->dev.of_node; | 249 | struct device_node *node = pdev->dev.of_node; |
279 | struct snd_soc_card *card = &omap_abe_card; | 250 | struct snd_soc_card *card = &omap_abe_card; |
251 | struct device_node *dai_node; | ||
280 | struct abe_twl6040 *priv; | 252 | struct abe_twl6040 *priv; |
281 | int num_links = 0; | 253 | int num_links = 0; |
282 | int ret = 0; | 254 | int ret = 0; |
283 | 255 | ||
256 | if (!node) { | ||
257 | dev_err(&pdev->dev, "of node is missing.\n"); | ||
258 | return -ENODEV; | ||
259 | } | ||
260 | |||
284 | card->dev = &pdev->dev; | 261 | card->dev = &pdev->dev; |
285 | 262 | ||
286 | priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); | 263 | priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); |
@@ -289,78 +266,50 @@ static int omap_abe_probe(struct platform_device *pdev) | |||
289 | 266 | ||
290 | priv->dmic_codec_dev = ERR_PTR(-EINVAL); | 267 | priv->dmic_codec_dev = ERR_PTR(-EINVAL); |
291 | 268 | ||
292 | if (node) { | 269 | if (snd_soc_of_parse_card_name(card, "ti,model")) { |
293 | struct device_node *dai_node; | 270 | dev_err(&pdev->dev, "Card name is not provided\n"); |
294 | 271 | return -ENODEV; | |
295 | if (snd_soc_of_parse_card_name(card, "ti,model")) { | 272 | } |
296 | dev_err(&pdev->dev, "Card name is not provided\n"); | ||
297 | return -ENODEV; | ||
298 | } | ||
299 | 273 | ||
300 | ret = snd_soc_of_parse_audio_routing(card, | 274 | ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing"); |
301 | "ti,audio-routing"); | 275 | if (ret) { |
302 | if (ret) { | 276 | dev_err(&pdev->dev, "Error while parsing DAPM routing\n"); |
303 | dev_err(&pdev->dev, | 277 | return ret; |
304 | "Error while parsing DAPM routing\n"); | 278 | } |
305 | return ret; | ||
306 | } | ||
307 | 279 | ||
308 | dai_node = of_parse_phandle(node, "ti,mcpdm", 0); | 280 | dai_node = of_parse_phandle(node, "ti,mcpdm", 0); |
309 | if (!dai_node) { | 281 | if (!dai_node) { |
310 | dev_err(&pdev->dev, "McPDM node is not provided\n"); | 282 | dev_err(&pdev->dev, "McPDM node is not provided\n"); |
311 | return -EINVAL; | 283 | return -EINVAL; |
312 | } | 284 | } |
313 | abe_twl6040_dai_links[0].cpu_dai_name = NULL; | 285 | abe_twl6040_dai_links[0].cpu_dai_name = NULL; |
314 | abe_twl6040_dai_links[0].cpu_of_node = dai_node; | 286 | abe_twl6040_dai_links[0].cpu_of_node = dai_node; |
315 | 287 | ||
316 | dai_node = of_parse_phandle(node, "ti,dmic", 0); | 288 | dai_node = of_parse_phandle(node, "ti,dmic", 0); |
317 | if (dai_node) { | 289 | if (dai_node) { |
318 | num_links = 2; | 290 | num_links = 2; |
319 | abe_twl6040_dai_links[1].cpu_dai_name = NULL; | 291 | abe_twl6040_dai_links[1].cpu_dai_name = NULL; |
320 | abe_twl6040_dai_links[1].cpu_of_node = dai_node; | 292 | abe_twl6040_dai_links[1].cpu_of_node = dai_node; |
321 | 293 | ||
322 | priv->dmic_codec_dev = platform_device_register_simple( | 294 | priv->dmic_codec_dev = platform_device_register_simple( |
323 | "dmic-codec", -1, NULL, 0); | 295 | "dmic-codec", -1, NULL, 0); |
324 | if (IS_ERR(priv->dmic_codec_dev)) { | 296 | if (IS_ERR(priv->dmic_codec_dev)) { |
325 | dev_err(&pdev->dev, | 297 | dev_err(&pdev->dev, "Can't instantiate dmic-codec\n"); |
326 | "Can't instantiate dmic-codec\n"); | 298 | return PTR_ERR(priv->dmic_codec_dev); |
327 | return PTR_ERR(priv->dmic_codec_dev); | ||
328 | } | ||
329 | } else { | ||
330 | num_links = 1; | ||
331 | } | ||
332 | |||
333 | priv->jack_detection = of_property_read_bool(node, | ||
334 | "ti,jack-detection"); | ||
335 | of_property_read_u32(node, "ti,mclk-freq", | ||
336 | &priv->mclk_freq); | ||
337 | if (!priv->mclk_freq) { | ||
338 | dev_err(&pdev->dev, "MCLK frequency not provided\n"); | ||
339 | ret = -EINVAL; | ||
340 | goto err_unregister; | ||
341 | } | 299 | } |
342 | |||
343 | omap_abe_card.fully_routed = 1; | ||
344 | } else if (pdata) { | ||
345 | if (pdata->card_name) { | ||
346 | card->name = pdata->card_name; | ||
347 | } else { | ||
348 | dev_err(&pdev->dev, "Card name is not provided\n"); | ||
349 | return -ENODEV; | ||
350 | } | ||
351 | |||
352 | if (pdata->has_dmic) | ||
353 | num_links = 2; | ||
354 | else | ||
355 | num_links = 1; | ||
356 | |||
357 | priv->jack_detection = pdata->jack_detection; | ||
358 | priv->mclk_freq = pdata->mclk_freq; | ||
359 | } else { | 300 | } else { |
360 | dev_err(&pdev->dev, "Missing pdata\n"); | 301 | num_links = 1; |
361 | return -ENODEV; | 302 | } |
303 | |||
304 | priv->jack_detection = of_property_read_bool(node, "ti,jack-detection"); | ||
305 | of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq); | ||
306 | if (!priv->mclk_freq) { | ||
307 | dev_err(&pdev->dev, "MCLK frequency not provided\n"); | ||
308 | ret = -EINVAL; | ||
309 | goto err_unregister; | ||
362 | } | 310 | } |
363 | 311 | ||
312 | card->fully_routed = 1; | ||
364 | 313 | ||
365 | if (!priv->mclk_freq) { | 314 | if (!priv->mclk_freq) { |
366 | dev_err(&pdev->dev, "MCLK frequency missing\n"); | 315 | dev_err(&pdev->dev, "MCLK frequency missing\n"); |
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 4db1f8e6e172..12e566be3793 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c | |||
@@ -480,15 +480,12 @@ static int asoc_dmic_probe(struct platform_device *pdev) | |||
480 | dmic->dma_data.filter_data = "up_link"; | 480 | dmic->dma_data.filter_data = "up_link"; |
481 | 481 | ||
482 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); | 482 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); |
483 | if (!res) { | 483 | dmic->io_base = devm_ioremap_resource(&pdev->dev, res); |
484 | dev_err(dmic->dev, "invalid memory resource\n"); | 484 | if (IS_ERR(dmic->io_base)) { |
485 | ret = -ENODEV; | 485 | ret = PTR_ERR(dmic->io_base); |
486 | goto err_put_clk; | 486 | goto err_put_clk; |
487 | } | 487 | } |
488 | 488 | ||
489 | dmic->io_base = devm_ioremap_resource(&pdev->dev, res); | ||
490 | if (IS_ERR(dmic->io_base)) | ||
491 | return PTR_ERR(dmic->io_base); | ||
492 | 489 | ||
493 | ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component, | 490 | ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component, |
494 | &omap_dmic_dai, 1); | 491 | &omap_dmic_dai, 1); |
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 7483efb6dc67..6c19bba23570 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -433,6 +433,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
433 | /* Sample rate generator drives the FS */ | 433 | /* Sample rate generator drives the FS */ |
434 | regs->srgr2 |= FSGM; | 434 | regs->srgr2 |= FSGM; |
435 | break; | 435 | break; |
436 | case SND_SOC_DAIFMT_CBM_CFS: | ||
437 | /* McBSP slave. FS clock as output */ | ||
438 | regs->srgr2 |= FSGM; | ||
439 | regs->pcr0 |= FSXM; | ||
440 | break; | ||
436 | case SND_SOC_DAIFMT_CBM_CFM: | 441 | case SND_SOC_DAIFMT_CBM_CFM: |
437 | /* McBSP slave */ | 442 | /* McBSP slave */ |
438 | break; | 443 | break; |
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index a49dc52f8abc..90d2a7cd2563 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c | |||
@@ -480,9 +480,6 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) | |||
480 | mcpdm->dma_data[1].filter_data = "up_link"; | 480 | mcpdm->dma_data[1].filter_data = "up_link"; |
481 | 481 | ||
482 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); | 482 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); |
483 | if (res == NULL) | ||
484 | return -ENOMEM; | ||
485 | |||
486 | mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res); | 483 | mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res); |
487 | if (IS_ERR(mcpdm->io_base)) | 484 | if (IS_ERR(mcpdm->io_base)) |
488 | return PTR_ERR(mcpdm->io_base); | 485 | return PTR_ERR(mcpdm->io_base); |
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index b35809467547..4db74a083db1 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -11,7 +11,7 @@ config SND_PXA2XX_SOC | |||
11 | config SND_MMP_SOC | 11 | config SND_MMP_SOC |
12 | bool "Soc Audio for Marvell MMP chips" | 12 | bool "Soc Audio for Marvell MMP chips" |
13 | depends on ARCH_MMP | 13 | depends on ARCH_MMP |
14 | select SND_SOC_DMAENGINE_PCM | 14 | select SND_DMAENGINE_PCM |
15 | select SND_ARM | 15 | select SND_ARM |
16 | help | 16 | help |
17 | Say Y if you want to add support for codecs attached to | 17 | Say Y if you want to add support for codecs attached to |
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 4ad76099dd43..5b7d969f89a9 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c | |||
@@ -129,6 +129,7 @@ static struct snd_soc_dai_link brownstone_wm8994_dai[] = { | |||
129 | /* audio machine driver */ | 129 | /* audio machine driver */ |
130 | static struct snd_soc_card brownstone = { | 130 | static struct snd_soc_card brownstone = { |
131 | .name = "brownstone", | 131 | .name = "brownstone", |
132 | .owner = THIS_MODULE, | ||
132 | .dai_link = brownstone_wm8994_dai, | 133 | .dai_link = brownstone_wm8994_dai, |
133 | .num_links = ARRAY_SIZE(brownstone_wm8994_dai), | 134 | .num_links = ARRAY_SIZE(brownstone_wm8994_dai), |
134 | 135 | ||
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 97b711e12821..bbea7780eac6 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c | |||
@@ -56,8 +56,6 @@ | |||
56 | #include "pxa2xx-ac97.h" | 56 | #include "pxa2xx-ac97.h" |
57 | #include "../codecs/wm9713.h" | 57 | #include "../codecs/wm9713.h" |
58 | 58 | ||
59 | #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) | ||
60 | |||
61 | #define AC97_GPIO_PULL 0x58 | 59 | #define AC97_GPIO_PULL 0x58 |
62 | 60 | ||
63 | /* Use GPIO8 for rear speaker amplifier */ | 61 | /* Use GPIO8 for rear speaker amplifier */ |
@@ -133,10 +131,11 @@ static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) | |||
133 | unsigned short reg; | 131 | unsigned short reg; |
134 | 132 | ||
135 | /* Add mioa701 specific widgets */ | 133 | /* Add mioa701 specific widgets */ |
136 | snd_soc_dapm_new_controls(dapm, ARRAY_AND_SIZE(mioa701_dapm_widgets)); | 134 | snd_soc_dapm_new_controls(dapm, mioa701_dapm_widgets, |
135 | ARRAY_SIZE(mioa701_dapm_widgets)); | ||
137 | 136 | ||
138 | /* Set up mioa701 specific audio path audio_mapnects */ | 137 | /* Set up mioa701 specific audio path audio_mapnects */ |
139 | snd_soc_dapm_add_routes(dapm, ARRAY_AND_SIZE(audio_map)); | 138 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
140 | 139 | ||
141 | /* Prepare GPIO8 for rear speaker amplifier */ | 140 | /* Prepare GPIO8 for rear speaker amplifier */ |
142 | reg = codec->driver->read(codec, AC97_GPIO_CFG); | 141 | reg = codec->driver->read(codec, AC97_GPIO_CFG); |
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 5d57e071cdf5..8235e231d89c 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/dmaengine.h> | 17 | #include <linux/dmaengine.h> |
18 | #include <linux/platform_data/dma-mmp_tdma.h> | 18 | #include <linux/platform_data/dma-mmp_tdma.h> |
19 | #include <linux/platform_data/mmp_audio.h> | 19 | #include <linux/platform_data/mmp_audio.h> |
20 | |||
20 | #include <sound/pxa2xx-lib.h> | 21 | #include <sound/pxa2xx-lib.h> |
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
@@ -67,7 +68,7 @@ static int mmp_pcm_hw_params(struct snd_pcm_substream *substream, | |||
67 | { | 68 | { |
68 | struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); | 69 | struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); |
69 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 70 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
70 | struct pxa2xx_pcm_dma_params *dma_params; | 71 | struct snd_dmaengine_dai_dma_data *dma_params; |
71 | struct dma_slave_config slave_config; | 72 | struct dma_slave_config slave_config; |
72 | int ret; | 73 | int ret; |
73 | 74 | ||
@@ -80,10 +81,10 @@ static int mmp_pcm_hw_params(struct snd_pcm_substream *substream, | |||
80 | return ret; | 81 | return ret; |
81 | 82 | ||
82 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 83 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
83 | slave_config.dst_addr = dma_params->dev_addr; | 84 | slave_config.dst_addr = dma_params->addr; |
84 | slave_config.dst_maxburst = 4; | 85 | slave_config.dst_maxburst = 4; |
85 | } else { | 86 | } else { |
86 | slave_config.src_addr = dma_params->dev_addr; | 87 | slave_config.src_addr = dma_params->addr; |
87 | slave_config.src_maxburst = 4; | 88 | slave_config.src_maxburst = 4; |
88 | } | 89 | } |
89 | 90 | ||
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 62142ce367c7..41752a5fe3b0 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c | |||
@@ -27,12 +27,15 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/pxa2xx_ssp.h> | 28 | #include <linux/pxa2xx_ssp.h> |
29 | #include <linux/io.h> | 29 | #include <linux/io.h> |
30 | #include <linux/dmaengine.h> | ||
31 | |||
30 | #include <sound/core.h> | 32 | #include <sound/core.h> |
31 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
32 | #include <sound/initval.h> | 34 | #include <sound/initval.h> |
33 | #include <sound/pcm_params.h> | 35 | #include <sound/pcm_params.h> |
34 | #include <sound/soc.h> | 36 | #include <sound/soc.h> |
35 | #include <sound/pxa2xx-lib.h> | 37 | #include <sound/pxa2xx-lib.h> |
38 | #include <sound/dmaengine_pcm.h> | ||
36 | #include "mmp-sspa.h" | 39 | #include "mmp-sspa.h" |
37 | 40 | ||
38 | /* | 41 | /* |
@@ -40,7 +43,7 @@ | |||
40 | */ | 43 | */ |
41 | struct sspa_priv { | 44 | struct sspa_priv { |
42 | struct ssp_device *sspa; | 45 | struct ssp_device *sspa; |
43 | struct pxa2xx_pcm_dma_params *dma_params; | 46 | struct snd_dmaengine_dai_dma_data *dma_params; |
44 | struct clk *audio_clk; | 47 | struct clk *audio_clk; |
45 | struct clk *sysclk; | 48 | struct clk *sysclk; |
46 | int dai_fmt; | 49 | int dai_fmt; |
@@ -266,7 +269,7 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream, | |||
266 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 269 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
267 | struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai); | 270 | struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai); |
268 | struct ssp_device *sspa = sspa_priv->sspa; | 271 | struct ssp_device *sspa = sspa_priv->sspa; |
269 | struct pxa2xx_pcm_dma_params *dma_params; | 272 | struct snd_dmaengine_dai_dma_data *dma_params; |
270 | u32 sspa_ctrl; | 273 | u32 sspa_ctrl; |
271 | 274 | ||
272 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 275 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
@@ -309,7 +312,7 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream, | |||
309 | } | 312 | } |
310 | 313 | ||
311 | dma_params = &sspa_priv->dma_params[substream->stream]; | 314 | dma_params = &sspa_priv->dma_params[substream->stream]; |
312 | dma_params->dev_addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | 315 | dma_params->addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? |
313 | (sspa->phys_base + SSPA_TXD) : | 316 | (sspa->phys_base + SSPA_TXD) : |
314 | (sspa->phys_base + SSPA_RXD); | 317 | (sspa->phys_base + SSPA_RXD); |
315 | snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params); | 318 | snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params); |
@@ -425,14 +428,12 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev) | |||
425 | return -ENOMEM; | 428 | return -ENOMEM; |
426 | 429 | ||
427 | priv->dma_params = devm_kzalloc(&pdev->dev, | 430 | priv->dma_params = devm_kzalloc(&pdev->dev, |
428 | 2 * sizeof(struct pxa2xx_pcm_dma_params), GFP_KERNEL); | 431 | 2 * sizeof(struct snd_dmaengine_dai_dma_data), |
432 | GFP_KERNEL); | ||
429 | if (priv->dma_params == NULL) | 433 | if (priv->dma_params == NULL) |
430 | return -ENOMEM; | 434 | return -ENOMEM; |
431 | 435 | ||
432 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 436 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
433 | if (res == NULL) | ||
434 | return -ENOMEM; | ||
435 | |||
436 | priv->sspa->mmio_base = devm_ioremap_resource(&pdev->dev, res); | 437 | priv->sspa->mmio_base = devm_ioremap_resource(&pdev->dev, res); |
437 | if (IS_ERR(priv->sspa->mmio_base)) | 438 | if (IS_ERR(priv->sspa->mmio_base)) |
438 | return PTR_ERR(priv->sspa->mmio_base); | 439 | return PTR_ERR(priv->sspa->mmio_base); |
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 6f4dd7543e82..a3119a00d8fa 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/clk.h> | 21 | #include <linux/clk.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/pxa2xx_ssp.h> | 23 | #include <linux/pxa2xx_ssp.h> |
24 | #include <linux/of.h> | ||
25 | #include <linux/dmaengine.h> | ||
24 | 26 | ||
25 | #include <asm/irq.h> | 27 | #include <asm/irq.h> |
26 | 28 | ||
@@ -30,9 +32,9 @@ | |||
30 | #include <sound/pcm_params.h> | 32 | #include <sound/pcm_params.h> |
31 | #include <sound/soc.h> | 33 | #include <sound/soc.h> |
32 | #include <sound/pxa2xx-lib.h> | 34 | #include <sound/pxa2xx-lib.h> |
35 | #include <sound/dmaengine_pcm.h> | ||
33 | 36 | ||
34 | #include <mach/hardware.h> | 37 | #include <mach/hardware.h> |
35 | #include <mach/dma.h> | ||
36 | 38 | ||
37 | #include "../../arm/pxa2xx-pcm.h" | 39 | #include "../../arm/pxa2xx-pcm.h" |
38 | #include "pxa-ssp.h" | 40 | #include "pxa-ssp.h" |
@@ -79,27 +81,13 @@ static void pxa_ssp_disable(struct ssp_device *ssp) | |||
79 | __raw_writel(sscr0, ssp->mmio_base + SSCR0); | 81 | __raw_writel(sscr0, ssp->mmio_base + SSCR0); |
80 | } | 82 | } |
81 | 83 | ||
82 | struct pxa2xx_pcm_dma_data { | ||
83 | struct pxa2xx_pcm_dma_params params; | ||
84 | char name[20]; | ||
85 | }; | ||
86 | |||
87 | static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4, | 84 | static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4, |
88 | int out, struct pxa2xx_pcm_dma_params *dma_data) | 85 | int out, struct snd_dmaengine_dai_dma_data *dma) |
89 | { | 86 | { |
90 | struct pxa2xx_pcm_dma_data *dma; | 87 | dma->addr_width = width4 ? DMA_SLAVE_BUSWIDTH_4_BYTES : |
91 | 88 | DMA_SLAVE_BUSWIDTH_2_BYTES; | |
92 | dma = container_of(dma_data, struct pxa2xx_pcm_dma_data, params); | 89 | dma->maxburst = 16; |
93 | 90 | dma->addr = ssp->phys_base + SSDR; | |
94 | snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id, | ||
95 | width4 ? "32-bit" : "16-bit", out ? "out" : "in"); | ||
96 | |||
97 | dma->params.name = dma->name; | ||
98 | dma->params.drcmr = &DRCMR(out ? ssp->drcmr_tx : ssp->drcmr_rx); | ||
99 | dma->params.dcmd = (out ? (DCMD_INCSRCADDR | DCMD_FLOWTRG) : | ||
100 | (DCMD_INCTRGADDR | DCMD_FLOWSRC)) | | ||
101 | (width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16; | ||
102 | dma->params.dev_addr = ssp->phys_base + SSDR; | ||
103 | } | 91 | } |
104 | 92 | ||
105 | static int pxa_ssp_startup(struct snd_pcm_substream *substream, | 93 | static int pxa_ssp_startup(struct snd_pcm_substream *substream, |
@@ -107,7 +95,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, | |||
107 | { | 95 | { |
108 | struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); | 96 | struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); |
109 | struct ssp_device *ssp = priv->ssp; | 97 | struct ssp_device *ssp = priv->ssp; |
110 | struct pxa2xx_pcm_dma_data *dma; | 98 | struct snd_dmaengine_dai_dma_data *dma; |
111 | int ret = 0; | 99 | int ret = 0; |
112 | 100 | ||
113 | if (!cpu_dai->active) { | 101 | if (!cpu_dai->active) { |
@@ -115,10 +103,14 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, | |||
115 | pxa_ssp_disable(ssp); | 103 | pxa_ssp_disable(ssp); |
116 | } | 104 | } |
117 | 105 | ||
118 | dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL); | 106 | dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL); |
119 | if (!dma) | 107 | if (!dma) |
120 | return -ENOMEM; | 108 | return -ENOMEM; |
121 | snd_soc_dai_set_dma_data(cpu_dai, substream, &dma->params); | 109 | |
110 | dma->filter_data = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | ||
111 | &ssp->drcmr_tx : &ssp->drcmr_rx; | ||
112 | |||
113 | snd_soc_dai_set_dma_data(cpu_dai, substream, dma); | ||
122 | 114 | ||
123 | return ret; | 115 | return ret; |
124 | } | 116 | } |
@@ -559,7 +551,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, | |||
559 | u32 sspsp; | 551 | u32 sspsp; |
560 | int width = snd_pcm_format_physical_width(params_format(params)); | 552 | int width = snd_pcm_format_physical_width(params_format(params)); |
561 | int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf; | 553 | int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf; |
562 | struct pxa2xx_pcm_dma_params *dma_data; | 554 | struct snd_dmaengine_dai_dma_data *dma_data; |
563 | 555 | ||
564 | dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); | 556 | dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); |
565 | 557 | ||
@@ -719,6 +711,7 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, | |||
719 | 711 | ||
720 | static int pxa_ssp_probe(struct snd_soc_dai *dai) | 712 | static int pxa_ssp_probe(struct snd_soc_dai *dai) |
721 | { | 713 | { |
714 | struct device *dev = dai->dev; | ||
722 | struct ssp_priv *priv; | 715 | struct ssp_priv *priv; |
723 | int ret; | 716 | int ret; |
724 | 717 | ||
@@ -726,10 +719,26 @@ static int pxa_ssp_probe(struct snd_soc_dai *dai) | |||
726 | if (!priv) | 719 | if (!priv) |
727 | return -ENOMEM; | 720 | return -ENOMEM; |
728 | 721 | ||
729 | priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio"); | 722 | if (dev->of_node) { |
730 | if (priv->ssp == NULL) { | 723 | struct device_node *ssp_handle; |
731 | ret = -ENODEV; | 724 | |
732 | goto err_priv; | 725 | ssp_handle = of_parse_phandle(dev->of_node, "port", 0); |
726 | if (!ssp_handle) { | ||
727 | dev_err(dev, "unable to get 'port' phandle\n"); | ||
728 | return -ENODEV; | ||
729 | } | ||
730 | |||
731 | priv->ssp = pxa_ssp_request_of(ssp_handle, "SoC audio"); | ||
732 | if (priv->ssp == NULL) { | ||
733 | ret = -ENODEV; | ||
734 | goto err_priv; | ||
735 | } | ||
736 | } else { | ||
737 | priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio"); | ||
738 | if (priv->ssp == NULL) { | ||
739 | ret = -ENODEV; | ||
740 | goto err_priv; | ||
741 | } | ||
733 | } | 742 | } |
734 | 743 | ||
735 | priv->dai_fmt = (unsigned int) -1; | 744 | priv->dai_fmt = (unsigned int) -1; |
@@ -798,6 +807,12 @@ static const struct snd_soc_component_driver pxa_ssp_component = { | |||
798 | .name = "pxa-ssp", | 807 | .name = "pxa-ssp", |
799 | }; | 808 | }; |
800 | 809 | ||
810 | #ifdef CONFIG_OF | ||
811 | static const struct of_device_id pxa_ssp_of_ids[] = { | ||
812 | { .compatible = "mrvl,pxa-ssp-dai" }, | ||
813 | }; | ||
814 | #endif | ||
815 | |||
801 | static int asoc_ssp_probe(struct platform_device *pdev) | 816 | static int asoc_ssp_probe(struct platform_device *pdev) |
802 | { | 817 | { |
803 | return snd_soc_register_component(&pdev->dev, &pxa_ssp_component, | 818 | return snd_soc_register_component(&pdev->dev, &pxa_ssp_component, |
@@ -812,8 +827,9 @@ static int asoc_ssp_remove(struct platform_device *pdev) | |||
812 | 827 | ||
813 | static struct platform_driver asoc_ssp_driver = { | 828 | static struct platform_driver asoc_ssp_driver = { |
814 | .driver = { | 829 | .driver = { |
815 | .name = "pxa-ssp-dai", | 830 | .name = "pxa-ssp-dai", |
816 | .owner = THIS_MODULE, | 831 | .owner = THIS_MODULE, |
832 | .of_match_table = of_match_ptr(pxa_ssp_of_ids), | ||
817 | }, | 833 | }, |
818 | 834 | ||
819 | .probe = asoc_ssp_probe, | 835 | .probe = asoc_ssp_probe, |
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 1475515712e6..f1059d999de6 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -14,15 +14,16 @@ | |||
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/dmaengine.h> | ||
17 | 18 | ||
18 | #include <sound/core.h> | 19 | #include <sound/core.h> |
19 | #include <sound/ac97_codec.h> | 20 | #include <sound/ac97_codec.h> |
20 | #include <sound/soc.h> | 21 | #include <sound/soc.h> |
21 | #include <sound/pxa2xx-lib.h> | 22 | #include <sound/pxa2xx-lib.h> |
23 | #include <sound/dmaengine_pcm.h> | ||
22 | 24 | ||
23 | #include <mach/hardware.h> | 25 | #include <mach/hardware.h> |
24 | #include <mach/regs-ac97.h> | 26 | #include <mach/regs-ac97.h> |
25 | #include <mach/dma.h> | ||
26 | #include <mach/audio.h> | 27 | #include <mach/audio.h> |
27 | 28 | ||
28 | #include "pxa2xx-ac97.h" | 29 | #include "pxa2xx-ac97.h" |
@@ -48,44 +49,44 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = { | |||
48 | .reset = pxa2xx_ac97_cold_reset, | 49 | .reset = pxa2xx_ac97_cold_reset, |
49 | }; | 50 | }; |
50 | 51 | ||
51 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { | 52 | static unsigned long pxa2xx_ac97_pcm_stereo_in_req = 12; |
52 | .name = "AC97 PCM Stereo out", | 53 | static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = { |
53 | .dev_addr = __PREG(PCDR), | 54 | .addr = __PREG(PCDR), |
54 | .drcmr = &DRCMR(12), | 55 | .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, |
55 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | 56 | .maxburst = 32, |
56 | DCMD_BURST32 | DCMD_WIDTH4, | 57 | .filter_data = &pxa2xx_ac97_pcm_stereo_in_req, |
57 | }; | 58 | }; |
58 | 59 | ||
59 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = { | 60 | static unsigned long pxa2xx_ac97_pcm_stereo_out_req = 11; |
60 | .name = "AC97 PCM Stereo in", | 61 | static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = { |
61 | .dev_addr = __PREG(PCDR), | 62 | .addr = __PREG(PCDR), |
62 | .drcmr = &DRCMR(11), | 63 | .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, |
63 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | 64 | .maxburst = 32, |
64 | DCMD_BURST32 | DCMD_WIDTH4, | 65 | .filter_data = &pxa2xx_ac97_pcm_stereo_out_req, |
65 | }; | 66 | }; |
66 | 67 | ||
67 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = { | 68 | static unsigned long pxa2xx_ac97_pcm_aux_mono_out_req = 10; |
68 | .name = "AC97 Aux PCM (Slot 5) Mono out", | 69 | static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = { |
69 | .dev_addr = __PREG(MODR), | 70 | .addr = __PREG(MODR), |
70 | .drcmr = &DRCMR(10), | 71 | .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, |
71 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | 72 | .maxburst = 16, |
72 | DCMD_BURST16 | DCMD_WIDTH2, | 73 | .filter_data = &pxa2xx_ac97_pcm_aux_mono_out_req, |
73 | }; | 74 | }; |
74 | 75 | ||
75 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = { | 76 | static unsigned long pxa2xx_ac97_pcm_aux_mono_in_req = 9; |
76 | .name = "AC97 Aux PCM (Slot 5) Mono in", | 77 | static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = { |
77 | .dev_addr = __PREG(MODR), | 78 | .addr = __PREG(MODR), |
78 | .drcmr = &DRCMR(9), | 79 | .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, |
79 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | 80 | .maxburst = 16, |
80 | DCMD_BURST16 | DCMD_WIDTH2, | 81 | .filter_data = &pxa2xx_ac97_pcm_aux_mono_in_req, |
81 | }; | 82 | }; |
82 | 83 | ||
83 | static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { | 84 | static unsigned long pxa2xx_ac97_pcm_aux_mic_mono_req = 8; |
84 | .name = "AC97 Mic PCM (Slot 6) Mono in", | 85 | static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = { |
85 | .dev_addr = __PREG(MCDR), | 86 | .addr = __PREG(MCDR), |
86 | .drcmr = &DRCMR(8), | 87 | .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, |
87 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | 88 | .maxburst = 16, |
88 | DCMD_BURST16 | DCMD_WIDTH2, | 89 | .filter_data = &pxa2xx_ac97_pcm_aux_mic_mono_req, |
89 | }; | 90 | }; |
90 | 91 | ||
91 | #ifdef CONFIG_PM | 92 | #ifdef CONFIG_PM |
@@ -119,7 +120,7 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, | |||
119 | struct snd_pcm_hw_params *params, | 120 | struct snd_pcm_hw_params *params, |
120 | struct snd_soc_dai *cpu_dai) | 121 | struct snd_soc_dai *cpu_dai) |
121 | { | 122 | { |
122 | struct pxa2xx_pcm_dma_params *dma_data; | 123 | struct snd_dmaengine_dai_dma_data *dma_data; |
123 | 124 | ||
124 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 125 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
125 | dma_data = &pxa2xx_ac97_pcm_stereo_out; | 126 | dma_data = &pxa2xx_ac97_pcm_stereo_out; |
@@ -135,7 +136,7 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, | |||
135 | struct snd_pcm_hw_params *params, | 136 | struct snd_pcm_hw_params *params, |
136 | struct snd_soc_dai *cpu_dai) | 137 | struct snd_soc_dai *cpu_dai) |
137 | { | 138 | { |
138 | struct pxa2xx_pcm_dma_params *dma_data; | 139 | struct snd_dmaengine_dai_dma_data *dma_data; |
139 | 140 | ||
140 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 141 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
141 | dma_data = &pxa2xx_ac97_pcm_aux_mono_out; | 142 | dma_data = &pxa2xx_ac97_pcm_aux_mono_out; |
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index f7ca71664112..d5340a088858 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
@@ -23,9 +23,9 @@ | |||
23 | #include <sound/initval.h> | 23 | #include <sound/initval.h> |
24 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
25 | #include <sound/pxa2xx-lib.h> | 25 | #include <sound/pxa2xx-lib.h> |
26 | #include <sound/dmaengine_pcm.h> | ||
26 | 27 | ||
27 | #include <mach/hardware.h> | 28 | #include <mach/hardware.h> |
28 | #include <mach/dma.h> | ||
29 | #include <mach/audio.h> | 29 | #include <mach/audio.h> |
30 | 30 | ||
31 | #include "pxa2xx-i2s.h" | 31 | #include "pxa2xx-i2s.h" |
@@ -82,20 +82,20 @@ static struct pxa_i2s_port pxa_i2s; | |||
82 | static struct clk *clk_i2s; | 82 | static struct clk *clk_i2s; |
83 | static int clk_ena = 0; | 83 | static int clk_ena = 0; |
84 | 84 | ||
85 | static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { | 85 | static unsigned long pxa2xx_i2s_pcm_stereo_out_req = 3; |
86 | .name = "I2S PCM Stereo out", | 86 | static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = { |
87 | .dev_addr = __PREG(SADR), | 87 | .addr = __PREG(SADR), |
88 | .drcmr = &DRCMR(3), | 88 | .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, |
89 | .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | | 89 | .maxburst = 32, |
90 | DCMD_BURST32 | DCMD_WIDTH4, | 90 | .filter_data = &pxa2xx_i2s_pcm_stereo_out_req, |
91 | }; | 91 | }; |
92 | 92 | ||
93 | static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = { | 93 | static unsigned long pxa2xx_i2s_pcm_stereo_in_req = 2; |
94 | .name = "I2S PCM Stereo in", | 94 | static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = { |
95 | .dev_addr = __PREG(SADR), | 95 | .addr = __PREG(SADR), |
96 | .drcmr = &DRCMR(2), | 96 | .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, |
97 | .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | | 97 | .maxburst = 32, |
98 | DCMD_BURST32 | DCMD_WIDTH4, | 98 | .filter_data = &pxa2xx_i2s_pcm_stereo_in_req, |
99 | }; | 99 | }; |
100 | 100 | ||
101 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, | 101 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, |
@@ -163,7 +163,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
163 | struct snd_pcm_hw_params *params, | 163 | struct snd_pcm_hw_params *params, |
164 | struct snd_soc_dai *dai) | 164 | struct snd_soc_dai *dai) |
165 | { | 165 | { |
166 | struct pxa2xx_pcm_dma_params *dma_data; | 166 | struct snd_dmaengine_dai_dma_data *dma_data; |
167 | 167 | ||
168 | BUG_ON(IS_ERR(clk_i2s)); | 168 | BUG_ON(IS_ERR(clk_i2s)); |
169 | clk_prepare_enable(clk_i2s); | 169 | clk_prepare_enable(clk_i2s); |
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index ecff116cb7b0..806da27b8b67 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
@@ -12,10 +12,13 @@ | |||
12 | 12 | ||
13 | #include <linux/dma-mapping.h> | 13 | #include <linux/dma-mapping.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/dmaengine.h> | ||
16 | #include <linux/of.h> | ||
15 | 17 | ||
16 | #include <sound/core.h> | 18 | #include <sound/core.h> |
17 | #include <sound/soc.h> | 19 | #include <sound/soc.h> |
18 | #include <sound/pxa2xx-lib.h> | 20 | #include <sound/pxa2xx-lib.h> |
21 | #include <sound/dmaengine_pcm.h> | ||
19 | 22 | ||
20 | #include "../../arm/pxa2xx-pcm.h" | 23 | #include "../../arm/pxa2xx-pcm.h" |
21 | 24 | ||
@@ -25,7 +28,7 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
25 | struct snd_pcm_runtime *runtime = substream->runtime; | 28 | struct snd_pcm_runtime *runtime = substream->runtime; |
26 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | 29 | struct pxa2xx_runtime_data *prtd = runtime->private_data; |
27 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 30 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
28 | struct pxa2xx_pcm_dma_params *dma; | 31 | struct snd_dmaengine_dai_dma_data *dma; |
29 | int ret; | 32 | int ret; |
30 | 33 | ||
31 | dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | 34 | dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); |
@@ -39,7 +42,7 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
39 | * with different params */ | 42 | * with different params */ |
40 | if (prtd->params == NULL) { | 43 | if (prtd->params == NULL) { |
41 | prtd->params = dma; | 44 | prtd->params = dma; |
42 | ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, | 45 | ret = pxa_request_dma("name", DMA_PRIO_LOW, |
43 | pxa2xx_pcm_dma_irq, substream); | 46 | pxa2xx_pcm_dma_irq, substream); |
44 | if (ret < 0) | 47 | if (ret < 0) |
45 | return ret; | 48 | return ret; |
@@ -47,7 +50,7 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
47 | } else if (prtd->params != dma) { | 50 | } else if (prtd->params != dma) { |
48 | pxa_free_dma(prtd->dma_ch); | 51 | pxa_free_dma(prtd->dma_ch); |
49 | prtd->params = dma; | 52 | prtd->params = dma; |
50 | ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, | 53 | ret = pxa_request_dma("name", DMA_PRIO_LOW, |
51 | pxa2xx_pcm_dma_irq, substream); | 54 | pxa2xx_pcm_dma_irq, substream); |
52 | if (ret < 0) | 55 | if (ret < 0) |
53 | return ret; | 56 | return ret; |
@@ -131,10 +134,18 @@ static int pxa2xx_soc_platform_remove(struct platform_device *pdev) | |||
131 | return 0; | 134 | return 0; |
132 | } | 135 | } |
133 | 136 | ||
137 | #ifdef CONFIG_OF | ||
138 | static const struct of_device_id snd_soc_pxa_audio_match[] = { | ||
139 | { .compatible = "mrvl,pxa-pcm-audio" }, | ||
140 | { } | ||
141 | }; | ||
142 | #endif | ||
143 | |||
134 | static struct platform_driver pxa_pcm_driver = { | 144 | static struct platform_driver pxa_pcm_driver = { |
135 | .driver = { | 145 | .driver = { |
136 | .name = "pxa-pcm-audio", | 146 | .name = "pxa-pcm-audio", |
137 | .owner = THIS_MODULE, | 147 | .owner = THIS_MODULE, |
148 | .of_match_table = of_match_ptr(snd_soc_pxa_audio_match), | ||
138 | }, | 149 | }, |
139 | 150 | ||
140 | .probe = pxa2xx_soc_platform_probe, | 151 | .probe = pxa2xx_soc_platform_probe, |
diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c index f4ea4f6663a2..13c9ee0cb83b 100644 --- a/sound/soc/pxa/ttc-dkb.c +++ b/sound/soc/pxa/ttc-dkb.c | |||
@@ -122,6 +122,7 @@ static struct snd_soc_dai_link ttc_pm860x_hifi_dai[] = { | |||
122 | /* ttc/td audio machine driver */ | 122 | /* ttc/td audio machine driver */ |
123 | static struct snd_soc_card ttc_dkb_card = { | 123 | static struct snd_soc_card ttc_dkb_card = { |
124 | .name = "ttc-dkb-hifi", | 124 | .name = "ttc-dkb-hifi", |
125 | .owner = THIS_MODULE, | ||
125 | .dai_link = ttc_pm860x_hifi_dai, | 126 | .dai_link = ttc_pm860x_hifi_dai, |
126 | .num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai), | 127 | .num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai), |
127 | 128 | ||
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c index 58cfb1eb7dd3..945e8abdc10f 100644 --- a/sound/soc/s6000/s6105-ipcam.c +++ b/sound/soc/s6000/s6105-ipcam.c | |||
@@ -192,7 +192,7 @@ static struct snd_soc_card snd_soc_card_s6105 = { | |||
192 | .num_links = 1, | 192 | .num_links = 1, |
193 | }; | 193 | }; |
194 | 194 | ||
195 | static struct s6000_snd_platform_data __initdata s6105_snd_data = { | 195 | static struct s6000_snd_platform_data s6105_snd_data __initdata = { |
196 | .wide = 0, | 196 | .wide = 0, |
197 | .channel_in = 0, | 197 | .channel_in = 0, |
198 | .channel_out = 1, | 198 | .channel_out = 1, |
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 2dd623fa3882..2acf987844e8 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c | |||
@@ -404,18 +404,13 @@ static int s3c_ac97_probe(struct platform_device *pdev) | |||
404 | return -ENXIO; | 404 | return -ENXIO; |
405 | } | 405 | } |
406 | 406 | ||
407 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
408 | if (!mem_res) { | ||
409 | dev_err(&pdev->dev, "Unable to get register resource\n"); | ||
410 | return -ENXIO; | ||
411 | } | ||
412 | |||
413 | irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 407 | irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
414 | if (!irq_res) { | 408 | if (!irq_res) { |
415 | dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); | 409 | dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); |
416 | return -ENXIO; | 410 | return -ENXIO; |
417 | } | 411 | } |
418 | 412 | ||
413 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
419 | s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res); | 414 | s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res); |
420 | if (IS_ERR(s3c_ac97.regs)) | 415 | if (IS_ERR(s3c_ac97.regs)) |
421 | return PTR_ERR(s3c_ac97.regs); | 416 | return PTR_ERR(s3c_ac97.regs); |
@@ -462,7 +457,7 @@ static int s3c_ac97_probe(struct platform_device *pdev) | |||
462 | if (ret) | 457 | if (ret) |
463 | goto err5; | 458 | goto err5; |
464 | 459 | ||
465 | ret = asoc_dma_platform_register(&pdev->dev); | 460 | ret = samsung_asoc_dma_platform_register(&pdev->dev); |
466 | if (ret) { | 461 | if (ret) { |
467 | dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); | 462 | dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); |
468 | goto err6; | 463 | goto err6; |
@@ -485,7 +480,7 @@ static int s3c_ac97_remove(struct platform_device *pdev) | |||
485 | { | 480 | { |
486 | struct resource *irq_res; | 481 | struct resource *irq_res; |
487 | 482 | ||
488 | asoc_dma_platform_unregister(&pdev->dev); | 483 | samsung_asoc_dma_platform_unregister(&pdev->dev); |
489 | snd_soc_unregister_component(&pdev->dev); | 484 | snd_soc_unregister_component(&pdev->dev); |
490 | 485 | ||
491 | irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 486 | irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 21b79262010e..a0c67f60f594 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c | |||
@@ -176,6 +176,10 @@ static int dma_hw_params(struct snd_pcm_substream *substream, | |||
176 | prtd->params->ch = prtd->params->ops->request( | 176 | prtd->params->ch = prtd->params->ops->request( |
177 | prtd->params->channel, &req, rtd->cpu_dai->dev, | 177 | prtd->params->channel, &req, rtd->cpu_dai->dev, |
178 | prtd->params->ch_name); | 178 | prtd->params->ch_name); |
179 | if (!prtd->params->ch) { | ||
180 | pr_err("Failed to allocate DMA channel\n"); | ||
181 | return -ENXIO; | ||
182 | } | ||
179 | prtd->params->ops->config(prtd->params->ch, &config); | 183 | prtd->params->ops->config(prtd->params->ch, &config); |
180 | } | 184 | } |
181 | 185 | ||
@@ -433,17 +437,17 @@ static struct snd_soc_platform_driver samsung_asoc_platform = { | |||
433 | .pcm_free = dma_free_dma_buffers, | 437 | .pcm_free = dma_free_dma_buffers, |
434 | }; | 438 | }; |
435 | 439 | ||
436 | int asoc_dma_platform_register(struct device *dev) | 440 | int samsung_asoc_dma_platform_register(struct device *dev) |
437 | { | 441 | { |
438 | return snd_soc_register_platform(dev, &samsung_asoc_platform); | 442 | return snd_soc_register_platform(dev, &samsung_asoc_platform); |
439 | } | 443 | } |
440 | EXPORT_SYMBOL_GPL(asoc_dma_platform_register); | 444 | EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register); |
441 | 445 | ||
442 | void asoc_dma_platform_unregister(struct device *dev) | 446 | void samsung_asoc_dma_platform_unregister(struct device *dev) |
443 | { | 447 | { |
444 | snd_soc_unregister_platform(dev); | 448 | snd_soc_unregister_platform(dev); |
445 | } | 449 | } |
446 | EXPORT_SYMBOL_GPL(asoc_dma_platform_unregister); | 450 | EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister); |
447 | 451 | ||
448 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | 452 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); |
449 | MODULE_DESCRIPTION("Samsung ASoC DMA Driver"); | 453 | MODULE_DESCRIPTION("Samsung ASoC DMA Driver"); |
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 189a7a6d5020..0e86315a3eaf 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h | |||
@@ -22,7 +22,7 @@ struct s3c_dma_params { | |||
22 | char *ch_name; | 22 | char *ch_name; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | int asoc_dma_platform_register(struct device *dev); | 25 | int samsung_asoc_dma_platform_register(struct device *dev); |
26 | void asoc_dma_platform_unregister(struct device *dev); | 26 | void samsung_asoc_dma_platform_unregister(struct device *dev); |
27 | 27 | ||
28 | #endif | 28 | #endif |
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h index c0e6d9a19efc..821a50231002 100644 --- a/sound/soc/samsung/i2s-regs.h +++ b/sound/soc/samsung/i2s-regs.h | |||
@@ -31,6 +31,10 @@ | |||
31 | #define I2SLVL1ADDR 0x34 | 31 | #define I2SLVL1ADDR 0x34 |
32 | #define I2SLVL2ADDR 0x38 | 32 | #define I2SLVL2ADDR 0x38 |
33 | #define I2SLVL3ADDR 0x3c | 33 | #define I2SLVL3ADDR 0x3c |
34 | #define I2SSTR1 0x40 | ||
35 | #define I2SVER 0x44 | ||
36 | #define I2SFIC2 0x48 | ||
37 | #define I2STDM 0x4c | ||
34 | 38 | ||
35 | #define CON_RSTCLR (1 << 31) | 39 | #define CON_RSTCLR (1 << 31) |
36 | #define CON_FRXOFSTATUS (1 << 26) | 40 | #define CON_FRXOFSTATUS (1 << 26) |
@@ -95,24 +99,39 @@ | |||
95 | #define MOD_RXONLY (1 << 8) | 99 | #define MOD_RXONLY (1 << 8) |
96 | #define MOD_TXRX (2 << 8) | 100 | #define MOD_TXRX (2 << 8) |
97 | #define MOD_MASK (3 << 8) | 101 | #define MOD_MASK (3 << 8) |
98 | #define MOD_LR_LLOW (0 << 7) | 102 | #define MOD_LRP_SHIFT 7 |
99 | #define MOD_LR_RLOW (1 << 7) | 103 | #define MOD_LR_LLOW 0 |
100 | #define MOD_SDF_IIS (0 << 5) | 104 | #define MOD_LR_RLOW 1 |
101 | #define MOD_SDF_MSB (1 << 5) | 105 | #define MOD_SDF_SHIFT 5 |
102 | #define MOD_SDF_LSB (2 << 5) | 106 | #define MOD_SDF_IIS 0 |
103 | #define MOD_SDF_MASK (3 << 5) | 107 | #define MOD_SDF_MSB 1 |
104 | #define MOD_RCLK_256FS (0 << 3) | 108 | #define MOD_SDF_LSB 2 |
105 | #define MOD_RCLK_512FS (1 << 3) | 109 | #define MOD_SDF_MASK 3 |
106 | #define MOD_RCLK_384FS (2 << 3) | 110 | #define MOD_RCLK_SHIFT 3 |
107 | #define MOD_RCLK_768FS (3 << 3) | 111 | #define MOD_RCLK_256FS 0 |
108 | #define MOD_RCLK_MASK (3 << 3) | 112 | #define MOD_RCLK_512FS 1 |
109 | #define MOD_BCLK_32FS (0 << 1) | 113 | #define MOD_RCLK_384FS 2 |
110 | #define MOD_BCLK_48FS (1 << 1) | 114 | #define MOD_RCLK_768FS 3 |
111 | #define MOD_BCLK_16FS (2 << 1) | 115 | #define MOD_RCLK_MASK 3 |
112 | #define MOD_BCLK_24FS (3 << 1) | 116 | #define MOD_BCLK_SHIFT 1 |
113 | #define MOD_BCLK_MASK (3 << 1) | 117 | #define MOD_BCLK_32FS 0 |
118 | #define MOD_BCLK_48FS 1 | ||
119 | #define MOD_BCLK_16FS 2 | ||
120 | #define MOD_BCLK_24FS 3 | ||
121 | #define MOD_BCLK_MASK 3 | ||
114 | #define MOD_8BIT (1 << 0) | 122 | #define MOD_8BIT (1 << 0) |
115 | 123 | ||
124 | #define EXYNOS5420_MOD_LRP_SHIFT 15 | ||
125 | #define EXYNOS5420_MOD_SDF_SHIFT 6 | ||
126 | #define EXYNOS5420_MOD_RCLK_SHIFT 4 | ||
127 | #define EXYNOS5420_MOD_BCLK_SHIFT 0 | ||
128 | #define EXYNOS5420_MOD_BCLK_64FS 4 | ||
129 | #define EXYNOS5420_MOD_BCLK_96FS 5 | ||
130 | #define EXYNOS5420_MOD_BCLK_128FS 6 | ||
131 | #define EXYNOS5420_MOD_BCLK_192FS 7 | ||
132 | #define EXYNOS5420_MOD_BCLK_256FS 8 | ||
133 | #define EXYNOS5420_MOD_BCLK_MASK 0xf | ||
134 | |||
116 | #define MOD_CDCLKCON (1 << 12) | 135 | #define MOD_CDCLKCON (1 << 12) |
117 | 136 | ||
118 | #define PSR_PSREN (1 << 15) | 137 | #define PSR_PSREN (1 << 15) |
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 959c702235c8..b302f3b7a587 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -40,6 +40,7 @@ enum samsung_dai_type { | |||
40 | 40 | ||
41 | struct samsung_i2s_dai_data { | 41 | struct samsung_i2s_dai_data { |
42 | int dai_type; | 42 | int dai_type; |
43 | u32 quirks; | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | struct i2s_dai { | 46 | struct i2s_dai { |
@@ -198,7 +199,13 @@ static inline bool is_manager(struct i2s_dai *i2s) | |||
198 | /* Read RCLK of I2S (in multiples of LRCLK) */ | 199 | /* Read RCLK of I2S (in multiples of LRCLK) */ |
199 | static inline unsigned get_rfs(struct i2s_dai *i2s) | 200 | static inline unsigned get_rfs(struct i2s_dai *i2s) |
200 | { | 201 | { |
201 | u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3; | 202 | u32 rfs; |
203 | |||
204 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) | ||
205 | rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT; | ||
206 | else | ||
207 | rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT); | ||
208 | rfs &= MOD_RCLK_MASK; | ||
202 | 209 | ||
203 | switch (rfs) { | 210 | switch (rfs) { |
204 | case 3: return 768; | 211 | case 3: return 768; |
@@ -212,21 +219,26 @@ static inline unsigned get_rfs(struct i2s_dai *i2s) | |||
212 | static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) | 219 | static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) |
213 | { | 220 | { |
214 | u32 mod = readl(i2s->addr + I2SMOD); | 221 | u32 mod = readl(i2s->addr + I2SMOD); |
222 | int rfs_shift; | ||
215 | 223 | ||
216 | mod &= ~MOD_RCLK_MASK; | 224 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) |
225 | rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT; | ||
226 | else | ||
227 | rfs_shift = MOD_RCLK_SHIFT; | ||
228 | mod &= ~(MOD_RCLK_MASK << rfs_shift); | ||
217 | 229 | ||
218 | switch (rfs) { | 230 | switch (rfs) { |
219 | case 768: | 231 | case 768: |
220 | mod |= MOD_RCLK_768FS; | 232 | mod |= (MOD_RCLK_768FS << rfs_shift); |
221 | break; | 233 | break; |
222 | case 512: | 234 | case 512: |
223 | mod |= MOD_RCLK_512FS; | 235 | mod |= (MOD_RCLK_512FS << rfs_shift); |
224 | break; | 236 | break; |
225 | case 384: | 237 | case 384: |
226 | mod |= MOD_RCLK_384FS; | 238 | mod |= (MOD_RCLK_384FS << rfs_shift); |
227 | break; | 239 | break; |
228 | default: | 240 | default: |
229 | mod |= MOD_RCLK_256FS; | 241 | mod |= (MOD_RCLK_256FS << rfs_shift); |
230 | break; | 242 | break; |
231 | } | 243 | } |
232 | 244 | ||
@@ -236,9 +248,22 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) | |||
236 | /* Read Bit-Clock of I2S (in multiples of LRCLK) */ | 248 | /* Read Bit-Clock of I2S (in multiples of LRCLK) */ |
237 | static inline unsigned get_bfs(struct i2s_dai *i2s) | 249 | static inline unsigned get_bfs(struct i2s_dai *i2s) |
238 | { | 250 | { |
239 | u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3; | 251 | u32 bfs; |
252 | |||
253 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) { | ||
254 | bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT; | ||
255 | bfs &= EXYNOS5420_MOD_BCLK_MASK; | ||
256 | } else { | ||
257 | bfs = readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT; | ||
258 | bfs &= MOD_BCLK_MASK; | ||
259 | } | ||
240 | 260 | ||
241 | switch (bfs) { | 261 | switch (bfs) { |
262 | case 8: return 256; | ||
263 | case 7: return 192; | ||
264 | case 6: return 128; | ||
265 | case 5: return 96; | ||
266 | case 4: return 64; | ||
242 | case 3: return 24; | 267 | case 3: return 24; |
243 | case 2: return 16; | 268 | case 2: return 16; |
244 | case 1: return 48; | 269 | case 1: return 48; |
@@ -250,21 +275,50 @@ static inline unsigned get_bfs(struct i2s_dai *i2s) | |||
250 | static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) | 275 | static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) |
251 | { | 276 | { |
252 | u32 mod = readl(i2s->addr + I2SMOD); | 277 | u32 mod = readl(i2s->addr + I2SMOD); |
278 | int bfs_shift; | ||
279 | int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; | ||
253 | 280 | ||
254 | mod &= ~MOD_BCLK_MASK; | 281 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) { |
282 | bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT; | ||
283 | mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift); | ||
284 | } else { | ||
285 | bfs_shift = MOD_BCLK_SHIFT; | ||
286 | mod &= ~(MOD_BCLK_MASK << bfs_shift); | ||
287 | } | ||
288 | |||
289 | /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ | ||
290 | if (!tdm && bfs > 48) { | ||
291 | dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n"); | ||
292 | return; | ||
293 | } | ||
255 | 294 | ||
256 | switch (bfs) { | 295 | switch (bfs) { |
257 | case 48: | 296 | case 48: |
258 | mod |= MOD_BCLK_48FS; | 297 | mod |= (MOD_BCLK_48FS << bfs_shift); |
259 | break; | 298 | break; |
260 | case 32: | 299 | case 32: |
261 | mod |= MOD_BCLK_32FS; | 300 | mod |= (MOD_BCLK_32FS << bfs_shift); |
262 | break; | 301 | break; |
263 | case 24: | 302 | case 24: |
264 | mod |= MOD_BCLK_24FS; | 303 | mod |= (MOD_BCLK_24FS << bfs_shift); |
265 | break; | 304 | break; |
266 | case 16: | 305 | case 16: |
267 | mod |= MOD_BCLK_16FS; | 306 | mod |= (MOD_BCLK_16FS << bfs_shift); |
307 | break; | ||
308 | case 64: | ||
309 | mod |= (EXYNOS5420_MOD_BCLK_64FS << bfs_shift); | ||
310 | break; | ||
311 | case 96: | ||
312 | mod |= (EXYNOS5420_MOD_BCLK_96FS << bfs_shift); | ||
313 | break; | ||
314 | case 128: | ||
315 | mod |= (EXYNOS5420_MOD_BCLK_128FS << bfs_shift); | ||
316 | break; | ||
317 | case 192: | ||
318 | mod |= (EXYNOS5420_MOD_BCLK_192FS << bfs_shift); | ||
319 | break; | ||
320 | case 256: | ||
321 | mod |= (EXYNOS5420_MOD_BCLK_256FS << bfs_shift); | ||
268 | break; | 322 | break; |
269 | default: | 323 | default: |
270 | dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n"); | 324 | dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n"); |
@@ -491,20 +545,32 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, | |||
491 | { | 545 | { |
492 | struct i2s_dai *i2s = to_info(dai); | 546 | struct i2s_dai *i2s = to_info(dai); |
493 | u32 mod = readl(i2s->addr + I2SMOD); | 547 | u32 mod = readl(i2s->addr + I2SMOD); |
548 | int lrp_shift, sdf_shift, sdf_mask, lrp_rlow; | ||
494 | u32 tmp = 0; | 549 | u32 tmp = 0; |
495 | 550 | ||
551 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) { | ||
552 | lrp_shift = EXYNOS5420_MOD_LRP_SHIFT; | ||
553 | sdf_shift = EXYNOS5420_MOD_SDF_SHIFT; | ||
554 | } else { | ||
555 | lrp_shift = MOD_LRP_SHIFT; | ||
556 | sdf_shift = MOD_SDF_SHIFT; | ||
557 | } | ||
558 | |||
559 | sdf_mask = MOD_SDF_MASK << sdf_shift; | ||
560 | lrp_rlow = MOD_LR_RLOW << lrp_shift; | ||
561 | |||
496 | /* Format is priority */ | 562 | /* Format is priority */ |
497 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 563 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
498 | case SND_SOC_DAIFMT_RIGHT_J: | 564 | case SND_SOC_DAIFMT_RIGHT_J: |
499 | tmp |= MOD_LR_RLOW; | 565 | tmp |= lrp_rlow; |
500 | tmp |= MOD_SDF_MSB; | 566 | tmp |= (MOD_SDF_MSB << sdf_shift); |
501 | break; | 567 | break; |
502 | case SND_SOC_DAIFMT_LEFT_J: | 568 | case SND_SOC_DAIFMT_LEFT_J: |
503 | tmp |= MOD_LR_RLOW; | 569 | tmp |= lrp_rlow; |
504 | tmp |= MOD_SDF_LSB; | 570 | tmp |= (MOD_SDF_LSB << sdf_shift); |
505 | break; | 571 | break; |
506 | case SND_SOC_DAIFMT_I2S: | 572 | case SND_SOC_DAIFMT_I2S: |
507 | tmp |= MOD_SDF_IIS; | 573 | tmp |= (MOD_SDF_IIS << sdf_shift); |
508 | break; | 574 | break; |
509 | default: | 575 | default: |
510 | dev_err(&i2s->pdev->dev, "Format not supported\n"); | 576 | dev_err(&i2s->pdev->dev, "Format not supported\n"); |
@@ -519,10 +585,10 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, | |||
519 | case SND_SOC_DAIFMT_NB_NF: | 585 | case SND_SOC_DAIFMT_NB_NF: |
520 | break; | 586 | break; |
521 | case SND_SOC_DAIFMT_NB_IF: | 587 | case SND_SOC_DAIFMT_NB_IF: |
522 | if (tmp & MOD_LR_RLOW) | 588 | if (tmp & lrp_rlow) |
523 | tmp &= ~MOD_LR_RLOW; | 589 | tmp &= ~lrp_rlow; |
524 | else | 590 | else |
525 | tmp |= MOD_LR_RLOW; | 591 | tmp |= lrp_rlow; |
526 | break; | 592 | break; |
527 | default: | 593 | default: |
528 | dev_err(&i2s->pdev->dev, "Polarity not supported\n"); | 594 | dev_err(&i2s->pdev->dev, "Polarity not supported\n"); |
@@ -544,15 +610,18 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, | |||
544 | return -EINVAL; | 610 | return -EINVAL; |
545 | } | 611 | } |
546 | 612 | ||
613 | /* | ||
614 | * Don't change the I2S mode if any controller is active on this | ||
615 | * channel. | ||
616 | */ | ||
547 | if (any_active(i2s) && | 617 | if (any_active(i2s) && |
548 | ((mod & (MOD_SDF_MASK | MOD_LR_RLOW | 618 | ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) { |
549 | | MOD_SLAVE)) != tmp)) { | ||
550 | dev_err(&i2s->pdev->dev, | 619 | dev_err(&i2s->pdev->dev, |
551 | "%s:%d Other DAI busy\n", __func__, __LINE__); | 620 | "%s:%d Other DAI busy\n", __func__, __LINE__); |
552 | return -EAGAIN; | 621 | return -EAGAIN; |
553 | } | 622 | } |
554 | 623 | ||
555 | mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE); | 624 | mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE); |
556 | mod |= tmp; | 625 | mod |= tmp; |
557 | writel(mod, i2s->addr + I2SMOD); | 626 | writel(mod, i2s->addr + I2SMOD); |
558 | 627 | ||
@@ -1007,6 +1076,8 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) | |||
1007 | if (IS_ERR(i2s->pdev)) | 1076 | if (IS_ERR(i2s->pdev)) |
1008 | return NULL; | 1077 | return NULL; |
1009 | 1078 | ||
1079 | i2s->pdev->dev.parent = &pdev->dev; | ||
1080 | |||
1010 | platform_set_drvdata(i2s->pdev, i2s); | 1081 | platform_set_drvdata(i2s->pdev, i2s); |
1011 | ret = platform_device_add(i2s->pdev); | 1082 | ret = platform_device_add(i2s->pdev); |
1012 | if (ret < 0) | 1083 | if (ret < 0) |
@@ -1018,18 +1089,18 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) | |||
1018 | 1089 | ||
1019 | static const struct of_device_id exynos_i2s_match[]; | 1090 | static const struct of_device_id exynos_i2s_match[]; |
1020 | 1091 | ||
1021 | static inline int samsung_i2s_get_driver_data(struct platform_device *pdev) | 1092 | static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data( |
1093 | struct platform_device *pdev) | ||
1022 | { | 1094 | { |
1023 | #ifdef CONFIG_OF | 1095 | #ifdef CONFIG_OF |
1024 | struct samsung_i2s_dai_data *data; | ||
1025 | if (pdev->dev.of_node) { | 1096 | if (pdev->dev.of_node) { |
1026 | const struct of_device_id *match; | 1097 | const struct of_device_id *match; |
1027 | match = of_match_node(exynos_i2s_match, pdev->dev.of_node); | 1098 | match = of_match_node(exynos_i2s_match, pdev->dev.of_node); |
1028 | data = (struct samsung_i2s_dai_data *) match->data; | 1099 | return match->data; |
1029 | return data->dai_type; | ||
1030 | } else | 1100 | } else |
1031 | #endif | 1101 | #endif |
1032 | return platform_get_device_id(pdev)->driver_data; | 1102 | return (struct samsung_i2s_dai_data *) |
1103 | platform_get_device_id(pdev)->driver_data; | ||
1033 | } | 1104 | } |
1034 | 1105 | ||
1035 | #ifdef CONFIG_PM_RUNTIME | 1106 | #ifdef CONFIG_PM_RUNTIME |
@@ -1060,13 +1131,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1060 | struct resource *res; | 1131 | struct resource *res; |
1061 | u32 regs_base, quirks = 0, idma_addr = 0; | 1132 | u32 regs_base, quirks = 0, idma_addr = 0; |
1062 | struct device_node *np = pdev->dev.of_node; | 1133 | struct device_node *np = pdev->dev.of_node; |
1063 | enum samsung_dai_type samsung_dai_type; | 1134 | const struct samsung_i2s_dai_data *i2s_dai_data; |
1064 | int ret = 0; | 1135 | int ret = 0; |
1065 | 1136 | ||
1066 | /* Call during Seconday interface registration */ | 1137 | /* Call during Seconday interface registration */ |
1067 | samsung_dai_type = samsung_i2s_get_driver_data(pdev); | 1138 | i2s_dai_data = samsung_i2s_get_driver_data(pdev); |
1068 | 1139 | ||
1069 | if (samsung_dai_type == TYPE_SEC) { | 1140 | if (i2s_dai_data->dai_type == TYPE_SEC) { |
1070 | sec_dai = dev_get_drvdata(&pdev->dev); | 1141 | sec_dai = dev_get_drvdata(&pdev->dev); |
1071 | if (!sec_dai) { | 1142 | if (!sec_dai) { |
1072 | dev_err(&pdev->dev, "Unable to get drvdata\n"); | 1143 | dev_err(&pdev->dev, "Unable to get drvdata\n"); |
@@ -1075,7 +1146,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1075 | snd_soc_register_component(&sec_dai->pdev->dev, | 1146 | snd_soc_register_component(&sec_dai->pdev->dev, |
1076 | &samsung_i2s_component, | 1147 | &samsung_i2s_component, |
1077 | &sec_dai->i2s_dai_drv, 1); | 1148 | &sec_dai->i2s_dai_drv, 1); |
1078 | asoc_dma_platform_register(&pdev->dev); | 1149 | samsung_asoc_dma_platform_register(&pdev->dev); |
1079 | return 0; | 1150 | return 0; |
1080 | } | 1151 | } |
1081 | 1152 | ||
@@ -1115,15 +1186,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1115 | idma_addr = i2s_cfg->idma_addr; | 1186 | idma_addr = i2s_cfg->idma_addr; |
1116 | } | 1187 | } |
1117 | } else { | 1188 | } else { |
1118 | if (of_find_property(np, "samsung,supports-6ch", NULL)) | 1189 | quirks = i2s_dai_data->quirks; |
1119 | quirks |= QUIRK_PRI_6CHAN; | ||
1120 | |||
1121 | if (of_find_property(np, "samsung,supports-secdai", NULL)) | ||
1122 | quirks |= QUIRK_SEC_DAI; | ||
1123 | |||
1124 | if (of_find_property(np, "samsung,supports-rstclr", NULL)) | ||
1125 | quirks |= QUIRK_NEED_RSTCLR; | ||
1126 | |||
1127 | if (of_property_read_u32(np, "samsung,idma-addr", | 1190 | if (of_property_read_u32(np, "samsung,idma-addr", |
1128 | &idma_addr)) { | 1191 | &idma_addr)) { |
1129 | if (quirks & QUIRK_SEC_DAI) { | 1192 | if (quirks & QUIRK_SEC_DAI) { |
@@ -1200,7 +1263,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1200 | 1263 | ||
1201 | pm_runtime_enable(&pdev->dev); | 1264 | pm_runtime_enable(&pdev->dev); |
1202 | 1265 | ||
1203 | asoc_dma_platform_register(&pdev->dev); | 1266 | samsung_asoc_dma_platform_register(&pdev->dev); |
1204 | 1267 | ||
1205 | return 0; | 1268 | return 0; |
1206 | err: | 1269 | err: |
@@ -1230,33 +1293,59 @@ static int samsung_i2s_remove(struct platform_device *pdev) | |||
1230 | i2s->pri_dai = NULL; | 1293 | i2s->pri_dai = NULL; |
1231 | i2s->sec_dai = NULL; | 1294 | i2s->sec_dai = NULL; |
1232 | 1295 | ||
1233 | asoc_dma_platform_unregister(&pdev->dev); | 1296 | samsung_asoc_dma_platform_unregister(&pdev->dev); |
1234 | snd_soc_unregister_component(&pdev->dev); | 1297 | snd_soc_unregister_component(&pdev->dev); |
1235 | 1298 | ||
1236 | return 0; | 1299 | return 0; |
1237 | } | 1300 | } |
1238 | 1301 | ||
1302 | static const struct samsung_i2s_dai_data i2sv3_dai_type = { | ||
1303 | .dai_type = TYPE_PRI, | ||
1304 | .quirks = QUIRK_NO_MUXPSR, | ||
1305 | }; | ||
1306 | |||
1307 | static const struct samsung_i2s_dai_data i2sv5_dai_type = { | ||
1308 | .dai_type = TYPE_PRI, | ||
1309 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR, | ||
1310 | }; | ||
1311 | |||
1312 | static const struct samsung_i2s_dai_data i2sv6_dai_type = { | ||
1313 | .dai_type = TYPE_PRI, | ||
1314 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | | ||
1315 | QUIRK_SUPPORTS_TDM, | ||
1316 | }; | ||
1317 | |||
1318 | static const struct samsung_i2s_dai_data samsung_dai_type_pri = { | ||
1319 | .dai_type = TYPE_PRI, | ||
1320 | }; | ||
1321 | |||
1322 | static const struct samsung_i2s_dai_data samsung_dai_type_sec = { | ||
1323 | .dai_type = TYPE_SEC, | ||
1324 | }; | ||
1325 | |||
1239 | static struct platform_device_id samsung_i2s_driver_ids[] = { | 1326 | static struct platform_device_id samsung_i2s_driver_ids[] = { |
1240 | { | 1327 | { |
1241 | .name = "samsung-i2s", | 1328 | .name = "samsung-i2s", |
1242 | .driver_data = TYPE_PRI, | 1329 | .driver_data = (kernel_ulong_t)&samsung_dai_type_pri, |
1243 | }, { | 1330 | }, { |
1244 | .name = "samsung-i2s-sec", | 1331 | .name = "samsung-i2s-sec", |
1245 | .driver_data = TYPE_SEC, | 1332 | .driver_data = (kernel_ulong_t)&samsung_dai_type_sec, |
1246 | }, | 1333 | }, |
1247 | {}, | 1334 | {}, |
1248 | }; | 1335 | }; |
1249 | MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids); | 1336 | MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids); |
1250 | 1337 | ||
1251 | #ifdef CONFIG_OF | 1338 | #ifdef CONFIG_OF |
1252 | static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = { | ||
1253 | [TYPE_PRI] = { TYPE_PRI }, | ||
1254 | [TYPE_SEC] = { TYPE_SEC }, | ||
1255 | }; | ||
1256 | |||
1257 | static const struct of_device_id exynos_i2s_match[] = { | 1339 | static const struct of_device_id exynos_i2s_match[] = { |
1258 | { .compatible = "samsung,i2s-v5", | 1340 | { |
1259 | .data = &samsung_i2s_dai_data_array[TYPE_PRI], | 1341 | .compatible = "samsung,s3c6410-i2s", |
1342 | .data = &i2sv3_dai_type, | ||
1343 | }, { | ||
1344 | .compatible = "samsung,s5pv210-i2s", | ||
1345 | .data = &i2sv5_dai_type, | ||
1346 | }, { | ||
1347 | .compatible = "samsung,exynos5420-i2s", | ||
1348 | .data = &i2sv6_dai_type, | ||
1260 | }, | 1349 | }, |
1261 | {}, | 1350 | {}, |
1262 | }; | 1351 | }; |
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 1566afe9ef52..e54256fc4b2c 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c | |||
@@ -594,7 +594,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) | |||
594 | goto err5; | 594 | goto err5; |
595 | } | 595 | } |
596 | 596 | ||
597 | ret = asoc_dma_platform_register(&pdev->dev); | 597 | ret = samsung_asoc_dma_platform_register(&pdev->dev); |
598 | if (ret) { | 598 | if (ret) { |
599 | dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); | 599 | dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); |
600 | goto err6; | 600 | goto err6; |
@@ -623,7 +623,7 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev) | |||
623 | struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; | 623 | struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; |
624 | struct resource *mem_res; | 624 | struct resource *mem_res; |
625 | 625 | ||
626 | asoc_dma_platform_unregister(&pdev->dev); | 626 | samsung_asoc_dma_platform_unregister(&pdev->dev); |
627 | snd_soc_unregister_component(&pdev->dev); | 627 | snd_soc_unregister_component(&pdev->dev); |
628 | 628 | ||
629 | pm_runtime_disable(&pdev->dev); | 629 | pm_runtime_disable(&pdev->dev); |
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 47e23864ea72..ea885cb9f76c 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c | |||
@@ -176,7 +176,7 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) | |||
176 | return ret; | 176 | return ret; |
177 | } | 177 | } |
178 | 178 | ||
179 | ret = asoc_dma_platform_register(&pdev->dev); | 179 | ret = samsung_asoc_dma_platform_register(&pdev->dev); |
180 | if (ret) { | 180 | if (ret) { |
181 | pr_err("failed to register the DMA: %d\n", ret); | 181 | pr_err("failed to register the DMA: %d\n", ret); |
182 | goto err; | 182 | goto err; |
@@ -190,7 +190,7 @@ err: | |||
190 | 190 | ||
191 | static int s3c2412_iis_dev_remove(struct platform_device *pdev) | 191 | static int s3c2412_iis_dev_remove(struct platform_device *pdev) |
192 | { | 192 | { |
193 | asoc_dma_platform_unregister(&pdev->dev); | 193 | samsung_asoc_dma_platform_unregister(&pdev->dev); |
194 | snd_soc_unregister_component(&pdev->dev); | 194 | snd_soc_unregister_component(&pdev->dev); |
195 | return 0; | 195 | return 0; |
196 | } | 196 | } |
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 8b3414551a62..9c8ebd872fac 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c | |||
@@ -480,7 +480,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) | |||
480 | return ret; | 480 | return ret; |
481 | } | 481 | } |
482 | 482 | ||
483 | ret = asoc_dma_platform_register(&pdev->dev); | 483 | ret = samsung_asoc_dma_platform_register(&pdev->dev); |
484 | if (ret) { | 484 | if (ret) { |
485 | pr_err("failed to register the dma: %d\n", ret); | 485 | pr_err("failed to register the dma: %d\n", ret); |
486 | goto err; | 486 | goto err; |
@@ -494,7 +494,7 @@ err: | |||
494 | 494 | ||
495 | static int s3c24xx_iis_dev_remove(struct platform_device *pdev) | 495 | static int s3c24xx_iis_dev_remove(struct platform_device *pdev) |
496 | { | 496 | { |
497 | asoc_dma_platform_unregister(&pdev->dev); | 497 | samsung_asoc_dma_platform_unregister(&pdev->dev); |
498 | snd_soc_unregister_component(&pdev->dev); | 498 | snd_soc_unregister_component(&pdev->dev); |
499 | return 0; | 499 | return 0; |
500 | } | 500 | } |
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 581ea4a06fc6..5fd7a05a9b9e 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <sound/pcm_params.h> | 11 | #include <sound/pcm_params.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/of.h> | 13 | #include <linux/of.h> |
14 | #include <linux/of_device.h> | ||
14 | 15 | ||
15 | /* | 16 | /* |
16 | * Default CFG switch settings to use this driver: | 17 | * Default CFG switch settings to use this driver: |
@@ -37,11 +38,19 @@ | |||
37 | /* SMDK has a 16.934MHZ crystal attached to WM8994 */ | 38 | /* SMDK has a 16.934MHZ crystal attached to WM8994 */ |
38 | #define SMDK_WM8994_FREQ 16934000 | 39 | #define SMDK_WM8994_FREQ 16934000 |
39 | 40 | ||
41 | struct smdk_wm8994_data { | ||
42 | int mclk1_rate; | ||
43 | }; | ||
44 | |||
45 | /* Default SMDKs */ | ||
46 | static struct smdk_wm8994_data smdk_board_data = { | ||
47 | .mclk1_rate = SMDK_WM8994_FREQ, | ||
48 | }; | ||
49 | |||
40 | static int smdk_hw_params(struct snd_pcm_substream *substream, | 50 | static int smdk_hw_params(struct snd_pcm_substream *substream, |
41 | struct snd_pcm_hw_params *params) | 51 | struct snd_pcm_hw_params *params) |
42 | { | 52 | { |
43 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 53 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
44 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
45 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 54 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
46 | unsigned int pll_out; | 55 | unsigned int pll_out; |
47 | int ret; | 56 | int ret; |
@@ -54,18 +63,6 @@ static int smdk_hw_params(struct snd_pcm_substream *substream, | |||
54 | else | 63 | else |
55 | pll_out = params_rate(params) * 256; | 64 | pll_out = params_rate(params) * 256; |
56 | 65 | ||
57 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | ||
58 | | SND_SOC_DAIFMT_NB_NF | ||
59 | | SND_SOC_DAIFMT_CBM_CFM); | ||
60 | if (ret < 0) | ||
61 | return ret; | ||
62 | |||
63 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | ||
64 | | SND_SOC_DAIFMT_NB_NF | ||
65 | | SND_SOC_DAIFMT_CBM_CFM); | ||
66 | if (ret < 0) | ||
67 | return ret; | ||
68 | |||
69 | ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, | 66 | ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, |
70 | SMDK_WM8994_FREQ, pll_out); | 67 | SMDK_WM8994_FREQ, pll_out); |
71 | if (ret < 0) | 68 | if (ret < 0) |
@@ -131,6 +128,8 @@ static struct snd_soc_dai_link smdk_dai[] = { | |||
131 | .platform_name = "samsung-i2s.0", | 128 | .platform_name = "samsung-i2s.0", |
132 | .codec_name = "wm8994-codec", | 129 | .codec_name = "wm8994-codec", |
133 | .init = smdk_wm8994_init_paiftx, | 130 | .init = smdk_wm8994_init_paiftx, |
131 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
132 | SND_SOC_DAIFMT_CBM_CFM, | ||
134 | .ops = &smdk_ops, | 133 | .ops = &smdk_ops, |
135 | }, { /* Sec_Fifo Playback i/f */ | 134 | }, { /* Sec_Fifo Playback i/f */ |
136 | .name = "Sec_FIFO TX", | 135 | .name = "Sec_FIFO TX", |
@@ -139,6 +138,8 @@ static struct snd_soc_dai_link smdk_dai[] = { | |||
139 | .codec_dai_name = "wm8994-aif1", | 138 | .codec_dai_name = "wm8994-aif1", |
140 | .platform_name = "samsung-i2s-sec", | 139 | .platform_name = "samsung-i2s-sec", |
141 | .codec_name = "wm8994-codec", | 140 | .codec_name = "wm8994-codec", |
141 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
142 | SND_SOC_DAIFMT_CBM_CFM, | ||
142 | .ops = &smdk_ops, | 143 | .ops = &smdk_ops, |
143 | }, | 144 | }, |
144 | }; | 145 | }; |
@@ -150,15 +151,28 @@ static struct snd_soc_card smdk = { | |||
150 | .num_links = ARRAY_SIZE(smdk_dai), | 151 | .num_links = ARRAY_SIZE(smdk_dai), |
151 | }; | 152 | }; |
152 | 153 | ||
154 | #ifdef CONFIG_OF | ||
155 | static const struct of_device_id samsung_wm8994_of_match[] = { | ||
156 | { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data }, | ||
157 | {}, | ||
158 | }; | ||
159 | MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); | ||
160 | #endif /* CONFIG_OF */ | ||
153 | 161 | ||
154 | static int smdk_audio_probe(struct platform_device *pdev) | 162 | static int smdk_audio_probe(struct platform_device *pdev) |
155 | { | 163 | { |
156 | int ret; | 164 | int ret; |
157 | struct device_node *np = pdev->dev.of_node; | 165 | struct device_node *np = pdev->dev.of_node; |
158 | struct snd_soc_card *card = &smdk; | 166 | struct snd_soc_card *card = &smdk; |
167 | struct smdk_wm8994_data *board; | ||
168 | const struct of_device_id *id; | ||
159 | 169 | ||
160 | card->dev = &pdev->dev; | 170 | card->dev = &pdev->dev; |
161 | 171 | ||
172 | board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL); | ||
173 | if (!board) | ||
174 | return -ENOMEM; | ||
175 | |||
162 | if (np) { | 176 | if (np) { |
163 | smdk_dai[0].cpu_dai_name = NULL; | 177 | smdk_dai[0].cpu_dai_name = NULL; |
164 | smdk_dai[0].cpu_of_node = of_parse_phandle(np, | 178 | smdk_dai[0].cpu_of_node = of_parse_phandle(np, |
@@ -173,6 +187,12 @@ static int smdk_audio_probe(struct platform_device *pdev) | |||
173 | smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node; | 187 | smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node; |
174 | } | 188 | } |
175 | 189 | ||
190 | id = of_match_device(samsung_wm8994_of_match, &pdev->dev); | ||
191 | if (id) | ||
192 | *board = *((struct smdk_wm8994_data *)id->data); | ||
193 | |||
194 | platform_set_drvdata(pdev, board); | ||
195 | |||
176 | ret = snd_soc_register_card(card); | 196 | ret = snd_soc_register_card(card); |
177 | 197 | ||
178 | if (ret) | 198 | if (ret) |
@@ -190,17 +210,9 @@ static int smdk_audio_remove(struct platform_device *pdev) | |||
190 | return 0; | 210 | return 0; |
191 | } | 211 | } |
192 | 212 | ||
193 | #ifdef CONFIG_OF | ||
194 | static const struct of_device_id samsung_wm8994_of_match[] = { | ||
195 | { .compatible = "samsung,smdk-wm8994", }, | ||
196 | {}, | ||
197 | }; | ||
198 | MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); | ||
199 | #endif /* CONFIG_OF */ | ||
200 | |||
201 | static struct platform_driver smdk_audio_driver = { | 213 | static struct platform_driver smdk_audio_driver = { |
202 | .driver = { | 214 | .driver = { |
203 | .name = "smdk-audio", | 215 | .name = "smdk-audio-wm8894", |
204 | .owner = THIS_MODULE, | 216 | .owner = THIS_MODULE, |
205 | .of_match_table = of_match_ptr(samsung_wm8994_of_match), | 217 | .of_match_table = of_match_ptr(samsung_wm8994_of_match), |
206 | }, | 218 | }, |
@@ -212,4 +224,4 @@ module_platform_driver(smdk_audio_driver); | |||
212 | 224 | ||
213 | MODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); | 225 | MODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); |
214 | MODULE_LICENSE("GPL"); | 226 | MODULE_LICENSE("GPL"); |
215 | MODULE_ALIAS("platform:smdk-audio"); | 227 | MODULE_ALIAS("platform:smdk-audio-wm8994"); |
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 2e5ebb2f1982..28487dcc4538 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c | |||
@@ -395,7 +395,7 @@ static int spdif_probe(struct platform_device *pdev) | |||
395 | 395 | ||
396 | spin_lock_init(&spdif->lock); | 396 | spin_lock_init(&spdif->lock); |
397 | 397 | ||
398 | spdif->pclk = clk_get(&pdev->dev, "spdif"); | 398 | spdif->pclk = devm_clk_get(&pdev->dev, "spdif"); |
399 | if (IS_ERR(spdif->pclk)) { | 399 | if (IS_ERR(spdif->pclk)) { |
400 | dev_err(&pdev->dev, "failed to get peri-clock\n"); | 400 | dev_err(&pdev->dev, "failed to get peri-clock\n"); |
401 | ret = -ENOENT; | 401 | ret = -ENOENT; |
@@ -403,7 +403,7 @@ static int spdif_probe(struct platform_device *pdev) | |||
403 | } | 403 | } |
404 | clk_prepare_enable(spdif->pclk); | 404 | clk_prepare_enable(spdif->pclk); |
405 | 405 | ||
406 | spdif->sclk = clk_get(&pdev->dev, "sclk_spdif"); | 406 | spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif"); |
407 | if (IS_ERR(spdif->sclk)) { | 407 | if (IS_ERR(spdif->sclk)) { |
408 | dev_err(&pdev->dev, "failed to get internal source clock\n"); | 408 | dev_err(&pdev->dev, "failed to get internal source clock\n"); |
409 | ret = -ENOENT; | 409 | ret = -ENOENT; |
@@ -442,7 +442,7 @@ static int spdif_probe(struct platform_device *pdev) | |||
442 | 442 | ||
443 | spdif->dma_playback = &spdif_stereo_out; | 443 | spdif->dma_playback = &spdif_stereo_out; |
444 | 444 | ||
445 | ret = asoc_dma_platform_register(&pdev->dev); | 445 | ret = samsung_asoc_dma_platform_register(&pdev->dev); |
446 | if (ret) { | 446 | if (ret) { |
447 | dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); | 447 | dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); |
448 | goto err5; | 448 | goto err5; |
@@ -457,10 +457,8 @@ err3: | |||
457 | release_mem_region(mem_res->start, resource_size(mem_res)); | 457 | release_mem_region(mem_res->start, resource_size(mem_res)); |
458 | err2: | 458 | err2: |
459 | clk_disable_unprepare(spdif->sclk); | 459 | clk_disable_unprepare(spdif->sclk); |
460 | clk_put(spdif->sclk); | ||
461 | err1: | 460 | err1: |
462 | clk_disable_unprepare(spdif->pclk); | 461 | clk_disable_unprepare(spdif->pclk); |
463 | clk_put(spdif->pclk); | ||
464 | err0: | 462 | err0: |
465 | return ret; | 463 | return ret; |
466 | } | 464 | } |
@@ -470,7 +468,7 @@ static int spdif_remove(struct platform_device *pdev) | |||
470 | struct samsung_spdif_info *spdif = &spdif_info; | 468 | struct samsung_spdif_info *spdif = &spdif_info; |
471 | struct resource *mem_res; | 469 | struct resource *mem_res; |
472 | 470 | ||
473 | asoc_dma_platform_unregister(&pdev->dev); | 471 | samsung_asoc_dma_platform_unregister(&pdev->dev); |
474 | snd_soc_unregister_component(&pdev->dev); | 472 | snd_soc_unregister_component(&pdev->dev); |
475 | 473 | ||
476 | iounmap(spdif->regs); | 474 | iounmap(spdif->regs); |
@@ -480,9 +478,7 @@ static int spdif_remove(struct platform_device *pdev) | |||
480 | release_mem_region(mem_res->start, resource_size(mem_res)); | 478 | release_mem_region(mem_res->start, resource_size(mem_res)); |
481 | 479 | ||
482 | clk_disable_unprepare(spdif->sclk); | 480 | clk_disable_unprepare(spdif->sclk); |
483 | clk_put(spdif->sclk); | ||
484 | clk_disable_unprepare(spdif->pclk); | 481 | clk_disable_unprepare(spdif->pclk); |
485 | clk_put(spdif->pclk); | ||
486 | 482 | ||
487 | return 0; | 483 | return 0; |
488 | } | 484 | } |
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 6bcb1164d599..56d8ff6a402d 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -34,6 +34,13 @@ config SND_SOC_SH4_SIU | |||
34 | select SH_DMAE | 34 | select SH_DMAE |
35 | select FW_LOADER | 35 | select FW_LOADER |
36 | 36 | ||
37 | config SND_SOC_RCAR | ||
38 | tristate "R-Car series SRU/SCU/SSIU/SSI support" | ||
39 | select SND_SIMPLE_CARD | ||
40 | select RCAR_CLK_ADG | ||
41 | help | ||
42 | This option enables R-Car SUR/SCU/SSIU/SSI sound support | ||
43 | |||
37 | ## | 44 | ## |
38 | ## Boards | 45 | ## Boards |
39 | ## | 46 | ## |
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index 849b387d17d9..aaf3dcd1ee2a 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/Makefile | |||
@@ -12,6 +12,9 @@ obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o | |||
12 | obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o | 12 | obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o |
13 | obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o | 13 | obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o |
14 | 14 | ||
15 | ## audio units for R-Car | ||
16 | obj-$(CONFIG_SND_SOC_RCAR) += rcar/ | ||
17 | |||
15 | ## boards | 18 | ## boards |
16 | snd-soc-sh7760-ac97-objs := sh7760-ac97.o | 19 | snd-soc-sh7760-ac97-objs := sh7760-ac97.o |
17 | snd-soc-migor-objs := migor.o | 20 | snd-soc-migor-objs := migor.o |
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile new file mode 100644 index 000000000000..0ff492df7929 --- /dev/null +++ b/sound/soc/sh/rcar/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | snd-soc-rcar-objs := core.o gen.o scu.o adg.o ssi.o | ||
2 | obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file | ||
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c new file mode 100644 index 000000000000..d80deb7ccf13 --- /dev/null +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * Helper routines for R-Car sound ADG. | ||
3 | * | ||
4 | * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/sh_clk.h> | ||
11 | #include <mach/clock.h> | ||
12 | #include "rsnd.h" | ||
13 | |||
14 | #define CLKA 0 | ||
15 | #define CLKB 1 | ||
16 | #define CLKC 2 | ||
17 | #define CLKI 3 | ||
18 | #define CLKMAX 4 | ||
19 | |||
20 | struct rsnd_adg { | ||
21 | struct clk *clk[CLKMAX]; | ||
22 | |||
23 | int rate_of_441khz_div_6; | ||
24 | int rate_of_48khz_div_6; | ||
25 | }; | ||
26 | |||
27 | #define for_each_rsnd_clk(pos, adg, i) \ | ||
28 | for (i = 0, (pos) = adg->clk[i]; \ | ||
29 | i < CLKMAX; \ | ||
30 | i++, (pos) = adg->clk[i]) | ||
31 | #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) | ||
32 | |||
33 | static enum rsnd_reg rsnd_adg_ssi_reg_get(int id) | ||
34 | { | ||
35 | enum rsnd_reg reg; | ||
36 | |||
37 | /* | ||
38 | * SSI 8 is not connected to ADG. | ||
39 | * it works with SSI 7 | ||
40 | */ | ||
41 | if (id == 8) | ||
42 | return RSND_REG_MAX; | ||
43 | |||
44 | if (0 <= id && id <= 3) | ||
45 | reg = RSND_REG_AUDIO_CLK_SEL0; | ||
46 | else if (4 <= id && id <= 7) | ||
47 | reg = RSND_REG_AUDIO_CLK_SEL1; | ||
48 | else | ||
49 | reg = RSND_REG_AUDIO_CLK_SEL2; | ||
50 | |||
51 | return reg; | ||
52 | } | ||
53 | |||
54 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod) | ||
55 | { | ||
56 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
57 | enum rsnd_reg reg; | ||
58 | int id; | ||
59 | |||
60 | /* | ||
61 | * "mod" = "ssi" here. | ||
62 | * we can get "ssi id" from mod | ||
63 | */ | ||
64 | id = rsnd_mod_id(mod); | ||
65 | reg = rsnd_adg_ssi_reg_get(id); | ||
66 | |||
67 | rsnd_write(priv, mod, reg, 0); | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) | ||
73 | { | ||
74 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
75 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | ||
76 | struct device *dev = rsnd_priv_to_dev(priv); | ||
77 | struct clk *clk; | ||
78 | enum rsnd_reg reg; | ||
79 | int id, shift, i; | ||
80 | u32 data; | ||
81 | int sel_table[] = { | ||
82 | [CLKA] = 0x1, | ||
83 | [CLKB] = 0x2, | ||
84 | [CLKC] = 0x3, | ||
85 | [CLKI] = 0x0, | ||
86 | }; | ||
87 | |||
88 | dev_dbg(dev, "request clock = %d\n", rate); | ||
89 | |||
90 | /* | ||
91 | * find suitable clock from | ||
92 | * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. | ||
93 | */ | ||
94 | data = 0; | ||
95 | for_each_rsnd_clk(clk, adg, i) { | ||
96 | if (rate == clk_get_rate(clk)) { | ||
97 | data = sel_table[i]; | ||
98 | goto found_clock; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * find 1/6 clock from BRGA/BRGB | ||
104 | */ | ||
105 | if (rate == adg->rate_of_441khz_div_6) { | ||
106 | data = 0x10; | ||
107 | goto found_clock; | ||
108 | } | ||
109 | |||
110 | if (rate == adg->rate_of_48khz_div_6) { | ||
111 | data = 0x20; | ||
112 | goto found_clock; | ||
113 | } | ||
114 | |||
115 | return -EIO; | ||
116 | |||
117 | found_clock: | ||
118 | |||
119 | /* | ||
120 | * This "mod" = "ssi" here. | ||
121 | * we can get "ssi id" from mod | ||
122 | */ | ||
123 | id = rsnd_mod_id(mod); | ||
124 | reg = rsnd_adg_ssi_reg_get(id); | ||
125 | |||
126 | dev_dbg(dev, "ADG: ssi%d selects clk%d = %d", id, i, rate); | ||
127 | |||
128 | /* | ||
129 | * Enable SSIx clock | ||
130 | */ | ||
131 | shift = (id % 4) * 8; | ||
132 | |||
133 | rsnd_bset(priv, mod, reg, | ||
134 | 0xFF << shift, | ||
135 | data << shift); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg) | ||
141 | { | ||
142 | struct clk *clk; | ||
143 | unsigned long rate; | ||
144 | u32 ckr; | ||
145 | int i; | ||
146 | int brg_table[] = { | ||
147 | [CLKA] = 0x0, | ||
148 | [CLKB] = 0x1, | ||
149 | [CLKC] = 0x4, | ||
150 | [CLKI] = 0x2, | ||
151 | }; | ||
152 | |||
153 | /* | ||
154 | * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC | ||
155 | * have 44.1kHz or 48kHz base clocks for now. | ||
156 | * | ||
157 | * SSI itself can divide parent clock by 1/1 - 1/16 | ||
158 | * So, BRGA outputs 44.1kHz base parent clock 1/32, | ||
159 | * and, BRGB outputs 48.0kHz base parent clock 1/32 here. | ||
160 | * see | ||
161 | * rsnd_adg_ssi_clk_try_start() | ||
162 | */ | ||
163 | ckr = 0; | ||
164 | adg->rate_of_441khz_div_6 = 0; | ||
165 | adg->rate_of_48khz_div_6 = 0; | ||
166 | for_each_rsnd_clk(clk, adg, i) { | ||
167 | rate = clk_get_rate(clk); | ||
168 | |||
169 | if (0 == rate) /* not used */ | ||
170 | continue; | ||
171 | |||
172 | /* RBGA */ | ||
173 | if (!adg->rate_of_441khz_div_6 && (0 == rate % 44100)) { | ||
174 | adg->rate_of_441khz_div_6 = rate / 6; | ||
175 | ckr |= brg_table[i] << 20; | ||
176 | } | ||
177 | |||
178 | /* RBGB */ | ||
179 | if (!adg->rate_of_48khz_div_6 && (0 == rate % 48000)) { | ||
180 | adg->rate_of_48khz_div_6 = rate / 6; | ||
181 | ckr |= brg_table[i] << 16; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | rsnd_priv_bset(priv, SSICKR, 0x00FF0000, ckr); | ||
186 | rsnd_priv_write(priv, BRRA, 0x00000002); /* 1/6 */ | ||
187 | rsnd_priv_write(priv, BRRB, 0x00000002); /* 1/6 */ | ||
188 | } | ||
189 | |||
190 | int rsnd_adg_probe(struct platform_device *pdev, | ||
191 | struct rcar_snd_info *info, | ||
192 | struct rsnd_priv *priv) | ||
193 | { | ||
194 | struct rsnd_adg *adg; | ||
195 | struct device *dev = rsnd_priv_to_dev(priv); | ||
196 | struct clk *clk; | ||
197 | int i; | ||
198 | |||
199 | adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); | ||
200 | if (!adg) { | ||
201 | dev_err(dev, "ADG allocate failed\n"); | ||
202 | return -ENOMEM; | ||
203 | } | ||
204 | |||
205 | adg->clk[CLKA] = clk_get(NULL, "audio_clk_a"); | ||
206 | adg->clk[CLKB] = clk_get(NULL, "audio_clk_b"); | ||
207 | adg->clk[CLKC] = clk_get(NULL, "audio_clk_c"); | ||
208 | adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal"); | ||
209 | for_each_rsnd_clk(clk, adg, i) { | ||
210 | if (IS_ERR(clk)) { | ||
211 | dev_err(dev, "Audio clock failed\n"); | ||
212 | return -EIO; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | rsnd_adg_ssi_clk_init(priv, adg); | ||
217 | |||
218 | priv->adg = adg; | ||
219 | |||
220 | dev_dbg(dev, "adg probed\n"); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | void rsnd_adg_remove(struct platform_device *pdev, | ||
226 | struct rsnd_priv *priv) | ||
227 | { | ||
228 | struct rsnd_adg *adg = priv->adg; | ||
229 | struct clk *clk; | ||
230 | int i; | ||
231 | |||
232 | for_each_rsnd_clk(clk, adg, i) | ||
233 | clk_put(clk); | ||
234 | } | ||
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c new file mode 100644 index 000000000000..a35706028514 --- /dev/null +++ b/sound/soc/sh/rcar/core.c | |||
@@ -0,0 +1,861 @@ | |||
1 | /* | ||
2 | * Renesas R-Car SRU/SCU/SSIU/SSI support | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * Based on fsi.c | ||
8 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * Renesas R-Car sound device structure | ||
17 | * | ||
18 | * Gen1 | ||
19 | * | ||
20 | * SRU : Sound Routing Unit | ||
21 | * - SRC : Sampling Rate Converter | ||
22 | * - CMD | ||
23 | * - CTU : Channel Count Conversion Unit | ||
24 | * - MIX : Mixer | ||
25 | * - DVC : Digital Volume and Mute Function | ||
26 | * - SSI : Serial Sound Interface | ||
27 | * | ||
28 | * Gen2 | ||
29 | * | ||
30 | * SCU : Sampling Rate Converter Unit | ||
31 | * - SRC : Sampling Rate Converter | ||
32 | * - CMD | ||
33 | * - CTU : Channel Count Conversion Unit | ||
34 | * - MIX : Mixer | ||
35 | * - DVC : Digital Volume and Mute Function | ||
36 | * SSIU : Serial Sound Interface Unit | ||
37 | * - SSI : Serial Sound Interface | ||
38 | */ | ||
39 | |||
40 | /* | ||
41 | * driver data Image | ||
42 | * | ||
43 | * rsnd_priv | ||
44 | * | | ||
45 | * | ** this depends on Gen1/Gen2 | ||
46 | * | | ||
47 | * +- gen | ||
48 | * | | ||
49 | * | ** these depend on data path | ||
50 | * | ** gen and platform data control it | ||
51 | * | | ||
52 | * +- rdai[0] | ||
53 | * | | sru ssiu ssi | ||
54 | * | +- playback -> [mod] -> [mod] -> [mod] -> ... | ||
55 | * | | | ||
56 | * | | sru ssiu ssi | ||
57 | * | +- capture -> [mod] -> [mod] -> [mod] -> ... | ||
58 | * | | ||
59 | * +- rdai[1] | ||
60 | * | | sru ssiu ssi | ||
61 | * | +- playback -> [mod] -> [mod] -> [mod] -> ... | ||
62 | * | | | ||
63 | * | | sru ssiu ssi | ||
64 | * | +- capture -> [mod] -> [mod] -> [mod] -> ... | ||
65 | * ... | ||
66 | * | | ||
67 | * | ** these control ssi | ||
68 | * | | ||
69 | * +- ssi | ||
70 | * | | | ||
71 | * | +- ssi[0] | ||
72 | * | +- ssi[1] | ||
73 | * | +- ssi[2] | ||
74 | * | ... | ||
75 | * | | ||
76 | * | ** these control scu | ||
77 | * | | ||
78 | * +- scu | ||
79 | * | | ||
80 | * +- scu[0] | ||
81 | * +- scu[1] | ||
82 | * +- scu[2] | ||
83 | * ... | ||
84 | * | ||
85 | * | ||
86 | * for_each_rsnd_dai(xx, priv, xx) | ||
87 | * rdai[0] => rdai[1] => rdai[2] => ... | ||
88 | * | ||
89 | * for_each_rsnd_mod(xx, rdai, xx) | ||
90 | * [mod] => [mod] => [mod] => ... | ||
91 | * | ||
92 | * rsnd_dai_call(xxx, fn ) | ||
93 | * [mod]->fn() -> [mod]->fn() -> [mod]->fn()... | ||
94 | * | ||
95 | */ | ||
96 | #include <linux/pm_runtime.h> | ||
97 | #include "rsnd.h" | ||
98 | |||
99 | #define RSND_RATES SNDRV_PCM_RATE_8000_96000 | ||
100 | #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) | ||
101 | |||
102 | /* | ||
103 | * rsnd_platform functions | ||
104 | */ | ||
105 | #define rsnd_platform_call(priv, dai, func, param...) \ | ||
106 | (!(priv->info->func) ? -ENODEV : \ | ||
107 | priv->info->func(param)) | ||
108 | |||
109 | |||
110 | /* | ||
111 | * basic function | ||
112 | */ | ||
113 | u32 rsnd_read(struct rsnd_priv *priv, | ||
114 | struct rsnd_mod *mod, enum rsnd_reg reg) | ||
115 | { | ||
116 | void __iomem *base = rsnd_gen_reg_get(priv, mod, reg); | ||
117 | |||
118 | BUG_ON(!base); | ||
119 | |||
120 | return ioread32(base); | ||
121 | } | ||
122 | |||
123 | void rsnd_write(struct rsnd_priv *priv, | ||
124 | struct rsnd_mod *mod, | ||
125 | enum rsnd_reg reg, u32 data) | ||
126 | { | ||
127 | void __iomem *base = rsnd_gen_reg_get(priv, mod, reg); | ||
128 | struct device *dev = rsnd_priv_to_dev(priv); | ||
129 | |||
130 | BUG_ON(!base); | ||
131 | |||
132 | dev_dbg(dev, "w %p : %08x\n", base, data); | ||
133 | |||
134 | iowrite32(data, base); | ||
135 | } | ||
136 | |||
137 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | ||
138 | enum rsnd_reg reg, u32 mask, u32 data) | ||
139 | { | ||
140 | void __iomem *base = rsnd_gen_reg_get(priv, mod, reg); | ||
141 | struct device *dev = rsnd_priv_to_dev(priv); | ||
142 | u32 val; | ||
143 | |||
144 | BUG_ON(!base); | ||
145 | |||
146 | val = ioread32(base); | ||
147 | val &= ~mask; | ||
148 | val |= data & mask; | ||
149 | iowrite32(val, base); | ||
150 | |||
151 | dev_dbg(dev, "s %p : %08x\n", base, val); | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * rsnd_mod functions | ||
156 | */ | ||
157 | char *rsnd_mod_name(struct rsnd_mod *mod) | ||
158 | { | ||
159 | if (!mod || !mod->ops) | ||
160 | return "unknown"; | ||
161 | |||
162 | return mod->ops->name; | ||
163 | } | ||
164 | |||
165 | void rsnd_mod_init(struct rsnd_priv *priv, | ||
166 | struct rsnd_mod *mod, | ||
167 | struct rsnd_mod_ops *ops, | ||
168 | int id) | ||
169 | { | ||
170 | mod->priv = priv; | ||
171 | mod->id = id; | ||
172 | mod->ops = ops; | ||
173 | INIT_LIST_HEAD(&mod->list); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * rsnd_dma functions | ||
178 | */ | ||
179 | static void rsnd_dma_continue(struct rsnd_dma *dma) | ||
180 | { | ||
181 | /* push next A or B plane */ | ||
182 | dma->submit_loop = 1; | ||
183 | schedule_work(&dma->work); | ||
184 | } | ||
185 | |||
186 | void rsnd_dma_start(struct rsnd_dma *dma) | ||
187 | { | ||
188 | /* push both A and B plane*/ | ||
189 | dma->submit_loop = 2; | ||
190 | schedule_work(&dma->work); | ||
191 | } | ||
192 | |||
193 | void rsnd_dma_stop(struct rsnd_dma *dma) | ||
194 | { | ||
195 | dma->submit_loop = 0; | ||
196 | cancel_work_sync(&dma->work); | ||
197 | dmaengine_terminate_all(dma->chan); | ||
198 | } | ||
199 | |||
200 | static void rsnd_dma_complete(void *data) | ||
201 | { | ||
202 | struct rsnd_dma *dma = (struct rsnd_dma *)data; | ||
203 | struct rsnd_priv *priv = dma->priv; | ||
204 | unsigned long flags; | ||
205 | |||
206 | rsnd_lock(priv, flags); | ||
207 | |||
208 | dma->complete(dma); | ||
209 | |||
210 | if (dma->submit_loop) | ||
211 | rsnd_dma_continue(dma); | ||
212 | |||
213 | rsnd_unlock(priv, flags); | ||
214 | } | ||
215 | |||
216 | static void rsnd_dma_do_work(struct work_struct *work) | ||
217 | { | ||
218 | struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work); | ||
219 | struct rsnd_priv *priv = dma->priv; | ||
220 | struct device *dev = rsnd_priv_to_dev(priv); | ||
221 | struct dma_async_tx_descriptor *desc; | ||
222 | dma_addr_t buf; | ||
223 | size_t len; | ||
224 | int i; | ||
225 | |||
226 | for (i = 0; i < dma->submit_loop; i++) { | ||
227 | |||
228 | if (dma->inquiry(dma, &buf, &len) < 0) | ||
229 | return; | ||
230 | |||
231 | desc = dmaengine_prep_slave_single( | ||
232 | dma->chan, buf, len, dma->dir, | ||
233 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
234 | if (!desc) { | ||
235 | dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | desc->callback = rsnd_dma_complete; | ||
240 | desc->callback_param = dma; | ||
241 | |||
242 | if (dmaengine_submit(desc) < 0) { | ||
243 | dev_err(dev, "dmaengine_submit() fail\n"); | ||
244 | return; | ||
245 | } | ||
246 | |||
247 | } | ||
248 | |||
249 | dma_async_issue_pending(dma->chan); | ||
250 | } | ||
251 | |||
252 | int rsnd_dma_available(struct rsnd_dma *dma) | ||
253 | { | ||
254 | return !!dma->chan; | ||
255 | } | ||
256 | |||
257 | static bool rsnd_dma_filter(struct dma_chan *chan, void *param) | ||
258 | { | ||
259 | chan->private = param; | ||
260 | |||
261 | return true; | ||
262 | } | ||
263 | |||
264 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | ||
265 | int is_play, int id, | ||
266 | int (*inquiry)(struct rsnd_dma *dma, | ||
267 | dma_addr_t *buf, int *len), | ||
268 | int (*complete)(struct rsnd_dma *dma)) | ||
269 | { | ||
270 | struct device *dev = rsnd_priv_to_dev(priv); | ||
271 | dma_cap_mask_t mask; | ||
272 | |||
273 | if (dma->chan) { | ||
274 | dev_err(dev, "it already has dma channel\n"); | ||
275 | return -EIO; | ||
276 | } | ||
277 | |||
278 | dma_cap_zero(mask); | ||
279 | dma_cap_set(DMA_SLAVE, mask); | ||
280 | |||
281 | dma->slave.shdma_slave.slave_id = id; | ||
282 | |||
283 | dma->chan = dma_request_channel(mask, rsnd_dma_filter, | ||
284 | &dma->slave.shdma_slave); | ||
285 | if (!dma->chan) { | ||
286 | dev_err(dev, "can't get dma channel\n"); | ||
287 | return -EIO; | ||
288 | } | ||
289 | |||
290 | dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | ||
291 | dma->priv = priv; | ||
292 | dma->inquiry = inquiry; | ||
293 | dma->complete = complete; | ||
294 | INIT_WORK(&dma->work, rsnd_dma_do_work); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | void rsnd_dma_quit(struct rsnd_priv *priv, | ||
300 | struct rsnd_dma *dma) | ||
301 | { | ||
302 | if (dma->chan) | ||
303 | dma_release_channel(dma->chan); | ||
304 | |||
305 | dma->chan = NULL; | ||
306 | } | ||
307 | |||
308 | /* | ||
309 | * rsnd_dai functions | ||
310 | */ | ||
311 | #define rsnd_dai_call(rdai, io, fn) \ | ||
312 | ({ \ | ||
313 | struct rsnd_mod *mod, *n; \ | ||
314 | int ret = 0; \ | ||
315 | for_each_rsnd_mod(mod, n, io) { \ | ||
316 | ret = rsnd_mod_call(mod, fn, rdai, io); \ | ||
317 | if (ret < 0) \ | ||
318 | break; \ | ||
319 | } \ | ||
320 | ret; \ | ||
321 | }) | ||
322 | |||
323 | int rsnd_dai_connect(struct rsnd_dai *rdai, | ||
324 | struct rsnd_mod *mod, | ||
325 | struct rsnd_dai_stream *io) | ||
326 | { | ||
327 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
328 | struct device *dev = rsnd_priv_to_dev(priv); | ||
329 | |||
330 | if (!mod) { | ||
331 | dev_err(dev, "NULL mod\n"); | ||
332 | return -EIO; | ||
333 | } | ||
334 | |||
335 | if (!list_empty(&mod->list)) { | ||
336 | dev_err(dev, "%s%d is not empty\n", | ||
337 | rsnd_mod_name(mod), | ||
338 | rsnd_mod_id(mod)); | ||
339 | return -EIO; | ||
340 | } | ||
341 | |||
342 | list_add_tail(&mod->list, &io->head); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | int rsnd_dai_disconnect(struct rsnd_mod *mod) | ||
348 | { | ||
349 | list_del_init(&mod->list); | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) | ||
355 | { | ||
356 | int id = rdai - priv->rdai; | ||
357 | |||
358 | if ((id < 0) || (id >= rsnd_dai_nr(priv))) | ||
359 | return -EINVAL; | ||
360 | |||
361 | return id; | ||
362 | } | ||
363 | |||
364 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id) | ||
365 | { | ||
366 | return priv->rdai + id; | ||
367 | } | ||
368 | |||
369 | static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) | ||
370 | { | ||
371 | struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai); | ||
372 | |||
373 | return rsnd_dai_get(priv, dai->id); | ||
374 | } | ||
375 | |||
376 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io) | ||
377 | { | ||
378 | return &rdai->playback == io; | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * rsnd_soc_dai functions | ||
383 | */ | ||
384 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional) | ||
385 | { | ||
386 | struct snd_pcm_substream *substream = io->substream; | ||
387 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
388 | int pos = io->byte_pos + additional; | ||
389 | |||
390 | pos %= (runtime->periods * io->byte_per_period); | ||
391 | |||
392 | return pos; | ||
393 | } | ||
394 | |||
395 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) | ||
396 | { | ||
397 | io->byte_pos += byte; | ||
398 | |||
399 | if (io->byte_pos >= io->next_period_byte) { | ||
400 | struct snd_pcm_substream *substream = io->substream; | ||
401 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
402 | |||
403 | io->period_pos++; | ||
404 | io->next_period_byte += io->byte_per_period; | ||
405 | |||
406 | if (io->period_pos >= runtime->periods) { | ||
407 | io->byte_pos = 0; | ||
408 | io->period_pos = 0; | ||
409 | io->next_period_byte = io->byte_per_period; | ||
410 | } | ||
411 | |||
412 | snd_pcm_period_elapsed(substream); | ||
413 | } | ||
414 | } | ||
415 | |||
416 | static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, | ||
417 | struct snd_pcm_substream *substream) | ||
418 | { | ||
419 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
420 | |||
421 | if (!list_empty(&io->head)) | ||
422 | return -EIO; | ||
423 | |||
424 | INIT_LIST_HEAD(&io->head); | ||
425 | io->substream = substream; | ||
426 | io->byte_pos = 0; | ||
427 | io->period_pos = 0; | ||
428 | io->byte_per_period = runtime->period_size * | ||
429 | runtime->channels * | ||
430 | samples_to_bytes(runtime, 1); | ||
431 | io->next_period_byte = io->byte_per_period; | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static | ||
437 | struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream) | ||
438 | { | ||
439 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
440 | |||
441 | return rtd->cpu_dai; | ||
442 | } | ||
443 | |||
444 | static | ||
445 | struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai, | ||
446 | struct snd_pcm_substream *substream) | ||
447 | { | ||
448 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
449 | return &rdai->playback; | ||
450 | else | ||
451 | return &rdai->capture; | ||
452 | } | ||
453 | |||
454 | static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | ||
455 | struct snd_soc_dai *dai) | ||
456 | { | ||
457 | struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai); | ||
458 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | ||
459 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | ||
460 | struct rsnd_mod *mod = rsnd_ssi_mod_get_frm_dai(priv, | ||
461 | rsnd_dai_id(priv, rdai), | ||
462 | rsnd_dai_is_play(rdai, io)); | ||
463 | int ssi_id = rsnd_mod_id(mod); | ||
464 | int ret; | ||
465 | unsigned long flags; | ||
466 | |||
467 | rsnd_lock(priv, flags); | ||
468 | |||
469 | switch (cmd) { | ||
470 | case SNDRV_PCM_TRIGGER_START: | ||
471 | ret = rsnd_dai_stream_init(io, substream); | ||
472 | if (ret < 0) | ||
473 | goto dai_trigger_end; | ||
474 | |||
475 | ret = rsnd_platform_call(priv, dai, start, ssi_id); | ||
476 | if (ret < 0) | ||
477 | goto dai_trigger_end; | ||
478 | |||
479 | ret = rsnd_gen_path_init(priv, rdai, io); | ||
480 | if (ret < 0) | ||
481 | goto dai_trigger_end; | ||
482 | |||
483 | ret = rsnd_dai_call(rdai, io, init); | ||
484 | if (ret < 0) | ||
485 | goto dai_trigger_end; | ||
486 | |||
487 | ret = rsnd_dai_call(rdai, io, start); | ||
488 | if (ret < 0) | ||
489 | goto dai_trigger_end; | ||
490 | break; | ||
491 | case SNDRV_PCM_TRIGGER_STOP: | ||
492 | ret = rsnd_dai_call(rdai, io, stop); | ||
493 | if (ret < 0) | ||
494 | goto dai_trigger_end; | ||
495 | |||
496 | ret = rsnd_dai_call(rdai, io, quit); | ||
497 | if (ret < 0) | ||
498 | goto dai_trigger_end; | ||
499 | |||
500 | ret = rsnd_gen_path_exit(priv, rdai, io); | ||
501 | if (ret < 0) | ||
502 | goto dai_trigger_end; | ||
503 | |||
504 | ret = rsnd_platform_call(priv, dai, stop, ssi_id); | ||
505 | if (ret < 0) | ||
506 | goto dai_trigger_end; | ||
507 | break; | ||
508 | default: | ||
509 | ret = -EINVAL; | ||
510 | } | ||
511 | |||
512 | dai_trigger_end: | ||
513 | rsnd_unlock(priv, flags); | ||
514 | |||
515 | return ret; | ||
516 | } | ||
517 | |||
518 | static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
519 | { | ||
520 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | ||
521 | |||
522 | /* set master/slave audio interface */ | ||
523 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
524 | case SND_SOC_DAIFMT_CBM_CFM: | ||
525 | rdai->clk_master = 1; | ||
526 | break; | ||
527 | case SND_SOC_DAIFMT_CBS_CFS: | ||
528 | rdai->clk_master = 0; | ||
529 | break; | ||
530 | default: | ||
531 | return -EINVAL; | ||
532 | } | ||
533 | |||
534 | /* set clock inversion */ | ||
535 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
536 | case SND_SOC_DAIFMT_NB_IF: | ||
537 | rdai->bit_clk_inv = 0; | ||
538 | rdai->frm_clk_inv = 1; | ||
539 | break; | ||
540 | case SND_SOC_DAIFMT_IB_NF: | ||
541 | rdai->bit_clk_inv = 1; | ||
542 | rdai->frm_clk_inv = 0; | ||
543 | break; | ||
544 | case SND_SOC_DAIFMT_IB_IF: | ||
545 | rdai->bit_clk_inv = 1; | ||
546 | rdai->frm_clk_inv = 1; | ||
547 | break; | ||
548 | case SND_SOC_DAIFMT_NB_NF: | ||
549 | default: | ||
550 | rdai->bit_clk_inv = 0; | ||
551 | rdai->frm_clk_inv = 0; | ||
552 | break; | ||
553 | } | ||
554 | |||
555 | /* set format */ | ||
556 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
557 | case SND_SOC_DAIFMT_I2S: | ||
558 | rdai->sys_delay = 0; | ||
559 | rdai->data_alignment = 0; | ||
560 | break; | ||
561 | case SND_SOC_DAIFMT_LEFT_J: | ||
562 | rdai->sys_delay = 1; | ||
563 | rdai->data_alignment = 0; | ||
564 | break; | ||
565 | case SND_SOC_DAIFMT_RIGHT_J: | ||
566 | rdai->sys_delay = 1; | ||
567 | rdai->data_alignment = 1; | ||
568 | break; | ||
569 | } | ||
570 | |||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { | ||
575 | .trigger = rsnd_soc_dai_trigger, | ||
576 | .set_fmt = rsnd_soc_dai_set_fmt, | ||
577 | }; | ||
578 | |||
579 | static int rsnd_dai_probe(struct platform_device *pdev, | ||
580 | struct rcar_snd_info *info, | ||
581 | struct rsnd_priv *priv) | ||
582 | { | ||
583 | struct snd_soc_dai_driver *drv; | ||
584 | struct rsnd_dai *rdai; | ||
585 | struct rsnd_mod *pmod, *cmod; | ||
586 | struct device *dev = rsnd_priv_to_dev(priv); | ||
587 | int dai_nr; | ||
588 | int i; | ||
589 | |||
590 | /* get max dai nr */ | ||
591 | for (dai_nr = 0; dai_nr < 32; dai_nr++) { | ||
592 | pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1); | ||
593 | cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0); | ||
594 | |||
595 | if (!pmod && !cmod) | ||
596 | break; | ||
597 | } | ||
598 | |||
599 | if (!dai_nr) { | ||
600 | dev_err(dev, "no dai\n"); | ||
601 | return -EIO; | ||
602 | } | ||
603 | |||
604 | drv = devm_kzalloc(dev, sizeof(*drv) * dai_nr, GFP_KERNEL); | ||
605 | rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL); | ||
606 | if (!drv || !rdai) { | ||
607 | dev_err(dev, "dai allocate failed\n"); | ||
608 | return -ENOMEM; | ||
609 | } | ||
610 | |||
611 | for (i = 0; i < dai_nr; i++) { | ||
612 | |||
613 | pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1); | ||
614 | cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0); | ||
615 | |||
616 | /* | ||
617 | * init rsnd_dai | ||
618 | */ | ||
619 | INIT_LIST_HEAD(&rdai[i].playback.head); | ||
620 | INIT_LIST_HEAD(&rdai[i].capture.head); | ||
621 | |||
622 | snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i); | ||
623 | |||
624 | /* | ||
625 | * init snd_soc_dai_driver | ||
626 | */ | ||
627 | drv[i].name = rdai[i].name; | ||
628 | drv[i].ops = &rsnd_soc_dai_ops; | ||
629 | if (pmod) { | ||
630 | drv[i].playback.rates = RSND_RATES; | ||
631 | drv[i].playback.formats = RSND_FMTS; | ||
632 | drv[i].playback.channels_min = 2; | ||
633 | drv[i].playback.channels_max = 2; | ||
634 | } | ||
635 | if (cmod) { | ||
636 | drv[i].capture.rates = RSND_RATES; | ||
637 | drv[i].capture.formats = RSND_FMTS; | ||
638 | drv[i].capture.channels_min = 2; | ||
639 | drv[i].capture.channels_max = 2; | ||
640 | } | ||
641 | |||
642 | dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name, | ||
643 | pmod ? "play" : " -- ", | ||
644 | cmod ? "capture" : " -- "); | ||
645 | } | ||
646 | |||
647 | priv->dai_nr = dai_nr; | ||
648 | priv->daidrv = drv; | ||
649 | priv->rdai = rdai; | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static void rsnd_dai_remove(struct platform_device *pdev, | ||
655 | struct rsnd_priv *priv) | ||
656 | { | ||
657 | } | ||
658 | |||
659 | /* | ||
660 | * pcm ops | ||
661 | */ | ||
662 | static struct snd_pcm_hardware rsnd_pcm_hardware = { | ||
663 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
664 | SNDRV_PCM_INFO_MMAP | | ||
665 | SNDRV_PCM_INFO_MMAP_VALID | | ||
666 | SNDRV_PCM_INFO_PAUSE, | ||
667 | .formats = RSND_FMTS, | ||
668 | .rates = RSND_RATES, | ||
669 | .rate_min = 8000, | ||
670 | .rate_max = 192000, | ||
671 | .channels_min = 2, | ||
672 | .channels_max = 2, | ||
673 | .buffer_bytes_max = 64 * 1024, | ||
674 | .period_bytes_min = 32, | ||
675 | .period_bytes_max = 8192, | ||
676 | .periods_min = 1, | ||
677 | .periods_max = 32, | ||
678 | .fifo_size = 256, | ||
679 | }; | ||
680 | |||
681 | static int rsnd_pcm_open(struct snd_pcm_substream *substream) | ||
682 | { | ||
683 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
684 | int ret = 0; | ||
685 | |||
686 | snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware); | ||
687 | |||
688 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
689 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
690 | |||
691 | return ret; | ||
692 | } | ||
693 | |||
694 | static int rsnd_hw_params(struct snd_pcm_substream *substream, | ||
695 | struct snd_pcm_hw_params *hw_params) | ||
696 | { | ||
697 | return snd_pcm_lib_malloc_pages(substream, | ||
698 | params_buffer_bytes(hw_params)); | ||
699 | } | ||
700 | |||
701 | static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) | ||
702 | { | ||
703 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
704 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); | ||
705 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | ||
706 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | ||
707 | |||
708 | return bytes_to_frames(runtime, io->byte_pos); | ||
709 | } | ||
710 | |||
711 | static struct snd_pcm_ops rsnd_pcm_ops = { | ||
712 | .open = rsnd_pcm_open, | ||
713 | .ioctl = snd_pcm_lib_ioctl, | ||
714 | .hw_params = rsnd_hw_params, | ||
715 | .hw_free = snd_pcm_lib_free_pages, | ||
716 | .pointer = rsnd_pointer, | ||
717 | }; | ||
718 | |||
719 | /* | ||
720 | * snd_soc_platform | ||
721 | */ | ||
722 | |||
723 | #define PREALLOC_BUFFER (32 * 1024) | ||
724 | #define PREALLOC_BUFFER_MAX (32 * 1024) | ||
725 | |||
726 | static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
727 | { | ||
728 | return snd_pcm_lib_preallocate_pages_for_all( | ||
729 | rtd->pcm, | ||
730 | SNDRV_DMA_TYPE_DEV, | ||
731 | rtd->card->snd_card->dev, | ||
732 | PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); | ||
733 | } | ||
734 | |||
735 | static void rsnd_pcm_free(struct snd_pcm *pcm) | ||
736 | { | ||
737 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
738 | } | ||
739 | |||
740 | static struct snd_soc_platform_driver rsnd_soc_platform = { | ||
741 | .ops = &rsnd_pcm_ops, | ||
742 | .pcm_new = rsnd_pcm_new, | ||
743 | .pcm_free = rsnd_pcm_free, | ||
744 | }; | ||
745 | |||
746 | static const struct snd_soc_component_driver rsnd_soc_component = { | ||
747 | .name = "rsnd", | ||
748 | }; | ||
749 | |||
750 | /* | ||
751 | * rsnd probe | ||
752 | */ | ||
753 | static int rsnd_probe(struct platform_device *pdev) | ||
754 | { | ||
755 | struct rcar_snd_info *info; | ||
756 | struct rsnd_priv *priv; | ||
757 | struct device *dev = &pdev->dev; | ||
758 | int ret; | ||
759 | |||
760 | info = pdev->dev.platform_data; | ||
761 | if (!info) { | ||
762 | dev_err(dev, "driver needs R-Car sound information\n"); | ||
763 | return -ENODEV; | ||
764 | } | ||
765 | |||
766 | /* | ||
767 | * init priv data | ||
768 | */ | ||
769 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
770 | if (!priv) { | ||
771 | dev_err(dev, "priv allocate failed\n"); | ||
772 | return -ENODEV; | ||
773 | } | ||
774 | |||
775 | priv->dev = dev; | ||
776 | priv->info = info; | ||
777 | spin_lock_init(&priv->lock); | ||
778 | |||
779 | /* | ||
780 | * init each module | ||
781 | */ | ||
782 | ret = rsnd_gen_probe(pdev, info, priv); | ||
783 | if (ret < 0) | ||
784 | return ret; | ||
785 | |||
786 | ret = rsnd_scu_probe(pdev, info, priv); | ||
787 | if (ret < 0) | ||
788 | return ret; | ||
789 | |||
790 | ret = rsnd_adg_probe(pdev, info, priv); | ||
791 | if (ret < 0) | ||
792 | return ret; | ||
793 | |||
794 | ret = rsnd_ssi_probe(pdev, info, priv); | ||
795 | if (ret < 0) | ||
796 | return ret; | ||
797 | |||
798 | ret = rsnd_dai_probe(pdev, info, priv); | ||
799 | if (ret < 0) | ||
800 | return ret; | ||
801 | |||
802 | /* | ||
803 | * asoc register | ||
804 | */ | ||
805 | ret = snd_soc_register_platform(dev, &rsnd_soc_platform); | ||
806 | if (ret < 0) { | ||
807 | dev_err(dev, "cannot snd soc register\n"); | ||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | ret = snd_soc_register_component(dev, &rsnd_soc_component, | ||
812 | priv->daidrv, rsnd_dai_nr(priv)); | ||
813 | if (ret < 0) { | ||
814 | dev_err(dev, "cannot snd dai register\n"); | ||
815 | goto exit_snd_soc; | ||
816 | } | ||
817 | |||
818 | dev_set_drvdata(dev, priv); | ||
819 | |||
820 | pm_runtime_enable(dev); | ||
821 | |||
822 | dev_info(dev, "probed\n"); | ||
823 | return ret; | ||
824 | |||
825 | exit_snd_soc: | ||
826 | snd_soc_unregister_platform(dev); | ||
827 | |||
828 | return ret; | ||
829 | } | ||
830 | |||
831 | static int rsnd_remove(struct platform_device *pdev) | ||
832 | { | ||
833 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); | ||
834 | |||
835 | pm_runtime_disable(&pdev->dev); | ||
836 | |||
837 | /* | ||
838 | * remove each module | ||
839 | */ | ||
840 | rsnd_ssi_remove(pdev, priv); | ||
841 | rsnd_adg_remove(pdev, priv); | ||
842 | rsnd_scu_remove(pdev, priv); | ||
843 | rsnd_dai_remove(pdev, priv); | ||
844 | rsnd_gen_remove(pdev, priv); | ||
845 | |||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | static struct platform_driver rsnd_driver = { | ||
850 | .driver = { | ||
851 | .name = "rcar_sound", | ||
852 | }, | ||
853 | .probe = rsnd_probe, | ||
854 | .remove = rsnd_remove, | ||
855 | }; | ||
856 | module_platform_driver(rsnd_driver); | ||
857 | |||
858 | MODULE_LICENSE("GPL"); | ||
859 | MODULE_DESCRIPTION("Renesas R-Car audio driver"); | ||
860 | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); | ||
861 | MODULE_ALIAS("platform:rcar-pcm-audio"); | ||
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c new file mode 100644 index 000000000000..babb203b43b7 --- /dev/null +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -0,0 +1,280 @@ | |||
1 | /* | ||
2 | * Renesas R-Car Gen1 SRU/SSI support | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include "rsnd.h" | ||
12 | |||
13 | struct rsnd_gen_ops { | ||
14 | int (*path_init)(struct rsnd_priv *priv, | ||
15 | struct rsnd_dai *rdai, | ||
16 | struct rsnd_dai_stream *io); | ||
17 | int (*path_exit)(struct rsnd_priv *priv, | ||
18 | struct rsnd_dai *rdai, | ||
19 | struct rsnd_dai_stream *io); | ||
20 | }; | ||
21 | |||
22 | struct rsnd_gen_reg_map { | ||
23 | int index; /* -1 : not supported */ | ||
24 | u32 offset_id; /* offset of ssi0, ssi1, ssi2... */ | ||
25 | u32 offset_adr; /* offset of SSICR, SSISR, ... */ | ||
26 | }; | ||
27 | |||
28 | struct rsnd_gen { | ||
29 | void __iomem *base[RSND_BASE_MAX]; | ||
30 | |||
31 | struct rsnd_gen_reg_map reg_map[RSND_REG_MAX]; | ||
32 | struct rsnd_gen_ops *ops; | ||
33 | }; | ||
34 | |||
35 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) | ||
36 | |||
37 | /* | ||
38 | * Gen2 | ||
39 | * will be filled in the future | ||
40 | */ | ||
41 | |||
42 | /* | ||
43 | * Gen1 | ||
44 | */ | ||
45 | static int rsnd_gen1_path_init(struct rsnd_priv *priv, | ||
46 | struct rsnd_dai *rdai, | ||
47 | struct rsnd_dai_stream *io) | ||
48 | { | ||
49 | struct rsnd_mod *mod; | ||
50 | int ret; | ||
51 | int id; | ||
52 | |||
53 | /* | ||
54 | * Gen1 is created by SRU/SSI, and this SRU is base module of | ||
55 | * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) | ||
56 | * | ||
57 | * Easy image is.. | ||
58 | * Gen1 SRU = Gen2 SCU + SSIU + etc | ||
59 | * | ||
60 | * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is | ||
61 | * using fixed path. | ||
62 | * | ||
63 | * Then, SSI id = SCU id here | ||
64 | */ | ||
65 | |||
66 | /* get SSI's ID */ | ||
67 | mod = rsnd_ssi_mod_get_frm_dai(priv, | ||
68 | rsnd_dai_id(priv, rdai), | ||
69 | rsnd_dai_is_play(rdai, io)); | ||
70 | id = rsnd_mod_id(mod); | ||
71 | |||
72 | /* SSI */ | ||
73 | mod = rsnd_ssi_mod_get(priv, id); | ||
74 | ret = rsnd_dai_connect(rdai, mod, io); | ||
75 | if (ret < 0) | ||
76 | return ret; | ||
77 | |||
78 | /* SCU */ | ||
79 | mod = rsnd_scu_mod_get(priv, id); | ||
80 | ret = rsnd_dai_connect(rdai, mod, io); | ||
81 | |||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | static int rsnd_gen1_path_exit(struct rsnd_priv *priv, | ||
86 | struct rsnd_dai *rdai, | ||
87 | struct rsnd_dai_stream *io) | ||
88 | { | ||
89 | struct rsnd_mod *mod, *n; | ||
90 | int ret = 0; | ||
91 | |||
92 | /* | ||
93 | * remove all mod from rdai | ||
94 | */ | ||
95 | for_each_rsnd_mod(mod, n, io) | ||
96 | ret |= rsnd_dai_disconnect(mod); | ||
97 | |||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | static struct rsnd_gen_ops rsnd_gen1_ops = { | ||
102 | .path_init = rsnd_gen1_path_init, | ||
103 | .path_exit = rsnd_gen1_path_exit, | ||
104 | }; | ||
105 | |||
106 | #define RSND_GEN1_REG_MAP(g, s, i, oi, oa) \ | ||
107 | do { \ | ||
108 | (g)->reg_map[RSND_REG_##i].index = RSND_GEN1_##s; \ | ||
109 | (g)->reg_map[RSND_REG_##i].offset_id = oi; \ | ||
110 | (g)->reg_map[RSND_REG_##i].offset_adr = oa; \ | ||
111 | } while (0) | ||
112 | |||
113 | static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen) | ||
114 | { | ||
115 | RSND_GEN1_REG_MAP(gen, SRU, SRC_ROUTE_SEL, 0x0, 0x00); | ||
116 | RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL0, 0x0, 0x08); | ||
117 | RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL1, 0x0, 0x0c); | ||
118 | RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL2, 0x0, 0x10); | ||
119 | RSND_GEN1_REG_MAP(gen, SRU, SRC_CTRL, 0x0, 0xc0); | ||
120 | RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE0, 0x0, 0xD0); | ||
121 | RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE1, 0x0, 0xD4); | ||
122 | RSND_GEN1_REG_MAP(gen, SRU, BUSIF_MODE, 0x4, 0x20); | ||
123 | RSND_GEN1_REG_MAP(gen, SRU, BUSIF_ADINR, 0x40, 0x214); | ||
124 | |||
125 | RSND_GEN1_REG_MAP(gen, ADG, BRRA, 0x0, 0x00); | ||
126 | RSND_GEN1_REG_MAP(gen, ADG, BRRB, 0x0, 0x04); | ||
127 | RSND_GEN1_REG_MAP(gen, ADG, SSICKR, 0x0, 0x08); | ||
128 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL0, 0x0, 0x0c); | ||
129 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL1, 0x0, 0x10); | ||
130 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL3, 0x0, 0x18); | ||
131 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL4, 0x0, 0x1c); | ||
132 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL5, 0x0, 0x20); | ||
133 | |||
134 | RSND_GEN1_REG_MAP(gen, SSI, SSICR, 0x40, 0x00); | ||
135 | RSND_GEN1_REG_MAP(gen, SSI, SSISR, 0x40, 0x04); | ||
136 | RSND_GEN1_REG_MAP(gen, SSI, SSITDR, 0x40, 0x08); | ||
137 | RSND_GEN1_REG_MAP(gen, SSI, SSIRDR, 0x40, 0x0c); | ||
138 | RSND_GEN1_REG_MAP(gen, SSI, SSIWSR, 0x40, 0x20); | ||
139 | } | ||
140 | |||
141 | static int rsnd_gen1_probe(struct platform_device *pdev, | ||
142 | struct rcar_snd_info *info, | ||
143 | struct rsnd_priv *priv) | ||
144 | { | ||
145 | struct device *dev = rsnd_priv_to_dev(priv); | ||
146 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
147 | struct resource *sru_res; | ||
148 | struct resource *adg_res; | ||
149 | struct resource *ssi_res; | ||
150 | |||
151 | /* | ||
152 | * map address | ||
153 | */ | ||
154 | sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU); | ||
155 | adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG); | ||
156 | ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI); | ||
157 | |||
158 | gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res); | ||
159 | gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res); | ||
160 | gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res); | ||
161 | if (IS_ERR(gen->base[RSND_GEN1_SRU]) || | ||
162 | IS_ERR(gen->base[RSND_GEN1_ADG]) || | ||
163 | IS_ERR(gen->base[RSND_GEN1_SSI])) | ||
164 | return -ENODEV; | ||
165 | |||
166 | gen->ops = &rsnd_gen1_ops; | ||
167 | rsnd_gen1_reg_map_init(gen); | ||
168 | |||
169 | dev_dbg(dev, "Gen1 device probed\n"); | ||
170 | dev_dbg(dev, "SRU : %08x => %p\n", sru_res->start, | ||
171 | gen->base[RSND_GEN1_SRU]); | ||
172 | dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, | ||
173 | gen->base[RSND_GEN1_ADG]); | ||
174 | dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start, | ||
175 | gen->base[RSND_GEN1_SSI]); | ||
176 | |||
177 | return 0; | ||
178 | |||
179 | } | ||
180 | |||
181 | static void rsnd_gen1_remove(struct platform_device *pdev, | ||
182 | struct rsnd_priv *priv) | ||
183 | { | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Gen | ||
188 | */ | ||
189 | int rsnd_gen_path_init(struct rsnd_priv *priv, | ||
190 | struct rsnd_dai *rdai, | ||
191 | struct rsnd_dai_stream *io) | ||
192 | { | ||
193 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
194 | |||
195 | return gen->ops->path_init(priv, rdai, io); | ||
196 | } | ||
197 | |||
198 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | ||
199 | struct rsnd_dai *rdai, | ||
200 | struct rsnd_dai_stream *io) | ||
201 | { | ||
202 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
203 | |||
204 | return gen->ops->path_exit(priv, rdai, io); | ||
205 | } | ||
206 | |||
207 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | ||
208 | struct rsnd_mod *mod, | ||
209 | enum rsnd_reg reg) | ||
210 | { | ||
211 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
212 | struct device *dev = rsnd_priv_to_dev(priv); | ||
213 | int index; | ||
214 | u32 offset_id, offset_adr; | ||
215 | |||
216 | if (reg >= RSND_REG_MAX) { | ||
217 | dev_err(dev, "rsnd_reg reg error\n"); | ||
218 | return NULL; | ||
219 | } | ||
220 | |||
221 | index = gen->reg_map[reg].index; | ||
222 | offset_id = gen->reg_map[reg].offset_id; | ||
223 | offset_adr = gen->reg_map[reg].offset_adr; | ||
224 | |||
225 | if (index < 0) { | ||
226 | dev_err(dev, "unsupported reg access %d\n", reg); | ||
227 | return NULL; | ||
228 | } | ||
229 | |||
230 | if (offset_id && mod) | ||
231 | offset_id *= rsnd_mod_id(mod); | ||
232 | |||
233 | /* | ||
234 | * index/offset were set on gen1/gen2 | ||
235 | */ | ||
236 | |||
237 | return gen->base[index] + offset_id + offset_adr; | ||
238 | } | ||
239 | |||
240 | int rsnd_gen_probe(struct platform_device *pdev, | ||
241 | struct rcar_snd_info *info, | ||
242 | struct rsnd_priv *priv) | ||
243 | { | ||
244 | struct device *dev = rsnd_priv_to_dev(priv); | ||
245 | struct rsnd_gen *gen; | ||
246 | int i; | ||
247 | |||
248 | gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); | ||
249 | if (!gen) { | ||
250 | dev_err(dev, "GEN allocate failed\n"); | ||
251 | return -ENOMEM; | ||
252 | } | ||
253 | |||
254 | priv->gen = gen; | ||
255 | |||
256 | /* | ||
257 | * see | ||
258 | * rsnd_reg_get() | ||
259 | * rsnd_gen_probe() | ||
260 | */ | ||
261 | for (i = 0; i < RSND_REG_MAX; i++) | ||
262 | gen->reg_map[i].index = -1; | ||
263 | |||
264 | /* | ||
265 | * init each module | ||
266 | */ | ||
267 | if (rsnd_is_gen1(priv)) | ||
268 | return rsnd_gen1_probe(pdev, info, priv); | ||
269 | |||
270 | dev_err(dev, "unknown generation R-Car sound device\n"); | ||
271 | |||
272 | return -ENODEV; | ||
273 | } | ||
274 | |||
275 | void rsnd_gen_remove(struct platform_device *pdev, | ||
276 | struct rsnd_priv *priv) | ||
277 | { | ||
278 | if (rsnd_is_gen1(priv)) | ||
279 | rsnd_gen1_remove(pdev, priv); | ||
280 | } | ||
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h new file mode 100644 index 000000000000..9cc6986a8cfb --- /dev/null +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * Renesas R-Car | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #ifndef RSND_H | ||
12 | #define RSND_H | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/sh_dma.h> | ||
21 | #include <linux/workqueue.h> | ||
22 | #include <sound/rcar_snd.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | |||
26 | /* | ||
27 | * pseudo register | ||
28 | * | ||
29 | * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different. | ||
30 | * This driver uses pseudo register in order to hide it. | ||
31 | * see gen1/gen2 for detail | ||
32 | */ | ||
33 | enum rsnd_reg { | ||
34 | /* SRU/SCU */ | ||
35 | RSND_REG_SRC_ROUTE_SEL, | ||
36 | RSND_REG_SRC_TMG_SEL0, | ||
37 | RSND_REG_SRC_TMG_SEL1, | ||
38 | RSND_REG_SRC_TMG_SEL2, | ||
39 | RSND_REG_SRC_CTRL, | ||
40 | RSND_REG_SSI_MODE0, | ||
41 | RSND_REG_SSI_MODE1, | ||
42 | RSND_REG_BUSIF_MODE, | ||
43 | RSND_REG_BUSIF_ADINR, | ||
44 | |||
45 | /* ADG */ | ||
46 | RSND_REG_BRRA, | ||
47 | RSND_REG_BRRB, | ||
48 | RSND_REG_SSICKR, | ||
49 | RSND_REG_AUDIO_CLK_SEL0, | ||
50 | RSND_REG_AUDIO_CLK_SEL1, | ||
51 | RSND_REG_AUDIO_CLK_SEL2, | ||
52 | RSND_REG_AUDIO_CLK_SEL3, | ||
53 | RSND_REG_AUDIO_CLK_SEL4, | ||
54 | RSND_REG_AUDIO_CLK_SEL5, | ||
55 | |||
56 | /* SSI */ | ||
57 | RSND_REG_SSICR, | ||
58 | RSND_REG_SSISR, | ||
59 | RSND_REG_SSITDR, | ||
60 | RSND_REG_SSIRDR, | ||
61 | RSND_REG_SSIWSR, | ||
62 | |||
63 | RSND_REG_MAX, | ||
64 | }; | ||
65 | |||
66 | struct rsnd_priv; | ||
67 | struct rsnd_mod; | ||
68 | struct rsnd_dai; | ||
69 | struct rsnd_dai_stream; | ||
70 | |||
71 | /* | ||
72 | * R-Car basic functions | ||
73 | */ | ||
74 | #define rsnd_mod_read(m, r) \ | ||
75 | rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r) | ||
76 | #define rsnd_mod_write(m, r, d) \ | ||
77 | rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) | ||
78 | #define rsnd_mod_bset(m, r, s, d) \ | ||
79 | rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) | ||
80 | |||
81 | #define rsnd_priv_read(p, r) rsnd_read(p, NULL, RSND_REG_##r) | ||
82 | #define rsnd_priv_write(p, r, d) rsnd_write(p, NULL, RSND_REG_##r, d) | ||
83 | #define rsnd_priv_bset(p, r, s, d) rsnd_bset(p, NULL, RSND_REG_##r, s, d) | ||
84 | |||
85 | u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); | ||
86 | void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, | ||
87 | enum rsnd_reg reg, u32 data); | ||
88 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, | ||
89 | u32 mask, u32 data); | ||
90 | |||
91 | /* | ||
92 | * R-Car DMA | ||
93 | */ | ||
94 | struct rsnd_dma { | ||
95 | struct rsnd_priv *priv; | ||
96 | struct sh_dmae_slave slave; | ||
97 | struct work_struct work; | ||
98 | struct dma_chan *chan; | ||
99 | enum dma_data_direction dir; | ||
100 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len); | ||
101 | int (*complete)(struct rsnd_dma *dma); | ||
102 | |||
103 | int submit_loop; | ||
104 | }; | ||
105 | |||
106 | void rsnd_dma_start(struct rsnd_dma *dma); | ||
107 | void rsnd_dma_stop(struct rsnd_dma *dma); | ||
108 | int rsnd_dma_available(struct rsnd_dma *dma); | ||
109 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | ||
110 | int is_play, int id, | ||
111 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len), | ||
112 | int (*complete)(struct rsnd_dma *dma)); | ||
113 | void rsnd_dma_quit(struct rsnd_priv *priv, | ||
114 | struct rsnd_dma *dma); | ||
115 | |||
116 | |||
117 | /* | ||
118 | * R-Car sound mod | ||
119 | */ | ||
120 | |||
121 | struct rsnd_mod_ops { | ||
122 | char *name; | ||
123 | int (*init)(struct rsnd_mod *mod, | ||
124 | struct rsnd_dai *rdai, | ||
125 | struct rsnd_dai_stream *io); | ||
126 | int (*quit)(struct rsnd_mod *mod, | ||
127 | struct rsnd_dai *rdai, | ||
128 | struct rsnd_dai_stream *io); | ||
129 | int (*start)(struct rsnd_mod *mod, | ||
130 | struct rsnd_dai *rdai, | ||
131 | struct rsnd_dai_stream *io); | ||
132 | int (*stop)(struct rsnd_mod *mod, | ||
133 | struct rsnd_dai *rdai, | ||
134 | struct rsnd_dai_stream *io); | ||
135 | }; | ||
136 | |||
137 | struct rsnd_mod { | ||
138 | int id; | ||
139 | struct rsnd_priv *priv; | ||
140 | struct rsnd_mod_ops *ops; | ||
141 | struct list_head list; /* connect to rsnd_dai playback/capture */ | ||
142 | struct rsnd_dma dma; | ||
143 | }; | ||
144 | |||
145 | #define rsnd_mod_to_priv(mod) ((mod)->priv) | ||
146 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) | ||
147 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) | ||
148 | #define rsnd_mod_id(mod) ((mod)->id) | ||
149 | #define for_each_rsnd_mod(pos, n, io) \ | ||
150 | list_for_each_entry_safe(pos, n, &(io)->head, list) | ||
151 | #define rsnd_mod_call(mod, func, rdai, io) \ | ||
152 | (!(mod) ? -ENODEV : \ | ||
153 | !((mod)->ops->func) ? 0 : \ | ||
154 | (mod)->ops->func(mod, rdai, io)) | ||
155 | |||
156 | void rsnd_mod_init(struct rsnd_priv *priv, | ||
157 | struct rsnd_mod *mod, | ||
158 | struct rsnd_mod_ops *ops, | ||
159 | int id); | ||
160 | char *rsnd_mod_name(struct rsnd_mod *mod); | ||
161 | |||
162 | /* | ||
163 | * R-Car sound DAI | ||
164 | */ | ||
165 | #define RSND_DAI_NAME_SIZE 16 | ||
166 | struct rsnd_dai_stream { | ||
167 | struct list_head head; /* head of rsnd_mod list */ | ||
168 | struct snd_pcm_substream *substream; | ||
169 | int byte_pos; | ||
170 | int period_pos; | ||
171 | int byte_per_period; | ||
172 | int next_period_byte; | ||
173 | }; | ||
174 | |||
175 | struct rsnd_dai { | ||
176 | char name[RSND_DAI_NAME_SIZE]; | ||
177 | struct rsnd_dai_platform_info *info; /* rcar_snd.h */ | ||
178 | struct rsnd_dai_stream playback; | ||
179 | struct rsnd_dai_stream capture; | ||
180 | |||
181 | int clk_master:1; | ||
182 | int bit_clk_inv:1; | ||
183 | int frm_clk_inv:1; | ||
184 | int sys_delay:1; | ||
185 | int data_alignment:1; | ||
186 | }; | ||
187 | |||
188 | #define rsnd_dai_nr(priv) ((priv)->dai_nr) | ||
189 | #define for_each_rsnd_dai(rdai, priv, i) \ | ||
190 | for (i = 0, (rdai) = rsnd_dai_get(priv, i); \ | ||
191 | i < rsnd_dai_nr(priv); \ | ||
192 | i++, (rdai) = rsnd_dai_get(priv, i)) | ||
193 | |||
194 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); | ||
195 | int rsnd_dai_disconnect(struct rsnd_mod *mod); | ||
196 | int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod, | ||
197 | struct rsnd_dai_stream *io); | ||
198 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); | ||
199 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); | ||
200 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) | ||
201 | #define rsnd_io_to_runtime(io) ((io)->substream->runtime) | ||
202 | |||
203 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); | ||
204 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); | ||
205 | |||
206 | /* | ||
207 | * R-Car Gen1/Gen2 | ||
208 | */ | ||
209 | int rsnd_gen_probe(struct platform_device *pdev, | ||
210 | struct rcar_snd_info *info, | ||
211 | struct rsnd_priv *priv); | ||
212 | void rsnd_gen_remove(struct platform_device *pdev, | ||
213 | struct rsnd_priv *priv); | ||
214 | int rsnd_gen_path_init(struct rsnd_priv *priv, | ||
215 | struct rsnd_dai *rdai, | ||
216 | struct rsnd_dai_stream *io); | ||
217 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | ||
218 | struct rsnd_dai *rdai, | ||
219 | struct rsnd_dai_stream *io); | ||
220 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | ||
221 | struct rsnd_mod *mod, | ||
222 | enum rsnd_reg reg); | ||
223 | #define rsnd_is_gen1(s) ((s)->info->flags & RSND_GEN1) | ||
224 | #define rsnd_is_gen2(s) ((s)->info->flags & RSND_GEN2) | ||
225 | |||
226 | /* | ||
227 | * R-Car ADG | ||
228 | */ | ||
229 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); | ||
230 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); | ||
231 | int rsnd_adg_probe(struct platform_device *pdev, | ||
232 | struct rcar_snd_info *info, | ||
233 | struct rsnd_priv *priv); | ||
234 | void rsnd_adg_remove(struct platform_device *pdev, | ||
235 | struct rsnd_priv *priv); | ||
236 | |||
237 | /* | ||
238 | * R-Car sound priv | ||
239 | */ | ||
240 | struct rsnd_priv { | ||
241 | |||
242 | struct device *dev; | ||
243 | struct rcar_snd_info *info; | ||
244 | spinlock_t lock; | ||
245 | |||
246 | /* | ||
247 | * below value will be filled on rsnd_gen_probe() | ||
248 | */ | ||
249 | void *gen; | ||
250 | |||
251 | /* | ||
252 | * below value will be filled on rsnd_scu_probe() | ||
253 | */ | ||
254 | void *scu; | ||
255 | int scu_nr; | ||
256 | |||
257 | /* | ||
258 | * below value will be filled on rsnd_adg_probe() | ||
259 | */ | ||
260 | void *adg; | ||
261 | |||
262 | /* | ||
263 | * below value will be filled on rsnd_ssi_probe() | ||
264 | */ | ||
265 | void *ssiu; | ||
266 | |||
267 | /* | ||
268 | * below value will be filled on rsnd_dai_probe() | ||
269 | */ | ||
270 | struct snd_soc_dai_driver *daidrv; | ||
271 | struct rsnd_dai *rdai; | ||
272 | int dai_nr; | ||
273 | }; | ||
274 | |||
275 | #define rsnd_priv_to_dev(priv) ((priv)->dev) | ||
276 | #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) | ||
277 | #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) | ||
278 | |||
279 | /* | ||
280 | * R-Car SCU | ||
281 | */ | ||
282 | int rsnd_scu_probe(struct platform_device *pdev, | ||
283 | struct rcar_snd_info *info, | ||
284 | struct rsnd_priv *priv); | ||
285 | void rsnd_scu_remove(struct platform_device *pdev, | ||
286 | struct rsnd_priv *priv); | ||
287 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); | ||
288 | #define rsnd_scu_nr(priv) ((priv)->scu_nr) | ||
289 | |||
290 | /* | ||
291 | * R-Car SSI | ||
292 | */ | ||
293 | int rsnd_ssi_probe(struct platform_device *pdev, | ||
294 | struct rcar_snd_info *info, | ||
295 | struct rsnd_priv *priv); | ||
296 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
297 | struct rsnd_priv *priv); | ||
298 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | ||
299 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, | ||
300 | int dai_id, int is_play); | ||
301 | |||
302 | #endif | ||
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c new file mode 100644 index 000000000000..184d9008cecd --- /dev/null +++ b/sound/soc/sh/rcar/scu.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * Renesas R-Car SCU support | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include "rsnd.h" | ||
12 | |||
13 | struct rsnd_scu { | ||
14 | struct rsnd_scu_platform_info *info; /* rcar_snd.h */ | ||
15 | struct rsnd_mod mod; | ||
16 | }; | ||
17 | |||
18 | #define rsnd_scu_mode_flags(p) ((p)->info->flags) | ||
19 | |||
20 | /* | ||
21 | * ADINR | ||
22 | */ | ||
23 | #define OTBL_24 (0 << 16) | ||
24 | #define OTBL_22 (2 << 16) | ||
25 | #define OTBL_20 (4 << 16) | ||
26 | #define OTBL_18 (6 << 16) | ||
27 | #define OTBL_16 (8 << 16) | ||
28 | |||
29 | |||
30 | #define rsnd_mod_to_scu(_mod) \ | ||
31 | container_of((_mod), struct rsnd_scu, mod) | ||
32 | |||
33 | #define for_each_rsnd_scu(pos, priv, i) \ | ||
34 | for ((i) = 0; \ | ||
35 | ((i) < rsnd_scu_nr(priv)) && \ | ||
36 | ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ | ||
37 | i++) | ||
38 | |||
39 | static int rsnd_scu_set_route(struct rsnd_priv *priv, | ||
40 | struct rsnd_mod *mod, | ||
41 | struct rsnd_dai *rdai, | ||
42 | struct rsnd_dai_stream *io) | ||
43 | { | ||
44 | struct scu_route_config { | ||
45 | u32 mask; | ||
46 | int shift; | ||
47 | } routes[] = { | ||
48 | { 0xF, 0, }, /* 0 */ | ||
49 | { 0xF, 4, }, /* 1 */ | ||
50 | { 0xF, 8, }, /* 2 */ | ||
51 | { 0x7, 12, }, /* 3 */ | ||
52 | { 0x7, 16, }, /* 4 */ | ||
53 | { 0x7, 20, }, /* 5 */ | ||
54 | { 0x7, 24, }, /* 6 */ | ||
55 | { 0x3, 28, }, /* 7 */ | ||
56 | { 0x3, 30, }, /* 8 */ | ||
57 | }; | ||
58 | |||
59 | u32 mask; | ||
60 | u32 val; | ||
61 | int shift; | ||
62 | int id; | ||
63 | |||
64 | /* | ||
65 | * Gen1 only | ||
66 | */ | ||
67 | if (!rsnd_is_gen1(priv)) | ||
68 | return 0; | ||
69 | |||
70 | id = rsnd_mod_id(mod); | ||
71 | if (id < 0 || id > ARRAY_SIZE(routes)) | ||
72 | return -EIO; | ||
73 | |||
74 | /* | ||
75 | * SRC_ROUTE_SELECT | ||
76 | */ | ||
77 | val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2; | ||
78 | val = val << routes[id].shift; | ||
79 | mask = routes[id].mask << routes[id].shift; | ||
80 | |||
81 | rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); | ||
82 | |||
83 | /* | ||
84 | * SRC_TIMING_SELECT | ||
85 | */ | ||
86 | shift = (id % 4) * 8; | ||
87 | mask = 0x1F << shift; | ||
88 | if (8 == id) /* SRU8 is very special */ | ||
89 | val = id << shift; | ||
90 | else | ||
91 | val = (id + 1) << shift; | ||
92 | |||
93 | switch (id / 4) { | ||
94 | case 0: | ||
95 | rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); | ||
96 | break; | ||
97 | case 1: | ||
98 | rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); | ||
99 | break; | ||
100 | case 2: | ||
101 | rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); | ||
102 | break; | ||
103 | } | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int rsnd_scu_set_mode(struct rsnd_priv *priv, | ||
109 | struct rsnd_mod *mod, | ||
110 | struct rsnd_dai *rdai, | ||
111 | struct rsnd_dai_stream *io) | ||
112 | { | ||
113 | int id = rsnd_mod_id(mod); | ||
114 | u32 val; | ||
115 | |||
116 | if (rsnd_is_gen1(priv)) { | ||
117 | val = (1 << id); | ||
118 | rsnd_mod_bset(mod, SRC_CTRL, val, val); | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, | ||
125 | struct rsnd_mod *mod, | ||
126 | struct rsnd_dai *rdai, | ||
127 | struct rsnd_dai_stream *io) | ||
128 | { | ||
129 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
130 | u32 adinr = runtime->channels; | ||
131 | |||
132 | switch (runtime->sample_bits) { | ||
133 | case 16: | ||
134 | adinr |= OTBL_16; | ||
135 | break; | ||
136 | case 32: | ||
137 | adinr |= OTBL_24; | ||
138 | break; | ||
139 | default: | ||
140 | return -EIO; | ||
141 | } | ||
142 | |||
143 | rsnd_mod_write(mod, BUSIF_MODE, 1); | ||
144 | rsnd_mod_write(mod, BUSIF_ADINR, adinr); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int rsnd_scu_start(struct rsnd_mod *mod, | ||
150 | struct rsnd_dai *rdai, | ||
151 | struct rsnd_dai_stream *io) | ||
152 | { | ||
153 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
154 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
155 | struct device *dev = rsnd_priv_to_dev(priv); | ||
156 | u32 flags = rsnd_scu_mode_flags(scu); | ||
157 | int ret; | ||
158 | |||
159 | /* | ||
160 | * SCU will be used if it has RSND_SCU_USB_HPBIF flags | ||
161 | */ | ||
162 | if (!(flags & RSND_SCU_USB_HPBIF)) { | ||
163 | /* it use PIO transter */ | ||
164 | dev_dbg(dev, "%s%d is not used\n", | ||
165 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* it use DMA transter */ | ||
171 | ret = rsnd_scu_set_route(priv, mod, rdai, io); | ||
172 | if (ret < 0) | ||
173 | return ret; | ||
174 | |||
175 | ret = rsnd_scu_set_mode(priv, mod, rdai, io); | ||
176 | if (ret < 0) | ||
177 | return ret; | ||
178 | |||
179 | ret = rsnd_scu_set_hpbif(priv, mod, rdai, io); | ||
180 | if (ret < 0) | ||
181 | return ret; | ||
182 | |||
183 | dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static struct rsnd_mod_ops rsnd_scu_ops = { | ||
189 | .name = "scu", | ||
190 | .start = rsnd_scu_start, | ||
191 | }; | ||
192 | |||
193 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) | ||
194 | { | ||
195 | BUG_ON(id < 0 || id >= rsnd_scu_nr(priv)); | ||
196 | |||
197 | return &((struct rsnd_scu *)(priv->scu) + id)->mod; | ||
198 | } | ||
199 | |||
200 | int rsnd_scu_probe(struct platform_device *pdev, | ||
201 | struct rcar_snd_info *info, | ||
202 | struct rsnd_priv *priv) | ||
203 | { | ||
204 | struct device *dev = rsnd_priv_to_dev(priv); | ||
205 | struct rsnd_scu *scu; | ||
206 | int i, nr; | ||
207 | |||
208 | /* | ||
209 | * init SCU | ||
210 | */ | ||
211 | nr = info->scu_info_nr; | ||
212 | scu = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL); | ||
213 | if (!scu) { | ||
214 | dev_err(dev, "SCU allocate failed\n"); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | |||
218 | priv->scu_nr = nr; | ||
219 | priv->scu = scu; | ||
220 | |||
221 | for_each_rsnd_scu(scu, priv, i) { | ||
222 | rsnd_mod_init(priv, &scu->mod, | ||
223 | &rsnd_scu_ops, i); | ||
224 | scu->info = &info->scu_info[i]; | ||
225 | |||
226 | dev_dbg(dev, "SCU%d probed\n", i); | ||
227 | } | ||
228 | dev_dbg(dev, "scu probed\n"); | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | void rsnd_scu_remove(struct platform_device *pdev, | ||
234 | struct rsnd_priv *priv) | ||
235 | { | ||
236 | } | ||
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c new file mode 100644 index 000000000000..fae26d3f79d2 --- /dev/null +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -0,0 +1,728 @@ | |||
1 | /* | ||
2 | * Renesas R-Car SSIU/SSI support | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * Based on fsi.c | ||
8 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | #include <linux/delay.h> | ||
15 | #include "rsnd.h" | ||
16 | #define RSND_SSI_NAME_SIZE 16 | ||
17 | |||
18 | /* | ||
19 | * SSICR | ||
20 | */ | ||
21 | #define FORCE (1 << 31) /* Fixed */ | ||
22 | #define DMEN (1 << 28) /* DMA Enable */ | ||
23 | #define UIEN (1 << 27) /* Underflow Interrupt Enable */ | ||
24 | #define OIEN (1 << 26) /* Overflow Interrupt Enable */ | ||
25 | #define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ | ||
26 | #define DIEN (1 << 24) /* Data Interrupt Enable */ | ||
27 | |||
28 | #define DWL_8 (0 << 19) /* Data Word Length */ | ||
29 | #define DWL_16 (1 << 19) /* Data Word Length */ | ||
30 | #define DWL_18 (2 << 19) /* Data Word Length */ | ||
31 | #define DWL_20 (3 << 19) /* Data Word Length */ | ||
32 | #define DWL_22 (4 << 19) /* Data Word Length */ | ||
33 | #define DWL_24 (5 << 19) /* Data Word Length */ | ||
34 | #define DWL_32 (6 << 19) /* Data Word Length */ | ||
35 | |||
36 | #define SWL_32 (3 << 16) /* R/W System Word Length */ | ||
37 | #define SCKD (1 << 15) /* Serial Bit Clock Direction */ | ||
38 | #define SWSD (1 << 14) /* Serial WS Direction */ | ||
39 | #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ | ||
40 | #define SWSP (1 << 12) /* Serial WS Polarity */ | ||
41 | #define SDTA (1 << 10) /* Serial Data Alignment */ | ||
42 | #define DEL (1 << 8) /* Serial Data Delay */ | ||
43 | #define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ | ||
44 | #define TRMD (1 << 1) /* Transmit/Receive Mode Select */ | ||
45 | #define EN (1 << 0) /* SSI Module Enable */ | ||
46 | |||
47 | /* | ||
48 | * SSISR | ||
49 | */ | ||
50 | #define UIRQ (1 << 27) /* Underflow Error Interrupt Status */ | ||
51 | #define OIRQ (1 << 26) /* Overflow Error Interrupt Status */ | ||
52 | #define IIRQ (1 << 25) /* Idle Mode Interrupt Status */ | ||
53 | #define DIRQ (1 << 24) /* Data Interrupt Status Flag */ | ||
54 | |||
55 | /* | ||
56 | * SSIWSR | ||
57 | */ | ||
58 | #define CONT (1 << 8) /* WS Continue Function */ | ||
59 | |||
60 | struct rsnd_ssi { | ||
61 | struct clk *clk; | ||
62 | struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ | ||
63 | struct rsnd_ssi *parent; | ||
64 | struct rsnd_mod mod; | ||
65 | |||
66 | struct rsnd_dai *rdai; | ||
67 | struct rsnd_dai_stream *io; | ||
68 | u32 cr_own; | ||
69 | u32 cr_clk; | ||
70 | u32 cr_etc; | ||
71 | int err; | ||
72 | int dma_offset; | ||
73 | unsigned int usrcnt; | ||
74 | unsigned int rate; | ||
75 | }; | ||
76 | |||
77 | struct rsnd_ssiu { | ||
78 | u32 ssi_mode0; | ||
79 | u32 ssi_mode1; | ||
80 | |||
81 | int ssi_nr; | ||
82 | struct rsnd_ssi *ssi; | ||
83 | }; | ||
84 | |||
85 | #define for_each_rsnd_ssi(pos, priv, i) \ | ||
86 | for (i = 0; \ | ||
87 | (i < rsnd_ssi_nr(priv)) && \ | ||
88 | ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \ | ||
89 | i++) | ||
90 | |||
91 | #define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr) | ||
92 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | ||
93 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) | ||
94 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) | ||
95 | #define rsnd_ssi_dma_available(ssi) \ | ||
96 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) | ||
97 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) | ||
98 | #define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) | ||
99 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) | ||
100 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) | ||
101 | #define rsnd_ssi_to_ssiu(ssi)\ | ||
102 | (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1) | ||
103 | |||
104 | static void rsnd_ssi_mode_init(struct rsnd_priv *priv, | ||
105 | struct rsnd_ssiu *ssiu) | ||
106 | { | ||
107 | struct device *dev = rsnd_priv_to_dev(priv); | ||
108 | struct rsnd_ssi *ssi; | ||
109 | u32 flags; | ||
110 | u32 val; | ||
111 | int i; | ||
112 | |||
113 | /* | ||
114 | * SSI_MODE0 | ||
115 | */ | ||
116 | ssiu->ssi_mode0 = 0; | ||
117 | for_each_rsnd_ssi(ssi, priv, i) { | ||
118 | flags = rsnd_ssi_mode_flags(ssi); | ||
119 | |||
120 | /* see also BUSIF_MODE */ | ||
121 | if (!(flags & RSND_SSI_DEPENDENT)) { | ||
122 | ssiu->ssi_mode0 |= (1 << i); | ||
123 | dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", i); | ||
124 | } else { | ||
125 | dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * SSI_MODE1 | ||
131 | */ | ||
132 | #define ssi_parent_set(p, sync, adg, ext) \ | ||
133 | do { \ | ||
134 | ssi->parent = ssiu->ssi + p; \ | ||
135 | if (flags & RSND_SSI_CLK_FROM_ADG) \ | ||
136 | val = adg; \ | ||
137 | else \ | ||
138 | val = ext; \ | ||
139 | if (flags & RSND_SSI_SYNC) \ | ||
140 | val |= sync; \ | ||
141 | } while (0) | ||
142 | |||
143 | ssiu->ssi_mode1 = 0; | ||
144 | for_each_rsnd_ssi(ssi, priv, i) { | ||
145 | flags = rsnd_ssi_mode_flags(ssi); | ||
146 | |||
147 | if (!(flags & RSND_SSI_CLK_PIN_SHARE)) | ||
148 | continue; | ||
149 | |||
150 | val = 0; | ||
151 | switch (i) { | ||
152 | case 1: | ||
153 | ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0)); | ||
154 | break; | ||
155 | case 2: | ||
156 | ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2)); | ||
157 | break; | ||
158 | case 4: | ||
159 | ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16)); | ||
160 | break; | ||
161 | case 8: | ||
162 | ssi_parent_set(7, 0, 0, 0); | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | ssiu->ssi_mode1 |= val; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi) | ||
171 | { | ||
172 | struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi); | ||
173 | |||
174 | rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0); | ||
175 | rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1); | ||
176 | } | ||
177 | |||
178 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, | ||
179 | u32 bit) | ||
180 | { | ||
181 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
182 | struct device *dev = rsnd_priv_to_dev(priv); | ||
183 | u32 status; | ||
184 | int i; | ||
185 | |||
186 | for (i = 0; i < 1024; i++) { | ||
187 | status = rsnd_mod_read(mod, SSISR); | ||
188 | if (status & bit) | ||
189 | return; | ||
190 | |||
191 | udelay(50); | ||
192 | } | ||
193 | |||
194 | dev_warn(dev, "status check failed\n"); | ||
195 | } | ||
196 | |||
197 | static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | ||
198 | unsigned int rate) | ||
199 | { | ||
200 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | ||
201 | struct device *dev = rsnd_priv_to_dev(priv); | ||
202 | int i, j, ret; | ||
203 | int adg_clk_div_table[] = { | ||
204 | 1, 6, /* see adg.c */ | ||
205 | }; | ||
206 | int ssi_clk_mul_table[] = { | ||
207 | 1, 2, 4, 8, 16, 6, 12, | ||
208 | }; | ||
209 | unsigned int main_rate; | ||
210 | |||
211 | /* | ||
212 | * Find best clock, and try to start ADG | ||
213 | */ | ||
214 | for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) { | ||
215 | for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { | ||
216 | |||
217 | /* | ||
218 | * this driver is assuming that | ||
219 | * system word is 64fs (= 2 x 32bit) | ||
220 | * see rsnd_ssi_start() | ||
221 | */ | ||
222 | main_rate = rate / adg_clk_div_table[i] | ||
223 | * 32 * 2 * ssi_clk_mul_table[j]; | ||
224 | |||
225 | ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate); | ||
226 | if (0 == ret) { | ||
227 | ssi->rate = rate; | ||
228 | ssi->cr_clk = FORCE | SWL_32 | | ||
229 | SCKD | SWSD | CKDV(j); | ||
230 | |||
231 | dev_dbg(dev, "ssi%d outputs %u Hz\n", | ||
232 | rsnd_mod_id(&ssi->mod), rate); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | |||
239 | dev_err(dev, "unsupported clock rate\n"); | ||
240 | return -EIO; | ||
241 | } | ||
242 | |||
243 | static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi) | ||
244 | { | ||
245 | ssi->rate = 0; | ||
246 | ssi->cr_clk = 0; | ||
247 | rsnd_adg_ssi_clk_stop(&ssi->mod); | ||
248 | } | ||
249 | |||
250 | static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | ||
251 | struct rsnd_dai *rdai, | ||
252 | struct rsnd_dai_stream *io) | ||
253 | { | ||
254 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | ||
255 | struct device *dev = rsnd_priv_to_dev(priv); | ||
256 | u32 cr; | ||
257 | |||
258 | if (0 == ssi->usrcnt) { | ||
259 | clk_enable(ssi->clk); | ||
260 | |||
261 | if (rsnd_rdai_is_clk_master(rdai)) { | ||
262 | struct snd_pcm_runtime *runtime; | ||
263 | |||
264 | runtime = rsnd_io_to_runtime(io); | ||
265 | |||
266 | if (rsnd_ssi_clk_from_parent(ssi)) | ||
267 | rsnd_ssi_hw_start(ssi->parent, rdai, io); | ||
268 | else | ||
269 | rsnd_ssi_master_clk_start(ssi, runtime->rate); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | cr = ssi->cr_own | | ||
274 | ssi->cr_clk | | ||
275 | ssi->cr_etc | | ||
276 | EN; | ||
277 | |||
278 | rsnd_mod_write(&ssi->mod, SSICR, cr); | ||
279 | |||
280 | ssi->usrcnt++; | ||
281 | |||
282 | dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod)); | ||
283 | } | ||
284 | |||
285 | static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, | ||
286 | struct rsnd_dai *rdai) | ||
287 | { | ||
288 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | ||
289 | struct device *dev = rsnd_priv_to_dev(priv); | ||
290 | u32 cr; | ||
291 | |||
292 | if (0 == ssi->usrcnt) /* stop might be called without start */ | ||
293 | return; | ||
294 | |||
295 | ssi->usrcnt--; | ||
296 | |||
297 | if (0 == ssi->usrcnt) { | ||
298 | /* | ||
299 | * disable all IRQ, | ||
300 | * and, wait all data was sent | ||
301 | */ | ||
302 | cr = ssi->cr_own | | ||
303 | ssi->cr_clk; | ||
304 | |||
305 | rsnd_mod_write(&ssi->mod, SSICR, cr | EN); | ||
306 | rsnd_ssi_status_check(&ssi->mod, DIRQ); | ||
307 | |||
308 | /* | ||
309 | * disable SSI, | ||
310 | * and, wait idle state | ||
311 | */ | ||
312 | rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */ | ||
313 | rsnd_ssi_status_check(&ssi->mod, IIRQ); | ||
314 | |||
315 | if (rsnd_rdai_is_clk_master(rdai)) { | ||
316 | if (rsnd_ssi_clk_from_parent(ssi)) | ||
317 | rsnd_ssi_hw_stop(ssi->parent, rdai); | ||
318 | else | ||
319 | rsnd_ssi_master_clk_stop(ssi); | ||
320 | } | ||
321 | |||
322 | clk_disable(ssi->clk); | ||
323 | } | ||
324 | |||
325 | dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod)); | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * SSI mod common functions | ||
330 | */ | ||
331 | static int rsnd_ssi_init(struct rsnd_mod *mod, | ||
332 | struct rsnd_dai *rdai, | ||
333 | struct rsnd_dai_stream *io) | ||
334 | { | ||
335 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
336 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
337 | struct device *dev = rsnd_priv_to_dev(priv); | ||
338 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
339 | u32 cr; | ||
340 | |||
341 | cr = FORCE; | ||
342 | |||
343 | /* | ||
344 | * always use 32bit system word for easy clock calculation. | ||
345 | * see also rsnd_ssi_master_clk_enable() | ||
346 | */ | ||
347 | cr |= SWL_32; | ||
348 | |||
349 | /* | ||
350 | * init clock settings for SSICR | ||
351 | */ | ||
352 | switch (runtime->sample_bits) { | ||
353 | case 16: | ||
354 | cr |= DWL_16; | ||
355 | break; | ||
356 | case 32: | ||
357 | cr |= DWL_24; | ||
358 | break; | ||
359 | default: | ||
360 | return -EIO; | ||
361 | } | ||
362 | |||
363 | if (rdai->bit_clk_inv) | ||
364 | cr |= SCKP; | ||
365 | if (rdai->frm_clk_inv) | ||
366 | cr |= SWSP; | ||
367 | if (rdai->data_alignment) | ||
368 | cr |= SDTA; | ||
369 | if (rdai->sys_delay) | ||
370 | cr |= DEL; | ||
371 | if (rsnd_dai_is_play(rdai, io)) | ||
372 | cr |= TRMD; | ||
373 | |||
374 | /* | ||
375 | * set ssi parameter | ||
376 | */ | ||
377 | ssi->rdai = rdai; | ||
378 | ssi->io = io; | ||
379 | ssi->cr_own = cr; | ||
380 | ssi->err = -1; /* ignore 1st error */ | ||
381 | |||
382 | rsnd_ssi_mode_set(ssi); | ||
383 | |||
384 | dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int rsnd_ssi_quit(struct rsnd_mod *mod, | ||
390 | struct rsnd_dai *rdai, | ||
391 | struct rsnd_dai_stream *io) | ||
392 | { | ||
393 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
394 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
395 | struct device *dev = rsnd_priv_to_dev(priv); | ||
396 | |||
397 | dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
398 | |||
399 | if (ssi->err > 0) | ||
400 | dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err); | ||
401 | |||
402 | ssi->rdai = NULL; | ||
403 | ssi->io = NULL; | ||
404 | ssi->cr_own = 0; | ||
405 | ssi->err = 0; | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | ||
411 | { | ||
412 | /* under/over flow error */ | ||
413 | if (status & (UIRQ | OIRQ)) { | ||
414 | ssi->err++; | ||
415 | |||
416 | /* clear error status */ | ||
417 | rsnd_mod_write(&ssi->mod, SSISR, 0); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | /* | ||
422 | * SSI PIO | ||
423 | */ | ||
424 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | ||
425 | { | ||
426 | struct rsnd_ssi *ssi = data; | ||
427 | struct rsnd_dai_stream *io = ssi->io; | ||
428 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | ||
429 | irqreturn_t ret = IRQ_NONE; | ||
430 | |||
431 | if (io && (status & DIRQ)) { | ||
432 | struct rsnd_dai *rdai = ssi->rdai; | ||
433 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
434 | u32 *buf = (u32 *)(runtime->dma_area + | ||
435 | rsnd_dai_pointer_offset(io, 0)); | ||
436 | |||
437 | rsnd_ssi_record_error(ssi, status); | ||
438 | |||
439 | /* | ||
440 | * 8/16/32 data can be assesse to TDR/RDR register | ||
441 | * directly as 32bit data | ||
442 | * see rsnd_ssi_init() | ||
443 | */ | ||
444 | if (rsnd_dai_is_play(rdai, io)) | ||
445 | rsnd_mod_write(&ssi->mod, SSITDR, *buf); | ||
446 | else | ||
447 | *buf = rsnd_mod_read(&ssi->mod, SSIRDR); | ||
448 | |||
449 | rsnd_dai_pointer_update(io, sizeof(*buf)); | ||
450 | |||
451 | ret = IRQ_HANDLED; | ||
452 | } | ||
453 | |||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | ||
458 | struct rsnd_dai *rdai, | ||
459 | struct rsnd_dai_stream *io) | ||
460 | { | ||
461 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
462 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
463 | struct device *dev = rsnd_priv_to_dev(priv); | ||
464 | |||
465 | /* enable PIO IRQ */ | ||
466 | ssi->cr_etc = UIEN | OIEN | DIEN; | ||
467 | |||
468 | rsnd_ssi_hw_start(ssi, rdai, io); | ||
469 | |||
470 | dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | ||
476 | struct rsnd_dai *rdai, | ||
477 | struct rsnd_dai_stream *io) | ||
478 | { | ||
479 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
480 | struct device *dev = rsnd_priv_to_dev(priv); | ||
481 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
482 | |||
483 | dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
484 | |||
485 | ssi->cr_etc = 0; | ||
486 | |||
487 | rsnd_ssi_hw_stop(ssi, rdai); | ||
488 | |||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | ||
493 | .name = "ssi (pio)", | ||
494 | .init = rsnd_ssi_init, | ||
495 | .quit = rsnd_ssi_quit, | ||
496 | .start = rsnd_ssi_pio_start, | ||
497 | .stop = rsnd_ssi_pio_stop, | ||
498 | }; | ||
499 | |||
500 | static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len) | ||
501 | { | ||
502 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | ||
503 | struct rsnd_dai_stream *io = ssi->io; | ||
504 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
505 | |||
506 | *len = io->byte_per_period; | ||
507 | *buf = runtime->dma_addr + | ||
508 | rsnd_dai_pointer_offset(io, ssi->dma_offset + *len); | ||
509 | ssi->dma_offset = *len; /* it cares A/B plane */ | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static int rsnd_ssi_dma_complete(struct rsnd_dma *dma) | ||
515 | { | ||
516 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | ||
517 | struct rsnd_dai_stream *io = ssi->io; | ||
518 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | ||
519 | |||
520 | rsnd_ssi_record_error(ssi, status); | ||
521 | |||
522 | rsnd_dai_pointer_update(ssi->io, io->byte_per_period); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | ||
528 | struct rsnd_dai *rdai, | ||
529 | struct rsnd_dai_stream *io) | ||
530 | { | ||
531 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
532 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); | ||
533 | |||
534 | /* enable DMA transfer */ | ||
535 | ssi->cr_etc = DMEN; | ||
536 | ssi->dma_offset = 0; | ||
537 | |||
538 | rsnd_dma_start(dma); | ||
539 | |||
540 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); | ||
541 | |||
542 | /* enable WS continue */ | ||
543 | if (rsnd_rdai_is_clk_master(rdai)) | ||
544 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | ||
550 | struct rsnd_dai *rdai, | ||
551 | struct rsnd_dai_stream *io) | ||
552 | { | ||
553 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
554 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); | ||
555 | |||
556 | ssi->cr_etc = 0; | ||
557 | |||
558 | rsnd_ssi_hw_stop(ssi, rdai); | ||
559 | |||
560 | rsnd_dma_stop(dma); | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | ||
566 | .name = "ssi (dma)", | ||
567 | .init = rsnd_ssi_init, | ||
568 | .quit = rsnd_ssi_quit, | ||
569 | .start = rsnd_ssi_dma_start, | ||
570 | .stop = rsnd_ssi_dma_stop, | ||
571 | }; | ||
572 | |||
573 | /* | ||
574 | * Non SSI | ||
575 | */ | ||
576 | static int rsnd_ssi_non(struct rsnd_mod *mod, | ||
577 | struct rsnd_dai *rdai, | ||
578 | struct rsnd_dai_stream *io) | ||
579 | { | ||
580 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
581 | struct device *dev = rsnd_priv_to_dev(priv); | ||
582 | |||
583 | dev_dbg(dev, "%s\n", __func__); | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { | ||
589 | .name = "ssi (non)", | ||
590 | .init = rsnd_ssi_non, | ||
591 | .quit = rsnd_ssi_non, | ||
592 | .start = rsnd_ssi_non, | ||
593 | .stop = rsnd_ssi_non, | ||
594 | }; | ||
595 | |||
596 | /* | ||
597 | * ssi mod function | ||
598 | */ | ||
599 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, | ||
600 | int dai_id, int is_play) | ||
601 | { | ||
602 | struct rsnd_ssi *ssi; | ||
603 | int i, has_play; | ||
604 | |||
605 | is_play = !!is_play; | ||
606 | |||
607 | for_each_rsnd_ssi(ssi, priv, i) { | ||
608 | if (rsnd_ssi_dai_id(ssi) != dai_id) | ||
609 | continue; | ||
610 | |||
611 | has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); | ||
612 | |||
613 | if (is_play == has_play) | ||
614 | return &ssi->mod; | ||
615 | } | ||
616 | |||
617 | return NULL; | ||
618 | } | ||
619 | |||
620 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) | ||
621 | { | ||
622 | BUG_ON(id < 0 || id >= rsnd_ssi_nr(priv)); | ||
623 | |||
624 | return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod; | ||
625 | } | ||
626 | |||
627 | int rsnd_ssi_probe(struct platform_device *pdev, | ||
628 | struct rcar_snd_info *info, | ||
629 | struct rsnd_priv *priv) | ||
630 | { | ||
631 | struct rsnd_ssi_platform_info *pinfo; | ||
632 | struct device *dev = rsnd_priv_to_dev(priv); | ||
633 | struct rsnd_mod_ops *ops; | ||
634 | struct clk *clk; | ||
635 | struct rsnd_ssiu *ssiu; | ||
636 | struct rsnd_ssi *ssi; | ||
637 | char name[RSND_SSI_NAME_SIZE]; | ||
638 | int i, nr, ret; | ||
639 | |||
640 | /* | ||
641 | * init SSI | ||
642 | */ | ||
643 | nr = info->ssi_info_nr; | ||
644 | ssiu = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr), | ||
645 | GFP_KERNEL); | ||
646 | if (!ssiu) { | ||
647 | dev_err(dev, "SSI allocate failed\n"); | ||
648 | return -ENOMEM; | ||
649 | } | ||
650 | |||
651 | priv->ssiu = ssiu; | ||
652 | ssiu->ssi = (struct rsnd_ssi *)(ssiu + 1); | ||
653 | ssiu->ssi_nr = nr; | ||
654 | |||
655 | for_each_rsnd_ssi(ssi, priv, i) { | ||
656 | pinfo = &info->ssi_info[i]; | ||
657 | |||
658 | snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i); | ||
659 | |||
660 | clk = clk_get(dev, name); | ||
661 | if (IS_ERR(clk)) | ||
662 | return PTR_ERR(clk); | ||
663 | |||
664 | ssi->info = pinfo; | ||
665 | ssi->clk = clk; | ||
666 | |||
667 | ops = &rsnd_ssi_non_ops; | ||
668 | |||
669 | /* | ||
670 | * SSI DMA case | ||
671 | */ | ||
672 | if (pinfo->dma_id > 0) { | ||
673 | ret = rsnd_dma_init( | ||
674 | priv, rsnd_mod_to_dma(&ssi->mod), | ||
675 | (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY), | ||
676 | pinfo->dma_id, | ||
677 | rsnd_ssi_dma_inquiry, | ||
678 | rsnd_ssi_dma_complete); | ||
679 | if (ret < 0) | ||
680 | dev_info(dev, "SSI DMA failed. try PIO transter\n"); | ||
681 | else | ||
682 | ops = &rsnd_ssi_dma_ops; | ||
683 | |||
684 | dev_dbg(dev, "SSI%d use DMA transfer\n", i); | ||
685 | } | ||
686 | |||
687 | /* | ||
688 | * SSI PIO case | ||
689 | */ | ||
690 | if (!rsnd_ssi_dma_available(ssi) && | ||
691 | rsnd_ssi_pio_available(ssi)) { | ||
692 | ret = devm_request_irq(dev, pinfo->pio_irq, | ||
693 | &rsnd_ssi_pio_interrupt, | ||
694 | IRQF_SHARED, | ||
695 | dev_name(dev), ssi); | ||
696 | if (ret) { | ||
697 | dev_err(dev, "SSI request interrupt failed\n"); | ||
698 | return ret; | ||
699 | } | ||
700 | |||
701 | ops = &rsnd_ssi_pio_ops; | ||
702 | |||
703 | dev_dbg(dev, "SSI%d use PIO transfer\n", i); | ||
704 | } | ||
705 | |||
706 | rsnd_mod_init(priv, &ssi->mod, ops, i); | ||
707 | } | ||
708 | |||
709 | rsnd_ssi_mode_init(priv, ssiu); | ||
710 | |||
711 | dev_dbg(dev, "ssi probed\n"); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
717 | struct rsnd_priv *priv) | ||
718 | { | ||
719 | struct rsnd_ssi *ssi; | ||
720 | int i; | ||
721 | |||
722 | for_each_rsnd_ssi(ssi, priv, i) { | ||
723 | clk_put(ssi->clk); | ||
724 | if (rsnd_ssi_dma_available(ssi)) | ||
725 | rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod)); | ||
726 | } | ||
727 | |||
728 | } | ||
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 06a8000aa07b..53c9ecdd119f 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c | |||
@@ -149,8 +149,9 @@ static int soc_compr_free(struct snd_compr_stream *cstream) | |||
149 | SND_SOC_DAPM_STREAM_STOP); | 149 | SND_SOC_DAPM_STREAM_STOP); |
150 | } else { | 150 | } else { |
151 | rtd->pop_wait = 1; | 151 | rtd->pop_wait = 1; |
152 | schedule_delayed_work(&rtd->delayed_work, | 152 | queue_delayed_work(system_power_efficient_wq, |
153 | msecs_to_jiffies(rtd->pmdown_time)); | 153 | &rtd->delayed_work, |
154 | msecs_to_jiffies(rtd->pmdown_time)); | ||
154 | } | 155 | } |
155 | } else { | 156 | } else { |
156 | /* capture streams can be powered down now */ | 157 | /* capture streams can be powered down now */ |
@@ -334,7 +335,7 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, | |||
334 | return ret; | 335 | return ret; |
335 | } | 336 | } |
336 | 337 | ||
337 | static int sst_compr_set_metadata(struct snd_compr_stream *cstream, | 338 | static int soc_compr_set_metadata(struct snd_compr_stream *cstream, |
338 | struct snd_compr_metadata *metadata) | 339 | struct snd_compr_metadata *metadata) |
339 | { | 340 | { |
340 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 341 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
@@ -347,7 +348,7 @@ static int sst_compr_set_metadata(struct snd_compr_stream *cstream, | |||
347 | return ret; | 348 | return ret; |
348 | } | 349 | } |
349 | 350 | ||
350 | static int sst_compr_get_metadata(struct snd_compr_stream *cstream, | 351 | static int soc_compr_get_metadata(struct snd_compr_stream *cstream, |
351 | struct snd_compr_metadata *metadata) | 352 | struct snd_compr_metadata *metadata) |
352 | { | 353 | { |
353 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 354 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
@@ -364,8 +365,8 @@ static struct snd_compr_ops soc_compr_ops = { | |||
364 | .open = soc_compr_open, | 365 | .open = soc_compr_open, |
365 | .free = soc_compr_free, | 366 | .free = soc_compr_free, |
366 | .set_params = soc_compr_set_params, | 367 | .set_params = soc_compr_set_params, |
367 | .set_metadata = sst_compr_set_metadata, | 368 | .set_metadata = soc_compr_set_metadata, |
368 | .get_metadata = sst_compr_get_metadata, | 369 | .get_metadata = soc_compr_get_metadata, |
369 | .get_params = soc_compr_get_params, | 370 | .get_params = soc_compr_get_params, |
370 | .trigger = soc_compr_trigger, | 371 | .trigger = soc_compr_trigger, |
371 | .pointer = soc_compr_pointer, | 372 | .pointer = soc_compr_pointer, |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d82ee386eab5..528f8708221d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -30,9 +30,12 @@ | |||
30 | #include <linux/bitops.h> | 30 | #include <linux/bitops.h> |
31 | #include <linux/debugfs.h> | 31 | #include <linux/debugfs.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/pinctrl/consumer.h> | ||
33 | #include <linux/ctype.h> | 34 | #include <linux/ctype.h> |
34 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
35 | #include <linux/of.h> | 36 | #include <linux/of.h> |
37 | #include <linux/gpio.h> | ||
38 | #include <linux/of_gpio.h> | ||
36 | #include <sound/ac97_codec.h> | 39 | #include <sound/ac97_codec.h> |
37 | #include <sound/core.h> | 40 | #include <sound/core.h> |
38 | #include <sound/jack.h> | 41 | #include <sound/jack.h> |
@@ -47,8 +50,6 @@ | |||
47 | 50 | ||
48 | #define NAME_SIZE 32 | 51 | #define NAME_SIZE 32 |
49 | 52 | ||
50 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); | ||
51 | |||
52 | #ifdef CONFIG_DEBUG_FS | 53 | #ifdef CONFIG_DEBUG_FS |
53 | struct dentry *snd_soc_debugfs_root; | 54 | struct dentry *snd_soc_debugfs_root; |
54 | EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); | 55 | EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); |
@@ -69,6 +70,16 @@ static int pmdown_time = 5000; | |||
69 | module_param(pmdown_time, int, 0); | 70 | module_param(pmdown_time, int, 0); |
70 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); | 71 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); |
71 | 72 | ||
73 | struct snd_ac97_reset_cfg { | ||
74 | struct pinctrl *pctl; | ||
75 | struct pinctrl_state *pstate_reset; | ||
76 | struct pinctrl_state *pstate_warm_reset; | ||
77 | struct pinctrl_state *pstate_run; | ||
78 | int gpio_sdata; | ||
79 | int gpio_sync; | ||
80 | int gpio_reset; | ||
81 | }; | ||
82 | |||
72 | /* returns the minimum number of bytes needed to represent | 83 | /* returns the minimum number of bytes needed to represent |
73 | * a particular given value */ | 84 | * a particular given value */ |
74 | static int min_bytes_needed(unsigned long val) | 85 | static int min_bytes_needed(unsigned long val) |
@@ -530,6 +541,15 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) | |||
530 | } | 541 | } |
531 | #endif | 542 | #endif |
532 | 543 | ||
544 | static void codec2codec_close_delayed_work(struct work_struct *work) | ||
545 | { | ||
546 | /* Currently nothing to do for c2c links | ||
547 | * Since c2c links are internal nodes in the DAPM graph and | ||
548 | * don't interface with the outside world or application layer | ||
549 | * we don't have to do any special handling on close. | ||
550 | */ | ||
551 | } | ||
552 | |||
533 | #ifdef CONFIG_PM_SLEEP | 553 | #ifdef CONFIG_PM_SLEEP |
534 | /* powers down audio subsystem for suspend */ | 554 | /* powers down audio subsystem for suspend */ |
535 | int snd_soc_suspend(struct device *dev) | 555 | int snd_soc_suspend(struct device *dev) |
@@ -1428,6 +1448,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1428 | return ret; | 1448 | return ret; |
1429 | } | 1449 | } |
1430 | } else { | 1450 | } else { |
1451 | INIT_DELAYED_WORK(&rtd->delayed_work, | ||
1452 | codec2codec_close_delayed_work); | ||
1453 | |||
1431 | /* link the DAI widgets */ | 1454 | /* link the DAI widgets */ |
1432 | play_w = codec_dai->playback_widget; | 1455 | play_w = codec_dai->playback_widget; |
1433 | capture_w = cpu_dai->capture_widget; | 1456 | capture_w = cpu_dai->capture_widget; |
@@ -2080,6 +2103,117 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | |||
2080 | } | 2103 | } |
2081 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | 2104 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); |
2082 | 2105 | ||
2106 | static struct snd_ac97_reset_cfg snd_ac97_rst_cfg; | ||
2107 | |||
2108 | static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97) | ||
2109 | { | ||
2110 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
2111 | |||
2112 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset); | ||
2113 | |||
2114 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1); | ||
2115 | |||
2116 | udelay(10); | ||
2117 | |||
2118 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
2119 | |||
2120 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
2121 | msleep(2); | ||
2122 | } | ||
2123 | |||
2124 | static void snd_soc_ac97_reset(struct snd_ac97 *ac97) | ||
2125 | { | ||
2126 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
2127 | |||
2128 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset); | ||
2129 | |||
2130 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
2131 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0); | ||
2132 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0); | ||
2133 | |||
2134 | udelay(10); | ||
2135 | |||
2136 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1); | ||
2137 | |||
2138 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
2139 | msleep(2); | ||
2140 | } | ||
2141 | |||
2142 | static int snd_soc_ac97_parse_pinctl(struct device *dev, | ||
2143 | struct snd_ac97_reset_cfg *cfg) | ||
2144 | { | ||
2145 | struct pinctrl *p; | ||
2146 | struct pinctrl_state *state; | ||
2147 | int gpio; | ||
2148 | int ret; | ||
2149 | |||
2150 | p = devm_pinctrl_get(dev); | ||
2151 | if (IS_ERR(p)) { | ||
2152 | dev_err(dev, "Failed to get pinctrl\n"); | ||
2153 | return PTR_RET(p); | ||
2154 | } | ||
2155 | cfg->pctl = p; | ||
2156 | |||
2157 | state = pinctrl_lookup_state(p, "ac97-reset"); | ||
2158 | if (IS_ERR(state)) { | ||
2159 | dev_err(dev, "Can't find pinctrl state ac97-reset\n"); | ||
2160 | return PTR_RET(state); | ||
2161 | } | ||
2162 | cfg->pstate_reset = state; | ||
2163 | |||
2164 | state = pinctrl_lookup_state(p, "ac97-warm-reset"); | ||
2165 | if (IS_ERR(state)) { | ||
2166 | dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); | ||
2167 | return PTR_RET(state); | ||
2168 | } | ||
2169 | cfg->pstate_warm_reset = state; | ||
2170 | |||
2171 | state = pinctrl_lookup_state(p, "ac97-running"); | ||
2172 | if (IS_ERR(state)) { | ||
2173 | dev_err(dev, "Can't find pinctrl state ac97-running\n"); | ||
2174 | return PTR_RET(state); | ||
2175 | } | ||
2176 | cfg->pstate_run = state; | ||
2177 | |||
2178 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0); | ||
2179 | if (gpio < 0) { | ||
2180 | dev_err(dev, "Can't find ac97-sync gpio\n"); | ||
2181 | return gpio; | ||
2182 | } | ||
2183 | ret = devm_gpio_request(dev, gpio, "AC97 link sync"); | ||
2184 | if (ret) { | ||
2185 | dev_err(dev, "Failed requesting ac97-sync gpio\n"); | ||
2186 | return ret; | ||
2187 | } | ||
2188 | cfg->gpio_sync = gpio; | ||
2189 | |||
2190 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1); | ||
2191 | if (gpio < 0) { | ||
2192 | dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio); | ||
2193 | return gpio; | ||
2194 | } | ||
2195 | ret = devm_gpio_request(dev, gpio, "AC97 link sdata"); | ||
2196 | if (ret) { | ||
2197 | dev_err(dev, "Failed requesting ac97-sdata gpio\n"); | ||
2198 | return ret; | ||
2199 | } | ||
2200 | cfg->gpio_sdata = gpio; | ||
2201 | |||
2202 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); | ||
2203 | if (gpio < 0) { | ||
2204 | dev_err(dev, "Can't find ac97-reset gpio\n"); | ||
2205 | return gpio; | ||
2206 | } | ||
2207 | ret = devm_gpio_request(dev, gpio, "AC97 link reset"); | ||
2208 | if (ret) { | ||
2209 | dev_err(dev, "Failed requesting ac97-reset gpio\n"); | ||
2210 | return ret; | ||
2211 | } | ||
2212 | cfg->gpio_reset = gpio; | ||
2213 | |||
2214 | return 0; | ||
2215 | } | ||
2216 | |||
2083 | struct snd_ac97_bus_ops *soc_ac97_ops; | 2217 | struct snd_ac97_bus_ops *soc_ac97_ops; |
2084 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | 2218 | EXPORT_SYMBOL_GPL(soc_ac97_ops); |
2085 | 2219 | ||
@@ -2098,6 +2232,35 @@ int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) | |||
2098 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); | 2232 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); |
2099 | 2233 | ||
2100 | /** | 2234 | /** |
2235 | * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions | ||
2236 | * | ||
2237 | * This function sets the reset and warm_reset properties of ops and parses | ||
2238 | * the device node of pdev to get pinctrl states and gpio numbers to use. | ||
2239 | */ | ||
2240 | int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, | ||
2241 | struct platform_device *pdev) | ||
2242 | { | ||
2243 | struct device *dev = &pdev->dev; | ||
2244 | struct snd_ac97_reset_cfg cfg; | ||
2245 | int ret; | ||
2246 | |||
2247 | ret = snd_soc_ac97_parse_pinctl(dev, &cfg); | ||
2248 | if (ret) | ||
2249 | return ret; | ||
2250 | |||
2251 | ret = snd_soc_set_ac97_ops(ops); | ||
2252 | if (ret) | ||
2253 | return ret; | ||
2254 | |||
2255 | ops->warm_reset = snd_soc_ac97_warm_reset; | ||
2256 | ops->reset = snd_soc_ac97_reset; | ||
2257 | |||
2258 | snd_ac97_rst_cfg = cfg; | ||
2259 | return 0; | ||
2260 | } | ||
2261 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); | ||
2262 | |||
2263 | /** | ||
2101 | * snd_soc_free_ac97_codec - free AC97 codec device | 2264 | * snd_soc_free_ac97_codec - free AC97 codec device |
2102 | * @codec: audio codec | 2265 | * @codec: audio codec |
2103 | * | 2266 | * |
@@ -2299,6 +2462,22 @@ static int snd_soc_add_controls(struct snd_card *card, struct device *dev, | |||
2299 | return 0; | 2462 | return 0; |
2300 | } | 2463 | } |
2301 | 2464 | ||
2465 | struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, | ||
2466 | const char *name) | ||
2467 | { | ||
2468 | struct snd_card *card = soc_card->snd_card; | ||
2469 | struct snd_kcontrol *kctl; | ||
2470 | |||
2471 | if (unlikely(!name)) | ||
2472 | return NULL; | ||
2473 | |||
2474 | list_for_each_entry(kctl, &card->controls, list) | ||
2475 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) | ||
2476 | return kctl; | ||
2477 | return NULL; | ||
2478 | } | ||
2479 | EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); | ||
2480 | |||
2302 | /** | 2481 | /** |
2303 | * snd_soc_add_codec_controls - add an array of controls to a codec. | 2482 | * snd_soc_add_codec_controls - add an array of controls to a codec. |
2304 | * Convenience function to add a list of controls. Many codecs were | 2483 | * Convenience function to add a list of controls. Many codecs were |
@@ -2541,59 +2720,6 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2541 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); | 2720 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); |
2542 | 2721 | ||
2543 | /** | 2722 | /** |
2544 | * snd_soc_info_enum_ext - external enumerated single mixer info callback | ||
2545 | * @kcontrol: mixer control | ||
2546 | * @uinfo: control element information | ||
2547 | * | ||
2548 | * Callback to provide information about an external enumerated | ||
2549 | * single mixer. | ||
2550 | * | ||
2551 | * Returns 0 for success. | ||
2552 | */ | ||
2553 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | ||
2554 | struct snd_ctl_elem_info *uinfo) | ||
2555 | { | ||
2556 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2557 | |||
2558 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2559 | uinfo->count = 1; | ||
2560 | uinfo->value.enumerated.items = e->max; | ||
2561 | |||
2562 | if (uinfo->value.enumerated.item > e->max - 1) | ||
2563 | uinfo->value.enumerated.item = e->max - 1; | ||
2564 | strcpy(uinfo->value.enumerated.name, | ||
2565 | e->texts[uinfo->value.enumerated.item]); | ||
2566 | return 0; | ||
2567 | } | ||
2568 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext); | ||
2569 | |||
2570 | /** | ||
2571 | * snd_soc_info_volsw_ext - external single mixer info callback | ||
2572 | * @kcontrol: mixer control | ||
2573 | * @uinfo: control element information | ||
2574 | * | ||
2575 | * Callback to provide information about a single external mixer control. | ||
2576 | * | ||
2577 | * Returns 0 for success. | ||
2578 | */ | ||
2579 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | ||
2580 | struct snd_ctl_elem_info *uinfo) | ||
2581 | { | ||
2582 | int max = kcontrol->private_value; | ||
2583 | |||
2584 | if (max == 1 && !strstr(kcontrol->id.name, " Volume")) | ||
2585 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
2586 | else | ||
2587 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2588 | |||
2589 | uinfo->count = 1; | ||
2590 | uinfo->value.integer.min = 0; | ||
2591 | uinfo->value.integer.max = max; | ||
2592 | return 0; | ||
2593 | } | ||
2594 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); | ||
2595 | |||
2596 | /** | ||
2597 | * snd_soc_info_volsw - single mixer info callback | 2723 | * snd_soc_info_volsw - single mixer info callback |
2598 | * @kcontrol: mixer control | 2724 | * @kcontrol: mixer control |
2599 | * @uinfo: control element information | 2725 | * @uinfo: control element information |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4375c9f2b791..d84bd0f167b6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -47,6 +47,15 @@ | |||
47 | 47 | ||
48 | #define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++; | 48 | #define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++; |
49 | 49 | ||
50 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | ||
51 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, | ||
52 | const char *control, | ||
53 | int (*connected)(struct snd_soc_dapm_widget *source, | ||
54 | struct snd_soc_dapm_widget *sink)); | ||
55 | static struct snd_soc_dapm_widget * | ||
56 | snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | ||
57 | const struct snd_soc_dapm_widget *widget); | ||
58 | |||
50 | /* dapm power sequences - make this per codec in the future */ | 59 | /* dapm power sequences - make this per codec in the future */ |
51 | static int dapm_up_seq[] = { | 60 | static int dapm_up_seq[] = { |
52 | [snd_soc_dapm_pre] = 0, | 61 | [snd_soc_dapm_pre] = 0, |
@@ -73,16 +82,18 @@ static int dapm_up_seq[] = { | |||
73 | [snd_soc_dapm_hp] = 10, | 82 | [snd_soc_dapm_hp] = 10, |
74 | [snd_soc_dapm_spk] = 10, | 83 | [snd_soc_dapm_spk] = 10, |
75 | [snd_soc_dapm_line] = 10, | 84 | [snd_soc_dapm_line] = 10, |
76 | [snd_soc_dapm_post] = 11, | 85 | [snd_soc_dapm_kcontrol] = 11, |
86 | [snd_soc_dapm_post] = 12, | ||
77 | }; | 87 | }; |
78 | 88 | ||
79 | static int dapm_down_seq[] = { | 89 | static int dapm_down_seq[] = { |
80 | [snd_soc_dapm_pre] = 0, | 90 | [snd_soc_dapm_pre] = 0, |
81 | [snd_soc_dapm_adc] = 1, | 91 | [snd_soc_dapm_kcontrol] = 1, |
82 | [snd_soc_dapm_hp] = 2, | 92 | [snd_soc_dapm_adc] = 2, |
83 | [snd_soc_dapm_spk] = 2, | 93 | [snd_soc_dapm_hp] = 3, |
84 | [snd_soc_dapm_line] = 2, | 94 | [snd_soc_dapm_spk] = 3, |
85 | [snd_soc_dapm_out_drv] = 2, | 95 | [snd_soc_dapm_line] = 3, |
96 | [snd_soc_dapm_out_drv] = 3, | ||
86 | [snd_soc_dapm_pga] = 4, | 97 | [snd_soc_dapm_pga] = 4, |
87 | [snd_soc_dapm_switch] = 5, | 98 | [snd_soc_dapm_switch] = 5, |
88 | [snd_soc_dapm_mixer_named_ctl] = 5, | 99 | [snd_soc_dapm_mixer_named_ctl] = 5, |
@@ -174,36 +185,176 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | |||
174 | return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); | 185 | return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); |
175 | } | 186 | } |
176 | 187 | ||
177 | /* get snd_card from DAPM context */ | 188 | struct dapm_kcontrol_data { |
178 | static inline struct snd_card *dapm_get_snd_card( | 189 | unsigned int value; |
179 | struct snd_soc_dapm_context *dapm) | 190 | struct snd_soc_dapm_widget *widget; |
191 | struct list_head paths; | ||
192 | struct snd_soc_dapm_widget_list *wlist; | ||
193 | }; | ||
194 | |||
195 | static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, | ||
196 | struct snd_kcontrol *kcontrol) | ||
180 | { | 197 | { |
181 | if (dapm->codec) | 198 | struct dapm_kcontrol_data *data; |
182 | return dapm->codec->card->snd_card; | 199 | struct soc_mixer_control *mc; |
183 | else if (dapm->platform) | ||
184 | return dapm->platform->card->snd_card; | ||
185 | else | ||
186 | BUG(); | ||
187 | 200 | ||
188 | /* unreachable */ | 201 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
189 | return NULL; | 202 | if (!data) { |
203 | dev_err(widget->dapm->dev, | ||
204 | "ASoC: can't allocate kcontrol data for %s\n", | ||
205 | widget->name); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | INIT_LIST_HEAD(&data->paths); | ||
210 | |||
211 | switch (widget->id) { | ||
212 | case snd_soc_dapm_switch: | ||
213 | case snd_soc_dapm_mixer: | ||
214 | case snd_soc_dapm_mixer_named_ctl: | ||
215 | mc = (struct soc_mixer_control *)kcontrol->private_value; | ||
216 | |||
217 | if (mc->autodisable) { | ||
218 | struct snd_soc_dapm_widget template; | ||
219 | |||
220 | memset(&template, 0, sizeof(template)); | ||
221 | template.reg = mc->reg; | ||
222 | template.mask = (1 << fls(mc->max)) - 1; | ||
223 | template.shift = mc->shift; | ||
224 | if (mc->invert) | ||
225 | template.off_val = mc->max; | ||
226 | else | ||
227 | template.off_val = 0; | ||
228 | template.on_val = template.off_val; | ||
229 | template.id = snd_soc_dapm_kcontrol; | ||
230 | template.name = kcontrol->id.name; | ||
231 | |||
232 | data->widget = snd_soc_dapm_new_control(widget->dapm, | ||
233 | &template); | ||
234 | if (!data->widget) { | ||
235 | kfree(data); | ||
236 | return -ENOMEM; | ||
237 | } | ||
238 | } | ||
239 | break; | ||
240 | default: | ||
241 | break; | ||
242 | } | ||
243 | |||
244 | kcontrol->private_data = data; | ||
245 | |||
246 | return 0; | ||
190 | } | 247 | } |
191 | 248 | ||
192 | /* get soc_card from DAPM context */ | 249 | static void dapm_kcontrol_free(struct snd_kcontrol *kctl) |
193 | static inline struct snd_soc_card *dapm_get_soc_card( | ||
194 | struct snd_soc_dapm_context *dapm) | ||
195 | { | 250 | { |
196 | if (dapm->codec) | 251 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl); |
197 | return dapm->codec->card; | 252 | kfree(data->widget); |
198 | else if (dapm->platform) | 253 | kfree(data->wlist); |
199 | return dapm->platform->card; | 254 | kfree(data); |
255 | } | ||
256 | |||
257 | static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist( | ||
258 | const struct snd_kcontrol *kcontrol) | ||
259 | { | ||
260 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
261 | |||
262 | return data->wlist; | ||
263 | } | ||
264 | |||
265 | static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol, | ||
266 | struct snd_soc_dapm_widget *widget) | ||
267 | { | ||
268 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
269 | struct snd_soc_dapm_widget_list *new_wlist; | ||
270 | unsigned int n; | ||
271 | |||
272 | if (data->wlist) | ||
273 | n = data->wlist->num_widgets + 1; | ||
200 | else | 274 | else |
201 | BUG(); | 275 | n = 1; |
202 | 276 | ||
203 | /* unreachable */ | 277 | new_wlist = krealloc(data->wlist, |
204 | return NULL; | 278 | sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL); |
279 | if (!new_wlist) | ||
280 | return -ENOMEM; | ||
281 | |||
282 | new_wlist->widgets[n - 1] = widget; | ||
283 | new_wlist->num_widgets = n; | ||
284 | |||
285 | data->wlist = new_wlist; | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol, | ||
291 | struct snd_soc_dapm_path *path) | ||
292 | { | ||
293 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
294 | |||
295 | list_add_tail(&path->list_kcontrol, &data->paths); | ||
296 | |||
297 | if (data->widget) { | ||
298 | snd_soc_dapm_add_path(data->widget->dapm, data->widget, | ||
299 | path->source, NULL, NULL); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol) | ||
304 | { | ||
305 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
306 | |||
307 | if (!data->widget) | ||
308 | return true; | ||
309 | |||
310 | return data->widget->power; | ||
311 | } | ||
312 | |||
313 | static struct list_head *dapm_kcontrol_get_path_list( | ||
314 | const struct snd_kcontrol *kcontrol) | ||
315 | { | ||
316 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
317 | |||
318 | return &data->paths; | ||
319 | } | ||
320 | |||
321 | #define dapm_kcontrol_for_each_path(path, kcontrol) \ | ||
322 | list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \ | ||
323 | list_kcontrol) | ||
324 | |||
325 | static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) | ||
326 | { | ||
327 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
328 | |||
329 | return data->value; | ||
330 | } | ||
331 | |||
332 | static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, | ||
333 | unsigned int value) | ||
334 | { | ||
335 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
336 | |||
337 | if (data->value == value) | ||
338 | return false; | ||
339 | |||
340 | if (data->widget) | ||
341 | data->widget->on_val = value; | ||
342 | |||
343 | data->value = value; | ||
344 | |||
345 | return true; | ||
205 | } | 346 | } |
206 | 347 | ||
348 | /** | ||
349 | * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol | ||
350 | * @kcontrol: The kcontrol | ||
351 | */ | ||
352 | struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol) | ||
353 | { | ||
354 | return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec; | ||
355 | } | ||
356 | EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec); | ||
357 | |||
207 | static void dapm_reset(struct snd_soc_card *card) | 358 | static void dapm_reset(struct snd_soc_card *card) |
208 | { | 359 | { |
209 | struct snd_soc_dapm_widget *w; | 360 | struct snd_soc_dapm_widget *w; |
@@ -211,6 +362,7 @@ static void dapm_reset(struct snd_soc_card *card) | |||
211 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); | 362 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); |
212 | 363 | ||
213 | list_for_each_entry(w, &card->widgets, list) { | 364 | list_for_each_entry(w, &card->widgets, list) { |
365 | w->new_power = w->power; | ||
214 | w->power_checked = false; | 366 | w->power_checked = false; |
215 | w->inputs = -1; | 367 | w->inputs = -1; |
216 | w->outputs = -1; | 368 | w->outputs = -1; |
@@ -428,6 +580,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
428 | case snd_soc_dapm_spk: | 580 | case snd_soc_dapm_spk: |
429 | case snd_soc_dapm_line: | 581 | case snd_soc_dapm_line: |
430 | case snd_soc_dapm_dai_link: | 582 | case snd_soc_dapm_dai_link: |
583 | case snd_soc_dapm_kcontrol: | ||
431 | p->connect = 1; | 584 | p->connect = 1; |
432 | break; | 585 | break; |
433 | /* does affect routing - dynamically connected */ | 586 | /* does affect routing - dynamically connected */ |
@@ -507,17 +660,12 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, | |||
507 | return 0; | 660 | return 0; |
508 | } | 661 | } |
509 | 662 | ||
510 | static void dapm_kcontrol_free(struct snd_kcontrol *kctl) | ||
511 | { | ||
512 | kfree(kctl->private_data); | ||
513 | } | ||
514 | |||
515 | /* | 663 | /* |
516 | * Determine if a kcontrol is shared. If it is, look it up. If it isn't, | 664 | * Determine if a kcontrol is shared. If it is, look it up. If it isn't, |
517 | * create it. Either way, add the widget into the control's widget list | 665 | * create it. Either way, add the widget into the control's widget list |
518 | */ | 666 | */ |
519 | static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | 667 | static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, |
520 | int kci, struct snd_soc_dapm_path *path) | 668 | int kci) |
521 | { | 669 | { |
522 | struct snd_soc_dapm_context *dapm = w->dapm; | 670 | struct snd_soc_dapm_context *dapm = w->dapm; |
523 | struct snd_card *card = dapm->card->snd_card; | 671 | struct snd_card *card = dapm->card->snd_card; |
@@ -525,9 +673,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
525 | size_t prefix_len; | 673 | size_t prefix_len; |
526 | int shared; | 674 | int shared; |
527 | struct snd_kcontrol *kcontrol; | 675 | struct snd_kcontrol *kcontrol; |
528 | struct snd_soc_dapm_widget_list *wlist; | ||
529 | int wlistentries; | ||
530 | size_t wlistsize; | ||
531 | bool wname_in_long_name, kcname_in_long_name; | 676 | bool wname_in_long_name, kcname_in_long_name; |
532 | char *long_name; | 677 | char *long_name; |
533 | const char *name; | 678 | const char *name; |
@@ -546,25 +691,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
546 | shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci], | 691 | shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci], |
547 | &kcontrol); | 692 | &kcontrol); |
548 | 693 | ||
549 | if (kcontrol) { | ||
550 | wlist = kcontrol->private_data; | ||
551 | wlistentries = wlist->num_widgets + 1; | ||
552 | } else { | ||
553 | wlist = NULL; | ||
554 | wlistentries = 1; | ||
555 | } | ||
556 | |||
557 | wlistsize = sizeof(struct snd_soc_dapm_widget_list) + | ||
558 | wlistentries * sizeof(struct snd_soc_dapm_widget *); | ||
559 | wlist = krealloc(wlist, wlistsize, GFP_KERNEL); | ||
560 | if (wlist == NULL) { | ||
561 | dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n", | ||
562 | w->name); | ||
563 | return -ENOMEM; | ||
564 | } | ||
565 | wlist->num_widgets = wlistentries; | ||
566 | wlist->widgets[wlistentries - 1] = w; | ||
567 | |||
568 | if (!kcontrol) { | 694 | if (!kcontrol) { |
569 | if (shared) { | 695 | if (shared) { |
570 | wname_in_long_name = false; | 696 | wname_in_long_name = false; |
@@ -587,7 +713,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
587 | kcname_in_long_name = false; | 713 | kcname_in_long_name = false; |
588 | break; | 714 | break; |
589 | default: | 715 | default: |
590 | kfree(wlist); | ||
591 | return -EINVAL; | 716 | return -EINVAL; |
592 | } | 717 | } |
593 | } | 718 | } |
@@ -602,10 +727,8 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
602 | long_name = kasprintf(GFP_KERNEL, "%s %s", | 727 | long_name = kasprintf(GFP_KERNEL, "%s %s", |
603 | w->name + prefix_len, | 728 | w->name + prefix_len, |
604 | w->kcontrol_news[kci].name); | 729 | w->kcontrol_news[kci].name); |
605 | if (long_name == NULL) { | 730 | if (long_name == NULL) |
606 | kfree(wlist); | ||
607 | return -ENOMEM; | 731 | return -ENOMEM; |
608 | } | ||
609 | 732 | ||
610 | name = long_name; | 733 | name = long_name; |
611 | } else if (wname_in_long_name) { | 734 | } else if (wname_in_long_name) { |
@@ -616,23 +739,33 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
616 | name = w->kcontrol_news[kci].name; | 739 | name = w->kcontrol_news[kci].name; |
617 | } | 740 | } |
618 | 741 | ||
619 | kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name, | 742 | kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name, |
620 | prefix); | 743 | prefix); |
621 | kcontrol->private_free = dapm_kcontrol_free; | ||
622 | kfree(long_name); | 744 | kfree(long_name); |
745 | if (!kcontrol) | ||
746 | return -ENOMEM; | ||
747 | kcontrol->private_free = dapm_kcontrol_free; | ||
748 | |||
749 | ret = dapm_kcontrol_data_alloc(w, kcontrol); | ||
750 | if (ret) { | ||
751 | snd_ctl_free_one(kcontrol); | ||
752 | return ret; | ||
753 | } | ||
754 | |||
623 | ret = snd_ctl_add(card, kcontrol); | 755 | ret = snd_ctl_add(card, kcontrol); |
624 | if (ret < 0) { | 756 | if (ret < 0) { |
625 | dev_err(dapm->dev, | 757 | dev_err(dapm->dev, |
626 | "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", | 758 | "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", |
627 | w->name, name, ret); | 759 | w->name, name, ret); |
628 | kfree(wlist); | ||
629 | return ret; | 760 | return ret; |
630 | } | 761 | } |
631 | } | 762 | } |
632 | 763 | ||
633 | kcontrol->private_data = wlist; | 764 | ret = dapm_kcontrol_add_widget(kcontrol, w); |
765 | if (ret) | ||
766 | return ret; | ||
767 | |||
634 | w->kcontrols[kci] = kcontrol; | 768 | w->kcontrols[kci] = kcontrol; |
635 | path->kcontrol = kcontrol; | ||
636 | 769 | ||
637 | return 0; | 770 | return 0; |
638 | } | 771 | } |
@@ -652,13 +785,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) | |||
652 | continue; | 785 | continue; |
653 | 786 | ||
654 | if (w->kcontrols[i]) { | 787 | if (w->kcontrols[i]) { |
655 | path->kcontrol = w->kcontrols[i]; | 788 | dapm_kcontrol_add_path(w->kcontrols[i], path); |
656 | continue; | 789 | continue; |
657 | } | 790 | } |
658 | 791 | ||
659 | ret = dapm_create_or_share_mixmux_kcontrol(w, i, path); | 792 | ret = dapm_create_or_share_mixmux_kcontrol(w, i); |
660 | if (ret < 0) | 793 | if (ret < 0) |
661 | return ret; | 794 | return ret; |
795 | |||
796 | dapm_kcontrol_add_path(w->kcontrols[i], path); | ||
662 | } | 797 | } |
663 | } | 798 | } |
664 | 799 | ||
@@ -684,15 +819,12 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
684 | return -EINVAL; | 819 | return -EINVAL; |
685 | } | 820 | } |
686 | 821 | ||
687 | path = list_first_entry(&w->sources, struct snd_soc_dapm_path, | 822 | ret = dapm_create_or_share_mixmux_kcontrol(w, 0); |
688 | list_sink); | ||
689 | |||
690 | ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path); | ||
691 | if (ret < 0) | 823 | if (ret < 0) |
692 | return ret; | 824 | return ret; |
693 | 825 | ||
694 | list_for_each_entry(path, &w->sources, list_sink) | 826 | list_for_each_entry(path, &w->sources, list_sink) |
695 | path->kcontrol = w->kcontrols[0]; | 827 | dapm_kcontrol_add_path(w->kcontrols[0], path); |
696 | 828 | ||
697 | return 0; | 829 | return 0; |
698 | } | 830 | } |
@@ -813,6 +945,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, | |||
813 | case snd_soc_dapm_supply: | 945 | case snd_soc_dapm_supply: |
814 | case snd_soc_dapm_regulator_supply: | 946 | case snd_soc_dapm_regulator_supply: |
815 | case snd_soc_dapm_clock_supply: | 947 | case snd_soc_dapm_clock_supply: |
948 | case snd_soc_dapm_kcontrol: | ||
816 | return 0; | 949 | return 0; |
817 | default: | 950 | default: |
818 | break; | 951 | break; |
@@ -908,6 +1041,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
908 | case snd_soc_dapm_supply: | 1041 | case snd_soc_dapm_supply: |
909 | case snd_soc_dapm_regulator_supply: | 1042 | case snd_soc_dapm_regulator_supply: |
910 | case snd_soc_dapm_clock_supply: | 1043 | case snd_soc_dapm_clock_supply: |
1044 | case snd_soc_dapm_kcontrol: | ||
911 | return 0; | 1045 | return 0; |
912 | default: | 1046 | default: |
913 | break; | 1047 | break; |
@@ -1062,7 +1196,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1062 | int ret; | 1196 | int ret; |
1063 | 1197 | ||
1064 | if (SND_SOC_DAPM_EVENT_ON(event)) { | 1198 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
1065 | if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { | 1199 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
1066 | ret = regulator_allow_bypass(w->regulator, false); | 1200 | ret = regulator_allow_bypass(w->regulator, false); |
1067 | if (ret != 0) | 1201 | if (ret != 0) |
1068 | dev_warn(w->dapm->dev, | 1202 | dev_warn(w->dapm->dev, |
@@ -1072,7 +1206,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1072 | 1206 | ||
1073 | return regulator_enable(w->regulator); | 1207 | return regulator_enable(w->regulator); |
1074 | } else { | 1208 | } else { |
1075 | if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { | 1209 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
1076 | ret = regulator_allow_bypass(w->regulator, true); | 1210 | ret = regulator_allow_bypass(w->regulator, true); |
1077 | if (ret != 0) | 1211 | if (ret != 0) |
1078 | dev_warn(w->dapm->dev, | 1212 | dev_warn(w->dapm->dev, |
@@ -1244,10 +1378,9 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, | |||
1244 | list_add_tail(&new_widget->power_list, list); | 1378 | list_add_tail(&new_widget->power_list, list); |
1245 | } | 1379 | } |
1246 | 1380 | ||
1247 | static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, | 1381 | static void dapm_seq_check_event(struct snd_soc_card *card, |
1248 | struct snd_soc_dapm_widget *w, int event) | 1382 | struct snd_soc_dapm_widget *w, int event) |
1249 | { | 1383 | { |
1250 | struct snd_soc_card *card = dapm->card; | ||
1251 | const char *ev_name; | 1384 | const char *ev_name; |
1252 | int power, ret; | 1385 | int power, ret; |
1253 | 1386 | ||
@@ -1281,55 +1414,50 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, | |||
1281 | return; | 1414 | return; |
1282 | } | 1415 | } |
1283 | 1416 | ||
1284 | if (w->power != power) | 1417 | if (w->new_power != power) |
1285 | return; | 1418 | return; |
1286 | 1419 | ||
1287 | if (w->event && (w->event_flags & event)) { | 1420 | if (w->event && (w->event_flags & event)) { |
1288 | pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n", | 1421 | pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n", |
1289 | w->name, ev_name); | 1422 | w->name, ev_name); |
1290 | trace_snd_soc_dapm_widget_event_start(w, event); | 1423 | trace_snd_soc_dapm_widget_event_start(w, event); |
1291 | ret = w->event(w, NULL, event); | 1424 | ret = w->event(w, NULL, event); |
1292 | trace_snd_soc_dapm_widget_event_done(w, event); | 1425 | trace_snd_soc_dapm_widget_event_done(w, event); |
1293 | if (ret < 0) | 1426 | if (ret < 0) |
1294 | dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n", | 1427 | dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n", |
1295 | ev_name, w->name, ret); | 1428 | ev_name, w->name, ret); |
1296 | } | 1429 | } |
1297 | } | 1430 | } |
1298 | 1431 | ||
1299 | /* Apply the coalesced changes from a DAPM sequence */ | 1432 | /* Apply the coalesced changes from a DAPM sequence */ |
1300 | static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | 1433 | static void dapm_seq_run_coalesced(struct snd_soc_card *card, |
1301 | struct list_head *pending) | 1434 | struct list_head *pending) |
1302 | { | 1435 | { |
1303 | struct snd_soc_card *card = dapm->card; | ||
1304 | struct snd_soc_dapm_widget *w; | 1436 | struct snd_soc_dapm_widget *w; |
1305 | int reg, power; | 1437 | int reg; |
1306 | unsigned int value = 0; | 1438 | unsigned int value = 0; |
1307 | unsigned int mask = 0; | 1439 | unsigned int mask = 0; |
1308 | unsigned int cur_mask; | ||
1309 | 1440 | ||
1310 | reg = list_first_entry(pending, struct snd_soc_dapm_widget, | 1441 | reg = list_first_entry(pending, struct snd_soc_dapm_widget, |
1311 | power_list)->reg; | 1442 | power_list)->reg; |
1312 | 1443 | ||
1313 | list_for_each_entry(w, pending, power_list) { | 1444 | list_for_each_entry(w, pending, power_list) { |
1314 | cur_mask = 1 << w->shift; | ||
1315 | BUG_ON(reg != w->reg); | 1445 | BUG_ON(reg != w->reg); |
1446 | w->power = w->new_power; | ||
1316 | 1447 | ||
1317 | if (w->invert) | 1448 | mask |= w->mask << w->shift; |
1318 | power = !w->power; | 1449 | if (w->power) |
1450 | value |= w->on_val << w->shift; | ||
1319 | else | 1451 | else |
1320 | power = w->power; | 1452 | value |= w->off_val << w->shift; |
1321 | 1453 | ||
1322 | mask |= cur_mask; | 1454 | pop_dbg(w->dapm->dev, card->pop_time, |
1323 | if (power) | ||
1324 | value |= cur_mask; | ||
1325 | |||
1326 | pop_dbg(dapm->dev, card->pop_time, | ||
1327 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", | 1455 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", |
1328 | w->name, reg, value, mask); | 1456 | w->name, reg, value, mask); |
1329 | 1457 | ||
1330 | /* Check for events */ | 1458 | /* Check for events */ |
1331 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU); | 1459 | dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU); |
1332 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD); | 1460 | dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD); |
1333 | } | 1461 | } |
1334 | 1462 | ||
1335 | if (reg >= 0) { | 1463 | if (reg >= 0) { |
@@ -1339,7 +1467,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
1339 | w = list_first_entry(pending, struct snd_soc_dapm_widget, | 1467 | w = list_first_entry(pending, struct snd_soc_dapm_widget, |
1340 | power_list); | 1468 | power_list); |
1341 | 1469 | ||
1342 | pop_dbg(dapm->dev, card->pop_time, | 1470 | pop_dbg(w->dapm->dev, card->pop_time, |
1343 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", | 1471 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", |
1344 | value, mask, reg, card->pop_time); | 1472 | value, mask, reg, card->pop_time); |
1345 | pop_wait(card->pop_time); | 1473 | pop_wait(card->pop_time); |
@@ -1347,8 +1475,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
1347 | } | 1475 | } |
1348 | 1476 | ||
1349 | list_for_each_entry(w, pending, power_list) { | 1477 | list_for_each_entry(w, pending, power_list) { |
1350 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU); | 1478 | dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU); |
1351 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD); | 1479 | dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD); |
1352 | } | 1480 | } |
1353 | } | 1481 | } |
1354 | 1482 | ||
@@ -1360,8 +1488,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
1360 | * Currently anything that requires more than a single write is not | 1488 | * Currently anything that requires more than a single write is not |
1361 | * handled. | 1489 | * handled. |
1362 | */ | 1490 | */ |
1363 | static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | 1491 | static void dapm_seq_run(struct snd_soc_card *card, |
1364 | struct list_head *list, int event, bool power_up) | 1492 | struct list_head *list, int event, bool power_up) |
1365 | { | 1493 | { |
1366 | struct snd_soc_dapm_widget *w, *n; | 1494 | struct snd_soc_dapm_widget *w, *n; |
1367 | LIST_HEAD(pending); | 1495 | LIST_HEAD(pending); |
@@ -1384,7 +1512,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
1384 | if (sort[w->id] != cur_sort || w->reg != cur_reg || | 1512 | if (sort[w->id] != cur_sort || w->reg != cur_reg || |
1385 | w->dapm != cur_dapm || w->subseq != cur_subseq) { | 1513 | w->dapm != cur_dapm || w->subseq != cur_subseq) { |
1386 | if (!list_empty(&pending)) | 1514 | if (!list_empty(&pending)) |
1387 | dapm_seq_run_coalesced(cur_dapm, &pending); | 1515 | dapm_seq_run_coalesced(card, &pending); |
1388 | 1516 | ||
1389 | if (cur_dapm && cur_dapm->seq_notifier) { | 1517 | if (cur_dapm && cur_dapm->seq_notifier) { |
1390 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | 1518 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) |
@@ -1444,7 +1572,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
1444 | } | 1572 | } |
1445 | 1573 | ||
1446 | if (!list_empty(&pending)) | 1574 | if (!list_empty(&pending)) |
1447 | dapm_seq_run_coalesced(cur_dapm, &pending); | 1575 | dapm_seq_run_coalesced(card, &pending); |
1448 | 1576 | ||
1449 | if (cur_dapm && cur_dapm->seq_notifier) { | 1577 | if (cur_dapm && cur_dapm->seq_notifier) { |
1450 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | 1578 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) |
@@ -1454,37 +1582,48 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
1454 | } | 1582 | } |
1455 | } | 1583 | } |
1456 | 1584 | ||
1457 | static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | 1585 | static void dapm_widget_update(struct snd_soc_card *card) |
1458 | { | 1586 | { |
1459 | struct snd_soc_dapm_update *update = dapm->update; | 1587 | struct snd_soc_dapm_update *update = card->update; |
1460 | struct snd_soc_dapm_widget *w; | 1588 | struct snd_soc_dapm_widget_list *wlist; |
1589 | struct snd_soc_dapm_widget *w = NULL; | ||
1590 | unsigned int wi; | ||
1461 | int ret; | 1591 | int ret; |
1462 | 1592 | ||
1463 | if (!update) | 1593 | if (!update || !dapm_kcontrol_is_powered(update->kcontrol)) |
1464 | return; | 1594 | return; |
1465 | 1595 | ||
1466 | w = update->widget; | 1596 | wlist = dapm_kcontrol_get_wlist(update->kcontrol); |
1467 | 1597 | ||
1468 | if (w->event && | 1598 | for (wi = 0; wi < wlist->num_widgets; wi++) { |
1469 | (w->event_flags & SND_SOC_DAPM_PRE_REG)) { | 1599 | w = wlist->widgets[wi]; |
1470 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); | 1600 | |
1471 | if (ret != 0) | 1601 | if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) { |
1472 | dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", | 1602 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); |
1473 | w->name, ret); | 1603 | if (ret != 0) |
1604 | dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", | ||
1605 | w->name, ret); | ||
1606 | } | ||
1474 | } | 1607 | } |
1475 | 1608 | ||
1609 | if (!w) | ||
1610 | return; | ||
1611 | |||
1476 | ret = soc_widget_update_bits_locked(w, update->reg, update->mask, | 1612 | ret = soc_widget_update_bits_locked(w, update->reg, update->mask, |
1477 | update->val); | 1613 | update->val); |
1478 | if (ret < 0) | 1614 | if (ret < 0) |
1479 | dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n", | 1615 | dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", |
1480 | w->name, ret); | 1616 | w->name, ret); |
1481 | 1617 | ||
1482 | if (w->event && | 1618 | for (wi = 0; wi < wlist->num_widgets; wi++) { |
1483 | (w->event_flags & SND_SOC_DAPM_POST_REG)) { | 1619 | w = wlist->widgets[wi]; |
1484 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); | 1620 | |
1485 | if (ret != 0) | 1621 | if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) { |
1486 | dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", | 1622 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); |
1487 | w->name, ret); | 1623 | if (ret != 0) |
1624 | dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", | ||
1625 | w->name, ret); | ||
1626 | } | ||
1488 | } | 1627 | } |
1489 | } | 1628 | } |
1490 | 1629 | ||
@@ -1596,6 +1735,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1596 | case snd_soc_dapm_supply: | 1735 | case snd_soc_dapm_supply: |
1597 | case snd_soc_dapm_regulator_supply: | 1736 | case snd_soc_dapm_regulator_supply: |
1598 | case snd_soc_dapm_clock_supply: | 1737 | case snd_soc_dapm_clock_supply: |
1738 | case snd_soc_dapm_kcontrol: | ||
1599 | /* Supplies can't affect their outputs, only their inputs */ | 1739 | /* Supplies can't affect their outputs, only their inputs */ |
1600 | break; | 1740 | break; |
1601 | default: | 1741 | default: |
@@ -1612,8 +1752,6 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1612 | dapm_seq_insert(w, up_list, true); | 1752 | dapm_seq_insert(w, up_list, true); |
1613 | else | 1753 | else |
1614 | dapm_seq_insert(w, down_list, false); | 1754 | dapm_seq_insert(w, down_list, false); |
1615 | |||
1616 | w->power = power; | ||
1617 | } | 1755 | } |
1618 | 1756 | ||
1619 | static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, | 1757 | static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, |
@@ -1647,9 +1785,8 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, | |||
1647 | * o Input pin to Output pin (bypass, sidetone) | 1785 | * o Input pin to Output pin (bypass, sidetone) |
1648 | * o DAC to ADC (loopback). | 1786 | * o DAC to ADC (loopback). |
1649 | */ | 1787 | */ |
1650 | static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | 1788 | static int dapm_power_widgets(struct snd_soc_card *card, int event) |
1651 | { | 1789 | { |
1652 | struct snd_soc_card *card = dapm->card; | ||
1653 | struct snd_soc_dapm_widget *w; | 1790 | struct snd_soc_dapm_widget *w; |
1654 | struct snd_soc_dapm_context *d; | 1791 | struct snd_soc_dapm_context *d; |
1655 | LIST_HEAD(up_list); | 1792 | LIST_HEAD(up_list); |
@@ -1689,7 +1826,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1689 | break; | 1826 | break; |
1690 | } | 1827 | } |
1691 | 1828 | ||
1692 | if (w->power) { | 1829 | if (w->new_power) { |
1693 | d = w->dapm; | 1830 | d = w->dapm; |
1694 | 1831 | ||
1695 | /* Supplies and micbiases only bring the | 1832 | /* Supplies and micbiases only bring the |
@@ -1731,29 +1868,29 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1731 | trace_snd_soc_dapm_walk_done(card); | 1868 | trace_snd_soc_dapm_walk_done(card); |
1732 | 1869 | ||
1733 | /* Run all the bias changes in parallel */ | 1870 | /* Run all the bias changes in parallel */ |
1734 | list_for_each_entry(d, &dapm->card->dapm_list, list) | 1871 | list_for_each_entry(d, &card->dapm_list, list) |
1735 | async_schedule_domain(dapm_pre_sequence_async, d, | 1872 | async_schedule_domain(dapm_pre_sequence_async, d, |
1736 | &async_domain); | 1873 | &async_domain); |
1737 | async_synchronize_full_domain(&async_domain); | 1874 | async_synchronize_full_domain(&async_domain); |
1738 | 1875 | ||
1739 | list_for_each_entry(w, &down_list, power_list) { | 1876 | list_for_each_entry(w, &down_list, power_list) { |
1740 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD); | 1877 | dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD); |
1741 | } | 1878 | } |
1742 | 1879 | ||
1743 | list_for_each_entry(w, &up_list, power_list) { | 1880 | list_for_each_entry(w, &up_list, power_list) { |
1744 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU); | 1881 | dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU); |
1745 | } | 1882 | } |
1746 | 1883 | ||
1747 | /* Power down widgets first; try to avoid amplifying pops. */ | 1884 | /* Power down widgets first; try to avoid amplifying pops. */ |
1748 | dapm_seq_run(dapm, &down_list, event, false); | 1885 | dapm_seq_run(card, &down_list, event, false); |
1749 | 1886 | ||
1750 | dapm_widget_update(dapm); | 1887 | dapm_widget_update(card); |
1751 | 1888 | ||
1752 | /* Now power up. */ | 1889 | /* Now power up. */ |
1753 | dapm_seq_run(dapm, &up_list, event, true); | 1890 | dapm_seq_run(card, &up_list, event, true); |
1754 | 1891 | ||
1755 | /* Run all the bias changes in parallel */ | 1892 | /* Run all the bias changes in parallel */ |
1756 | list_for_each_entry(d, &dapm->card->dapm_list, list) | 1893 | list_for_each_entry(d, &card->dapm_list, list) |
1757 | async_schedule_domain(dapm_post_sequence_async, d, | 1894 | async_schedule_domain(dapm_post_sequence_async, d, |
1758 | &async_domain); | 1895 | &async_domain); |
1759 | async_synchronize_full_domain(&async_domain); | 1896 | async_synchronize_full_domain(&async_domain); |
@@ -1764,7 +1901,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1764 | d->stream_event(d, event); | 1901 | d->stream_event(d, event); |
1765 | } | 1902 | } |
1766 | 1903 | ||
1767 | pop_dbg(dapm->dev, card->pop_time, | 1904 | pop_dbg(card->dev, card->pop_time, |
1768 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); | 1905 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); |
1769 | pop_wait(card->pop_time); | 1906 | pop_wait(card->pop_time); |
1770 | 1907 | ||
@@ -1799,8 +1936,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1799 | 1936 | ||
1800 | if (w->reg >= 0) | 1937 | if (w->reg >= 0) |
1801 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1938 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1802 | " - R%d(0x%x) bit %d", | 1939 | " - R%d(0x%x) mask 0x%x", |
1803 | w->reg, w->reg, w->shift); | 1940 | w->reg, w->reg, w->mask << w->shift); |
1804 | 1941 | ||
1805 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); | 1942 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); |
1806 | 1943 | ||
@@ -1937,22 +2074,14 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | |||
1937 | #endif | 2074 | #endif |
1938 | 2075 | ||
1939 | /* test and update the power status of a mux widget */ | 2076 | /* test and update the power status of a mux widget */ |
1940 | static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 2077 | static int soc_dapm_mux_update_power(struct snd_soc_card *card, |
1941 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 2078 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) |
1942 | { | 2079 | { |
1943 | struct snd_soc_dapm_path *path; | 2080 | struct snd_soc_dapm_path *path; |
1944 | int found = 0; | 2081 | int found = 0; |
1945 | 2082 | ||
1946 | if (widget->id != snd_soc_dapm_mux && | ||
1947 | widget->id != snd_soc_dapm_virt_mux && | ||
1948 | widget->id != snd_soc_dapm_value_mux) | ||
1949 | return -ENODEV; | ||
1950 | |||
1951 | /* find dapm widget path assoc with kcontrol */ | 2083 | /* find dapm widget path assoc with kcontrol */ |
1952 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | 2084 | dapm_kcontrol_for_each_path(path, kcontrol) { |
1953 | if (path->kcontrol != kcontrol) | ||
1954 | continue; | ||
1955 | |||
1956 | if (!path->name || !e->texts[mux]) | 2085 | if (!path->name || !e->texts[mux]) |
1957 | continue; | 2086 | continue; |
1958 | 2087 | ||
@@ -1967,73 +2096,68 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1967 | "mux disconnection"); | 2096 | "mux disconnection"); |
1968 | path->connect = 0; /* old connection must be powered down */ | 2097 | path->connect = 0; /* old connection must be powered down */ |
1969 | } | 2098 | } |
2099 | dapm_mark_dirty(path->sink, "mux change"); | ||
1970 | } | 2100 | } |
1971 | 2101 | ||
1972 | if (found) { | 2102 | if (found) |
1973 | dapm_mark_dirty(widget, "mux change"); | 2103 | dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); |
1974 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); | ||
1975 | } | ||
1976 | 2104 | ||
1977 | return found; | 2105 | return found; |
1978 | } | 2106 | } |
1979 | 2107 | ||
1980 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 2108 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm, |
1981 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 2109 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e, |
2110 | struct snd_soc_dapm_update *update) | ||
1982 | { | 2111 | { |
1983 | struct snd_soc_card *card = widget->dapm->card; | 2112 | struct snd_soc_card *card = dapm->card; |
1984 | int ret; | 2113 | int ret; |
1985 | 2114 | ||
1986 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2115 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
1987 | ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 2116 | card->update = update; |
2117 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); | ||
2118 | card->update = NULL; | ||
1988 | mutex_unlock(&card->dapm_mutex); | 2119 | mutex_unlock(&card->dapm_mutex); |
1989 | if (ret > 0) | 2120 | if (ret > 0) |
1990 | soc_dpcm_runtime_update(widget); | 2121 | soc_dpcm_runtime_update(card); |
1991 | return ret; | 2122 | return ret; |
1992 | } | 2123 | } |
1993 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); | 2124 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); |
1994 | 2125 | ||
1995 | /* test and update the power status of a mixer or switch widget */ | 2126 | /* test and update the power status of a mixer or switch widget */ |
1996 | static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 2127 | static int soc_dapm_mixer_update_power(struct snd_soc_card *card, |
1997 | struct snd_kcontrol *kcontrol, int connect) | 2128 | struct snd_kcontrol *kcontrol, int connect) |
1998 | { | 2129 | { |
1999 | struct snd_soc_dapm_path *path; | 2130 | struct snd_soc_dapm_path *path; |
2000 | int found = 0; | 2131 | int found = 0; |
2001 | 2132 | ||
2002 | if (widget->id != snd_soc_dapm_mixer && | ||
2003 | widget->id != snd_soc_dapm_mixer_named_ctl && | ||
2004 | widget->id != snd_soc_dapm_switch) | ||
2005 | return -ENODEV; | ||
2006 | |||
2007 | /* find dapm widget path assoc with kcontrol */ | 2133 | /* find dapm widget path assoc with kcontrol */ |
2008 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | 2134 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2009 | if (path->kcontrol != kcontrol) | ||
2010 | continue; | ||
2011 | |||
2012 | /* found, now check type */ | ||
2013 | found = 1; | 2135 | found = 1; |
2014 | path->connect = connect; | 2136 | path->connect = connect; |
2015 | dapm_mark_dirty(path->source, "mixer connection"); | 2137 | dapm_mark_dirty(path->source, "mixer connection"); |
2138 | dapm_mark_dirty(path->sink, "mixer update"); | ||
2016 | } | 2139 | } |
2017 | 2140 | ||
2018 | if (found) { | 2141 | if (found) |
2019 | dapm_mark_dirty(widget, "mixer update"); | 2142 | dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); |
2020 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); | ||
2021 | } | ||
2022 | 2143 | ||
2023 | return found; | 2144 | return found; |
2024 | } | 2145 | } |
2025 | 2146 | ||
2026 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 2147 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, |
2027 | struct snd_kcontrol *kcontrol, int connect) | 2148 | struct snd_kcontrol *kcontrol, int connect, |
2149 | struct snd_soc_dapm_update *update) | ||
2028 | { | 2150 | { |
2029 | struct snd_soc_card *card = widget->dapm->card; | 2151 | struct snd_soc_card *card = dapm->card; |
2030 | int ret; | 2152 | int ret; |
2031 | 2153 | ||
2032 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2154 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2033 | ret = soc_dapm_mixer_update_power(widget, kcontrol, connect); | 2155 | card->update = update; |
2156 | ret = soc_dapm_mixer_update_power(card, kcontrol, connect); | ||
2157 | card->update = NULL; | ||
2034 | mutex_unlock(&card->dapm_mutex); | 2158 | mutex_unlock(&card->dapm_mutex); |
2035 | if (ret > 0) | 2159 | if (ret > 0) |
2036 | soc_dpcm_runtime_update(widget); | 2160 | soc_dpcm_runtime_update(card); |
2037 | return ret; | 2161 | return ret; |
2038 | } | 2162 | } |
2039 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); | 2163 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); |
@@ -2112,6 +2236,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) | |||
2112 | { | 2236 | { |
2113 | list_del(&path->list_sink); | 2237 | list_del(&path->list_sink); |
2114 | list_del(&path->list_source); | 2238 | list_del(&path->list_source); |
2239 | list_del(&path->list_kcontrol); | ||
2115 | list_del(&path->list); | 2240 | list_del(&path->list); |
2116 | kfree(path); | 2241 | kfree(path); |
2117 | } | 2242 | } |
@@ -2206,70 +2331,20 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
2206 | return 0; | 2331 | return 0; |
2207 | 2332 | ||
2208 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2333 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2209 | ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | 2334 | ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); |
2210 | mutex_unlock(&dapm->card->dapm_mutex); | 2335 | mutex_unlock(&dapm->card->dapm_mutex); |
2211 | return ret; | 2336 | return ret; |
2212 | } | 2337 | } |
2213 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 2338 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
2214 | 2339 | ||
2215 | static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | 2340 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, |
2216 | const struct snd_soc_dapm_route *route) | 2341 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, |
2342 | const char *control, | ||
2343 | int (*connected)(struct snd_soc_dapm_widget *source, | ||
2344 | struct snd_soc_dapm_widget *sink)) | ||
2217 | { | 2345 | { |
2218 | struct snd_soc_dapm_path *path; | 2346 | struct snd_soc_dapm_path *path; |
2219 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 2347 | int ret; |
2220 | struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; | ||
2221 | const char *sink; | ||
2222 | const char *control = route->control; | ||
2223 | const char *source; | ||
2224 | char prefixed_sink[80]; | ||
2225 | char prefixed_source[80]; | ||
2226 | int ret = 0; | ||
2227 | |||
2228 | if (dapm->codec && dapm->codec->name_prefix) { | ||
2229 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | ||
2230 | dapm->codec->name_prefix, route->sink); | ||
2231 | sink = prefixed_sink; | ||
2232 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | ||
2233 | dapm->codec->name_prefix, route->source); | ||
2234 | source = prefixed_source; | ||
2235 | } else { | ||
2236 | sink = route->sink; | ||
2237 | source = route->source; | ||
2238 | } | ||
2239 | |||
2240 | /* | ||
2241 | * find src and dest widgets over all widgets but favor a widget from | ||
2242 | * current DAPM context | ||
2243 | */ | ||
2244 | list_for_each_entry(w, &dapm->card->widgets, list) { | ||
2245 | if (!wsink && !(strcmp(w->name, sink))) { | ||
2246 | wtsink = w; | ||
2247 | if (w->dapm == dapm) | ||
2248 | wsink = w; | ||
2249 | continue; | ||
2250 | } | ||
2251 | if (!wsource && !(strcmp(w->name, source))) { | ||
2252 | wtsource = w; | ||
2253 | if (w->dapm == dapm) | ||
2254 | wsource = w; | ||
2255 | } | ||
2256 | } | ||
2257 | /* use widget from another DAPM context if not found from this */ | ||
2258 | if (!wsink) | ||
2259 | wsink = wtsink; | ||
2260 | if (!wsource) | ||
2261 | wsource = wtsource; | ||
2262 | |||
2263 | if (wsource == NULL) { | ||
2264 | dev_err(dapm->dev, "ASoC: no source widget found for %s\n", | ||
2265 | route->source); | ||
2266 | return -ENODEV; | ||
2267 | } | ||
2268 | if (wsink == NULL) { | ||
2269 | dev_err(dapm->dev, "ASoC: no sink widget found for %s\n", | ||
2270 | route->sink); | ||
2271 | return -ENODEV; | ||
2272 | } | ||
2273 | 2348 | ||
2274 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); | 2349 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); |
2275 | if (!path) | 2350 | if (!path) |
@@ -2277,8 +2352,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2277 | 2352 | ||
2278 | path->source = wsource; | 2353 | path->source = wsource; |
2279 | path->sink = wsink; | 2354 | path->sink = wsink; |
2280 | path->connected = route->connected; | 2355 | path->connected = connected; |
2281 | INIT_LIST_HEAD(&path->list); | 2356 | INIT_LIST_HEAD(&path->list); |
2357 | INIT_LIST_HEAD(&path->list_kcontrol); | ||
2282 | INIT_LIST_HEAD(&path->list_source); | 2358 | INIT_LIST_HEAD(&path->list_source); |
2283 | INIT_LIST_HEAD(&path->list_sink); | 2359 | INIT_LIST_HEAD(&path->list_sink); |
2284 | 2360 | ||
@@ -2328,6 +2404,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2328 | case snd_soc_dapm_dai_in: | 2404 | case snd_soc_dapm_dai_in: |
2329 | case snd_soc_dapm_dai_out: | 2405 | case snd_soc_dapm_dai_out: |
2330 | case snd_soc_dapm_dai_link: | 2406 | case snd_soc_dapm_dai_link: |
2407 | case snd_soc_dapm_kcontrol: | ||
2331 | list_add(&path->list, &dapm->card->paths); | 2408 | list_add(&path->list, &dapm->card->paths); |
2332 | list_add(&path->list_sink, &wsink->sources); | 2409 | list_add(&path->list_sink, &wsink->sources); |
2333 | list_add(&path->list_source, &wsource->sinks); | 2410 | list_add(&path->list_source, &wsource->sinks); |
@@ -2363,11 +2440,77 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2363 | dapm_mark_dirty(wsink, "Route added"); | 2440 | dapm_mark_dirty(wsink, "Route added"); |
2364 | 2441 | ||
2365 | return 0; | 2442 | return 0; |
2443 | err: | ||
2444 | kfree(path); | ||
2445 | return ret; | ||
2446 | } | ||
2447 | |||
2448 | static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | ||
2449 | const struct snd_soc_dapm_route *route) | ||
2450 | { | ||
2451 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | ||
2452 | struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; | ||
2453 | const char *sink; | ||
2454 | const char *source; | ||
2455 | char prefixed_sink[80]; | ||
2456 | char prefixed_source[80]; | ||
2457 | int ret; | ||
2458 | |||
2459 | if (dapm->codec && dapm->codec->name_prefix) { | ||
2460 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | ||
2461 | dapm->codec->name_prefix, route->sink); | ||
2462 | sink = prefixed_sink; | ||
2463 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | ||
2464 | dapm->codec->name_prefix, route->source); | ||
2465 | source = prefixed_source; | ||
2466 | } else { | ||
2467 | sink = route->sink; | ||
2468 | source = route->source; | ||
2469 | } | ||
2470 | |||
2471 | /* | ||
2472 | * find src and dest widgets over all widgets but favor a widget from | ||
2473 | * current DAPM context | ||
2474 | */ | ||
2475 | list_for_each_entry(w, &dapm->card->widgets, list) { | ||
2476 | if (!wsink && !(strcmp(w->name, sink))) { | ||
2477 | wtsink = w; | ||
2478 | if (w->dapm == dapm) | ||
2479 | wsink = w; | ||
2480 | continue; | ||
2481 | } | ||
2482 | if (!wsource && !(strcmp(w->name, source))) { | ||
2483 | wtsource = w; | ||
2484 | if (w->dapm == dapm) | ||
2485 | wsource = w; | ||
2486 | } | ||
2487 | } | ||
2488 | /* use widget from another DAPM context if not found from this */ | ||
2489 | if (!wsink) | ||
2490 | wsink = wtsink; | ||
2491 | if (!wsource) | ||
2492 | wsource = wtsource; | ||
2493 | |||
2494 | if (wsource == NULL) { | ||
2495 | dev_err(dapm->dev, "ASoC: no source widget found for %s\n", | ||
2496 | route->source); | ||
2497 | return -ENODEV; | ||
2498 | } | ||
2499 | if (wsink == NULL) { | ||
2500 | dev_err(dapm->dev, "ASoC: no sink widget found for %s\n", | ||
2501 | route->sink); | ||
2502 | return -ENODEV; | ||
2503 | } | ||
2366 | 2504 | ||
2505 | ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control, | ||
2506 | route->connected); | ||
2507 | if (ret) | ||
2508 | goto err; | ||
2509 | |||
2510 | return 0; | ||
2367 | err: | 2511 | err: |
2368 | dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", | 2512 | dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", |
2369 | source, control, sink); | 2513 | source, route->control, sink); |
2370 | kfree(path); | ||
2371 | return ret; | 2514 | return ret; |
2372 | } | 2515 | } |
2373 | 2516 | ||
@@ -2571,12 +2714,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); | |||
2571 | */ | 2714 | */ |
2572 | int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | 2715 | int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) |
2573 | { | 2716 | { |
2717 | struct snd_soc_card *card = dapm->card; | ||
2574 | struct snd_soc_dapm_widget *w; | 2718 | struct snd_soc_dapm_widget *w; |
2575 | unsigned int val; | 2719 | unsigned int val; |
2576 | 2720 | ||
2577 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | 2721 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); |
2578 | 2722 | ||
2579 | list_for_each_entry(w, &dapm->card->widgets, list) | 2723 | list_for_each_entry(w, &card->widgets, list) |
2580 | { | 2724 | { |
2581 | if (w->new) | 2725 | if (w->new) |
2582 | continue; | 2726 | continue; |
@@ -2586,7 +2730,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2586 | sizeof(struct snd_kcontrol *), | 2730 | sizeof(struct snd_kcontrol *), |
2587 | GFP_KERNEL); | 2731 | GFP_KERNEL); |
2588 | if (!w->kcontrols) { | 2732 | if (!w->kcontrols) { |
2589 | mutex_unlock(&dapm->card->dapm_mutex); | 2733 | mutex_unlock(&card->dapm_mutex); |
2590 | return -ENOMEM; | 2734 | return -ENOMEM; |
2591 | } | 2735 | } |
2592 | } | 2736 | } |
@@ -2612,12 +2756,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2612 | 2756 | ||
2613 | /* Read the initial power state from the device */ | 2757 | /* Read the initial power state from the device */ |
2614 | if (w->reg >= 0) { | 2758 | if (w->reg >= 0) { |
2615 | val = soc_widget_read(w, w->reg); | 2759 | val = soc_widget_read(w, w->reg) >> w->shift; |
2616 | val &= 1 << w->shift; | 2760 | val &= w->mask; |
2617 | if (w->invert) | 2761 | if (val == w->on_val) |
2618 | val = !val; | ||
2619 | |||
2620 | if (val) | ||
2621 | w->power = 1; | 2762 | w->power = 1; |
2622 | } | 2763 | } |
2623 | 2764 | ||
@@ -2627,8 +2768,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2627 | dapm_debugfs_add_widget(w); | 2768 | dapm_debugfs_add_widget(w); |
2628 | } | 2769 | } |
2629 | 2770 | ||
2630 | dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | 2771 | dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); |
2631 | mutex_unlock(&dapm->card->dapm_mutex); | 2772 | mutex_unlock(&card->dapm_mutex); |
2632 | return 0; | 2773 | return 0; |
2633 | } | 2774 | } |
2634 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | 2775 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); |
@@ -2645,8 +2786,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | |||
2645 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | 2786 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, |
2646 | struct snd_ctl_elem_value *ucontrol) | 2787 | struct snd_ctl_elem_value *ucontrol) |
2647 | { | 2788 | { |
2648 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2789 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2649 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | 2790 | struct snd_soc_card *card = codec->card; |
2650 | struct soc_mixer_control *mc = | 2791 | struct soc_mixer_control *mc = |
2651 | (struct soc_mixer_control *)kcontrol->private_value; | 2792 | (struct soc_mixer_control *)kcontrol->private_value; |
2652 | unsigned int reg = mc->reg; | 2793 | unsigned int reg = mc->reg; |
@@ -2654,17 +2795,24 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
2654 | int max = mc->max; | 2795 | int max = mc->max; |
2655 | unsigned int mask = (1 << fls(max)) - 1; | 2796 | unsigned int mask = (1 << fls(max)) - 1; |
2656 | unsigned int invert = mc->invert; | 2797 | unsigned int invert = mc->invert; |
2798 | unsigned int val; | ||
2657 | 2799 | ||
2658 | if (snd_soc_volsw_is_stereo(mc)) | 2800 | if (snd_soc_volsw_is_stereo(mc)) |
2659 | dev_warn(widget->dapm->dev, | 2801 | dev_warn(codec->dapm.dev, |
2660 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2802 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2661 | kcontrol->id.name); | 2803 | kcontrol->id.name); |
2662 | 2804 | ||
2663 | ucontrol->value.integer.value[0] = | 2805 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2664 | (snd_soc_read(widget->codec, reg) >> shift) & mask; | 2806 | if (dapm_kcontrol_is_powered(kcontrol)) |
2807 | val = (snd_soc_read(codec, reg) >> shift) & mask; | ||
2808 | else | ||
2809 | val = dapm_kcontrol_get_value(kcontrol); | ||
2810 | mutex_unlock(&card->dapm_mutex); | ||
2811 | |||
2665 | if (invert) | 2812 | if (invert) |
2666 | ucontrol->value.integer.value[0] = | 2813 | ucontrol->value.integer.value[0] = max - val; |
2667 | max - ucontrol->value.integer.value[0]; | 2814 | else |
2815 | ucontrol->value.integer.value[0] = val; | ||
2668 | 2816 | ||
2669 | return 0; | 2817 | return 0; |
2670 | } | 2818 | } |
@@ -2682,9 +2830,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | |||
2682 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | 2830 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, |
2683 | struct snd_ctl_elem_value *ucontrol) | 2831 | struct snd_ctl_elem_value *ucontrol) |
2684 | { | 2832 | { |
2685 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2833 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2686 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2687 | struct snd_soc_codec *codec = widget->codec; | ||
2688 | struct snd_soc_card *card = codec->card; | 2834 | struct snd_soc_card *card = codec->card; |
2689 | struct soc_mixer_control *mc = | 2835 | struct soc_mixer_control *mc = |
2690 | (struct soc_mixer_control *)kcontrol->private_value; | 2836 | (struct soc_mixer_control *)kcontrol->private_value; |
@@ -2696,10 +2842,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2696 | unsigned int val; | 2842 | unsigned int val; |
2697 | int connect, change; | 2843 | int connect, change; |
2698 | struct snd_soc_dapm_update update; | 2844 | struct snd_soc_dapm_update update; |
2699 | int wi; | ||
2700 | 2845 | ||
2701 | if (snd_soc_volsw_is_stereo(mc)) | 2846 | if (snd_soc_volsw_is_stereo(mc)) |
2702 | dev_warn(widget->dapm->dev, | 2847 | dev_warn(codec->dapm.dev, |
2703 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2848 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2704 | kcontrol->id.name); | 2849 | kcontrol->id.name); |
2705 | 2850 | ||
@@ -2708,29 +2853,26 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2708 | 2853 | ||
2709 | if (invert) | 2854 | if (invert) |
2710 | val = max - val; | 2855 | val = max - val; |
2711 | mask = mask << shift; | ||
2712 | val = val << shift; | ||
2713 | 2856 | ||
2714 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2857 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2715 | 2858 | ||
2716 | change = snd_soc_test_bits(widget->codec, reg, mask, val); | 2859 | dapm_kcontrol_set_value(kcontrol, val); |
2717 | if (change) { | ||
2718 | for (wi = 0; wi < wlist->num_widgets; wi++) { | ||
2719 | widget = wlist->widgets[wi]; | ||
2720 | 2860 | ||
2721 | widget->value = val; | 2861 | mask = mask << shift; |
2862 | val = val << shift; | ||
2722 | 2863 | ||
2723 | update.kcontrol = kcontrol; | 2864 | change = snd_soc_test_bits(codec, reg, mask, val); |
2724 | update.widget = widget; | 2865 | if (change) { |
2725 | update.reg = reg; | 2866 | update.kcontrol = kcontrol; |
2726 | update.mask = mask; | 2867 | update.reg = reg; |
2727 | update.val = val; | 2868 | update.mask = mask; |
2728 | widget->dapm->update = &update; | 2869 | update.val = val; |
2729 | 2870 | ||
2730 | soc_dapm_mixer_update_power(widget, kcontrol, connect); | 2871 | card->update = &update; |
2731 | 2872 | ||
2732 | widget->dapm->update = NULL; | 2873 | soc_dapm_mixer_update_power(card, kcontrol, connect); |
2733 | } | 2874 | |
2875 | card->update = NULL; | ||
2734 | } | 2876 | } |
2735 | 2877 | ||
2736 | mutex_unlock(&card->dapm_mutex); | 2878 | mutex_unlock(&card->dapm_mutex); |
@@ -2750,12 +2892,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | |||
2750 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | 2892 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, |
2751 | struct snd_ctl_elem_value *ucontrol) | 2893 | struct snd_ctl_elem_value *ucontrol) |
2752 | { | 2894 | { |
2753 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2895 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2754 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2755 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2896 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2756 | unsigned int val; | 2897 | unsigned int val; |
2757 | 2898 | ||
2758 | val = snd_soc_read(widget->codec, e->reg); | 2899 | val = snd_soc_read(codec, e->reg); |
2759 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; | 2900 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; |
2760 | if (e->shift_l != e->shift_r) | 2901 | if (e->shift_l != e->shift_r) |
2761 | ucontrol->value.enumerated.item[1] = | 2902 | ucontrol->value.enumerated.item[1] = |
@@ -2777,15 +2918,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | |||
2777 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | 2918 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
2778 | struct snd_ctl_elem_value *ucontrol) | 2919 | struct snd_ctl_elem_value *ucontrol) |
2779 | { | 2920 | { |
2780 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2921 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2781 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2782 | struct snd_soc_codec *codec = widget->codec; | ||
2783 | struct snd_soc_card *card = codec->card; | 2922 | struct snd_soc_card *card = codec->card; |
2784 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2923 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2785 | unsigned int val, mux, change; | 2924 | unsigned int val, mux, change; |
2786 | unsigned int mask; | 2925 | unsigned int mask; |
2787 | struct snd_soc_dapm_update update; | 2926 | struct snd_soc_dapm_update update; |
2788 | int wi; | ||
2789 | 2927 | ||
2790 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2928 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2791 | return -EINVAL; | 2929 | return -EINVAL; |
@@ -2801,24 +2939,17 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2801 | 2939 | ||
2802 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2940 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2803 | 2941 | ||
2804 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 2942 | change = snd_soc_test_bits(codec, e->reg, mask, val); |
2805 | if (change) { | 2943 | if (change) { |
2806 | for (wi = 0; wi < wlist->num_widgets; wi++) { | 2944 | update.kcontrol = kcontrol; |
2807 | widget = wlist->widgets[wi]; | 2945 | update.reg = e->reg; |
2946 | update.mask = mask; | ||
2947 | update.val = val; | ||
2948 | card->update = &update; | ||
2808 | 2949 | ||
2809 | widget->value = val; | 2950 | soc_dapm_mux_update_power(card, kcontrol, mux, e); |
2810 | 2951 | ||
2811 | update.kcontrol = kcontrol; | 2952 | card->update = NULL; |
2812 | update.widget = widget; | ||
2813 | update.reg = e->reg; | ||
2814 | update.mask = mask; | ||
2815 | update.val = val; | ||
2816 | widget->dapm->update = &update; | ||
2817 | |||
2818 | soc_dapm_mux_update_power(widget, kcontrol, mux, e); | ||
2819 | |||
2820 | widget->dapm->update = NULL; | ||
2821 | } | ||
2822 | } | 2953 | } |
2823 | 2954 | ||
2824 | mutex_unlock(&card->dapm_mutex); | 2955 | mutex_unlock(&card->dapm_mutex); |
@@ -2836,11 +2967,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | |||
2836 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | 2967 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, |
2837 | struct snd_ctl_elem_value *ucontrol) | 2968 | struct snd_ctl_elem_value *ucontrol) |
2838 | { | 2969 | { |
2839 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2970 | ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol); |
2840 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2841 | |||
2842 | ucontrol->value.enumerated.item[0] = widget->value; | ||
2843 | |||
2844 | return 0; | 2971 | return 0; |
2845 | } | 2972 | } |
2846 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | 2973 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); |
@@ -2855,30 +2982,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | |||
2855 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | 2982 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, |
2856 | struct snd_ctl_elem_value *ucontrol) | 2983 | struct snd_ctl_elem_value *ucontrol) |
2857 | { | 2984 | { |
2858 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2985 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2859 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2860 | struct snd_soc_codec *codec = widget->codec; | ||
2861 | struct snd_soc_card *card = codec->card; | 2986 | struct snd_soc_card *card = codec->card; |
2987 | unsigned int value; | ||
2862 | struct soc_enum *e = | 2988 | struct soc_enum *e = |
2863 | (struct soc_enum *)kcontrol->private_value; | 2989 | (struct soc_enum *)kcontrol->private_value; |
2864 | int change; | 2990 | int change; |
2865 | int wi; | ||
2866 | 2991 | ||
2867 | if (ucontrol->value.enumerated.item[0] >= e->max) | 2992 | if (ucontrol->value.enumerated.item[0] >= e->max) |
2868 | return -EINVAL; | 2993 | return -EINVAL; |
2869 | 2994 | ||
2870 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2995 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2871 | 2996 | ||
2872 | change = widget->value != ucontrol->value.enumerated.item[0]; | 2997 | value = ucontrol->value.enumerated.item[0]; |
2873 | if (change) { | 2998 | change = dapm_kcontrol_set_value(kcontrol, value); |
2874 | for (wi = 0; wi < wlist->num_widgets; wi++) { | 2999 | if (change) |
2875 | widget = wlist->widgets[wi]; | 3000 | soc_dapm_mux_update_power(card, kcontrol, value, e); |
2876 | |||
2877 | widget->value = ucontrol->value.enumerated.item[0]; | ||
2878 | |||
2879 | soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); | ||
2880 | } | ||
2881 | } | ||
2882 | 3001 | ||
2883 | mutex_unlock(&card->dapm_mutex); | 3002 | mutex_unlock(&card->dapm_mutex); |
2884 | return change; | 3003 | return change; |
@@ -2901,12 +3020,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | |||
2901 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | 3020 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, |
2902 | struct snd_ctl_elem_value *ucontrol) | 3021 | struct snd_ctl_elem_value *ucontrol) |
2903 | { | 3022 | { |
2904 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 3023 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2905 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2906 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 3024 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2907 | unsigned int reg_val, val, mux; | 3025 | unsigned int reg_val, val, mux; |
2908 | 3026 | ||
2909 | reg_val = snd_soc_read(widget->codec, e->reg); | 3027 | reg_val = snd_soc_read(codec, e->reg); |
2910 | val = (reg_val >> e->shift_l) & e->mask; | 3028 | val = (reg_val >> e->shift_l) & e->mask; |
2911 | for (mux = 0; mux < e->max; mux++) { | 3029 | for (mux = 0; mux < e->max; mux++) { |
2912 | if (val == e->values[mux]) | 3030 | if (val == e->values[mux]) |
@@ -2942,15 +3060,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | |||
2942 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | 3060 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, |
2943 | struct snd_ctl_elem_value *ucontrol) | 3061 | struct snd_ctl_elem_value *ucontrol) |
2944 | { | 3062 | { |
2945 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 3063 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2946 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2947 | struct snd_soc_codec *codec = widget->codec; | ||
2948 | struct snd_soc_card *card = codec->card; | 3064 | struct snd_soc_card *card = codec->card; |
2949 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 3065 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2950 | unsigned int val, mux, change; | 3066 | unsigned int val, mux, change; |
2951 | unsigned int mask; | 3067 | unsigned int mask; |
2952 | struct snd_soc_dapm_update update; | 3068 | struct snd_soc_dapm_update update; |
2953 | int wi; | ||
2954 | 3069 | ||
2955 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 3070 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2956 | return -EINVAL; | 3071 | return -EINVAL; |
@@ -2966,24 +3081,17 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2966 | 3081 | ||
2967 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 3082 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2968 | 3083 | ||
2969 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 3084 | change = snd_soc_test_bits(codec, e->reg, mask, val); |
2970 | if (change) { | 3085 | if (change) { |
2971 | for (wi = 0; wi < wlist->num_widgets; wi++) { | 3086 | update.kcontrol = kcontrol; |
2972 | widget = wlist->widgets[wi]; | 3087 | update.reg = e->reg; |
2973 | 3088 | update.mask = mask; | |
2974 | widget->value = val; | 3089 | update.val = val; |
3090 | card->update = &update; | ||
2975 | 3091 | ||
2976 | update.kcontrol = kcontrol; | 3092 | soc_dapm_mux_update_power(card, kcontrol, mux, e); |
2977 | update.widget = widget; | ||
2978 | update.reg = e->reg; | ||
2979 | update.mask = mask; | ||
2980 | update.val = val; | ||
2981 | widget->dapm->update = &update; | ||
2982 | 3093 | ||
2983 | soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 3094 | card->update = NULL; |
2984 | |||
2985 | widget->dapm->update = NULL; | ||
2986 | } | ||
2987 | } | 3095 | } |
2988 | 3096 | ||
2989 | mutex_unlock(&card->dapm_mutex); | 3097 | mutex_unlock(&card->dapm_mutex); |
@@ -3080,7 +3188,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3080 | return NULL; | 3188 | return NULL; |
3081 | } | 3189 | } |
3082 | 3190 | ||
3083 | if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { | 3191 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
3084 | ret = regulator_allow_bypass(w->regulator, true); | 3192 | ret = regulator_allow_bypass(w->regulator, true); |
3085 | if (ret != 0) | 3193 | if (ret != 0) |
3086 | dev_warn(w->dapm->dev, | 3194 | dev_warn(w->dapm->dev, |
@@ -3127,16 +3235,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3127 | case snd_soc_dapm_value_mux: | 3235 | case snd_soc_dapm_value_mux: |
3128 | w->power_check = dapm_generic_check_power; | 3236 | w->power_check = dapm_generic_check_power; |
3129 | break; | 3237 | break; |
3130 | case snd_soc_dapm_adc: | ||
3131 | case snd_soc_dapm_aif_out: | ||
3132 | case snd_soc_dapm_dai_out: | 3238 | case snd_soc_dapm_dai_out: |
3133 | w->power_check = dapm_adc_check_power; | 3239 | w->power_check = dapm_adc_check_power; |
3134 | break; | 3240 | break; |
3135 | case snd_soc_dapm_dac: | ||
3136 | case snd_soc_dapm_aif_in: | ||
3137 | case snd_soc_dapm_dai_in: | 3241 | case snd_soc_dapm_dai_in: |
3138 | w->power_check = dapm_dac_check_power; | 3242 | w->power_check = dapm_dac_check_power; |
3139 | break; | 3243 | break; |
3244 | case snd_soc_dapm_adc: | ||
3245 | case snd_soc_dapm_aif_out: | ||
3246 | case snd_soc_dapm_dac: | ||
3247 | case snd_soc_dapm_aif_in: | ||
3140 | case snd_soc_dapm_pga: | 3248 | case snd_soc_dapm_pga: |
3141 | case snd_soc_dapm_out_drv: | 3249 | case snd_soc_dapm_out_drv: |
3142 | case snd_soc_dapm_input: | 3250 | case snd_soc_dapm_input: |
@@ -3152,6 +3260,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3152 | case snd_soc_dapm_supply: | 3260 | case snd_soc_dapm_supply: |
3153 | case snd_soc_dapm_regulator_supply: | 3261 | case snd_soc_dapm_regulator_supply: |
3154 | case snd_soc_dapm_clock_supply: | 3262 | case snd_soc_dapm_clock_supply: |
3263 | case snd_soc_dapm_kcontrol: | ||
3155 | w->power_check = dapm_supply_check_power; | 3264 | w->power_check = dapm_supply_check_power; |
3156 | break; | 3265 | break; |
3157 | default: | 3266 | default: |
@@ -3416,9 +3525,6 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
3416 | { | 3525 | { |
3417 | struct snd_soc_dapm_widget *dai_w, *w; | 3526 | struct snd_soc_dapm_widget *dai_w, *w; |
3418 | struct snd_soc_dai *dai; | 3527 | struct snd_soc_dai *dai; |
3419 | struct snd_soc_dapm_route r; | ||
3420 | |||
3421 | memset(&r, 0, sizeof(r)); | ||
3422 | 3528 | ||
3423 | /* For each DAI widget... */ | 3529 | /* For each DAI widget... */ |
3424 | list_for_each_entry(dai_w, &card->widgets, list) { | 3530 | list_for_each_entry(dai_w, &card->widgets, list) { |
@@ -3445,29 +3551,27 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
3445 | break; | 3551 | break; |
3446 | } | 3552 | } |
3447 | 3553 | ||
3448 | if (!w->sname) | 3554 | if (!w->sname || !strstr(w->sname, dai_w->name)) |
3449 | continue; | 3555 | continue; |
3450 | 3556 | ||
3451 | if (dai->driver->playback.stream_name && | 3557 | if (dai->driver->playback.stream_name && |
3452 | strstr(w->sname, | 3558 | strstr(w->sname, |
3453 | dai->driver->playback.stream_name)) { | 3559 | dai->driver->playback.stream_name)) { |
3454 | r.source = dai->playback_widget->name; | ||
3455 | r.sink = w->name; | ||
3456 | dev_dbg(dai->dev, "%s -> %s\n", | 3560 | dev_dbg(dai->dev, "%s -> %s\n", |
3457 | r.source, r.sink); | 3561 | dai->playback_widget->name, w->name); |
3458 | 3562 | ||
3459 | snd_soc_dapm_add_route(w->dapm, &r); | 3563 | snd_soc_dapm_add_path(w->dapm, |
3564 | dai->playback_widget, w, NULL, NULL); | ||
3460 | } | 3565 | } |
3461 | 3566 | ||
3462 | if (dai->driver->capture.stream_name && | 3567 | if (dai->driver->capture.stream_name && |
3463 | strstr(w->sname, | 3568 | strstr(w->sname, |
3464 | dai->driver->capture.stream_name)) { | 3569 | dai->driver->capture.stream_name)) { |
3465 | r.source = w->name; | ||
3466 | r.sink = dai->capture_widget->name; | ||
3467 | dev_dbg(dai->dev, "%s -> %s\n", | 3570 | dev_dbg(dai->dev, "%s -> %s\n", |
3468 | r.source, r.sink); | 3571 | w->name, dai->capture_widget->name); |
3469 | 3572 | ||
3470 | snd_soc_dapm_add_route(w->dapm, &r); | 3573 | snd_soc_dapm_add_path(w->dapm, w, |
3574 | dai->capture_widget, NULL, NULL); | ||
3471 | } | 3575 | } |
3472 | } | 3576 | } |
3473 | } | 3577 | } |
@@ -3529,7 +3633,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | |||
3529 | } | 3633 | } |
3530 | } | 3634 | } |
3531 | 3635 | ||
3532 | dapm_power_widgets(&rtd->card->dapm, event); | 3636 | dapm_power_widgets(rtd->card, event); |
3533 | } | 3637 | } |
3534 | 3638 | ||
3535 | /** | 3639 | /** |
@@ -3798,7 +3902,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
3798 | if (dapm->bias_level == SND_SOC_BIAS_ON) | 3902 | if (dapm->bias_level == SND_SOC_BIAS_ON) |
3799 | snd_soc_dapm_set_bias_level(dapm, | 3903 | snd_soc_dapm_set_bias_level(dapm, |
3800 | SND_SOC_BIAS_PREPARE); | 3904 | SND_SOC_BIAS_PREPARE); |
3801 | dapm_seq_run(dapm, &down_list, 0, false); | 3905 | dapm_seq_run(card, &down_list, 0, false); |
3802 | if (dapm->bias_level == SND_SOC_BIAS_PREPARE) | 3906 | if (dapm->bias_level == SND_SOC_BIAS_PREPARE) |
3803 | snd_soc_dapm_set_bias_level(dapm, | 3907 | snd_soc_dapm_set_bias_level(dapm, |
3804 | SND_SOC_BIAS_STANDBY); | 3908 | SND_SOC_BIAS_STANDBY); |
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 0bb5cccd7766..7aa26b5178aa 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c | |||
@@ -263,7 +263,7 @@ static irqreturn_t gpio_handler(int irq, void *data) | |||
263 | if (device_may_wakeup(dev)) | 263 | if (device_may_wakeup(dev)) |
264 | pm_wakeup_event(dev, gpio->debounce_time + 50); | 264 | pm_wakeup_event(dev, gpio->debounce_time + 50); |
265 | 265 | ||
266 | schedule_delayed_work(&gpio->work, | 266 | queue_delayed_work(system_power_efficient_wq, &gpio->work, |
267 | msecs_to_jiffies(gpio->debounce_time)); | 267 | msecs_to_jiffies(gpio->debounce_time)); |
268 | 268 | ||
269 | return IRQ_HANDLED; | 269 | return IRQ_HANDLED; |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index b6c640332a17..fb70fbe26862 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -411,8 +411,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
411 | } else { | 411 | } else { |
412 | /* start delayed pop wq here for playback streams */ | 412 | /* start delayed pop wq here for playback streams */ |
413 | rtd->pop_wait = 1; | 413 | rtd->pop_wait = 1; |
414 | schedule_delayed_work(&rtd->delayed_work, | 414 | queue_delayed_work(system_power_efficient_wq, |
415 | msecs_to_jiffies(rtd->pmdown_time)); | 415 | &rtd->delayed_work, |
416 | msecs_to_jiffies(rtd->pmdown_time)); | ||
416 | } | 417 | } |
417 | } else { | 418 | } else { |
418 | /* capture streams can be powered down now */ | 419 | /* capture streams can be powered down now */ |
@@ -1832,18 +1833,10 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) | |||
1832 | /* Called by DAPM mixer/mux changes to update audio routing between PCMs and | 1833 | /* Called by DAPM mixer/mux changes to update audio routing between PCMs and |
1833 | * any DAI links. | 1834 | * any DAI links. |
1834 | */ | 1835 | */ |
1835 | int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) | 1836 | int soc_dpcm_runtime_update(struct snd_soc_card *card) |
1836 | { | 1837 | { |
1837 | struct snd_soc_card *card; | ||
1838 | int i, old, new, paths; | 1838 | int i, old, new, paths; |
1839 | 1839 | ||
1840 | if (widget->codec) | ||
1841 | card = widget->codec->card; | ||
1842 | else if (widget->platform) | ||
1843 | card = widget->platform->card; | ||
1844 | else | ||
1845 | return -EINVAL; | ||
1846 | |||
1847 | mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1840 | mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1848 | for (i = 0; i < card->num_rtd; i++) { | 1841 | for (i = 0; i < card->num_rtd; i++) { |
1849 | struct snd_soc_dapm_widget_list *list; | 1842 | struct snd_soc_dapm_widget_list *list; |
diff --git a/sound/soc/spear/Kconfig b/sound/soc/spear/Kconfig index 3567d73b218e..0a53053495f3 100644 --- a/sound/soc/spear/Kconfig +++ b/sound/soc/spear/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_SPEAR_SOC | 1 | config SND_SPEAR_SOC |
2 | tristate | 2 | tristate |
3 | select SND_SOC_DMAENGINE_PCM | 3 | select SND_DMAENGINE_PCM |
4 | 4 | ||
5 | config SND_SPEAR_SPDIF_OUT | 5 | config SND_SPEAR_SPDIF_OUT |
6 | tristate | 6 | tristate |
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 995b120c2cd0..8fc653ca3ab4 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig | |||
@@ -1,8 +1,8 @@ | |||
1 | config SND_SOC_TEGRA | 1 | config SND_SOC_TEGRA |
2 | tristate "SoC Audio for the Tegra System-on-Chip" | 2 | tristate "SoC Audio for the Tegra System-on-Chip" |
3 | depends on ARCH_TEGRA && TEGRA20_APB_DMA | 3 | depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST |
4 | select REGMAP_MMIO | 4 | select REGMAP_MMIO |
5 | select SND_SOC_GENERIC_DMAENGINE_PCM if TEGRA20_APB_DMA | 5 | select SND_SOC_GENERIC_DMAENGINE_PCM |
6 | help | 6 | help |
7 | Say Y or M here if you want support for SoC audio on Tegra. | 7 | Say Y or M here if you want support for SoC audio on Tegra. |
8 | 8 | ||
@@ -61,7 +61,7 @@ config SND_SOC_TEGRA30_I2S | |||
61 | 61 | ||
62 | config SND_SOC_TEGRA_RT5640 | 62 | config SND_SOC_TEGRA_RT5640 |
63 | tristate "SoC Audio support for Tegra boards using an RT5640 codec" | 63 | tristate "SoC Audio support for Tegra boards using an RT5640 codec" |
64 | depends on SND_SOC_TEGRA && I2C | 64 | depends on SND_SOC_TEGRA && I2C && GPIOLIB |
65 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | 65 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC |
66 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | 66 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC |
67 | select SND_SOC_RT5640 | 67 | select SND_SOC_RT5640 |
@@ -71,7 +71,7 @@ config SND_SOC_TEGRA_RT5640 | |||
71 | 71 | ||
72 | config SND_SOC_TEGRA_WM8753 | 72 | config SND_SOC_TEGRA_WM8753 |
73 | tristate "SoC Audio support for Tegra boards using a WM8753 codec" | 73 | tristate "SoC Audio support for Tegra boards using a WM8753 codec" |
74 | depends on SND_SOC_TEGRA && I2C | 74 | depends on SND_SOC_TEGRA && I2C && GPIOLIB |
75 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | 75 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC |
76 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | 76 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC |
77 | select SND_SOC_WM8753 | 77 | select SND_SOC_WM8753 |
@@ -81,7 +81,7 @@ config SND_SOC_TEGRA_WM8753 | |||
81 | 81 | ||
82 | config SND_SOC_TEGRA_WM8903 | 82 | config SND_SOC_TEGRA_WM8903 |
83 | tristate "SoC Audio support for Tegra boards using a WM8903 codec" | 83 | tristate "SoC Audio support for Tegra boards using a WM8903 codec" |
84 | depends on SND_SOC_TEGRA && I2C | 84 | depends on SND_SOC_TEGRA && I2C && GPIOLIB |
85 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | 85 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC |
86 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | 86 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC |
87 | select SND_SOC_WM8903 | 87 | select SND_SOC_WM8903 |
@@ -92,7 +92,7 @@ config SND_SOC_TEGRA_WM8903 | |||
92 | 92 | ||
93 | config SND_SOC_TEGRA_WM9712 | 93 | config SND_SOC_TEGRA_WM9712 |
94 | tristate "SoC Audio support for Tegra boards using a WM9712 codec" | 94 | tristate "SoC Audio support for Tegra boards using a WM9712 codec" |
95 | depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC | 95 | depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC && GPIOLIB |
96 | select SND_SOC_TEGRA20_AC97 | 96 | select SND_SOC_TEGRA20_AC97 |
97 | select SND_SOC_WM9712 | 97 | select SND_SOC_WM9712 |
98 | help | 98 | help |
@@ -110,7 +110,7 @@ config SND_SOC_TEGRA_TRIMSLICE | |||
110 | 110 | ||
111 | config SND_SOC_TEGRA_ALC5632 | 111 | config SND_SOC_TEGRA_ALC5632 |
112 | tristate "SoC Audio support for Tegra boards using an ALC5632 codec" | 112 | tristate "SoC Audio support for Tegra boards using an ALC5632 codec" |
113 | depends on SND_SOC_TEGRA && I2C | 113 | depends on SND_SOC_TEGRA && I2C && GPIOLIB |
114 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | 114 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC |
115 | select SND_SOC_ALC5632 | 115 | select SND_SOC_ALC5632 |
116 | help | 116 | help |
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 6c486625321b..ae27bcd586d2 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c | |||
@@ -334,12 +334,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) | |||
334 | } | 334 | } |
335 | 335 | ||
336 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 336 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
337 | if (!mem) { | ||
338 | dev_err(&pdev->dev, "No memory resource\n"); | ||
339 | ret = -ENODEV; | ||
340 | goto err_clk_put; | ||
341 | } | ||
342 | |||
343 | regs = devm_ioremap_resource(&pdev->dev, mem); | 337 | regs = devm_ioremap_resource(&pdev->dev, mem); |
344 | if (IS_ERR(regs)) { | 338 | if (IS_ERR(regs)) { |
345 | ret = PTR_ERR(regs); | 339 | ret = PTR_ERR(regs); |
@@ -432,8 +426,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) | |||
432 | 426 | ||
433 | return 0; | 427 | return 0; |
434 | 428 | ||
435 | err_unregister_pcm: | ||
436 | tegra_pcm_platform_unregister(&pdev->dev); | ||
437 | err_unregister_component: | 429 | err_unregister_component: |
438 | snd_soc_unregister_component(&pdev->dev); | 430 | snd_soc_unregister_component(&pdev->dev); |
439 | err_asoc_utils_fini: | 431 | err_asoc_utils_fini: |
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index 48d05d9e1002..c61ea3a1030f 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c | |||
@@ -13,8 +13,6 @@ | |||
13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <asm/mach-types.h> | ||
17 | |||
18 | #include <linux/module.h> | 16 | #include <linux/module.h> |
19 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
20 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index 08794f915a94..4511c5a875ec 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c | |||
@@ -99,6 +99,7 @@ static struct snd_soc_jack_gpio tegra_rt5640_hp_jack_gpio = { | |||
99 | static const struct snd_soc_dapm_widget tegra_rt5640_dapm_widgets[] = { | 99 | static const struct snd_soc_dapm_widget tegra_rt5640_dapm_widgets[] = { |
100 | SND_SOC_DAPM_HP("Headphones", NULL), | 100 | SND_SOC_DAPM_HP("Headphones", NULL), |
101 | SND_SOC_DAPM_SPK("Speakers", NULL), | 101 | SND_SOC_DAPM_SPK("Speakers", NULL), |
102 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
102 | }; | 103 | }; |
103 | 104 | ||
104 | static const struct snd_kcontrol_new tegra_rt5640_controls[] = { | 105 | static const struct snd_kcontrol_new tegra_rt5640_controls[] = { |
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index f87fc53e9b8c..8e774d1a243c 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c | |||
@@ -28,8 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <asm/mach-types.h> | ||
32 | |||
33 | #include <linux/module.h> | 31 | #include <linux/module.h> |
34 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
35 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 05c68aab5cf0..734bfcd21148 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c | |||
@@ -24,8 +24,6 @@ | |||
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <asm/mach-types.h> | ||
28 | |||
29 | #include <linux/module.h> | 27 | #include <linux/module.h> |
30 | #include <linux/of.h> | 28 | #include <linux/of.h> |
31 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index 4bcce8a3cded..e0305a148568 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c | |||
@@ -184,9 +184,6 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) | |||
184 | if (irq < 0) | 184 | if (irq < 0) |
185 | return irq; | 185 | return irq; |
186 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 186 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
187 | if (!r) | ||
188 | return -EBUSY; | ||
189 | |||
190 | drvdata->base = devm_ioremap_resource(&pdev->dev, r); | 187 | drvdata->base = devm_ioremap_resource(&pdev->dev, r); |
191 | if (IS_ERR(drvdata->base)) | 188 | if (IS_ERR(drvdata->base)) |
192 | return PTR_ERR(drvdata->base); | 189 | return PTR_ERR(drvdata->base); |
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index 8f5cd00a6e46..178d1bad6259 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c | |||
@@ -52,6 +52,7 @@ static struct snd_soc_dai_link mop500_dai_links[] = { | |||
52 | 52 | ||
53 | static struct snd_soc_card mop500_card = { | 53 | static struct snd_soc_card mop500_card = { |
54 | .name = "MOP500-card", | 54 | .name = "MOP500-card", |
55 | .owner = THIS_MODULE, | ||
55 | .probe = NULL, | 56 | .probe = NULL, |
56 | .dai_link = mop500_dai_links, | 57 | .dai_link = mop500_dai_links, |
57 | .num_links = ARRAY_SIZE(mop500_dai_links), | 58 | .num_links = ARRAY_SIZE(mop500_dai_links), |