diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 19:26:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 19:26:56 -0400 |
commit | 977dbfcf8e9ff1783355b260d93101af315de18a (patch) | |
tree | b586ca678499d1ccc2d199a97d65996c630b25d8 /sound | |
parent | aa7054f5a5a9ff728ce291cb103afa19f4f849eb (diff) | |
parent | b054087dbacee30a9dddaef2c9a96312146be04e (diff) |
Merge tag 'sound-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"Changes are seen in a wide range of codes, mainly due to ASoC DAPM
requirements; HD-audio shows a high peak in diffstat, it's just a
removal of bunch of old static quirks.
Some highlights:
- HDPM: Updates for AIO/RayDAT support, TCO/sync support
- RME96: Add PCM sync support
- HD-audio:
* A few HDMI/DP audio updates (CA assignment fix, stream switching
fix, Intel DP device list support)
* Device specific fixes (ASUS/CXT HP mic support, Thinkpad mic
improvements, Chromebook fixes, STAC9228 Dell fixes)
* Replace the all static quirks for AD codecs with the generic
parser
* WAKEEN support for handling irqs in the power saving mode
- USB-audio: Clean up implicit fb handling and related codes
- DAPM is now mandatory for ASoC CODEC drivers; all existing drivers
have had some level of DAPM support added. In addition, a lot of
cleanups and improvements in DAPM.
- Support for ASoC cross-platform compile test
- New drivers and support for Analog Devices ADAU1702 and
ADAU1401(a), Asahi Kasei Microdevices AK4554, Atmel AT91ASM9x5 and
WM8904 based machines, Freescale S/PDIF and SSI AC'97, Renesas
R-Car SoCs, Samsung Exynos5420 SoCs, Texas Instruments PCM1681 and
PCM1792A and Wolfson Microelectronics WM8997
- DT bindings for kirkwood and i.MX S/PDIF
- Clean up and bug fixes: ssm2602, rt5640 and sgtl5000.
- Core helpers for bitbanged AC'97 reset"
* tag 'sound-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (375 commits)
ALSA: hda - Re-setup HDMI pin and audio infoframe on stream switches
ALSA: hda - hdmi: Fallback to ALSA allocation when selecting CA
ASoC: mxs-sgtl5000: Configure the dai_links as unidirectional
ASoC: soc-pcm: Allow to specify unidirectional dai_link
ASoC: fsl_spdif: Staticse non-exported symbols
ASoC: ssm2602: Fix cache sync
ASoC: Remove unused sysfs_registered field from snd_soc_codec struct
ASoC: Remove unused debugfs_dapm field from snd_soc_{platform,codec} struct
ASoC: Remove unused control_type field from snd_soc_codec struct
ASoC: fsl: Add one blank space after ':=' in Makefile
ASoC: fsl: Add wrapping for dev_dbg() in fsl_spdif.c
ASoC: rt5640: change widget sequence for depop
ASoC: dapm: Fix auto-disable for inverted controls
ASoC: fsl: Drop SND_SOC_FSL_UTILS from SND_SOC_IMX_SPDIF
ASoC: Samsung: Do not queue cyclic buffers multiple times
ASoC: ep93xx-i2s: Remove unnecessary dev_set_drvdata()
ASoC: designware_i2s: Remove unnecessary dev_set_drvdata()
ASoC: fsl_spdif: remove redundant dev_err call in fsl_spdif_probe()
ASoC: fsl: Add S/PDIF machine driver
ASoc: kirkwood: Use the Kirkwood audio driver in Dove boards
...
Diffstat (limited to 'sound')
188 files changed, 11349 insertions, 7001 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/core/pcm_lib.c b/sound/core/pcm_lib.c index 82bb029d4414..6e03b465e44e 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -184,7 +184,7 @@ static void xrun(struct snd_pcm_substream *substream) | |||
184 | do { \ | 184 | do { \ |
185 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ | 185 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ |
186 | xrun_log_show(substream); \ | 186 | xrun_log_show(substream); \ |
187 | if (printk_ratelimit()) { \ | 187 | if (snd_printd_ratelimit()) { \ |
188 | snd_printd("PCM: " fmt, ##args); \ | 188 | snd_printd("PCM: " fmt, ##args); \ |
189 | } \ | 189 | } \ |
190 | dump_stack_on_xrun(substream); \ | 190 | dump_stack_on_xrun(substream); \ |
@@ -342,7 +342,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
342 | return -EPIPE; | 342 | return -EPIPE; |
343 | } | 343 | } |
344 | if (pos >= runtime->buffer_size) { | 344 | if (pos >= runtime->buffer_size) { |
345 | if (printk_ratelimit()) { | 345 | if (snd_printd_ratelimit()) { |
346 | char name[16]; | 346 | char name[16]; |
347 | snd_pcm_debug_name(substream, name, sizeof(name)); | 347 | snd_pcm_debug_name(substream, name, sizeof(name)); |
348 | xrun_log_show(substream); | 348 | xrun_log_show(substream); |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 11048cc744d0..915b4d7fbb23 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -1022,7 +1022,7 @@ static void dummy_proc_write(struct snd_info_entry *entry, | |||
1022 | if (i >= ARRAY_SIZE(fields)) | 1022 | if (i >= ARRAY_SIZE(fields)) |
1023 | continue; | 1023 | continue; |
1024 | snd_info_get_str(item, ptr, sizeof(item)); | 1024 | snd_info_get_str(item, ptr, sizeof(item)); |
1025 | if (strict_strtoull(item, 0, &val)) | 1025 | if (kstrtoull(item, 0, &val)) |
1026 | continue; | 1026 | continue; |
1027 | if (fields[i].size == sizeof(int)) | 1027 | if (fields[i].size == sizeof(int)) |
1028 | *get_dummy_int_ptr(dummy, fields[i].offset) = val; | 1028 | *get_dummy_int_ptr(dummy, fields[i].offset) = val; |
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c index 2c6386503940..fe9e6e2f2c5b 100644 --- a/sound/firewire/speakers.c +++ b/sound/firewire/speakers.c | |||
@@ -49,7 +49,6 @@ struct fwspk { | |||
49 | struct snd_card *card; | 49 | struct snd_card *card; |
50 | struct fw_unit *unit; | 50 | struct fw_unit *unit; |
51 | const struct device_info *device_info; | 51 | const struct device_info *device_info; |
52 | struct snd_pcm_substream *pcm; | ||
53 | struct mutex mutex; | 52 | struct mutex mutex; |
54 | struct cmp_connection connection; | 53 | struct cmp_connection connection; |
55 | struct amdtp_out_stream stream; | 54 | struct amdtp_out_stream stream; |
@@ -363,8 +362,7 @@ static int fwspk_create_pcm(struct fwspk *fwspk) | |||
363 | return err; | 362 | return err; |
364 | pcm->private_data = fwspk; | 363 | pcm->private_data = fwspk; |
365 | strcpy(pcm->name, fwspk->device_info->short_name); | 364 | strcpy(pcm->name, fwspk->device_info->short_name); |
366 | fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | 365 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); |
367 | fwspk->pcm->ops = &ops; | ||
368 | return 0; | 366 | return 0; |
369 | } | 367 | } |
370 | 368 | ||
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 9942691cc0ca..afef0d738078 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c | |||
@@ -443,8 +443,7 @@ static void snd_interwave_detect_memory(struct snd_gus_card *gus) | |||
443 | for (i = 0; i < 8; ++i) | 443 | for (i = 0; i < 8; ++i) |
444 | iwave[i] = snd_gf1_peek(gus, bank_pos + i); | 444 | iwave[i] = snd_gf1_peek(gus, bank_pos + i); |
445 | #ifdef CONFIG_SND_DEBUG_ROM | 445 | #ifdef CONFIG_SND_DEBUG_ROM |
446 | printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos, | 446 | printk(KERN_DEBUG "ROM at 0x%06x = %8phC\n", bank_pos, iwave); |
447 | 8, iwave); | ||
448 | #endif | 447 | #endif |
449 | if (strncmp(iwave, "INTRWAVE", 8)) | 448 | if (strncmp(iwave, "INTRWAVE", 8)) |
450 | continue; /* first check */ | 449 | continue; /* first check */ |
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c index a59c88818f48..461d94cfecbe 100644 --- a/sound/oss/dmabuf.c +++ b/sound/oss/dmabuf.c | |||
@@ -557,7 +557,6 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) | |||
557 | unsigned long flags; | 557 | unsigned long flags; |
558 | int err = 0, n = 0; | 558 | int err = 0, n = 0; |
559 | struct dma_buffparms *dmap = adev->dmap_in; | 559 | struct dma_buffparms *dmap = adev->dmap_in; |
560 | int go; | ||
561 | 560 | ||
562 | if (!(adev->open_mode & OPEN_READ)) | 561 | if (!(adev->open_mode & OPEN_READ)) |
563 | return -EIO; | 562 | return -EIO; |
@@ -584,7 +583,7 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) | |||
584 | spin_unlock_irqrestore(&dmap->lock,flags); | 583 | spin_unlock_irqrestore(&dmap->lock,flags); |
585 | return -EAGAIN; | 584 | return -EAGAIN; |
586 | } | 585 | } |
587 | if ((go = adev->go)) | 586 | if (adev->go) |
588 | timeout = dmabuf_timeout(dmap); | 587 | timeout = dmabuf_timeout(dmap); |
589 | 588 | ||
590 | spin_unlock_irqrestore(&dmap->lock,flags); | 589 | spin_unlock_irqrestore(&dmap->lock,flags); |
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 59c5e9c03d53..8de66ccd7279 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig | |||
@@ -152,14 +152,9 @@ config SND_HDA_CODEC_HDMI | |||
152 | This module is automatically loaded at probing. | 152 | This module is automatically loaded at probing. |
153 | 153 | ||
154 | config SND_HDA_I915 | 154 | config SND_HDA_I915 |
155 | bool "Build Display HD-audio controller/codec power well support for i915 cards" | 155 | bool |
156 | default y | ||
156 | depends on DRM_I915 | 157 | depends on DRM_I915 |
157 | help | ||
158 | Say Y here to include full HDMI and DisplayPort HD-audio controller/codec | ||
159 | power-well support for Intel Haswell graphics cards based on the i915 driver. | ||
160 | |||
161 | Note that this option must be enabled for Intel Haswell C+ stepping machines, otherwise | ||
162 | the GPU audio controller/codecs will not be initialized or damaged when exit from S3 mode. | ||
163 | 158 | ||
164 | config SND_HDA_CODEC_CIRRUS | 159 | config SND_HDA_CODEC_CIRRUS |
165 | bool "Build Cirrus Logic codec support" | 160 | bool "Build Cirrus Logic codec support" |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8a005f0e5ca4..5b6c4e3c92ca 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -666,6 +666,64 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, | |||
666 | } | 666 | } |
667 | EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); | 667 | EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); |
668 | 668 | ||
669 | |||
670 | /* return DEVLIST_LEN parameter of the given widget */ | ||
671 | static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid) | ||
672 | { | ||
673 | unsigned int wcaps = get_wcaps(codec, nid); | ||
674 | unsigned int parm; | ||
675 | |||
676 | if (!codec->dp_mst || !(wcaps & AC_WCAP_DIGITAL) || | ||
677 | get_wcaps_type(wcaps) != AC_WID_PIN) | ||
678 | return 0; | ||
679 | |||
680 | parm = snd_hda_param_read(codec, nid, AC_PAR_DEVLIST_LEN); | ||
681 | if (parm == -1 && codec->bus->rirb_error) | ||
682 | parm = 0; | ||
683 | return parm & AC_DEV_LIST_LEN_MASK; | ||
684 | } | ||
685 | |||
686 | /** | ||
687 | * snd_hda_get_devices - copy device list without cache | ||
688 | * @codec: the HDA codec | ||
689 | * @nid: NID of the pin to parse | ||
690 | * @dev_list: device list array | ||
691 | * @max_devices: max. number of devices to store | ||
692 | * | ||
693 | * Copy the device list. This info is dynamic and so not cached. | ||
694 | * Currently called only from hda_proc.c, so not exported. | ||
695 | */ | ||
696 | int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, | ||
697 | u8 *dev_list, int max_devices) | ||
698 | { | ||
699 | unsigned int parm; | ||
700 | int i, dev_len, devices; | ||
701 | |||
702 | parm = get_num_devices(codec, nid); | ||
703 | if (!parm) /* not multi-stream capable */ | ||
704 | return 0; | ||
705 | |||
706 | dev_len = parm + 1; | ||
707 | dev_len = dev_len < max_devices ? dev_len : max_devices; | ||
708 | |||
709 | devices = 0; | ||
710 | while (devices < dev_len) { | ||
711 | parm = snd_hda_codec_read(codec, nid, 0, | ||
712 | AC_VERB_GET_DEVICE_LIST, devices); | ||
713 | if (parm == -1 && codec->bus->rirb_error) | ||
714 | break; | ||
715 | |||
716 | for (i = 0; i < 8; i++) { | ||
717 | dev_list[devices] = (u8)parm; | ||
718 | parm >>= 4; | ||
719 | devices++; | ||
720 | if (devices >= dev_len) | ||
721 | break; | ||
722 | } | ||
723 | } | ||
724 | return devices; | ||
725 | } | ||
726 | |||
669 | /** | 727 | /** |
670 | * snd_hda_queue_unsol_event - add an unsolicited event to queue | 728 | * snd_hda_queue_unsol_event - add an unsolicited event to queue |
671 | * @bus: the BUS | 729 | * @bus: the BUS |
@@ -1216,11 +1274,13 @@ static void hda_jackpoll_work(struct work_struct *work) | |||
1216 | { | 1274 | { |
1217 | struct hda_codec *codec = | 1275 | struct hda_codec *codec = |
1218 | container_of(work, struct hda_codec, jackpoll_work.work); | 1276 | container_of(work, struct hda_codec, jackpoll_work.work); |
1219 | if (!codec->jackpoll_interval) | ||
1220 | return; | ||
1221 | 1277 | ||
1222 | snd_hda_jack_set_dirty_all(codec); | 1278 | snd_hda_jack_set_dirty_all(codec); |
1223 | snd_hda_jack_poll_all(codec); | 1279 | snd_hda_jack_poll_all(codec); |
1280 | |||
1281 | if (!codec->jackpoll_interval) | ||
1282 | return; | ||
1283 | |||
1224 | queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, | 1284 | queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, |
1225 | codec->jackpoll_interval); | 1285 | codec->jackpoll_interval); |
1226 | } | 1286 | } |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 701c2e069b10..7aa9870040c1 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -94,6 +94,8 @@ enum { | |||
94 | #define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 | 94 | #define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 |
95 | #define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 | 95 | #define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 |
96 | #define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 | 96 | #define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 |
97 | #define AC_VERB_GET_DEVICE_SEL 0xf35 | ||
98 | #define AC_VERB_GET_DEVICE_LIST 0xf36 | ||
97 | 99 | ||
98 | /* | 100 | /* |
99 | * SET verbs | 101 | * SET verbs |
@@ -133,6 +135,7 @@ enum { | |||
133 | #define AC_VERB_SET_HDMI_DIP_XMIT 0x732 | 135 | #define AC_VERB_SET_HDMI_DIP_XMIT 0x732 |
134 | #define AC_VERB_SET_HDMI_CP_CTRL 0x733 | 136 | #define AC_VERB_SET_HDMI_CP_CTRL 0x733 |
135 | #define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 | 137 | #define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 |
138 | #define AC_VERB_SET_DEVICE_SEL 0x735 | ||
136 | 139 | ||
137 | /* | 140 | /* |
138 | * Parameter IDs | 141 | * Parameter IDs |
@@ -154,6 +157,7 @@ enum { | |||
154 | #define AC_PAR_GPIO_CAP 0x11 | 157 | #define AC_PAR_GPIO_CAP 0x11 |
155 | #define AC_PAR_AMP_OUT_CAP 0x12 | 158 | #define AC_PAR_AMP_OUT_CAP 0x12 |
156 | #define AC_PAR_VOL_KNB_CAP 0x13 | 159 | #define AC_PAR_VOL_KNB_CAP 0x13 |
160 | #define AC_PAR_DEVLIST_LEN 0x15 | ||
157 | #define AC_PAR_HDMI_LPCM_CAP 0x20 | 161 | #define AC_PAR_HDMI_LPCM_CAP 0x20 |
158 | 162 | ||
159 | /* | 163 | /* |
@@ -251,6 +255,11 @@ enum { | |||
251 | #define AC_UNSOL_RES_TAG_SHIFT 26 | 255 | #define AC_UNSOL_RES_TAG_SHIFT 26 |
252 | #define AC_UNSOL_RES_SUBTAG (0x1f<<21) | 256 | #define AC_UNSOL_RES_SUBTAG (0x1f<<21) |
253 | #define AC_UNSOL_RES_SUBTAG_SHIFT 21 | 257 | #define AC_UNSOL_RES_SUBTAG_SHIFT 21 |
258 | #define AC_UNSOL_RES_DE (0x3f<<15) /* Device Entry | ||
259 | * (for DP1.2 MST) | ||
260 | */ | ||
261 | #define AC_UNSOL_RES_DE_SHIFT 15 | ||
262 | #define AC_UNSOL_RES_IA (1<<2) /* Inactive (for DP1.2 MST) */ | ||
254 | #define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ | 263 | #define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ |
255 | #define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ | 264 | #define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ |
256 | #define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ | 265 | #define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ |
@@ -352,6 +361,10 @@ enum { | |||
352 | #define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ | 361 | #define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ |
353 | #define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ | 362 | #define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ |
354 | 363 | ||
364 | /* Display pin's device list length */ | ||
365 | #define AC_DEV_LIST_LEN_MASK 0x3f | ||
366 | #define AC_MAX_DEV_LIST_LEN 64 | ||
367 | |||
355 | /* | 368 | /* |
356 | * Control Parameters | 369 | * Control Parameters |
357 | */ | 370 | */ |
@@ -460,6 +473,11 @@ enum { | |||
460 | #define AC_DEFCFG_PORT_CONN (0x3<<30) | 473 | #define AC_DEFCFG_PORT_CONN (0x3<<30) |
461 | #define AC_DEFCFG_PORT_CONN_SHIFT 30 | 474 | #define AC_DEFCFG_PORT_CONN_SHIFT 30 |
462 | 475 | ||
476 | /* Display pin's device list entry */ | ||
477 | #define AC_DE_PD (1<<0) | ||
478 | #define AC_DE_ELDV (1<<1) | ||
479 | #define AC_DE_IA (1<<2) | ||
480 | |||
463 | /* device device types (0x0-0xf) */ | 481 | /* device device types (0x0-0xf) */ |
464 | enum { | 482 | enum { |
465 | AC_JACK_LINE_OUT, | 483 | AC_JACK_LINE_OUT, |
@@ -885,6 +903,7 @@ struct hda_codec { | |||
885 | unsigned int pcm_format_first:1; /* PCM format must be set first */ | 903 | unsigned int pcm_format_first:1; /* PCM format must be set first */ |
886 | unsigned int epss:1; /* supporting EPSS? */ | 904 | unsigned int epss:1; /* supporting EPSS? */ |
887 | unsigned int cached_write:1; /* write only to caches */ | 905 | unsigned int cached_write:1; /* write only to caches */ |
906 | unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */ | ||
888 | #ifdef CONFIG_PM | 907 | #ifdef CONFIG_PM |
889 | unsigned int power_on :1; /* current (global) power-state */ | 908 | unsigned int power_on :1; /* current (global) power-state */ |
890 | unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ | 909 | unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ |
@@ -972,6 +991,8 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums, | |||
972 | const hda_nid_t *list); | 991 | const hda_nid_t *list); |
973 | int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, | 992 | int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, |
974 | hda_nid_t nid, int recursive); | 993 | hda_nid_t nid, int recursive); |
994 | int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, | ||
995 | u8 *dev_list, int max_devices); | ||
975 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | 996 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, |
976 | u32 *ratesp, u64 *formatsp, unsigned int *bpsp); | 997 | u32 *ratesp, u64 *formatsp, unsigned int *bpsp); |
977 | 998 | ||
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index e3c7ba8d7582..ac41e9cdc976 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -142,6 +142,9 @@ static void parse_user_hints(struct hda_codec *codec) | |||
142 | val = snd_hda_get_bool_hint(codec, "primary_hp"); | 142 | val = snd_hda_get_bool_hint(codec, "primary_hp"); |
143 | if (val >= 0) | 143 | if (val >= 0) |
144 | spec->no_primary_hp = !val; | 144 | spec->no_primary_hp = !val; |
145 | val = snd_hda_get_bool_hint(codec, "multi_io"); | ||
146 | if (val >= 0) | ||
147 | spec->no_multi_io = !val; | ||
145 | val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); | 148 | val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); |
146 | if (val >= 0) | 149 | if (val >= 0) |
147 | spec->multi_cap_vol = !!val; | 150 | spec->multi_cap_vol = !!val; |
@@ -813,6 +816,8 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx) | |||
813 | 816 | ||
814 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | 817 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, |
815 | struct snd_ctl_elem_value *ucontrol); | 818 | struct snd_ctl_elem_value *ucontrol); |
819 | static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, | ||
820 | struct snd_ctl_elem_value *ucontrol); | ||
816 | 821 | ||
817 | enum { | 822 | enum { |
818 | HDA_CTL_WIDGET_VOL, | 823 | HDA_CTL_WIDGET_VOL, |
@@ -830,7 +835,13 @@ static const struct snd_kcontrol_new control_templates[] = { | |||
830 | .put = hda_gen_mixer_mute_put, /* replaced */ | 835 | .put = hda_gen_mixer_mute_put, /* replaced */ |
831 | .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), | 836 | .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), |
832 | }, | 837 | }, |
833 | HDA_BIND_MUTE(NULL, 0, 0, 0), | 838 | { |
839 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
840 | .info = snd_hda_mixer_amp_switch_info, | ||
841 | .get = snd_hda_mixer_bind_switch_get, | ||
842 | .put = hda_gen_bind_mute_put, /* replaced */ | ||
843 | .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), | ||
844 | }, | ||
834 | }; | 845 | }; |
835 | 846 | ||
836 | /* add dynamic controls from template */ | 847 | /* add dynamic controls from template */ |
@@ -937,8 +948,8 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx, | |||
937 | } | 948 | } |
938 | 949 | ||
939 | /* playback mute control with the software mute bit check */ | 950 | /* playback mute control with the software mute bit check */ |
940 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | 951 | static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol, |
941 | struct snd_ctl_elem_value *ucontrol) | 952 | struct snd_ctl_elem_value *ucontrol) |
942 | { | 953 | { |
943 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 954 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
944 | struct hda_gen_spec *spec = codec->spec; | 955 | struct hda_gen_spec *spec = codec->spec; |
@@ -949,10 +960,22 @@ static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | |||
949 | ucontrol->value.integer.value[0] &= enabled; | 960 | ucontrol->value.integer.value[0] &= enabled; |
950 | ucontrol->value.integer.value[1] &= enabled; | 961 | ucontrol->value.integer.value[1] &= enabled; |
951 | } | 962 | } |
963 | } | ||
952 | 964 | ||
965 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | ||
966 | struct snd_ctl_elem_value *ucontrol) | ||
967 | { | ||
968 | sync_auto_mute_bits(kcontrol, ucontrol); | ||
953 | return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | 969 | return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); |
954 | } | 970 | } |
955 | 971 | ||
972 | static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, | ||
973 | struct snd_ctl_elem_value *ucontrol) | ||
974 | { | ||
975 | sync_auto_mute_bits(kcontrol, ucontrol); | ||
976 | return snd_hda_mixer_bind_switch_put(kcontrol, ucontrol); | ||
977 | } | ||
978 | |||
956 | /* any ctl assigned to the path with the given index? */ | 979 | /* any ctl assigned to the path with the given index? */ |
957 | static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) | 980 | static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) |
958 | { | 981 | { |
@@ -1541,7 +1564,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec, | |||
1541 | cfg->speaker_pins, | 1564 | cfg->speaker_pins, |
1542 | spec->multiout.extra_out_nid, | 1565 | spec->multiout.extra_out_nid, |
1543 | spec->speaker_paths); | 1566 | spec->speaker_paths); |
1544 | if (fill_mio_first && cfg->line_outs == 1 && | 1567 | if (!spec->no_multi_io && |
1568 | fill_mio_first && cfg->line_outs == 1 && | ||
1545 | cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { | 1569 | cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { |
1546 | err = fill_multi_ios(codec, cfg->line_out_pins[0], true); | 1570 | err = fill_multi_ios(codec, cfg->line_out_pins[0], true); |
1547 | if (!err) | 1571 | if (!err) |
@@ -1554,7 +1578,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec, | |||
1554 | spec->private_dac_nids, spec->out_paths, | 1578 | spec->private_dac_nids, spec->out_paths, |
1555 | spec->main_out_badness); | 1579 | spec->main_out_badness); |
1556 | 1580 | ||
1557 | if (fill_mio_first && | 1581 | if (!spec->no_multi_io && fill_mio_first && |
1558 | cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { | 1582 | cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { |
1559 | /* try to fill multi-io first */ | 1583 | /* try to fill multi-io first */ |
1560 | err = fill_multi_ios(codec, cfg->line_out_pins[0], false); | 1584 | err = fill_multi_ios(codec, cfg->line_out_pins[0], false); |
@@ -1582,7 +1606,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec, | |||
1582 | return err; | 1606 | return err; |
1583 | badness += err; | 1607 | badness += err; |
1584 | } | 1608 | } |
1585 | if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { | 1609 | if (!spec->no_multi_io && |
1610 | cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { | ||
1586 | err = fill_multi_ios(codec, cfg->line_out_pins[0], false); | 1611 | err = fill_multi_ios(codec, cfg->line_out_pins[0], false); |
1587 | if (err < 0) | 1612 | if (err < 0) |
1588 | return err; | 1613 | return err; |
@@ -1600,7 +1625,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec, | |||
1600 | check_aamix_out_path(codec, spec->speaker_paths[0]); | 1625 | check_aamix_out_path(codec, spec->speaker_paths[0]); |
1601 | } | 1626 | } |
1602 | 1627 | ||
1603 | if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | 1628 | if (!spec->no_multi_io && |
1629 | cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | ||
1604 | if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) | 1630 | if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) |
1605 | spec->multi_ios = 1; /* give badness */ | 1631 | spec->multi_ios = 1; /* give badness */ |
1606 | 1632 | ||
@@ -3724,7 +3750,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx, | |||
3724 | /* check each pin in the given array; returns true if any of them is plugged */ | 3750 | /* check each pin in the given array; returns true if any of them is plugged */ |
3725 | static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) | 3751 | static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) |
3726 | { | 3752 | { |
3727 | int i, present = 0; | 3753 | int i; |
3754 | bool present = false; | ||
3728 | 3755 | ||
3729 | for (i = 0; i < num_pins; i++) { | 3756 | for (i = 0; i < num_pins; i++) { |
3730 | hda_nid_t nid = pins[i]; | 3757 | hda_nid_t nid = pins[i]; |
@@ -3733,14 +3760,15 @@ static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) | |||
3733 | /* don't detect pins retasked as inputs */ | 3760 | /* don't detect pins retasked as inputs */ |
3734 | if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) | 3761 | if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) |
3735 | continue; | 3762 | continue; |
3736 | present |= snd_hda_jack_detect(codec, nid); | 3763 | if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT) |
3764 | present = true; | ||
3737 | } | 3765 | } |
3738 | return present; | 3766 | return present; |
3739 | } | 3767 | } |
3740 | 3768 | ||
3741 | /* standard HP/line-out auto-mute helper */ | 3769 | /* standard HP/line-out auto-mute helper */ |
3742 | static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | 3770 | static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, |
3743 | bool mute) | 3771 | int *paths, bool mute) |
3744 | { | 3772 | { |
3745 | struct hda_gen_spec *spec = codec->spec; | 3773 | struct hda_gen_spec *spec = codec->spec; |
3746 | int i; | 3774 | int i; |
@@ -3752,10 +3780,19 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | |||
3752 | break; | 3780 | break; |
3753 | 3781 | ||
3754 | if (spec->auto_mute_via_amp) { | 3782 | if (spec->auto_mute_via_amp) { |
3783 | struct nid_path *path; | ||
3784 | hda_nid_t mute_nid; | ||
3785 | |||
3786 | path = snd_hda_get_path_from_idx(codec, paths[i]); | ||
3787 | if (!path) | ||
3788 | continue; | ||
3789 | mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]); | ||
3790 | if (!mute_nid) | ||
3791 | continue; | ||
3755 | if (mute) | 3792 | if (mute) |
3756 | spec->mute_bits |= (1ULL << nid); | 3793 | spec->mute_bits |= (1ULL << mute_nid); |
3757 | else | 3794 | else |
3758 | spec->mute_bits &= ~(1ULL << nid); | 3795 | spec->mute_bits &= ~(1ULL << mute_nid); |
3759 | set_pin_eapd(codec, nid, !mute); | 3796 | set_pin_eapd(codec, nid, !mute); |
3760 | continue; | 3797 | continue; |
3761 | } | 3798 | } |
@@ -3786,14 +3823,19 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | |||
3786 | void snd_hda_gen_update_outputs(struct hda_codec *codec) | 3823 | void snd_hda_gen_update_outputs(struct hda_codec *codec) |
3787 | { | 3824 | { |
3788 | struct hda_gen_spec *spec = codec->spec; | 3825 | struct hda_gen_spec *spec = codec->spec; |
3826 | int *paths; | ||
3789 | int on; | 3827 | int on; |
3790 | 3828 | ||
3791 | /* Control HP pins/amps depending on master_mute state; | 3829 | /* Control HP pins/amps depending on master_mute state; |
3792 | * in general, HP pins/amps control should be enabled in all cases, | 3830 | * in general, HP pins/amps control should be enabled in all cases, |
3793 | * but currently set only for master_mute, just to be safe | 3831 | * but currently set only for master_mute, just to be safe |
3794 | */ | 3832 | */ |
3833 | if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) | ||
3834 | paths = spec->out_paths; | ||
3835 | else | ||
3836 | paths = spec->hp_paths; | ||
3795 | do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), | 3837 | do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), |
3796 | spec->autocfg.hp_pins, spec->master_mute); | 3838 | spec->autocfg.hp_pins, paths, spec->master_mute); |
3797 | 3839 | ||
3798 | if (!spec->automute_speaker) | 3840 | if (!spec->automute_speaker) |
3799 | on = 0; | 3841 | on = 0; |
@@ -3801,8 +3843,12 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec) | |||
3801 | on = spec->hp_jack_present | spec->line_jack_present; | 3843 | on = spec->hp_jack_present | spec->line_jack_present; |
3802 | on |= spec->master_mute; | 3844 | on |= spec->master_mute; |
3803 | spec->speaker_muted = on; | 3845 | spec->speaker_muted = on; |
3846 | if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) | ||
3847 | paths = spec->out_paths; | ||
3848 | else | ||
3849 | paths = spec->speaker_paths; | ||
3804 | do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), | 3850 | do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), |
3805 | spec->autocfg.speaker_pins, on); | 3851 | spec->autocfg.speaker_pins, paths, on); |
3806 | 3852 | ||
3807 | /* toggle line-out mutes if needed, too */ | 3853 | /* toggle line-out mutes if needed, too */ |
3808 | /* if LO is a copy of either HP or Speaker, don't need to handle it */ | 3854 | /* if LO is a copy of either HP or Speaker, don't need to handle it */ |
@@ -3815,8 +3861,9 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec) | |||
3815 | on = spec->hp_jack_present; | 3861 | on = spec->hp_jack_present; |
3816 | on |= spec->master_mute; | 3862 | on |= spec->master_mute; |
3817 | spec->line_out_muted = on; | 3863 | spec->line_out_muted = on; |
3864 | paths = spec->out_paths; | ||
3818 | do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), | 3865 | do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), |
3819 | spec->autocfg.line_out_pins, on); | 3866 | spec->autocfg.line_out_pins, paths, on); |
3820 | } | 3867 | } |
3821 | EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); | 3868 | EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); |
3822 | 3869 | ||
@@ -3887,7 +3934,7 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja | |||
3887 | /* don't detect pins retasked as outputs */ | 3934 | /* don't detect pins retasked as outputs */ |
3888 | if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) | 3935 | if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) |
3889 | continue; | 3936 | continue; |
3890 | if (snd_hda_jack_detect(codec, pin)) { | 3937 | if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) { |
3891 | mux_select(codec, 0, spec->am_entry[i].idx); | 3938 | mux_select(codec, 0, spec->am_entry[i].idx); |
3892 | return; | 3939 | return; |
3893 | } | 3940 | } |
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index e199a852388b..48d44026705b 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h | |||
@@ -220,6 +220,7 @@ struct hda_gen_spec { | |||
220 | unsigned int hp_mic:1; /* Allow HP as a mic-in */ | 220 | unsigned int hp_mic:1; /* Allow HP as a mic-in */ |
221 | unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */ | 221 | unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */ |
222 | unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ | 222 | unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ |
223 | unsigned int no_multi_io:1; /* Don't try multi I/O config */ | ||
223 | unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ | 224 | unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ |
224 | unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ | 225 | unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ |
225 | unsigned int own_eapd_ctl:1; /* set EAPD by own function */ | 226 | unsigned int own_eapd_ctl:1; /* set EAPD by own function */ |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index ce67608734b5..fe0bda19de15 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -295,7 +295,7 @@ static ssize_t type##_store(struct device *dev, \ | |||
295 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ | 295 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ |
296 | struct hda_codec *codec = hwdep->private_data; \ | 296 | struct hda_codec *codec = hwdep->private_data; \ |
297 | unsigned long val; \ | 297 | unsigned long val; \ |
298 | int err = strict_strtoul(buf, 0, &val); \ | 298 | int err = kstrtoul(buf, 0, &val); \ |
299 | if (err < 0) \ | 299 | if (err < 0) \ |
300 | return err; \ | 300 | return err; \ |
301 | codec->type = val; \ | 301 | codec->type = val; \ |
@@ -654,7 +654,7 @@ int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) | |||
654 | p = snd_hda_get_hint(codec, key); | 654 | p = snd_hda_get_hint(codec, key); |
655 | if (!p) | 655 | if (!p) |
656 | ret = -ENOENT; | 656 | ret = -ENOENT; |
657 | else if (strict_strtoul(p, 0, &val)) | 657 | else if (kstrtoul(p, 0, &val)) |
658 | ret = -EINVAL; | 658 | ret = -EINVAL; |
659 | else { | 659 | else { |
660 | *valp = val; | 660 | *valp = val; |
@@ -751,7 +751,7 @@ static void parse_##name##_mode(char *buf, struct hda_bus *bus, \ | |||
751 | struct hda_codec **codecp) \ | 751 | struct hda_codec **codecp) \ |
752 | { \ | 752 | { \ |
753 | unsigned long val; \ | 753 | unsigned long val; \ |
754 | if (!strict_strtoul(buf, 0, &val)) \ | 754 | if (!kstrtoul(buf, 0, &val)) \ |
755 | (*codecp)->name = val; \ | 755 | (*codecp)->name = val; \ |
756 | } | 756 | } |
757 | 757 | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8860dd529520..c6c98298ac39 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -1160,7 +1160,7 @@ static int azx_reset(struct azx *chip, int full_reset) | |||
1160 | goto __skip; | 1160 | goto __skip; |
1161 | 1161 | ||
1162 | /* clear STATESTS */ | 1162 | /* clear STATESTS */ |
1163 | azx_writeb(chip, STATESTS, STATESTS_INT_MASK); | 1163 | azx_writew(chip, STATESTS, STATESTS_INT_MASK); |
1164 | 1164 | ||
1165 | /* reset controller */ | 1165 | /* reset controller */ |
1166 | azx_enter_link_reset(chip); | 1166 | azx_enter_link_reset(chip); |
@@ -1242,7 +1242,7 @@ static void azx_int_clear(struct azx *chip) | |||
1242 | } | 1242 | } |
1243 | 1243 | ||
1244 | /* clear STATESTS */ | 1244 | /* clear STATESTS */ |
1245 | azx_writeb(chip, STATESTS, STATESTS_INT_MASK); | 1245 | azx_writew(chip, STATESTS, STATESTS_INT_MASK); |
1246 | 1246 | ||
1247 | /* clear rirb status */ | 1247 | /* clear rirb status */ |
1248 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); | 1248 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); |
@@ -1451,8 +1451,8 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) | |||
1451 | 1451 | ||
1452 | #if 0 | 1452 | #if 0 |
1453 | /* clear state status int */ | 1453 | /* clear state status int */ |
1454 | if (azx_readb(chip, STATESTS) & 0x04) | 1454 | if (azx_readw(chip, STATESTS) & 0x04) |
1455 | azx_writeb(chip, STATESTS, 0x04); | 1455 | azx_writew(chip, STATESTS, 0x04); |
1456 | #endif | 1456 | #endif |
1457 | spin_unlock(&chip->reg_lock); | 1457 | spin_unlock(&chip->reg_lock); |
1458 | 1458 | ||
@@ -2971,6 +2971,10 @@ static int azx_runtime_suspend(struct device *dev) | |||
2971 | struct snd_card *card = dev_get_drvdata(dev); | 2971 | struct snd_card *card = dev_get_drvdata(dev); |
2972 | struct azx *chip = card->private_data; | 2972 | struct azx *chip = card->private_data; |
2973 | 2973 | ||
2974 | /* enable controller wake up event */ | ||
2975 | azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | | ||
2976 | STATESTS_INT_MASK); | ||
2977 | |||
2974 | azx_stop_chip(chip); | 2978 | azx_stop_chip(chip); |
2975 | azx_enter_link_reset(chip); | 2979 | azx_enter_link_reset(chip); |
2976 | azx_clear_irq_pending(chip); | 2980 | azx_clear_irq_pending(chip); |
@@ -2983,11 +2987,31 @@ static int azx_runtime_resume(struct device *dev) | |||
2983 | { | 2987 | { |
2984 | struct snd_card *card = dev_get_drvdata(dev); | 2988 | struct snd_card *card = dev_get_drvdata(dev); |
2985 | struct azx *chip = card->private_data; | 2989 | struct azx *chip = card->private_data; |
2990 | struct hda_bus *bus; | ||
2991 | struct hda_codec *codec; | ||
2992 | int status; | ||
2986 | 2993 | ||
2987 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | 2994 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) |
2988 | hda_display_power(true); | 2995 | hda_display_power(true); |
2996 | |||
2997 | /* Read STATESTS before controller reset */ | ||
2998 | status = azx_readw(chip, STATESTS); | ||
2999 | |||
2989 | azx_init_pci(chip); | 3000 | azx_init_pci(chip); |
2990 | azx_init_chip(chip, 1); | 3001 | azx_init_chip(chip, 1); |
3002 | |||
3003 | bus = chip->bus; | ||
3004 | if (status && bus) { | ||
3005 | list_for_each_entry(codec, &bus->codec_list, list) | ||
3006 | if (status & (1 << codec->addr)) | ||
3007 | queue_delayed_work(codec->bus->workq, | ||
3008 | &codec->jackpoll_work, codec->jackpoll_interval); | ||
3009 | } | ||
3010 | |||
3011 | /* disable controller Wake Up event*/ | ||
3012 | azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & | ||
3013 | ~STATESTS_INT_MASK); | ||
3014 | |||
2991 | return 0; | 3015 | return 0; |
2992 | } | 3016 | } |
2993 | 3017 | ||
@@ -3831,11 +3855,13 @@ static int azx_probe_continue(struct azx *chip) | |||
3831 | 3855 | ||
3832 | /* Request power well for Haswell HDA controller and codec */ | 3856 | /* Request power well for Haswell HDA controller and codec */ |
3833 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | 3857 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { |
3858 | #ifdef CONFIG_SND_HDA_I915 | ||
3834 | err = hda_i915_init(); | 3859 | err = hda_i915_init(); |
3835 | if (err < 0) { | 3860 | if (err < 0) { |
3836 | snd_printk(KERN_ERR SFX "Error request power-well from i915\n"); | 3861 | snd_printk(KERN_ERR SFX "Error request power-well from i915\n"); |
3837 | goto out_free; | 3862 | goto out_free; |
3838 | } | 3863 | } |
3864 | #endif | ||
3839 | hda_display_power(true); | 3865 | hda_display_power(true); |
3840 | } | 3866 | } |
3841 | 3867 | ||
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 3fd2973183e2..05b3e3e9108f 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c | |||
@@ -194,18 +194,24 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) | |||
194 | EXPORT_SYMBOL_HDA(snd_hda_pin_sense); | 194 | EXPORT_SYMBOL_HDA(snd_hda_pin_sense); |
195 | 195 | ||
196 | /** | 196 | /** |
197 | * snd_hda_jack_detect - query pin Presence Detect status | 197 | * snd_hda_jack_detect_state - query pin Presence Detect status |
198 | * @codec: the CODEC to sense | 198 | * @codec: the CODEC to sense |
199 | * @nid: the pin NID to sense | 199 | * @nid: the pin NID to sense |
200 | * | 200 | * |
201 | * Query and return the pin's Presence Detect status. | 201 | * Query and return the pin's Presence Detect status, as either |
202 | * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. | ||
202 | */ | 203 | */ |
203 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) | 204 | int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) |
204 | { | 205 | { |
205 | u32 sense = snd_hda_pin_sense(codec, nid); | 206 | struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); |
206 | return get_jack_plug_state(sense); | 207 | if (jack && jack->phantom_jack) |
208 | return HDA_JACK_PHANTOM; | ||
209 | else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) | ||
210 | return HDA_JACK_PRESENT; | ||
211 | else | ||
212 | return HDA_JACK_NOT_PRESENT; | ||
207 | } | 213 | } |
208 | EXPORT_SYMBOL_HDA(snd_hda_jack_detect); | 214 | EXPORT_SYMBOL_HDA(snd_hda_jack_detect_state); |
209 | 215 | ||
210 | /** | 216 | /** |
211 | * snd_hda_jack_detect_enable - enable the jack-detection | 217 | * snd_hda_jack_detect_enable - enable the jack-detection |
@@ -247,8 +253,8 @@ EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); | |||
247 | int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, | 253 | int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, |
248 | hda_nid_t gating_nid) | 254 | hda_nid_t gating_nid) |
249 | { | 255 | { |
250 | struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid); | 256 | struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid); |
251 | struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid); | 257 | struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid); |
252 | 258 | ||
253 | if (!gated || !gating) | 259 | if (!gated || !gating) |
254 | return -EINVAL; | 260 | return -EINVAL; |
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index ec12abd45263..379420c44eef 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h | |||
@@ -75,7 +75,18 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, | |||
75 | hda_nid_t gating_nid); | 75 | hda_nid_t gating_nid); |
76 | 76 | ||
77 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); | 77 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); |
78 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); | 78 | |
79 | /* the jack state returned from snd_hda_jack_detect_state() */ | ||
80 | enum { | ||
81 | HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM, | ||
82 | }; | ||
83 | |||
84 | int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid); | ||
85 | |||
86 | static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) | ||
87 | { | ||
88 | return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT; | ||
89 | } | ||
79 | 90 | ||
80 | bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); | 91 | bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); |
81 | 92 | ||
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 9760f001916d..a8cb22eec89e 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -582,6 +582,36 @@ static void print_gpio(struct snd_info_buffer *buffer, | |||
582 | print_nid_array(buffer, codec, nid, &codec->nids); | 582 | print_nid_array(buffer, codec, nid, &codec->nids); |
583 | } | 583 | } |
584 | 584 | ||
585 | static void print_device_list(struct snd_info_buffer *buffer, | ||
586 | struct hda_codec *codec, hda_nid_t nid) | ||
587 | { | ||
588 | int i, curr = -1; | ||
589 | u8 dev_list[AC_MAX_DEV_LIST_LEN]; | ||
590 | int devlist_len; | ||
591 | |||
592 | devlist_len = snd_hda_get_devices(codec, nid, dev_list, | ||
593 | AC_MAX_DEV_LIST_LEN); | ||
594 | snd_iprintf(buffer, " Devices: %d\n", devlist_len); | ||
595 | if (devlist_len <= 0) | ||
596 | return; | ||
597 | |||
598 | curr = snd_hda_codec_read(codec, nid, 0, | ||
599 | AC_VERB_GET_DEVICE_SEL, 0); | ||
600 | |||
601 | for (i = 0; i < devlist_len; i++) { | ||
602 | if (i == curr) | ||
603 | snd_iprintf(buffer, " *"); | ||
604 | else | ||
605 | snd_iprintf(buffer, " "); | ||
606 | |||
607 | snd_iprintf(buffer, | ||
608 | "Dev %02d: PD = %d, ELDV = %d, IA = %d\n", i, | ||
609 | !!(dev_list[i] & AC_DE_PD), | ||
610 | !!(dev_list[i] & AC_DE_ELDV), | ||
611 | !!(dev_list[i] & AC_DE_IA)); | ||
612 | } | ||
613 | } | ||
614 | |||
585 | static void print_codec_info(struct snd_info_entry *entry, | 615 | static void print_codec_info(struct snd_info_entry *entry, |
586 | struct snd_info_buffer *buffer) | 616 | struct snd_info_buffer *buffer) |
587 | { | 617 | { |
@@ -751,6 +781,9 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
751 | (wid_caps & AC_WCAP_DELAY) >> | 781 | (wid_caps & AC_WCAP_DELAY) >> |
752 | AC_WCAP_DELAY_SHIFT); | 782 | AC_WCAP_DELAY_SHIFT); |
753 | 783 | ||
784 | if (wid_type == AC_WID_PIN && codec->dp_mst) | ||
785 | print_device_list(buffer, codec, nid); | ||
786 | |||
754 | if (wid_caps & AC_WCAP_CONN_LIST) | 787 | if (wid_caps & AC_WCAP_CONN_LIST) |
755 | print_conn_list(buffer, codec, nid, wid_type, | 788 | print_conn_list(buffer, codec, nid, wid_type, |
756 | conn, conn_len); | 789 | conn, conn_len); |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index d97f0d61a15b..0cbdd87dde6d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include "hda_jack.h" | 32 | #include "hda_jack.h" |
33 | #include "hda_generic.h" | 33 | #include "hda_generic.h" |
34 | 34 | ||
35 | #define ENABLE_AD_STATIC_QUIRKS | ||
36 | 35 | ||
37 | struct ad198x_spec { | 36 | struct ad198x_spec { |
38 | struct hda_gen_spec gen; | 37 | struct hda_gen_spec gen; |
@@ -43,114 +42,8 @@ struct ad198x_spec { | |||
43 | hda_nid_t eapd_nid; | 42 | hda_nid_t eapd_nid; |
44 | 43 | ||
45 | unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ | 44 | unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ |
46 | |||
47 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
48 | const struct snd_kcontrol_new *mixers[6]; | ||
49 | int num_mixers; | ||
50 | const struct hda_verb *init_verbs[6]; /* initialization verbs | ||
51 | * don't forget NULL termination! | ||
52 | */ | ||
53 | unsigned int num_init_verbs; | ||
54 | |||
55 | /* playback */ | ||
56 | struct hda_multi_out multiout; /* playback set-up | ||
57 | * max_channels, dacs must be set | ||
58 | * dig_out_nid and hp_nid are optional | ||
59 | */ | ||
60 | unsigned int cur_eapd; | ||
61 | unsigned int need_dac_fix; | ||
62 | |||
63 | /* capture */ | ||
64 | unsigned int num_adc_nids; | ||
65 | const hda_nid_t *adc_nids; | ||
66 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | ||
67 | |||
68 | /* capture source */ | ||
69 | const struct hda_input_mux *input_mux; | ||
70 | const hda_nid_t *capsrc_nids; | ||
71 | unsigned int cur_mux[3]; | ||
72 | |||
73 | /* channel model */ | ||
74 | const struct hda_channel_mode *channel_mode; | ||
75 | int num_channel_mode; | ||
76 | |||
77 | /* PCM information */ | ||
78 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ | ||
79 | |||
80 | unsigned int spdif_route; | ||
81 | |||
82 | unsigned int jack_present: 1; | ||
83 | unsigned int inv_jack_detect: 1;/* inverted jack-detection */ | ||
84 | unsigned int analog_beep: 1; /* analog beep input present */ | ||
85 | unsigned int avoid_init_slave_vol:1; | ||
86 | |||
87 | #ifdef CONFIG_PM | ||
88 | struct hda_loopback_check loopback; | ||
89 | #endif | ||
90 | /* for virtual master */ | ||
91 | hda_nid_t vmaster_nid; | ||
92 | const char * const *slave_vols; | ||
93 | const char * const *slave_sws; | ||
94 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
95 | }; | ||
96 | |||
97 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
98 | /* | ||
99 | * input MUX handling (common part) | ||
100 | */ | ||
101 | static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
102 | { | ||
103 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
104 | struct ad198x_spec *spec = codec->spec; | ||
105 | |||
106 | return snd_hda_input_mux_info(spec->input_mux, uinfo); | ||
107 | } | ||
108 | |||
109 | static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
110 | { | ||
111 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
112 | struct ad198x_spec *spec = codec->spec; | ||
113 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
114 | |||
115 | ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
120 | { | ||
121 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
122 | struct ad198x_spec *spec = codec->spec; | ||
123 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
124 | |||
125 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
126 | spec->capsrc_nids[adc_idx], | ||
127 | &spec->cur_mux[adc_idx]); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * initialization (common callbacks) | ||
132 | */ | ||
133 | static int ad198x_init(struct hda_codec *codec) | ||
134 | { | ||
135 | struct ad198x_spec *spec = codec->spec; | ||
136 | int i; | ||
137 | |||
138 | for (i = 0; i < spec->num_init_verbs; i++) | ||
139 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static const char * const ad_slave_pfxs[] = { | ||
144 | "Front", "Surround", "Center", "LFE", "Side", | ||
145 | "Headphone", "Mono", "Speaker", "IEC958", | ||
146 | NULL | ||
147 | }; | 45 | }; |
148 | 46 | ||
149 | static const char * const ad1988_6stack_fp_slave_pfxs[] = { | ||
150 | "Front", "Surround", "Center", "LFE", "Side", "IEC958", | ||
151 | NULL | ||
152 | }; | ||
153 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
154 | 47 | ||
155 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 48 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
156 | /* additional beep mixers; the actual parameters are overwritten at build */ | 49 | /* additional beep mixers; the actual parameters are overwritten at build */ |
@@ -160,12 +53,6 @@ static const struct snd_kcontrol_new ad_beep_mixer[] = { | |||
160 | { } /* end */ | 53 | { } /* end */ |
161 | }; | 54 | }; |
162 | 55 | ||
163 | static const struct snd_kcontrol_new ad_beep2_mixer[] = { | ||
164 | HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT), | ||
165 | HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT), | ||
166 | { } /* end */ | ||
167 | }; | ||
168 | |||
169 | #define set_beep_amp(spec, nid, idx, dir) \ | 56 | #define set_beep_amp(spec, nid, idx, dir) \ |
170 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ | 57 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ |
171 | #else | 58 | #else |
@@ -181,8 +68,7 @@ static int create_beep_ctls(struct hda_codec *codec) | |||
181 | if (!spec->beep_amp) | 68 | if (!spec->beep_amp) |
182 | return 0; | 69 | return 0; |
183 | 70 | ||
184 | knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; | 71 | for (knew = ad_beep_mixer ; knew->name; knew++) { |
185 | for ( ; knew->name; knew++) { | ||
186 | int err; | 72 | int err; |
187 | struct snd_kcontrol *kctl; | 73 | struct snd_kcontrol *kctl; |
188 | kctl = snd_ctl_new1(knew, codec); | 74 | kctl = snd_ctl_new1(knew, codec); |
@@ -199,268 +85,6 @@ static int create_beep_ctls(struct hda_codec *codec) | |||
199 | #define create_beep_ctls(codec) 0 | 85 | #define create_beep_ctls(codec) 0 |
200 | #endif | 86 | #endif |
201 | 87 | ||
202 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
203 | static int ad198x_build_controls(struct hda_codec *codec) | ||
204 | { | ||
205 | struct ad198x_spec *spec = codec->spec; | ||
206 | struct snd_kcontrol *kctl; | ||
207 | unsigned int i; | ||
208 | int err; | ||
209 | |||
210 | for (i = 0; i < spec->num_mixers; i++) { | ||
211 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | ||
212 | if (err < 0) | ||
213 | return err; | ||
214 | } | ||
215 | if (spec->multiout.dig_out_nid) { | ||
216 | err = snd_hda_create_spdif_out_ctls(codec, | ||
217 | spec->multiout.dig_out_nid, | ||
218 | spec->multiout.dig_out_nid); | ||
219 | if (err < 0) | ||
220 | return err; | ||
221 | err = snd_hda_create_spdif_share_sw(codec, | ||
222 | &spec->multiout); | ||
223 | if (err < 0) | ||
224 | return err; | ||
225 | spec->multiout.share_spdif = 1; | ||
226 | } | ||
227 | if (spec->dig_in_nid) { | ||
228 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | ||
229 | if (err < 0) | ||
230 | return err; | ||
231 | } | ||
232 | |||
233 | /* create beep controls if needed */ | ||
234 | err = create_beep_ctls(codec); | ||
235 | if (err < 0) | ||
236 | return err; | ||
237 | |||
238 | /* if we have no master control, let's create it */ | ||
239 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
240 | unsigned int vmaster_tlv[4]; | ||
241 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
242 | HDA_OUTPUT, vmaster_tlv); | ||
243 | err = __snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
244 | vmaster_tlv, | ||
245 | (spec->slave_vols ? | ||
246 | spec->slave_vols : ad_slave_pfxs), | ||
247 | "Playback Volume", | ||
248 | !spec->avoid_init_slave_vol, NULL); | ||
249 | if (err < 0) | ||
250 | return err; | ||
251 | } | ||
252 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
253 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
254 | NULL, | ||
255 | (spec->slave_sws ? | ||
256 | spec->slave_sws : ad_slave_pfxs), | ||
257 | "Playback Switch"); | ||
258 | if (err < 0) | ||
259 | return err; | ||
260 | } | ||
261 | |||
262 | /* assign Capture Source enums to NID */ | ||
263 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
264 | if (!kctl) | ||
265 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
266 | for (i = 0; kctl && i < kctl->count; i++) { | ||
267 | err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); | ||
268 | if (err < 0) | ||
269 | return err; | ||
270 | } | ||
271 | |||
272 | /* assign IEC958 enums to NID */ | ||
273 | kctl = snd_hda_find_mixer_ctl(codec, | ||
274 | SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); | ||
275 | if (kctl) { | ||
276 | err = snd_hda_add_nid(codec, kctl, 0, | ||
277 | spec->multiout.dig_out_nid); | ||
278 | if (err < 0) | ||
279 | return err; | ||
280 | } | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | #ifdef CONFIG_PM | ||
286 | static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) | ||
287 | { | ||
288 | struct ad198x_spec *spec = codec->spec; | ||
289 | return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); | ||
290 | } | ||
291 | #endif | ||
292 | |||
293 | /* | ||
294 | * Analog playback callbacks | ||
295 | */ | ||
296 | static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
297 | struct hda_codec *codec, | ||
298 | struct snd_pcm_substream *substream) | ||
299 | { | ||
300 | struct ad198x_spec *spec = codec->spec; | ||
301 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, | ||
302 | hinfo); | ||
303 | } | ||
304 | |||
305 | static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
306 | struct hda_codec *codec, | ||
307 | unsigned int stream_tag, | ||
308 | unsigned int format, | ||
309 | struct snd_pcm_substream *substream) | ||
310 | { | ||
311 | struct ad198x_spec *spec = codec->spec; | ||
312 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | ||
313 | format, substream); | ||
314 | } | ||
315 | |||
316 | static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
317 | struct hda_codec *codec, | ||
318 | struct snd_pcm_substream *substream) | ||
319 | { | ||
320 | struct ad198x_spec *spec = codec->spec; | ||
321 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Digital out | ||
326 | */ | ||
327 | static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
328 | struct hda_codec *codec, | ||
329 | struct snd_pcm_substream *substream) | ||
330 | { | ||
331 | struct ad198x_spec *spec = codec->spec; | ||
332 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
333 | } | ||
334 | |||
335 | static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
336 | struct hda_codec *codec, | ||
337 | struct snd_pcm_substream *substream) | ||
338 | { | ||
339 | struct ad198x_spec *spec = codec->spec; | ||
340 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
341 | } | ||
342 | |||
343 | static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
344 | struct hda_codec *codec, | ||
345 | unsigned int stream_tag, | ||
346 | unsigned int format, | ||
347 | struct snd_pcm_substream *substream) | ||
348 | { | ||
349 | struct ad198x_spec *spec = codec->spec; | ||
350 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | ||
351 | format, substream); | ||
352 | } | ||
353 | |||
354 | static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
355 | struct hda_codec *codec, | ||
356 | struct snd_pcm_substream *substream) | ||
357 | { | ||
358 | struct ad198x_spec *spec = codec->spec; | ||
359 | return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * Analog capture | ||
364 | */ | ||
365 | static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
366 | struct hda_codec *codec, | ||
367 | unsigned int stream_tag, | ||
368 | unsigned int format, | ||
369 | struct snd_pcm_substream *substream) | ||
370 | { | ||
371 | struct ad198x_spec *spec = codec->spec; | ||
372 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
373 | stream_tag, 0, format); | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
378 | struct hda_codec *codec, | ||
379 | struct snd_pcm_substream *substream) | ||
380 | { | ||
381 | struct ad198x_spec *spec = codec->spec; | ||
382 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | */ | ||
388 | static const struct hda_pcm_stream ad198x_pcm_analog_playback = { | ||
389 | .substreams = 1, | ||
390 | .channels_min = 2, | ||
391 | .channels_max = 6, /* changed later */ | ||
392 | .nid = 0, /* fill later */ | ||
393 | .ops = { | ||
394 | .open = ad198x_playback_pcm_open, | ||
395 | .prepare = ad198x_playback_pcm_prepare, | ||
396 | .cleanup = ad198x_playback_pcm_cleanup, | ||
397 | }, | ||
398 | }; | ||
399 | |||
400 | static const struct hda_pcm_stream ad198x_pcm_analog_capture = { | ||
401 | .substreams = 1, | ||
402 | .channels_min = 2, | ||
403 | .channels_max = 2, | ||
404 | .nid = 0, /* fill later */ | ||
405 | .ops = { | ||
406 | .prepare = ad198x_capture_pcm_prepare, | ||
407 | .cleanup = ad198x_capture_pcm_cleanup | ||
408 | }, | ||
409 | }; | ||
410 | |||
411 | static const struct hda_pcm_stream ad198x_pcm_digital_playback = { | ||
412 | .substreams = 1, | ||
413 | .channels_min = 2, | ||
414 | .channels_max = 2, | ||
415 | .nid = 0, /* fill later */ | ||
416 | .ops = { | ||
417 | .open = ad198x_dig_playback_pcm_open, | ||
418 | .close = ad198x_dig_playback_pcm_close, | ||
419 | .prepare = ad198x_dig_playback_pcm_prepare, | ||
420 | .cleanup = ad198x_dig_playback_pcm_cleanup | ||
421 | }, | ||
422 | }; | ||
423 | |||
424 | static const struct hda_pcm_stream ad198x_pcm_digital_capture = { | ||
425 | .substreams = 1, | ||
426 | .channels_min = 2, | ||
427 | .channels_max = 2, | ||
428 | /* NID is set in alc_build_pcms */ | ||
429 | }; | ||
430 | |||
431 | static int ad198x_build_pcms(struct hda_codec *codec) | ||
432 | { | ||
433 | struct ad198x_spec *spec = codec->spec; | ||
434 | struct hda_pcm *info = spec->pcm_rec; | ||
435 | |||
436 | codec->num_pcms = 1; | ||
437 | codec->pcm_info = info; | ||
438 | |||
439 | info->name = "AD198x Analog"; | ||
440 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback; | ||
441 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; | ||
442 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; | ||
443 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; | ||
444 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; | ||
445 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | ||
446 | |||
447 | if (spec->multiout.dig_out_nid) { | ||
448 | info++; | ||
449 | codec->num_pcms++; | ||
450 | codec->spdif_status_reset = 1; | ||
451 | info->name = "AD198x Digital"; | ||
452 | info->pcm_type = HDA_PCM_TYPE_SPDIF; | ||
453 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; | ||
454 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | ||
455 | if (spec->dig_in_nid) { | ||
456 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture; | ||
457 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
464 | 88 | ||
465 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, | 89 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, |
466 | hda_nid_t hp) | 90 | hda_nid_t hp) |
@@ -507,18 +131,6 @@ static void ad198x_shutup(struct hda_codec *codec) | |||
507 | ad198x_power_eapd(codec); | 131 | ad198x_power_eapd(codec); |
508 | } | 132 | } |
509 | 133 | ||
510 | static void ad198x_free(struct hda_codec *codec) | ||
511 | { | ||
512 | struct ad198x_spec *spec = codec->spec; | ||
513 | |||
514 | if (!spec) | ||
515 | return; | ||
516 | |||
517 | snd_hda_gen_spec_free(&spec->gen); | ||
518 | kfree(spec); | ||
519 | snd_hda_detach_beep_device(codec); | ||
520 | } | ||
521 | |||
522 | #ifdef CONFIG_PM | 134 | #ifdef CONFIG_PM |
523 | static int ad198x_suspend(struct hda_codec *codec) | 135 | static int ad198x_suspend(struct hda_codec *codec) |
524 | { | 136 | { |
@@ -527,65 +139,6 @@ static int ad198x_suspend(struct hda_codec *codec) | |||
527 | } | 139 | } |
528 | #endif | 140 | #endif |
529 | 141 | ||
530 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
531 | static const struct hda_codec_ops ad198x_patch_ops = { | ||
532 | .build_controls = ad198x_build_controls, | ||
533 | .build_pcms = ad198x_build_pcms, | ||
534 | .init = ad198x_init, | ||
535 | .free = ad198x_free, | ||
536 | #ifdef CONFIG_PM | ||
537 | .check_power_status = ad198x_check_power_status, | ||
538 | .suspend = ad198x_suspend, | ||
539 | #endif | ||
540 | .reboot_notify = ad198x_shutup, | ||
541 | }; | ||
542 | |||
543 | |||
544 | /* | ||
545 | * EAPD control | ||
546 | * the private value = nid | ||
547 | */ | ||
548 | #define ad198x_eapd_info snd_ctl_boolean_mono_info | ||
549 | |||
550 | static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, | ||
551 | struct snd_ctl_elem_value *ucontrol) | ||
552 | { | ||
553 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
554 | struct ad198x_spec *spec = codec->spec; | ||
555 | if (codec->inv_eapd) | ||
556 | ucontrol->value.integer.value[0] = ! spec->cur_eapd; | ||
557 | else | ||
558 | ucontrol->value.integer.value[0] = spec->cur_eapd; | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | ||
563 | struct snd_ctl_elem_value *ucontrol) | ||
564 | { | ||
565 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
566 | struct ad198x_spec *spec = codec->spec; | ||
567 | hda_nid_t nid = kcontrol->private_value & 0xff; | ||
568 | unsigned int eapd; | ||
569 | eapd = !!ucontrol->value.integer.value[0]; | ||
570 | if (codec->inv_eapd) | ||
571 | eapd = !eapd; | ||
572 | if (eapd == spec->cur_eapd) | ||
573 | return 0; | ||
574 | spec->cur_eapd = eapd; | ||
575 | snd_hda_codec_write_cache(codec, nid, | ||
576 | 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
577 | eapd ? 0x02 : 0x00); | ||
578 | return 1; | ||
579 | } | ||
580 | |||
581 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, | ||
582 | struct snd_ctl_elem_info *uinfo); | ||
583 | static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, | ||
584 | struct snd_ctl_elem_value *ucontrol); | ||
585 | static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | ||
586 | struct snd_ctl_elem_value *ucontrol); | ||
587 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
588 | |||
589 | 142 | ||
590 | /* | 143 | /* |
591 | * Automatic parse of I/O pins from the BIOS configuration | 144 | * Automatic parse of I/O pins from the BIOS configuration |
@@ -646,537 +199,6 @@ static int ad198x_parse_auto_config(struct hda_codec *codec) | |||
646 | * AD1986A specific | 199 | * AD1986A specific |
647 | */ | 200 | */ |
648 | 201 | ||
649 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
650 | #define AD1986A_SPDIF_OUT 0x02 | ||
651 | #define AD1986A_FRONT_DAC 0x03 | ||
652 | #define AD1986A_SURR_DAC 0x04 | ||
653 | #define AD1986A_CLFE_DAC 0x05 | ||
654 | #define AD1986A_ADC 0x06 | ||
655 | |||
656 | static const hda_nid_t ad1986a_dac_nids[3] = { | ||
657 | AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC | ||
658 | }; | ||
659 | static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; | ||
660 | static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; | ||
661 | |||
662 | static const struct hda_input_mux ad1986a_capture_source = { | ||
663 | .num_items = 7, | ||
664 | .items = { | ||
665 | { "Mic", 0x0 }, | ||
666 | { "CD", 0x1 }, | ||
667 | { "Aux", 0x3 }, | ||
668 | { "Line", 0x4 }, | ||
669 | { "Mix", 0x5 }, | ||
670 | { "Mono", 0x6 }, | ||
671 | { "Phone", 0x7 }, | ||
672 | }, | ||
673 | }; | ||
674 | |||
675 | |||
676 | static const struct hda_bind_ctls ad1986a_bind_pcm_vol = { | ||
677 | .ops = &snd_hda_bind_vol, | ||
678 | .values = { | ||
679 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), | ||
680 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), | ||
681 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), | ||
682 | 0 | ||
683 | }, | ||
684 | }; | ||
685 | |||
686 | static const struct hda_bind_ctls ad1986a_bind_pcm_sw = { | ||
687 | .ops = &snd_hda_bind_sw, | ||
688 | .values = { | ||
689 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), | ||
690 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), | ||
691 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), | ||
692 | 0 | ||
693 | }, | ||
694 | }; | ||
695 | |||
696 | /* | ||
697 | * mixers | ||
698 | */ | ||
699 | static const struct snd_kcontrol_new ad1986a_mixers[] = { | ||
700 | /* | ||
701 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity | ||
702 | */ | ||
703 | HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), | ||
704 | HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), | ||
705 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
706 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
707 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
708 | HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
709 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT), | ||
710 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT), | ||
711 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT), | ||
712 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT), | ||
713 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
714 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
715 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
716 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
717 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
718 | HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
719 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), | ||
720 | HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
721 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
722 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
723 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
724 | HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||
725 | HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), | ||
726 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
727 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
728 | { | ||
729 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
730 | .name = "Capture Source", | ||
731 | .info = ad198x_mux_enum_info, | ||
732 | .get = ad198x_mux_enum_get, | ||
733 | .put = ad198x_mux_enum_put, | ||
734 | }, | ||
735 | HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), | ||
736 | { } /* end */ | ||
737 | }; | ||
738 | |||
739 | /* additional mixers for 3stack mode */ | ||
740 | static const struct snd_kcontrol_new ad1986a_3st_mixers[] = { | ||
741 | { | ||
742 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
743 | .name = "Channel Mode", | ||
744 | .info = ad198x_ch_mode_info, | ||
745 | .get = ad198x_ch_mode_get, | ||
746 | .put = ad198x_ch_mode_put, | ||
747 | }, | ||
748 | { } /* end */ | ||
749 | }; | ||
750 | |||
751 | /* laptop model - 2ch only */ | ||
752 | static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; | ||
753 | |||
754 | /* master controls both pins 0x1a and 0x1b */ | ||
755 | static const struct hda_bind_ctls ad1986a_laptop_master_vol = { | ||
756 | .ops = &snd_hda_bind_vol, | ||
757 | .values = { | ||
758 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
759 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
760 | 0, | ||
761 | }, | ||
762 | }; | ||
763 | |||
764 | static const struct hda_bind_ctls ad1986a_laptop_master_sw = { | ||
765 | .ops = &snd_hda_bind_sw, | ||
766 | .values = { | ||
767 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
768 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
769 | 0, | ||
770 | }, | ||
771 | }; | ||
772 | |||
773 | static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | ||
774 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
775 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
776 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
777 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), | ||
778 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
779 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
780 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
781 | HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
782 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), | ||
783 | HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
784 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
785 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
786 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
787 | /* | ||
788 | HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||
789 | HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ | ||
790 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
791 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
792 | { | ||
793 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
794 | .name = "Capture Source", | ||
795 | .info = ad198x_mux_enum_info, | ||
796 | .get = ad198x_mux_enum_get, | ||
797 | .put = ad198x_mux_enum_put, | ||
798 | }, | ||
799 | { } /* end */ | ||
800 | }; | ||
801 | |||
802 | /* laptop-eapd model - 2ch only */ | ||
803 | |||
804 | static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = { | ||
805 | .num_items = 3, | ||
806 | .items = { | ||
807 | { "Mic", 0x0 }, | ||
808 | { "Internal Mic", 0x4 }, | ||
809 | { "Mix", 0x5 }, | ||
810 | }, | ||
811 | }; | ||
812 | |||
813 | static const struct hda_input_mux ad1986a_automic_capture_source = { | ||
814 | .num_items = 2, | ||
815 | .items = { | ||
816 | { "Mic", 0x0 }, | ||
817 | { "Mix", 0x5 }, | ||
818 | }, | ||
819 | }; | ||
820 | |||
821 | static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = { | ||
822 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
823 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), | ||
824 | { } /* end */ | ||
825 | }; | ||
826 | |||
827 | static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | ||
828 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
829 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
830 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
831 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
832 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
833 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
834 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
835 | { | ||
836 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
837 | .name = "Capture Source", | ||
838 | .info = ad198x_mux_enum_info, | ||
839 | .get = ad198x_mux_enum_get, | ||
840 | .put = ad198x_mux_enum_put, | ||
841 | }, | ||
842 | { | ||
843 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
844 | .name = "External Amplifier", | ||
845 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
846 | .info = ad198x_eapd_info, | ||
847 | .get = ad198x_eapd_get, | ||
848 | .put = ad198x_eapd_put, | ||
849 | .private_value = 0x1b, /* port-D */ | ||
850 | }, | ||
851 | { } /* end */ | ||
852 | }; | ||
853 | |||
854 | static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { | ||
855 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), | ||
856 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), | ||
857 | { } /* end */ | ||
858 | }; | ||
859 | |||
860 | /* re-connect the mic boost input according to the jack sensing */ | ||
861 | static void ad1986a_automic(struct hda_codec *codec) | ||
862 | { | ||
863 | unsigned int present; | ||
864 | present = snd_hda_jack_detect(codec, 0x1f); | ||
865 | /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ | ||
866 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, | ||
867 | present ? 0 : 2); | ||
868 | } | ||
869 | |||
870 | #define AD1986A_MIC_EVENT 0x36 | ||
871 | |||
872 | static void ad1986a_automic_unsol_event(struct hda_codec *codec, | ||
873 | unsigned int res) | ||
874 | { | ||
875 | if ((res >> 26) != AD1986A_MIC_EVENT) | ||
876 | return; | ||
877 | ad1986a_automic(codec); | ||
878 | } | ||
879 | |||
880 | static int ad1986a_automic_init(struct hda_codec *codec) | ||
881 | { | ||
882 | ad198x_init(codec); | ||
883 | ad1986a_automic(codec); | ||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | /* laptop-automute - 2ch only */ | ||
888 | |||
889 | static void ad1986a_update_hp(struct hda_codec *codec) | ||
890 | { | ||
891 | struct ad198x_spec *spec = codec->spec; | ||
892 | unsigned int mute; | ||
893 | |||
894 | if (spec->jack_present) | ||
895 | mute = HDA_AMP_MUTE; /* mute internal speaker */ | ||
896 | else | ||
897 | /* unmute internal speaker if necessary */ | ||
898 | mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); | ||
899 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
900 | HDA_AMP_MUTE, mute); | ||
901 | } | ||
902 | |||
903 | static void ad1986a_hp_automute(struct hda_codec *codec) | ||
904 | { | ||
905 | struct ad198x_spec *spec = codec->spec; | ||
906 | |||
907 | spec->jack_present = snd_hda_jack_detect(codec, 0x1a); | ||
908 | if (spec->inv_jack_detect) | ||
909 | spec->jack_present = !spec->jack_present; | ||
910 | ad1986a_update_hp(codec); | ||
911 | } | ||
912 | |||
913 | #define AD1986A_HP_EVENT 0x37 | ||
914 | |||
915 | static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
916 | { | ||
917 | if ((res >> 26) != AD1986A_HP_EVENT) | ||
918 | return; | ||
919 | ad1986a_hp_automute(codec); | ||
920 | } | ||
921 | |||
922 | static int ad1986a_hp_init(struct hda_codec *codec) | ||
923 | { | ||
924 | ad198x_init(codec); | ||
925 | ad1986a_hp_automute(codec); | ||
926 | return 0; | ||
927 | } | ||
928 | |||
929 | /* bind hp and internal speaker mute (with plug check) */ | ||
930 | static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
931 | struct snd_ctl_elem_value *ucontrol) | ||
932 | { | ||
933 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
934 | int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
935 | if (change) | ||
936 | ad1986a_update_hp(codec); | ||
937 | return change; | ||
938 | } | ||
939 | |||
940 | static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { | ||
941 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
942 | { | ||
943 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
944 | .name = "Master Playback Switch", | ||
945 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
946 | .info = snd_hda_mixer_amp_switch_info, | ||
947 | .get = snd_hda_mixer_amp_switch_get, | ||
948 | .put = ad1986a_hp_master_sw_put, | ||
949 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
950 | }, | ||
951 | { } /* end */ | ||
952 | }; | ||
953 | |||
954 | |||
955 | /* | ||
956 | * initialization verbs | ||
957 | */ | ||
958 | static const struct hda_verb ad1986a_init_verbs[] = { | ||
959 | /* Front, Surround, CLFE DAC; mute as default */ | ||
960 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
961 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
962 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
963 | /* Downmix - off */ | ||
964 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
965 | /* HP, Line-Out, Surround, CLFE selectors */ | ||
966 | {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
967 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
968 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
969 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
970 | /* Mono selector */ | ||
971 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
972 | /* Mic selector: Mic 1/2 pin */ | ||
973 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
974 | /* Line-in selector: Line-in */ | ||
975 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
976 | /* Mic 1/2 swap */ | ||
977 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
978 | /* Record selector: mic */ | ||
979 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
980 | /* Mic, Phone, CD, Aux, Line-In amp; mute as default */ | ||
981 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
982 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
983 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
984 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
985 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
986 | /* PC beep */ | ||
987 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
988 | /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */ | ||
989 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
990 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
991 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
992 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
993 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
994 | /* HP Pin */ | ||
995 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
996 | /* Front, Surround, CLFE Pins */ | ||
997 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
998 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
999 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1000 | /* Mono Pin */ | ||
1001 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1002 | /* Mic Pin */ | ||
1003 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1004 | /* Line, Aux, CD, Beep-In Pin */ | ||
1005 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1006 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1007 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1008 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1009 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1010 | { } /* end */ | ||
1011 | }; | ||
1012 | |||
1013 | static const struct hda_verb ad1986a_ch2_init[] = { | ||
1014 | /* Surround out -> Line In */ | ||
1015 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
1016 | /* Line-in selectors */ | ||
1017 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 }, | ||
1018 | /* CLFE -> Mic in */ | ||
1019 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
1020 | /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */ | ||
1021 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, | ||
1022 | { } /* end */ | ||
1023 | }; | ||
1024 | |||
1025 | static const struct hda_verb ad1986a_ch4_init[] = { | ||
1026 | /* Surround out -> Surround */ | ||
1027 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1028 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1029 | /* CLFE -> Mic in */ | ||
1030 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
1031 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, | ||
1032 | { } /* end */ | ||
1033 | }; | ||
1034 | |||
1035 | static const struct hda_verb ad1986a_ch6_init[] = { | ||
1036 | /* Surround out -> Surround out */ | ||
1037 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1038 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1039 | /* CLFE -> CLFE */ | ||
1040 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1041 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1042 | { } /* end */ | ||
1043 | }; | ||
1044 | |||
1045 | static const struct hda_channel_mode ad1986a_modes[3] = { | ||
1046 | { 2, ad1986a_ch2_init }, | ||
1047 | { 4, ad1986a_ch4_init }, | ||
1048 | { 6, ad1986a_ch6_init }, | ||
1049 | }; | ||
1050 | |||
1051 | /* eapd initialization */ | ||
1052 | static const struct hda_verb ad1986a_eapd_init_verbs[] = { | ||
1053 | {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, | ||
1054 | {} | ||
1055 | }; | ||
1056 | |||
1057 | static const struct hda_verb ad1986a_automic_verbs[] = { | ||
1058 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1059 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1060 | /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/ | ||
1061 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1062 | {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT}, | ||
1063 | {} | ||
1064 | }; | ||
1065 | |||
1066 | /* Ultra initialization */ | ||
1067 | static const struct hda_verb ad1986a_ultra_init[] = { | ||
1068 | /* eapd initialization */ | ||
1069 | { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, | ||
1070 | /* CLFE -> Mic in */ | ||
1071 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 }, | ||
1072 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1073 | { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
1074 | { } /* end */ | ||
1075 | }; | ||
1076 | |||
1077 | /* pin sensing on HP jack */ | ||
1078 | static const struct hda_verb ad1986a_hp_init_verbs[] = { | ||
1079 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, | ||
1080 | {} | ||
1081 | }; | ||
1082 | |||
1083 | static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec, | ||
1084 | unsigned int res) | ||
1085 | { | ||
1086 | switch (res >> 26) { | ||
1087 | case AD1986A_HP_EVENT: | ||
1088 | ad1986a_hp_automute(codec); | ||
1089 | break; | ||
1090 | case AD1986A_MIC_EVENT: | ||
1091 | ad1986a_automic(codec); | ||
1092 | break; | ||
1093 | } | ||
1094 | } | ||
1095 | |||
1096 | static int ad1986a_samsung_p50_init(struct hda_codec *codec) | ||
1097 | { | ||
1098 | ad198x_init(codec); | ||
1099 | ad1986a_hp_automute(codec); | ||
1100 | ad1986a_automic(codec); | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | |||
1105 | /* models */ | ||
1106 | enum { | ||
1107 | AD1986A_AUTO, | ||
1108 | AD1986A_6STACK, | ||
1109 | AD1986A_3STACK, | ||
1110 | AD1986A_LAPTOP, | ||
1111 | AD1986A_LAPTOP_EAPD, | ||
1112 | AD1986A_LAPTOP_AUTOMUTE, | ||
1113 | AD1986A_ULTRA, | ||
1114 | AD1986A_SAMSUNG, | ||
1115 | AD1986A_SAMSUNG_P50, | ||
1116 | AD1986A_MODELS | ||
1117 | }; | ||
1118 | |||
1119 | static const char * const ad1986a_models[AD1986A_MODELS] = { | ||
1120 | [AD1986A_AUTO] = "auto", | ||
1121 | [AD1986A_6STACK] = "6stack", | ||
1122 | [AD1986A_3STACK] = "3stack", | ||
1123 | [AD1986A_LAPTOP] = "laptop", | ||
1124 | [AD1986A_LAPTOP_EAPD] = "laptop-eapd", | ||
1125 | [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", | ||
1126 | [AD1986A_ULTRA] = "ultra", | ||
1127 | [AD1986A_SAMSUNG] = "samsung", | ||
1128 | [AD1986A_SAMSUNG_P50] = "samsung-p50", | ||
1129 | }; | ||
1130 | |||
1131 | static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { | ||
1132 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), | ||
1133 | SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), | ||
1134 | SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), | ||
1135 | SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), | ||
1136 | SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), | ||
1137 | SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), | ||
1138 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), | ||
1139 | SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), | ||
1140 | SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP), | ||
1141 | SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK), | ||
1142 | SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), | ||
1143 | SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), | ||
1144 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), | ||
1145 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), | ||
1146 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), | ||
1147 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | ||
1148 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), | ||
1149 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), | ||
1150 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), | ||
1151 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), | ||
1152 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), | ||
1153 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG), | ||
1154 | SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), | ||
1155 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), | ||
1156 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), | ||
1157 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), | ||
1158 | SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), | ||
1159 | {} | ||
1160 | }; | ||
1161 | |||
1162 | #ifdef CONFIG_PM | ||
1163 | static const struct hda_amp_list ad1986a_loopbacks[] = { | ||
1164 | { 0x13, HDA_OUTPUT, 0 }, /* Mic */ | ||
1165 | { 0x14, HDA_OUTPUT, 0 }, /* Phone */ | ||
1166 | { 0x15, HDA_OUTPUT, 0 }, /* CD */ | ||
1167 | { 0x16, HDA_OUTPUT, 0 }, /* Aux */ | ||
1168 | { 0x17, HDA_OUTPUT, 0 }, /* Line */ | ||
1169 | { } /* end */ | ||
1170 | }; | ||
1171 | #endif | ||
1172 | |||
1173 | static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) | ||
1174 | { | ||
1175 | unsigned int conf = snd_hda_codec_get_pincfg(codec, nid); | ||
1176 | return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; | ||
1177 | } | ||
1178 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1179 | |||
1180 | static int alloc_ad_spec(struct hda_codec *codec) | 202 | static int alloc_ad_spec(struct hda_codec *codec) |
1181 | { | 203 | { |
1182 | struct ad198x_spec *spec; | 204 | struct ad198x_spec *spec; |
@@ -1203,6 +225,11 @@ static void ad_fixup_inv_jack_detect(struct hda_codec *codec, | |||
1203 | 225 | ||
1204 | enum { | 226 | enum { |
1205 | AD1986A_FIXUP_INV_JACK_DETECT, | 227 | AD1986A_FIXUP_INV_JACK_DETECT, |
228 | AD1986A_FIXUP_ULTRA, | ||
229 | AD1986A_FIXUP_SAMSUNG, | ||
230 | AD1986A_FIXUP_3STACK, | ||
231 | AD1986A_FIXUP_LAPTOP, | ||
232 | AD1986A_FIXUP_LAPTOP_IMIC, | ||
1206 | }; | 233 | }; |
1207 | 234 | ||
1208 | static const struct hda_fixup ad1986a_fixups[] = { | 235 | static const struct hda_fixup ad1986a_fixups[] = { |
@@ -1210,16 +237,86 @@ static const struct hda_fixup ad1986a_fixups[] = { | |||
1210 | .type = HDA_FIXUP_FUNC, | 237 | .type = HDA_FIXUP_FUNC, |
1211 | .v.func = ad_fixup_inv_jack_detect, | 238 | .v.func = ad_fixup_inv_jack_detect, |
1212 | }, | 239 | }, |
240 | [AD1986A_FIXUP_ULTRA] = { | ||
241 | .type = HDA_FIXUP_PINS, | ||
242 | .v.pins = (const struct hda_pintbl[]) { | ||
243 | { 0x1b, 0x90170110 }, /* speaker */ | ||
244 | { 0x1d, 0x90a7013e }, /* int mic */ | ||
245 | {} | ||
246 | }, | ||
247 | }, | ||
248 | [AD1986A_FIXUP_SAMSUNG] = { | ||
249 | .type = HDA_FIXUP_PINS, | ||
250 | .v.pins = (const struct hda_pintbl[]) { | ||
251 | { 0x1b, 0x90170110 }, /* speaker */ | ||
252 | { 0x1d, 0x90a7013e }, /* int mic */ | ||
253 | { 0x20, 0x411111f0 }, /* N/A */ | ||
254 | { 0x24, 0x411111f0 }, /* N/A */ | ||
255 | {} | ||
256 | }, | ||
257 | }, | ||
258 | [AD1986A_FIXUP_3STACK] = { | ||
259 | .type = HDA_FIXUP_PINS, | ||
260 | .v.pins = (const struct hda_pintbl[]) { | ||
261 | { 0x1a, 0x02214021 }, /* headphone */ | ||
262 | { 0x1b, 0x01014011 }, /* front */ | ||
263 | { 0x1c, 0x01013012 }, /* surround */ | ||
264 | { 0x1d, 0x01019015 }, /* clfe */ | ||
265 | { 0x1e, 0x411111f0 }, /* N/A */ | ||
266 | { 0x1f, 0x02a190f0 }, /* mic */ | ||
267 | { 0x20, 0x018130f0 }, /* line-in */ | ||
268 | {} | ||
269 | }, | ||
270 | }, | ||
271 | [AD1986A_FIXUP_LAPTOP] = { | ||
272 | .type = HDA_FIXUP_PINS, | ||
273 | .v.pins = (const struct hda_pintbl[]) { | ||
274 | { 0x1a, 0x02214021 }, /* headphone */ | ||
275 | { 0x1b, 0x90170110 }, /* speaker */ | ||
276 | { 0x1c, 0x411111f0 }, /* N/A */ | ||
277 | { 0x1d, 0x411111f0 }, /* N/A */ | ||
278 | { 0x1e, 0x411111f0 }, /* N/A */ | ||
279 | { 0x1f, 0x02a191f0 }, /* mic */ | ||
280 | { 0x20, 0x411111f0 }, /* N/A */ | ||
281 | {} | ||
282 | }, | ||
283 | }, | ||
284 | [AD1986A_FIXUP_LAPTOP_IMIC] = { | ||
285 | .type = HDA_FIXUP_PINS, | ||
286 | .v.pins = (const struct hda_pintbl[]) { | ||
287 | { 0x1d, 0x90a7013e }, /* int mic */ | ||
288 | {} | ||
289 | }, | ||
290 | .chained_before = 1, | ||
291 | .chain_id = AD1986A_FIXUP_LAPTOP, | ||
292 | }, | ||
1213 | }; | 293 | }; |
1214 | 294 | ||
1215 | static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { | 295 | static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { |
296 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC), | ||
297 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK), | ||
298 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK), | ||
299 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK), | ||
300 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP), | ||
301 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), | ||
302 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), | ||
1216 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), | 303 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), |
304 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK), | ||
305 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK), | ||
306 | {} | ||
307 | }; | ||
308 | |||
309 | static const struct hda_model_fixup ad1986a_fixup_models[] = { | ||
310 | { .id = AD1986A_FIXUP_3STACK, .name = "3stack" }, | ||
311 | { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" }, | ||
312 | { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" }, | ||
313 | { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */ | ||
1217 | {} | 314 | {} |
1218 | }; | 315 | }; |
1219 | 316 | ||
1220 | /* | 317 | /* |
1221 | */ | 318 | */ |
1222 | static int ad1986a_parse_auto_config(struct hda_codec *codec) | 319 | static int patch_ad1986a(struct hda_codec *codec) |
1223 | { | 320 | { |
1224 | int err; | 321 | int err; |
1225 | struct ad198x_spec *spec; | 322 | struct ad198x_spec *spec; |
@@ -1244,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) | |||
1244 | */ | 341 | */ |
1245 | spec->gen.multiout.no_share_stream = 1; | 342 | spec->gen.multiout.no_share_stream = 1; |
1246 | 343 | ||
1247 | snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups); | 344 | snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl, |
345 | ad1986a_fixups); | ||
1248 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | 346 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); |
1249 | 347 | ||
1250 | err = ad198x_parse_auto_config(codec); | 348 | err = ad198x_parse_auto_config(codec); |
@@ -1258,330 +356,11 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) | |||
1258 | return 0; | 356 | return 0; |
1259 | } | 357 | } |
1260 | 358 | ||
1261 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1262 | static int patch_ad1986a(struct hda_codec *codec) | ||
1263 | { | ||
1264 | struct ad198x_spec *spec; | ||
1265 | int err, board_config; | ||
1266 | |||
1267 | board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, | ||
1268 | ad1986a_models, | ||
1269 | ad1986a_cfg_tbl); | ||
1270 | if (board_config < 0) { | ||
1271 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
1272 | codec->chip_name); | ||
1273 | board_config = AD1986A_AUTO; | ||
1274 | } | ||
1275 | |||
1276 | if (board_config == AD1986A_AUTO) | ||
1277 | return ad1986a_parse_auto_config(codec); | ||
1278 | |||
1279 | err = alloc_ad_spec(codec); | ||
1280 | if (err < 0) | ||
1281 | return err; | ||
1282 | spec = codec->spec; | ||
1283 | |||
1284 | err = snd_hda_attach_beep_device(codec, 0x19); | ||
1285 | if (err < 0) { | ||
1286 | ad198x_free(codec); | ||
1287 | return err; | ||
1288 | } | ||
1289 | set_beep_amp(spec, 0x18, 0, HDA_OUTPUT); | ||
1290 | |||
1291 | spec->multiout.max_channels = 6; | ||
1292 | spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); | ||
1293 | spec->multiout.dac_nids = ad1986a_dac_nids; | ||
1294 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; | ||
1295 | spec->num_adc_nids = 1; | ||
1296 | spec->adc_nids = ad1986a_adc_nids; | ||
1297 | spec->capsrc_nids = ad1986a_capsrc_nids; | ||
1298 | spec->input_mux = &ad1986a_capture_source; | ||
1299 | spec->num_mixers = 1; | ||
1300 | spec->mixers[0] = ad1986a_mixers; | ||
1301 | spec->num_init_verbs = 1; | ||
1302 | spec->init_verbs[0] = ad1986a_init_verbs; | ||
1303 | #ifdef CONFIG_PM | ||
1304 | spec->loopback.amplist = ad1986a_loopbacks; | ||
1305 | #endif | ||
1306 | spec->vmaster_nid = 0x1b; | ||
1307 | codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ | ||
1308 | |||
1309 | codec->patch_ops = ad198x_patch_ops; | ||
1310 | |||
1311 | /* override some parameters */ | ||
1312 | switch (board_config) { | ||
1313 | case AD1986A_3STACK: | ||
1314 | spec->num_mixers = 2; | ||
1315 | spec->mixers[1] = ad1986a_3st_mixers; | ||
1316 | spec->num_init_verbs = 2; | ||
1317 | spec->init_verbs[1] = ad1986a_ch2_init; | ||
1318 | spec->channel_mode = ad1986a_modes; | ||
1319 | spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); | ||
1320 | spec->need_dac_fix = 1; | ||
1321 | spec->multiout.max_channels = 2; | ||
1322 | spec->multiout.num_dacs = 1; | ||
1323 | break; | ||
1324 | case AD1986A_LAPTOP: | ||
1325 | spec->mixers[0] = ad1986a_laptop_mixers; | ||
1326 | spec->multiout.max_channels = 2; | ||
1327 | spec->multiout.num_dacs = 1; | ||
1328 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1329 | break; | ||
1330 | case AD1986A_LAPTOP_EAPD: | ||
1331 | spec->num_mixers = 3; | ||
1332 | spec->mixers[0] = ad1986a_laptop_master_mixers; | ||
1333 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1334 | spec->mixers[2] = ad1986a_laptop_intmic_mixers; | ||
1335 | spec->num_init_verbs = 2; | ||
1336 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1337 | spec->multiout.max_channels = 2; | ||
1338 | spec->multiout.num_dacs = 1; | ||
1339 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1340 | if (!is_jack_available(codec, 0x25)) | ||
1341 | spec->multiout.dig_out_nid = 0; | ||
1342 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
1343 | break; | ||
1344 | case AD1986A_SAMSUNG: | ||
1345 | spec->num_mixers = 2; | ||
1346 | spec->mixers[0] = ad1986a_laptop_master_mixers; | ||
1347 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1348 | spec->num_init_verbs = 3; | ||
1349 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1350 | spec->init_verbs[2] = ad1986a_automic_verbs; | ||
1351 | spec->multiout.max_channels = 2; | ||
1352 | spec->multiout.num_dacs = 1; | ||
1353 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1354 | if (!is_jack_available(codec, 0x25)) | ||
1355 | spec->multiout.dig_out_nid = 0; | ||
1356 | spec->input_mux = &ad1986a_automic_capture_source; | ||
1357 | codec->patch_ops.unsol_event = ad1986a_automic_unsol_event; | ||
1358 | codec->patch_ops.init = ad1986a_automic_init; | ||
1359 | break; | ||
1360 | case AD1986A_SAMSUNG_P50: | ||
1361 | spec->num_mixers = 2; | ||
1362 | spec->mixers[0] = ad1986a_automute_master_mixers; | ||
1363 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1364 | spec->num_init_verbs = 4; | ||
1365 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1366 | spec->init_verbs[2] = ad1986a_automic_verbs; | ||
1367 | spec->init_verbs[3] = ad1986a_hp_init_verbs; | ||
1368 | spec->multiout.max_channels = 2; | ||
1369 | spec->multiout.num_dacs = 1; | ||
1370 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1371 | if (!is_jack_available(codec, 0x25)) | ||
1372 | spec->multiout.dig_out_nid = 0; | ||
1373 | spec->input_mux = &ad1986a_automic_capture_source; | ||
1374 | codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event; | ||
1375 | codec->patch_ops.init = ad1986a_samsung_p50_init; | ||
1376 | break; | ||
1377 | case AD1986A_LAPTOP_AUTOMUTE: | ||
1378 | spec->num_mixers = 3; | ||
1379 | spec->mixers[0] = ad1986a_automute_master_mixers; | ||
1380 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1381 | spec->mixers[2] = ad1986a_laptop_intmic_mixers; | ||
1382 | spec->num_init_verbs = 3; | ||
1383 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1384 | spec->init_verbs[2] = ad1986a_hp_init_verbs; | ||
1385 | spec->multiout.max_channels = 2; | ||
1386 | spec->multiout.num_dacs = 1; | ||
1387 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1388 | if (!is_jack_available(codec, 0x25)) | ||
1389 | spec->multiout.dig_out_nid = 0; | ||
1390 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
1391 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; | ||
1392 | codec->patch_ops.init = ad1986a_hp_init; | ||
1393 | /* Lenovo N100 seems to report the reversed bit | ||
1394 | * for HP jack-sensing | ||
1395 | */ | ||
1396 | spec->inv_jack_detect = 1; | ||
1397 | break; | ||
1398 | case AD1986A_ULTRA: | ||
1399 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; | ||
1400 | spec->num_init_verbs = 2; | ||
1401 | spec->init_verbs[1] = ad1986a_ultra_init; | ||
1402 | spec->multiout.max_channels = 2; | ||
1403 | spec->multiout.num_dacs = 1; | ||
1404 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1405 | spec->multiout.dig_out_nid = 0; | ||
1406 | break; | ||
1407 | } | ||
1408 | |||
1409 | /* AD1986A has a hardware problem that it can't share a stream | ||
1410 | * with multiple output pins. The copy of front to surrounds | ||
1411 | * causes noisy or silent outputs at a certain timing, e.g. | ||
1412 | * changing the volume. | ||
1413 | * So, let's disable the shared stream. | ||
1414 | */ | ||
1415 | spec->multiout.no_share_stream = 1; | ||
1416 | |||
1417 | codec->no_trigger_sense = 1; | ||
1418 | codec->no_sticky_stream = 1; | ||
1419 | |||
1420 | return 0; | ||
1421 | } | ||
1422 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
1423 | #define patch_ad1986a ad1986a_parse_auto_config | ||
1424 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1425 | 359 | ||
1426 | /* | 360 | /* |
1427 | * AD1983 specific | 361 | * AD1983 specific |
1428 | */ | 362 | */ |
1429 | 363 | ||
1430 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1431 | #define AD1983_SPDIF_OUT 0x02 | ||
1432 | #define AD1983_DAC 0x03 | ||
1433 | #define AD1983_ADC 0x04 | ||
1434 | |||
1435 | static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; | ||
1436 | static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; | ||
1437 | static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; | ||
1438 | |||
1439 | static const struct hda_input_mux ad1983_capture_source = { | ||
1440 | .num_items = 4, | ||
1441 | .items = { | ||
1442 | { "Mic", 0x0 }, | ||
1443 | { "Line", 0x1 }, | ||
1444 | { "Mix", 0x2 }, | ||
1445 | { "Mix Mono", 0x3 }, | ||
1446 | }, | ||
1447 | }; | ||
1448 | |||
1449 | /* | ||
1450 | * SPDIF playback route | ||
1451 | */ | ||
1452 | static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
1453 | { | ||
1454 | static const char * const texts[] = { "PCM", "ADC" }; | ||
1455 | |||
1456 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1457 | uinfo->count = 1; | ||
1458 | uinfo->value.enumerated.items = 2; | ||
1459 | if (uinfo->value.enumerated.item > 1) | ||
1460 | uinfo->value.enumerated.item = 1; | ||
1461 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1462 | return 0; | ||
1463 | } | ||
1464 | |||
1465 | static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1466 | { | ||
1467 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1468 | struct ad198x_spec *spec = codec->spec; | ||
1469 | |||
1470 | ucontrol->value.enumerated.item[0] = spec->spdif_route; | ||
1471 | return 0; | ||
1472 | } | ||
1473 | |||
1474 | static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1475 | { | ||
1476 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1477 | struct ad198x_spec *spec = codec->spec; | ||
1478 | |||
1479 | if (ucontrol->value.enumerated.item[0] > 1) | ||
1480 | return -EINVAL; | ||
1481 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { | ||
1482 | spec->spdif_route = ucontrol->value.enumerated.item[0]; | ||
1483 | snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, | ||
1484 | AC_VERB_SET_CONNECT_SEL, | ||
1485 | spec->spdif_route); | ||
1486 | return 1; | ||
1487 | } | ||
1488 | return 0; | ||
1489 | } | ||
1490 | |||
1491 | static const struct snd_kcontrol_new ad1983_mixers[] = { | ||
1492 | HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
1493 | HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
1494 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1495 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
1496 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1497 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1498 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1499 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1500 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1501 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1502 | HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1503 | HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1504 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1505 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
1506 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1507 | { | ||
1508 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1509 | .name = "Capture Source", | ||
1510 | .info = ad198x_mux_enum_info, | ||
1511 | .get = ad198x_mux_enum_get, | ||
1512 | .put = ad198x_mux_enum_put, | ||
1513 | }, | ||
1514 | { | ||
1515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1516 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
1517 | .info = ad1983_spdif_route_info, | ||
1518 | .get = ad1983_spdif_route_get, | ||
1519 | .put = ad1983_spdif_route_put, | ||
1520 | }, | ||
1521 | { } /* end */ | ||
1522 | }; | ||
1523 | |||
1524 | static const struct hda_verb ad1983_init_verbs[] = { | ||
1525 | /* Front, HP, Mono; mute as default */ | ||
1526 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1527 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1528 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1529 | /* Beep, PCM, Mic, Line-In: mute */ | ||
1530 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1531 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1532 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1533 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1534 | /* Front, HP selectors; from Mix */ | ||
1535 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1536 | {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1537 | /* Mono selector; from Mix */ | ||
1538 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
1539 | /* Mic selector; Mic */ | ||
1540 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1541 | /* Line-in selector: Line-in */ | ||
1542 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1543 | /* Mic boost: 0dB */ | ||
1544 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1545 | /* Record selector: mic */ | ||
1546 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1547 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1548 | /* SPDIF route: PCM */ | ||
1549 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1550 | /* Front Pin */ | ||
1551 | {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1552 | /* HP Pin */ | ||
1553 | {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
1554 | /* Mono Pin */ | ||
1555 | {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1556 | /* Mic Pin */ | ||
1557 | {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1558 | /* Line Pin */ | ||
1559 | {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1560 | { } /* end */ | ||
1561 | }; | ||
1562 | |||
1563 | #ifdef CONFIG_PM | ||
1564 | static const struct hda_amp_list ad1983_loopbacks[] = { | ||
1565 | { 0x12, HDA_OUTPUT, 0 }, /* Mic */ | ||
1566 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1567 | { } /* end */ | ||
1568 | }; | ||
1569 | #endif | ||
1570 | |||
1571 | /* models */ | ||
1572 | enum { | ||
1573 | AD1983_AUTO, | ||
1574 | AD1983_BASIC, | ||
1575 | AD1983_MODELS | ||
1576 | }; | ||
1577 | |||
1578 | static const char * const ad1983_models[AD1983_MODELS] = { | ||
1579 | [AD1983_AUTO] = "auto", | ||
1580 | [AD1983_BASIC] = "basic", | ||
1581 | }; | ||
1582 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1583 | |||
1584 | |||
1585 | /* | 364 | /* |
1586 | * SPDIF mux control for AD1983 auto-parser | 365 | * SPDIF mux control for AD1983 auto-parser |
1587 | */ | 366 | */ |
@@ -1656,7 +435,7 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec) | |||
1656 | return 0; | 435 | return 0; |
1657 | } | 436 | } |
1658 | 437 | ||
1659 | static int ad1983_parse_auto_config(struct hda_codec *codec) | 438 | static int patch_ad1983(struct hda_codec *codec) |
1660 | { | 439 | { |
1661 | struct ad198x_spec *spec; | 440 | struct ad198x_spec *spec; |
1662 | int err; | 441 | int err; |
@@ -1681,432 +460,11 @@ static int ad1983_parse_auto_config(struct hda_codec *codec) | |||
1681 | return err; | 460 | return err; |
1682 | } | 461 | } |
1683 | 462 | ||
1684 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1685 | static int patch_ad1983(struct hda_codec *codec) | ||
1686 | { | ||
1687 | struct ad198x_spec *spec; | ||
1688 | int board_config; | ||
1689 | int err; | ||
1690 | |||
1691 | board_config = snd_hda_check_board_config(codec, AD1983_MODELS, | ||
1692 | ad1983_models, NULL); | ||
1693 | if (board_config < 0) { | ||
1694 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
1695 | codec->chip_name); | ||
1696 | board_config = AD1983_AUTO; | ||
1697 | } | ||
1698 | |||
1699 | if (board_config == AD1983_AUTO) | ||
1700 | return ad1983_parse_auto_config(codec); | ||
1701 | |||
1702 | err = alloc_ad_spec(codec); | ||
1703 | if (err < 0) | ||
1704 | return err; | ||
1705 | spec = codec->spec; | ||
1706 | |||
1707 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
1708 | if (err < 0) { | ||
1709 | ad198x_free(codec); | ||
1710 | return err; | ||
1711 | } | ||
1712 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
1713 | |||
1714 | spec->multiout.max_channels = 2; | ||
1715 | spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); | ||
1716 | spec->multiout.dac_nids = ad1983_dac_nids; | ||
1717 | spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; | ||
1718 | spec->num_adc_nids = 1; | ||
1719 | spec->adc_nids = ad1983_adc_nids; | ||
1720 | spec->capsrc_nids = ad1983_capsrc_nids; | ||
1721 | spec->input_mux = &ad1983_capture_source; | ||
1722 | spec->num_mixers = 1; | ||
1723 | spec->mixers[0] = ad1983_mixers; | ||
1724 | spec->num_init_verbs = 1; | ||
1725 | spec->init_verbs[0] = ad1983_init_verbs; | ||
1726 | spec->spdif_route = 0; | ||
1727 | #ifdef CONFIG_PM | ||
1728 | spec->loopback.amplist = ad1983_loopbacks; | ||
1729 | #endif | ||
1730 | spec->vmaster_nid = 0x05; | ||
1731 | |||
1732 | codec->patch_ops = ad198x_patch_ops; | ||
1733 | |||
1734 | codec->no_trigger_sense = 1; | ||
1735 | codec->no_sticky_stream = 1; | ||
1736 | |||
1737 | return 0; | ||
1738 | } | ||
1739 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
1740 | #define patch_ad1983 ad1983_parse_auto_config | ||
1741 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1742 | |||
1743 | 463 | ||
1744 | /* | 464 | /* |
1745 | * AD1981 HD specific | 465 | * AD1981 HD specific |
1746 | */ | 466 | */ |
1747 | 467 | ||
1748 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1749 | #define AD1981_SPDIF_OUT 0x02 | ||
1750 | #define AD1981_DAC 0x03 | ||
1751 | #define AD1981_ADC 0x04 | ||
1752 | |||
1753 | static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; | ||
1754 | static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; | ||
1755 | static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; | ||
1756 | |||
1757 | /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ | ||
1758 | static const struct hda_input_mux ad1981_capture_source = { | ||
1759 | .num_items = 7, | ||
1760 | .items = { | ||
1761 | { "Front Mic", 0x0 }, | ||
1762 | { "Line", 0x1 }, | ||
1763 | { "Mix", 0x2 }, | ||
1764 | { "Mix Mono", 0x3 }, | ||
1765 | { "CD", 0x4 }, | ||
1766 | { "Mic", 0x6 }, | ||
1767 | { "Aux", 0x7 }, | ||
1768 | }, | ||
1769 | }; | ||
1770 | |||
1771 | static const struct snd_kcontrol_new ad1981_mixers[] = { | ||
1772 | HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
1773 | HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
1774 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1775 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
1776 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1777 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1778 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1779 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1780 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1781 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1782 | HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1783 | HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1784 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
1785 | HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
1786 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
1787 | HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
1788 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
1789 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
1790 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT), | ||
1791 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT), | ||
1792 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
1793 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1794 | { | ||
1795 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1796 | .name = "Capture Source", | ||
1797 | .info = ad198x_mux_enum_info, | ||
1798 | .get = ad198x_mux_enum_get, | ||
1799 | .put = ad198x_mux_enum_put, | ||
1800 | }, | ||
1801 | /* identical with AD1983 */ | ||
1802 | { | ||
1803 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1804 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
1805 | .info = ad1983_spdif_route_info, | ||
1806 | .get = ad1983_spdif_route_get, | ||
1807 | .put = ad1983_spdif_route_put, | ||
1808 | }, | ||
1809 | { } /* end */ | ||
1810 | }; | ||
1811 | |||
1812 | static const struct hda_verb ad1981_init_verbs[] = { | ||
1813 | /* Front, HP, Mono; mute as default */ | ||
1814 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1815 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1816 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1817 | /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */ | ||
1818 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1819 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1820 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1821 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1822 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1823 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1824 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1825 | /* Front, HP selectors; from Mix */ | ||
1826 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1827 | {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1828 | /* Mono selector; from Mix */ | ||
1829 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
1830 | /* Mic Mixer; select Front Mic */ | ||
1831 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1832 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1833 | /* Mic boost: 0dB */ | ||
1834 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1835 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1836 | /* Record selector: Front mic */ | ||
1837 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1838 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1839 | /* SPDIF route: PCM */ | ||
1840 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1841 | /* Front Pin */ | ||
1842 | {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1843 | /* HP Pin */ | ||
1844 | {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
1845 | /* Mono Pin */ | ||
1846 | {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1847 | /* Front & Rear Mic Pins */ | ||
1848 | {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1849 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1850 | /* Line Pin */ | ||
1851 | {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1852 | /* Digital Beep */ | ||
1853 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1854 | /* Line-Out as Input: disabled */ | ||
1855 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1856 | { } /* end */ | ||
1857 | }; | ||
1858 | |||
1859 | #ifdef CONFIG_PM | ||
1860 | static const struct hda_amp_list ad1981_loopbacks[] = { | ||
1861 | { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ | ||
1862 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1863 | { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ | ||
1864 | { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ | ||
1865 | { 0x1d, HDA_OUTPUT, 0 }, /* CD */ | ||
1866 | { } /* end */ | ||
1867 | }; | ||
1868 | #endif | ||
1869 | |||
1870 | /* | ||
1871 | * Patch for HP nx6320 | ||
1872 | * | ||
1873 | * nx6320 uses EAPD in the reverse way - EAPD-on means the internal | ||
1874 | * speaker output enabled _and_ mute-LED off. | ||
1875 | */ | ||
1876 | |||
1877 | #define AD1981_HP_EVENT 0x37 | ||
1878 | #define AD1981_MIC_EVENT 0x38 | ||
1879 | |||
1880 | static const struct hda_verb ad1981_hp_init_verbs[] = { | ||
1881 | {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ | ||
1882 | /* pin sensing on HP and Mic jacks */ | ||
1883 | {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, | ||
1884 | {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, | ||
1885 | {} | ||
1886 | }; | ||
1887 | |||
1888 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
1889 | static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
1890 | struct snd_ctl_elem_value *ucontrol) | ||
1891 | { | ||
1892 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1893 | struct ad198x_spec *spec = codec->spec; | ||
1894 | |||
1895 | if (! ad198x_eapd_put(kcontrol, ucontrol)) | ||
1896 | return 0; | ||
1897 | /* change speaker pin appropriately */ | ||
1898 | snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0); | ||
1899 | /* toggle HP mute appropriately */ | ||
1900 | snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, | ||
1901 | HDA_AMP_MUTE, | ||
1902 | spec->cur_eapd ? 0 : HDA_AMP_MUTE); | ||
1903 | return 1; | ||
1904 | } | ||
1905 | |||
1906 | /* bind volumes of both NID 0x05 and 0x06 */ | ||
1907 | static const struct hda_bind_ctls ad1981_hp_bind_master_vol = { | ||
1908 | .ops = &snd_hda_bind_vol, | ||
1909 | .values = { | ||
1910 | HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), | ||
1911 | HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), | ||
1912 | 0 | ||
1913 | }, | ||
1914 | }; | ||
1915 | |||
1916 | /* mute internal speaker if HP is plugged */ | ||
1917 | static void ad1981_hp_automute(struct hda_codec *codec) | ||
1918 | { | ||
1919 | unsigned int present; | ||
1920 | |||
1921 | present = snd_hda_jack_detect(codec, 0x06); | ||
1922 | snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, | ||
1923 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
1924 | } | ||
1925 | |||
1926 | /* toggle input of built-in and mic jack appropriately */ | ||
1927 | static void ad1981_hp_automic(struct hda_codec *codec) | ||
1928 | { | ||
1929 | static const struct hda_verb mic_jack_on[] = { | ||
1930 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1931 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1932 | {} | ||
1933 | }; | ||
1934 | static const struct hda_verb mic_jack_off[] = { | ||
1935 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1936 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1937 | {} | ||
1938 | }; | ||
1939 | unsigned int present; | ||
1940 | |||
1941 | present = snd_hda_jack_detect(codec, 0x08); | ||
1942 | if (present) | ||
1943 | snd_hda_sequence_write(codec, mic_jack_on); | ||
1944 | else | ||
1945 | snd_hda_sequence_write(codec, mic_jack_off); | ||
1946 | } | ||
1947 | |||
1948 | /* unsolicited event for HP jack sensing */ | ||
1949 | static void ad1981_hp_unsol_event(struct hda_codec *codec, | ||
1950 | unsigned int res) | ||
1951 | { | ||
1952 | res >>= 26; | ||
1953 | switch (res) { | ||
1954 | case AD1981_HP_EVENT: | ||
1955 | ad1981_hp_automute(codec); | ||
1956 | break; | ||
1957 | case AD1981_MIC_EVENT: | ||
1958 | ad1981_hp_automic(codec); | ||
1959 | break; | ||
1960 | } | ||
1961 | } | ||
1962 | |||
1963 | static const struct hda_input_mux ad1981_hp_capture_source = { | ||
1964 | .num_items = 3, | ||
1965 | .items = { | ||
1966 | { "Mic", 0x0 }, | ||
1967 | { "Dock Mic", 0x1 }, | ||
1968 | { "Mix", 0x2 }, | ||
1969 | }, | ||
1970 | }; | ||
1971 | |||
1972 | static const struct snd_kcontrol_new ad1981_hp_mixers[] = { | ||
1973 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), | ||
1974 | { | ||
1975 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1976 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, | ||
1977 | .name = "Master Playback Switch", | ||
1978 | .info = ad198x_eapd_info, | ||
1979 | .get = ad198x_eapd_get, | ||
1980 | .put = ad1981_hp_master_sw_put, | ||
1981 | .private_value = 0x05, | ||
1982 | }, | ||
1983 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1984 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1985 | #if 0 | ||
1986 | /* FIXME: analog mic/line loopback doesn't work with my tests... | ||
1987 | * (although recording is OK) | ||
1988 | */ | ||
1989 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1990 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1991 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1992 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1993 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
1994 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
1995 | /* FIXME: does this laptop have analog CD connection? */ | ||
1996 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
1997 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
1998 | #endif | ||
1999 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), | ||
2000 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT), | ||
2001 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
2002 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
2003 | { | ||
2004 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2005 | .name = "Capture Source", | ||
2006 | .info = ad198x_mux_enum_info, | ||
2007 | .get = ad198x_mux_enum_get, | ||
2008 | .put = ad198x_mux_enum_put, | ||
2009 | }, | ||
2010 | { } /* end */ | ||
2011 | }; | ||
2012 | |||
2013 | /* initialize jack-sensing, too */ | ||
2014 | static int ad1981_hp_init(struct hda_codec *codec) | ||
2015 | { | ||
2016 | ad198x_init(codec); | ||
2017 | ad1981_hp_automute(codec); | ||
2018 | ad1981_hp_automic(codec); | ||
2019 | return 0; | ||
2020 | } | ||
2021 | |||
2022 | /* configuration for Toshiba Laptops */ | ||
2023 | static const struct hda_verb ad1981_toshiba_init_verbs[] = { | ||
2024 | {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */ | ||
2025 | /* pin sensing on HP and Mic jacks */ | ||
2026 | {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, | ||
2027 | {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, | ||
2028 | {} | ||
2029 | }; | ||
2030 | |||
2031 | static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = { | ||
2032 | HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
2033 | HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
2034 | { } | ||
2035 | }; | ||
2036 | |||
2037 | /* configuration for Lenovo Thinkpad T60 */ | ||
2038 | static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { | ||
2039 | HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
2040 | HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
2041 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
2042 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
2043 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
2044 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
2045 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
2046 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
2047 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), | ||
2048 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
2049 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
2050 | { | ||
2051 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2052 | .name = "Capture Source", | ||
2053 | .info = ad198x_mux_enum_info, | ||
2054 | .get = ad198x_mux_enum_get, | ||
2055 | .put = ad198x_mux_enum_put, | ||
2056 | }, | ||
2057 | /* identical with AD1983 */ | ||
2058 | { | ||
2059 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2060 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
2061 | .info = ad1983_spdif_route_info, | ||
2062 | .get = ad1983_spdif_route_get, | ||
2063 | .put = ad1983_spdif_route_put, | ||
2064 | }, | ||
2065 | { } /* end */ | ||
2066 | }; | ||
2067 | |||
2068 | static const struct hda_input_mux ad1981_thinkpad_capture_source = { | ||
2069 | .num_items = 3, | ||
2070 | .items = { | ||
2071 | { "Mic", 0x0 }, | ||
2072 | { "Mix", 0x2 }, | ||
2073 | { "CD", 0x4 }, | ||
2074 | }, | ||
2075 | }; | ||
2076 | |||
2077 | /* models */ | ||
2078 | enum { | ||
2079 | AD1981_AUTO, | ||
2080 | AD1981_BASIC, | ||
2081 | AD1981_HP, | ||
2082 | AD1981_THINKPAD, | ||
2083 | AD1981_TOSHIBA, | ||
2084 | AD1981_MODELS | ||
2085 | }; | ||
2086 | |||
2087 | static const char * const ad1981_models[AD1981_MODELS] = { | ||
2088 | [AD1981_AUTO] = "auto", | ||
2089 | [AD1981_HP] = "hp", | ||
2090 | [AD1981_THINKPAD] = "thinkpad", | ||
2091 | [AD1981_BASIC] = "basic", | ||
2092 | [AD1981_TOSHIBA] = "toshiba" | ||
2093 | }; | ||
2094 | |||
2095 | static const struct snd_pci_quirk ad1981_cfg_tbl[] = { | ||
2096 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | ||
2097 | SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), | ||
2098 | /* All HP models */ | ||
2099 | SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP), | ||
2100 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), | ||
2101 | /* Lenovo Thinkpad T60/X60/Z6xx */ | ||
2102 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD), | ||
2103 | /* HP nx6320 (reversed SSID, H/W bug) */ | ||
2104 | SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), | ||
2105 | {} | ||
2106 | }; | ||
2107 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
2108 | |||
2109 | |||
2110 | /* follow EAPD via vmaster hook */ | 468 | /* follow EAPD via vmaster hook */ |
2111 | static void ad_vmaster_eapd_hook(void *private_data, int enabled) | 469 | static void ad_vmaster_eapd_hook(void *private_data, int enabled) |
2112 | { | 470 | { |
@@ -2172,7 +530,7 @@ static const struct snd_pci_quirk ad1981_fixup_tbl[] = { | |||
2172 | {} | 530 | {} |
2173 | }; | 531 | }; |
2174 | 532 | ||
2175 | static int ad1981_parse_auto_config(struct hda_codec *codec) | 533 | static int patch_ad1981(struct hda_codec *codec) |
2176 | { | 534 | { |
2177 | struct ad198x_spec *spec; | 535 | struct ad198x_spec *spec; |
2178 | int err; | 536 | int err; |
@@ -2205,110 +563,6 @@ static int ad1981_parse_auto_config(struct hda_codec *codec) | |||
2205 | return err; | 563 | return err; |
2206 | } | 564 | } |
2207 | 565 | ||
2208 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
2209 | static int patch_ad1981(struct hda_codec *codec) | ||
2210 | { | ||
2211 | struct ad198x_spec *spec; | ||
2212 | int err, board_config; | ||
2213 | |||
2214 | board_config = snd_hda_check_board_config(codec, AD1981_MODELS, | ||
2215 | ad1981_models, | ||
2216 | ad1981_cfg_tbl); | ||
2217 | if (board_config < 0) { | ||
2218 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
2219 | codec->chip_name); | ||
2220 | board_config = AD1981_AUTO; | ||
2221 | } | ||
2222 | |||
2223 | if (board_config == AD1981_AUTO) | ||
2224 | return ad1981_parse_auto_config(codec); | ||
2225 | |||
2226 | err = alloc_ad_spec(codec); | ||
2227 | if (err < 0) | ||
2228 | return -ENOMEM; | ||
2229 | spec = codec->spec; | ||
2230 | |||
2231 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
2232 | if (err < 0) { | ||
2233 | ad198x_free(codec); | ||
2234 | return err; | ||
2235 | } | ||
2236 | set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT); | ||
2237 | |||
2238 | spec->multiout.max_channels = 2; | ||
2239 | spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); | ||
2240 | spec->multiout.dac_nids = ad1981_dac_nids; | ||
2241 | spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; | ||
2242 | spec->num_adc_nids = 1; | ||
2243 | spec->adc_nids = ad1981_adc_nids; | ||
2244 | spec->capsrc_nids = ad1981_capsrc_nids; | ||
2245 | spec->input_mux = &ad1981_capture_source; | ||
2246 | spec->num_mixers = 1; | ||
2247 | spec->mixers[0] = ad1981_mixers; | ||
2248 | spec->num_init_verbs = 1; | ||
2249 | spec->init_verbs[0] = ad1981_init_verbs; | ||
2250 | spec->spdif_route = 0; | ||
2251 | #ifdef CONFIG_PM | ||
2252 | spec->loopback.amplist = ad1981_loopbacks; | ||
2253 | #endif | ||
2254 | spec->vmaster_nid = 0x05; | ||
2255 | |||
2256 | codec->patch_ops = ad198x_patch_ops; | ||
2257 | |||
2258 | /* override some parameters */ | ||
2259 | switch (board_config) { | ||
2260 | case AD1981_HP: | ||
2261 | spec->mixers[0] = ad1981_hp_mixers; | ||
2262 | spec->num_init_verbs = 2; | ||
2263 | spec->init_verbs[1] = ad1981_hp_init_verbs; | ||
2264 | if (!is_jack_available(codec, 0x0a)) | ||
2265 | spec->multiout.dig_out_nid = 0; | ||
2266 | spec->input_mux = &ad1981_hp_capture_source; | ||
2267 | |||
2268 | codec->patch_ops.init = ad1981_hp_init; | ||
2269 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | ||
2270 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
2271 | * possible damage by overloading | ||
2272 | */ | ||
2273 | snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, | ||
2274 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
2275 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
2276 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
2277 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
2278 | break; | ||
2279 | case AD1981_THINKPAD: | ||
2280 | spec->mixers[0] = ad1981_thinkpad_mixers; | ||
2281 | spec->input_mux = &ad1981_thinkpad_capture_source; | ||
2282 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
2283 | * possible damage by overloading | ||
2284 | */ | ||
2285 | snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, | ||
2286 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
2287 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
2288 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
2289 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
2290 | break; | ||
2291 | case AD1981_TOSHIBA: | ||
2292 | spec->mixers[0] = ad1981_hp_mixers; | ||
2293 | spec->mixers[1] = ad1981_toshiba_mixers; | ||
2294 | spec->num_init_verbs = 2; | ||
2295 | spec->init_verbs[1] = ad1981_toshiba_init_verbs; | ||
2296 | spec->multiout.dig_out_nid = 0; | ||
2297 | spec->input_mux = &ad1981_hp_capture_source; | ||
2298 | codec->patch_ops.init = ad1981_hp_init; | ||
2299 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | ||
2300 | break; | ||
2301 | } | ||
2302 | |||
2303 | codec->no_trigger_sense = 1; | ||
2304 | codec->no_sticky_stream = 1; | ||
2305 | |||
2306 | return 0; | ||
2307 | } | ||
2308 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
2309 | #define patch_ad1981 ad1981_parse_auto_config | ||
2310 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
2311 | |||
2312 | 566 | ||
2313 | /* | 567 | /* |
2314 | * AD1988 | 568 | * AD1988 |
@@ -2395,90 +649,7 @@ static int patch_ad1981(struct hda_codec *codec) | |||
2395 | * E/F quad mic array | 649 | * E/F quad mic array |
2396 | */ | 650 | */ |
2397 | 651 | ||
2398 | |||
2399 | #ifdef ENABLE_AD_STATIC_QUIRKS | 652 | #ifdef ENABLE_AD_STATIC_QUIRKS |
2400 | /* models */ | ||
2401 | enum { | ||
2402 | AD1988_AUTO, | ||
2403 | AD1988_6STACK, | ||
2404 | AD1988_6STACK_DIG, | ||
2405 | AD1988_3STACK, | ||
2406 | AD1988_3STACK_DIG, | ||
2407 | AD1988_LAPTOP, | ||
2408 | AD1988_LAPTOP_DIG, | ||
2409 | AD1988_MODEL_LAST, | ||
2410 | }; | ||
2411 | |||
2412 | /* reivision id to check workarounds */ | ||
2413 | #define AD1988A_REV2 0x100200 | ||
2414 | |||
2415 | #define is_rev2(codec) \ | ||
2416 | ((codec)->vendor_id == 0x11d41988 && \ | ||
2417 | (codec)->revision_id == AD1988A_REV2) | ||
2418 | |||
2419 | /* | ||
2420 | * mixers | ||
2421 | */ | ||
2422 | |||
2423 | static const hda_nid_t ad1988_6stack_dac_nids[4] = { | ||
2424 | 0x04, 0x06, 0x05, 0x0a | ||
2425 | }; | ||
2426 | |||
2427 | static const hda_nid_t ad1988_3stack_dac_nids[3] = { | ||
2428 | 0x04, 0x05, 0x0a | ||
2429 | }; | ||
2430 | |||
2431 | /* for AD1988A revision-2, DAC2-4 are swapped */ | ||
2432 | static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { | ||
2433 | 0x04, 0x05, 0x0a, 0x06 | ||
2434 | }; | ||
2435 | |||
2436 | static const hda_nid_t ad1988_alt_dac_nid[1] = { | ||
2437 | 0x03 | ||
2438 | }; | ||
2439 | |||
2440 | static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { | ||
2441 | 0x04, 0x0a, 0x06 | ||
2442 | }; | ||
2443 | |||
2444 | static const hda_nid_t ad1988_adc_nids[3] = { | ||
2445 | 0x08, 0x09, 0x0f | ||
2446 | }; | ||
2447 | |||
2448 | static const hda_nid_t ad1988_capsrc_nids[3] = { | ||
2449 | 0x0c, 0x0d, 0x0e | ||
2450 | }; | ||
2451 | |||
2452 | #define AD1988_SPDIF_OUT 0x02 | ||
2453 | #define AD1988_SPDIF_OUT_HDMI 0x0b | ||
2454 | #define AD1988_SPDIF_IN 0x07 | ||
2455 | |||
2456 | static const hda_nid_t ad1989b_slave_dig_outs[] = { | ||
2457 | AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0 | ||
2458 | }; | ||
2459 | |||
2460 | static const struct hda_input_mux ad1988_6stack_capture_source = { | ||
2461 | .num_items = 5, | ||
2462 | .items = { | ||
2463 | { "Front Mic", 0x1 }, /* port-B */ | ||
2464 | { "Line", 0x2 }, /* port-C */ | ||
2465 | { "Mic", 0x4 }, /* port-E */ | ||
2466 | { "CD", 0x5 }, | ||
2467 | { "Mix", 0x9 }, | ||
2468 | }, | ||
2469 | }; | ||
2470 | |||
2471 | static const struct hda_input_mux ad1988_laptop_capture_source = { | ||
2472 | .num_items = 3, | ||
2473 | .items = { | ||
2474 | { "Mic/Line", 0x1 }, /* port-B */ | ||
2475 | { "CD", 0x5 }, | ||
2476 | { "Mix", 0x9 }, | ||
2477 | }, | ||
2478 | }; | ||
2479 | |||
2480 | /* | ||
2481 | */ | ||
2482 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, | 653 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, |
2483 | struct snd_ctl_elem_info *uinfo) | 654 | struct snd_ctl_elem_info *uinfo) |
2484 | { | 655 | { |
@@ -2509,569 +680,6 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
2509 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | 680 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; |
2510 | return err; | 681 | return err; |
2511 | } | 682 | } |
2512 | |||
2513 | /* 6-stack mode */ | ||
2514 | static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = { | ||
2515 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2516 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
2517 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
2518 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
2519 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
2520 | { } /* end */ | ||
2521 | }; | ||
2522 | |||
2523 | static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { | ||
2524 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2525 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
2526 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | ||
2527 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT), | ||
2528 | HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
2529 | { } /* end */ | ||
2530 | }; | ||
2531 | |||
2532 | static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = { | ||
2533 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2534 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | ||
2535 | HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), | ||
2536 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), | ||
2537 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), | ||
2538 | HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), | ||
2539 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | ||
2540 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2541 | |||
2542 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2543 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2544 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2545 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2546 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2547 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2548 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||
2549 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||
2550 | |||
2551 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2552 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2553 | |||
2554 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2555 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
2556 | { } /* end */ | ||
2557 | }; | ||
2558 | |||
2559 | /* 3-stack mode */ | ||
2560 | static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = { | ||
2561 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2562 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
2563 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
2564 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
2565 | { } /* end */ | ||
2566 | }; | ||
2567 | |||
2568 | static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { | ||
2569 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2570 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
2571 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT), | ||
2572 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT), | ||
2573 | { } /* end */ | ||
2574 | }; | ||
2575 | |||
2576 | static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = { | ||
2577 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2578 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | ||
2579 | HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT), | ||
2580 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT), | ||
2581 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT), | ||
2582 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | ||
2583 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2584 | |||
2585 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2586 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2587 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2588 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2589 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2590 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2591 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||
2592 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||
2593 | |||
2594 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2595 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2596 | |||
2597 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2598 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
2599 | { | ||
2600 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2601 | .name = "Channel Mode", | ||
2602 | .info = ad198x_ch_mode_info, | ||
2603 | .get = ad198x_ch_mode_get, | ||
2604 | .put = ad198x_ch_mode_put, | ||
2605 | }, | ||
2606 | |||
2607 | { } /* end */ | ||
2608 | }; | ||
2609 | |||
2610 | /* laptop mode */ | ||
2611 | static const struct snd_kcontrol_new ad1988_laptop_mixers[] = { | ||
2612 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2613 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2614 | HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT), | ||
2615 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2616 | |||
2617 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2618 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2619 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2620 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2621 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2622 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2623 | |||
2624 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2625 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2626 | |||
2627 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2628 | |||
2629 | { | ||
2630 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2631 | .name = "External Amplifier", | ||
2632 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, | ||
2633 | .info = ad198x_eapd_info, | ||
2634 | .get = ad198x_eapd_get, | ||
2635 | .put = ad198x_eapd_put, | ||
2636 | .private_value = 0x12, /* port-D */ | ||
2637 | }, | ||
2638 | |||
2639 | { } /* end */ | ||
2640 | }; | ||
2641 | |||
2642 | /* capture */ | ||
2643 | static const struct snd_kcontrol_new ad1988_capture_mixers[] = { | ||
2644 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
2645 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
2646 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
2647 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
2648 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT), | ||
2649 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT), | ||
2650 | { | ||
2651 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2652 | /* The multiple "Capture Source" controls confuse alsamixer | ||
2653 | * So call somewhat different.. | ||
2654 | */ | ||
2655 | /* .name = "Capture Source", */ | ||
2656 | .name = "Input Source", | ||
2657 | .count = 3, | ||
2658 | .info = ad198x_mux_enum_info, | ||
2659 | .get = ad198x_mux_enum_get, | ||
2660 | .put = ad198x_mux_enum_put, | ||
2661 | }, | ||
2662 | { } /* end */ | ||
2663 | }; | ||
2664 | |||
2665 | static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol, | ||
2666 | struct snd_ctl_elem_info *uinfo) | ||
2667 | { | ||
2668 | static const char * const texts[] = { | ||
2669 | "PCM", "ADC1", "ADC2", "ADC3" | ||
2670 | }; | ||
2671 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2672 | uinfo->count = 1; | ||
2673 | uinfo->value.enumerated.items = 4; | ||
2674 | if (uinfo->value.enumerated.item >= 4) | ||
2675 | uinfo->value.enumerated.item = 3; | ||
2676 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2677 | return 0; | ||
2678 | } | ||
2679 | |||
2680 | static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, | ||
2681 | struct snd_ctl_elem_value *ucontrol) | ||
2682 | { | ||
2683 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2684 | unsigned int sel; | ||
2685 | |||
2686 | sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, | ||
2687 | AC_AMP_GET_INPUT); | ||
2688 | if (!(sel & 0x80)) | ||
2689 | ucontrol->value.enumerated.item[0] = 0; | ||
2690 | else { | ||
2691 | sel = snd_hda_codec_read(codec, 0x0b, 0, | ||
2692 | AC_VERB_GET_CONNECT_SEL, 0); | ||
2693 | if (sel < 3) | ||
2694 | sel++; | ||
2695 | else | ||
2696 | sel = 0; | ||
2697 | ucontrol->value.enumerated.item[0] = sel; | ||
2698 | } | ||
2699 | return 0; | ||
2700 | } | ||
2701 | |||
2702 | static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, | ||
2703 | struct snd_ctl_elem_value *ucontrol) | ||
2704 | { | ||
2705 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2706 | unsigned int val, sel; | ||
2707 | int change; | ||
2708 | |||
2709 | val = ucontrol->value.enumerated.item[0]; | ||
2710 | if (val > 3) | ||
2711 | return -EINVAL; | ||
2712 | if (!val) { | ||
2713 | sel = snd_hda_codec_read(codec, 0x1d, 0, | ||
2714 | AC_VERB_GET_AMP_GAIN_MUTE, | ||
2715 | AC_AMP_GET_INPUT); | ||
2716 | change = sel & 0x80; | ||
2717 | if (change) { | ||
2718 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2719 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2720 | AMP_IN_UNMUTE(0)); | ||
2721 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2722 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2723 | AMP_IN_MUTE(1)); | ||
2724 | } | ||
2725 | } else { | ||
2726 | sel = snd_hda_codec_read(codec, 0x1d, 0, | ||
2727 | AC_VERB_GET_AMP_GAIN_MUTE, | ||
2728 | AC_AMP_GET_INPUT | 0x01); | ||
2729 | change = sel & 0x80; | ||
2730 | if (change) { | ||
2731 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2732 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2733 | AMP_IN_MUTE(0)); | ||
2734 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2735 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2736 | AMP_IN_UNMUTE(1)); | ||
2737 | } | ||
2738 | sel = snd_hda_codec_read(codec, 0x0b, 0, | ||
2739 | AC_VERB_GET_CONNECT_SEL, 0) + 1; | ||
2740 | change |= sel != val; | ||
2741 | if (change) | ||
2742 | snd_hda_codec_write_cache(codec, 0x0b, 0, | ||
2743 | AC_VERB_SET_CONNECT_SEL, | ||
2744 | val - 1); | ||
2745 | } | ||
2746 | return change; | ||
2747 | } | ||
2748 | |||
2749 | static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { | ||
2750 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
2751 | { | ||
2752 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2753 | .name = "IEC958 Playback Source", | ||
2754 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
2755 | .info = ad1988_spdif_playback_source_info, | ||
2756 | .get = ad1988_spdif_playback_source_get, | ||
2757 | .put = ad1988_spdif_playback_source_put, | ||
2758 | }, | ||
2759 | { } /* end */ | ||
2760 | }; | ||
2761 | |||
2762 | static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { | ||
2763 | HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT), | ||
2764 | { } /* end */ | ||
2765 | }; | ||
2766 | |||
2767 | static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { | ||
2768 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
2769 | HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
2770 | { } /* end */ | ||
2771 | }; | ||
2772 | |||
2773 | /* | ||
2774 | * initialization verbs | ||
2775 | */ | ||
2776 | |||
2777 | /* | ||
2778 | * for 6-stack (+dig) | ||
2779 | */ | ||
2780 | static const struct hda_verb ad1988_6stack_init_verbs[] = { | ||
2781 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
2782 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2783 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2784 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2785 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2786 | /* Port-A front headphon path */ | ||
2787 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2788 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2789 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2790 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2791 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2792 | /* Port-D line-out path */ | ||
2793 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2794 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2795 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2796 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2797 | /* Port-F surround path */ | ||
2798 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2799 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2800 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2801 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2802 | /* Port-G CLFE path */ | ||
2803 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2804 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2805 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2806 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2807 | /* Port-H side path */ | ||
2808 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2809 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2810 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2811 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2812 | /* Mono out path */ | ||
2813 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
2814 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2815 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2816 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2817 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
2818 | /* Port-B front mic-in path */ | ||
2819 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2820 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2821 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2822 | /* Port-C line-in path */ | ||
2823 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2824 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2825 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2826 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2827 | /* Port-E mic-in path */ | ||
2828 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2829 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2830 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2831 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2832 | /* Analog CD Input */ | ||
2833 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2834 | /* Analog Mix output amp */ | ||
2835 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
2836 | |||
2837 | { } | ||
2838 | }; | ||
2839 | |||
2840 | static const struct hda_verb ad1988_6stack_fp_init_verbs[] = { | ||
2841 | /* Headphone; unmute as default */ | ||
2842 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2843 | /* Port-A front headphon path */ | ||
2844 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2845 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2846 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2847 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2848 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2849 | |||
2850 | { } | ||
2851 | }; | ||
2852 | |||
2853 | static const struct hda_verb ad1988_capture_init_verbs[] = { | ||
2854 | /* mute analog mix */ | ||
2855 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2856 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2857 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2858 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2859 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2860 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
2861 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
2862 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
2863 | /* select ADCs - front-mic */ | ||
2864 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2865 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2866 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2867 | |||
2868 | { } | ||
2869 | }; | ||
2870 | |||
2871 | static const struct hda_verb ad1988_spdif_init_verbs[] = { | ||
2872 | /* SPDIF out sel */ | ||
2873 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
2874 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ | ||
2875 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2876 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2877 | /* SPDIF out pin */ | ||
2878 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
2879 | |||
2880 | { } | ||
2881 | }; | ||
2882 | |||
2883 | static const struct hda_verb ad1988_spdif_in_init_verbs[] = { | ||
2884 | /* unmute SPDIF input pin */ | ||
2885 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2886 | { } | ||
2887 | }; | ||
2888 | |||
2889 | /* AD1989 has no ADC -> SPDIF route */ | ||
2890 | static const struct hda_verb ad1989_spdif_init_verbs[] = { | ||
2891 | /* SPDIF-1 out pin */ | ||
2892 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2893 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
2894 | /* SPDIF-2/HDMI out pin */ | ||
2895 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2896 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
2897 | { } | ||
2898 | }; | ||
2899 | |||
2900 | /* | ||
2901 | * verbs for 3stack (+dig) | ||
2902 | */ | ||
2903 | static const struct hda_verb ad1988_3stack_ch2_init[] = { | ||
2904 | /* set port-C to line-in */ | ||
2905 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2906 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
2907 | /* set port-E to mic-in */ | ||
2908 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2909 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
2910 | { } /* end */ | ||
2911 | }; | ||
2912 | |||
2913 | static const struct hda_verb ad1988_3stack_ch6_init[] = { | ||
2914 | /* set port-C to surround out */ | ||
2915 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2916 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2917 | /* set port-E to CLFE out */ | ||
2918 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2919 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2920 | { } /* end */ | ||
2921 | }; | ||
2922 | |||
2923 | static const struct hda_channel_mode ad1988_3stack_modes[2] = { | ||
2924 | { 2, ad1988_3stack_ch2_init }, | ||
2925 | { 6, ad1988_3stack_ch6_init }, | ||
2926 | }; | ||
2927 | |||
2928 | static const struct hda_verb ad1988_3stack_init_verbs[] = { | ||
2929 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
2930 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2931 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2932 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2933 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2934 | /* Port-A front headphon path */ | ||
2935 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2936 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2937 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2938 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2939 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2940 | /* Port-D line-out path */ | ||
2941 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2942 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2943 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2944 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2945 | /* Mono out path */ | ||
2946 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
2947 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2948 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2949 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2950 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
2951 | /* Port-B front mic-in path */ | ||
2952 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2953 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2954 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2955 | /* Port-C line-in/surround path - 6ch mode as default */ | ||
2956 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2957 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2958 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2959 | {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */ | ||
2960 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2961 | /* Port-E mic-in/CLFE path - 6ch mode as default */ | ||
2962 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2963 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2964 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2965 | {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */ | ||
2966 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2967 | /* mute analog mix */ | ||
2968 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2969 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2970 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2971 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2972 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2973 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
2974 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
2975 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
2976 | /* select ADCs - front-mic */ | ||
2977 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2978 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2979 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2980 | /* Analog Mix output amp */ | ||
2981 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
2982 | { } | ||
2983 | }; | ||
2984 | |||
2985 | /* | ||
2986 | * verbs for laptop mode (+dig) | ||
2987 | */ | ||
2988 | static const struct hda_verb ad1988_laptop_hp_on[] = { | ||
2989 | /* unmute port-A and mute port-D */ | ||
2990 | { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2991 | { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2992 | { } /* end */ | ||
2993 | }; | ||
2994 | static const struct hda_verb ad1988_laptop_hp_off[] = { | ||
2995 | /* mute port-A and unmute port-D */ | ||
2996 | { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2997 | { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2998 | { } /* end */ | ||
2999 | }; | ||
3000 | |||
3001 | #define AD1988_HP_EVENT 0x01 | ||
3002 | |||
3003 | static const struct hda_verb ad1988_laptop_init_verbs[] = { | ||
3004 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
3005 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3006 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3007 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3008 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3009 | /* Port-A front headphon path */ | ||
3010 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
3011 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3012 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3013 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3014 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3015 | /* unsolicited event for pin-sense */ | ||
3016 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT }, | ||
3017 | /* Port-D line-out path + EAPD */ | ||
3018 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3019 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3020 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3021 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
3022 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */ | ||
3023 | /* Mono out path */ | ||
3024 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
3025 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3026 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3027 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
3028 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
3029 | /* Port-B mic-in path */ | ||
3030 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3031 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3032 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3033 | /* Port-C docking station - try to output */ | ||
3034 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3035 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
3036 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3037 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
3038 | /* mute analog mix */ | ||
3039 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3040 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3041 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
3042 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
3043 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
3044 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
3045 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
3046 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
3047 | /* select ADCs - mic */ | ||
3048 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3049 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3050 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3051 | /* Analog Mix output amp */ | ||
3052 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
3053 | { } | ||
3054 | }; | ||
3055 | |||
3056 | static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) | ||
3057 | { | ||
3058 | if ((res >> 26) != AD1988_HP_EVENT) | ||
3059 | return; | ||
3060 | if (snd_hda_jack_detect(codec, 0x11)) | ||
3061 | snd_hda_sequence_write(codec, ad1988_laptop_hp_on); | ||
3062 | else | ||
3063 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); | ||
3064 | } | ||
3065 | |||
3066 | #ifdef CONFIG_PM | ||
3067 | static const struct hda_amp_list ad1988_loopbacks[] = { | ||
3068 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
3069 | { 0x20, HDA_INPUT, 1 }, /* Line */ | ||
3070 | { 0x20, HDA_INPUT, 4 }, /* Mic */ | ||
3071 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
3072 | { } /* end */ | ||
3073 | }; | ||
3074 | #endif | ||
3075 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | 683 | #endif /* ENABLE_AD_STATIC_QUIRKS */ |
3076 | 684 | ||
3077 | static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, | 685 | static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, |
@@ -3220,7 +828,34 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec) | |||
3220 | /* | 828 | /* |
3221 | */ | 829 | */ |
3222 | 830 | ||
3223 | static int ad1988_parse_auto_config(struct hda_codec *codec) | 831 | enum { |
832 | AD1988_FIXUP_6STACK_DIG, | ||
833 | }; | ||
834 | |||
835 | static const struct hda_fixup ad1988_fixups[] = { | ||
836 | [AD1988_FIXUP_6STACK_DIG] = { | ||
837 | .type = HDA_FIXUP_PINS, | ||
838 | .v.pins = (const struct hda_pintbl[]) { | ||
839 | { 0x11, 0x02214130 }, /* front-hp */ | ||
840 | { 0x12, 0x01014010 }, /* line-out */ | ||
841 | { 0x14, 0x02a19122 }, /* front-mic */ | ||
842 | { 0x15, 0x01813021 }, /* line-in */ | ||
843 | { 0x16, 0x01011012 }, /* line-out */ | ||
844 | { 0x17, 0x01a19020 }, /* mic */ | ||
845 | { 0x1b, 0x0145f1f0 }, /* SPDIF */ | ||
846 | { 0x24, 0x01016011 }, /* line-out */ | ||
847 | { 0x25, 0x01012013 }, /* line-out */ | ||
848 | { } | ||
849 | } | ||
850 | }, | ||
851 | }; | ||
852 | |||
853 | static const struct hda_model_fixup ad1988_fixup_models[] = { | ||
854 | { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" }, | ||
855 | {} | ||
856 | }; | ||
857 | |||
858 | static int patch_ad1988(struct hda_codec *codec) | ||
3224 | { | 859 | { |
3225 | struct ad198x_spec *spec; | 860 | struct ad198x_spec *spec; |
3226 | int err; | 861 | int err; |
@@ -3234,12 +869,19 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | |||
3234 | spec->gen.mixer_merge_nid = 0x21; | 869 | spec->gen.mixer_merge_nid = 0x21; |
3235 | spec->gen.beep_nid = 0x10; | 870 | spec->gen.beep_nid = 0x10; |
3236 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | 871 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); |
872 | |||
873 | snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups); | ||
874 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | ||
875 | |||
3237 | err = ad198x_parse_auto_config(codec); | 876 | err = ad198x_parse_auto_config(codec); |
3238 | if (err < 0) | 877 | if (err < 0) |
3239 | goto error; | 878 | goto error; |
3240 | err = ad1988_add_spdif_mux_ctl(codec); | 879 | err = ad1988_add_spdif_mux_ctl(codec); |
3241 | if (err < 0) | 880 | if (err < 0) |
3242 | goto error; | 881 | goto error; |
882 | |||
883 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); | ||
884 | |||
3243 | return 0; | 885 | return 0; |
3244 | 886 | ||
3245 | error: | 887 | error: |
@@ -3247,169 +889,6 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | |||
3247 | return err; | 889 | return err; |
3248 | } | 890 | } |
3249 | 891 | ||
3250 | /* | ||
3251 | */ | ||
3252 | |||
3253 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3254 | static const char * const ad1988_models[AD1988_MODEL_LAST] = { | ||
3255 | [AD1988_6STACK] = "6stack", | ||
3256 | [AD1988_6STACK_DIG] = "6stack-dig", | ||
3257 | [AD1988_3STACK] = "3stack", | ||
3258 | [AD1988_3STACK_DIG] = "3stack-dig", | ||
3259 | [AD1988_LAPTOP] = "laptop", | ||
3260 | [AD1988_LAPTOP_DIG] = "laptop-dig", | ||
3261 | [AD1988_AUTO] = "auto", | ||
3262 | }; | ||
3263 | |||
3264 | static const struct snd_pci_quirk ad1988_cfg_tbl[] = { | ||
3265 | SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), | ||
3266 | SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), | ||
3267 | SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG), | ||
3268 | SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG), | ||
3269 | SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG), | ||
3270 | {} | ||
3271 | }; | ||
3272 | |||
3273 | static int patch_ad1988(struct hda_codec *codec) | ||
3274 | { | ||
3275 | struct ad198x_spec *spec; | ||
3276 | int err, board_config; | ||
3277 | |||
3278 | board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, | ||
3279 | ad1988_models, ad1988_cfg_tbl); | ||
3280 | if (board_config < 0) { | ||
3281 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3282 | codec->chip_name); | ||
3283 | board_config = AD1988_AUTO; | ||
3284 | } | ||
3285 | |||
3286 | if (board_config == AD1988_AUTO) | ||
3287 | return ad1988_parse_auto_config(codec); | ||
3288 | |||
3289 | err = alloc_ad_spec(codec); | ||
3290 | if (err < 0) | ||
3291 | return err; | ||
3292 | spec = codec->spec; | ||
3293 | |||
3294 | if (is_rev2(codec)) | ||
3295 | snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); | ||
3296 | |||
3297 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
3298 | if (err < 0) { | ||
3299 | ad198x_free(codec); | ||
3300 | return err; | ||
3301 | } | ||
3302 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
3303 | |||
3304 | if (!spec->multiout.hp_nid) | ||
3305 | spec->multiout.hp_nid = ad1988_alt_dac_nid[0]; | ||
3306 | switch (board_config) { | ||
3307 | case AD1988_6STACK: | ||
3308 | case AD1988_6STACK_DIG: | ||
3309 | spec->multiout.max_channels = 8; | ||
3310 | spec->multiout.num_dacs = 4; | ||
3311 | if (is_rev2(codec)) | ||
3312 | spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2; | ||
3313 | else | ||
3314 | spec->multiout.dac_nids = ad1988_6stack_dac_nids; | ||
3315 | spec->input_mux = &ad1988_6stack_capture_source; | ||
3316 | spec->num_mixers = 2; | ||
3317 | if (is_rev2(codec)) | ||
3318 | spec->mixers[0] = ad1988_6stack_mixers1_rev2; | ||
3319 | else | ||
3320 | spec->mixers[0] = ad1988_6stack_mixers1; | ||
3321 | spec->mixers[1] = ad1988_6stack_mixers2; | ||
3322 | spec->num_init_verbs = 1; | ||
3323 | spec->init_verbs[0] = ad1988_6stack_init_verbs; | ||
3324 | if (board_config == AD1988_6STACK_DIG) { | ||
3325 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
3326 | spec->dig_in_nid = AD1988_SPDIF_IN; | ||
3327 | } | ||
3328 | break; | ||
3329 | case AD1988_3STACK: | ||
3330 | case AD1988_3STACK_DIG: | ||
3331 | spec->multiout.max_channels = 6; | ||
3332 | spec->multiout.num_dacs = 3; | ||
3333 | if (is_rev2(codec)) | ||
3334 | spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2; | ||
3335 | else | ||
3336 | spec->multiout.dac_nids = ad1988_3stack_dac_nids; | ||
3337 | spec->input_mux = &ad1988_6stack_capture_source; | ||
3338 | spec->channel_mode = ad1988_3stack_modes; | ||
3339 | spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes); | ||
3340 | spec->num_mixers = 2; | ||
3341 | if (is_rev2(codec)) | ||
3342 | spec->mixers[0] = ad1988_3stack_mixers1_rev2; | ||
3343 | else | ||
3344 | spec->mixers[0] = ad1988_3stack_mixers1; | ||
3345 | spec->mixers[1] = ad1988_3stack_mixers2; | ||
3346 | spec->num_init_verbs = 1; | ||
3347 | spec->init_verbs[0] = ad1988_3stack_init_verbs; | ||
3348 | if (board_config == AD1988_3STACK_DIG) | ||
3349 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
3350 | break; | ||
3351 | case AD1988_LAPTOP: | ||
3352 | case AD1988_LAPTOP_DIG: | ||
3353 | spec->multiout.max_channels = 2; | ||
3354 | spec->multiout.num_dacs = 1; | ||
3355 | spec->multiout.dac_nids = ad1988_3stack_dac_nids; | ||
3356 | spec->input_mux = &ad1988_laptop_capture_source; | ||
3357 | spec->num_mixers = 1; | ||
3358 | spec->mixers[0] = ad1988_laptop_mixers; | ||
3359 | codec->inv_eapd = 1; /* inverted EAPD */ | ||
3360 | spec->num_init_verbs = 1; | ||
3361 | spec->init_verbs[0] = ad1988_laptop_init_verbs; | ||
3362 | if (board_config == AD1988_LAPTOP_DIG) | ||
3363 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
3364 | break; | ||
3365 | } | ||
3366 | |||
3367 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | ||
3368 | spec->adc_nids = ad1988_adc_nids; | ||
3369 | spec->capsrc_nids = ad1988_capsrc_nids; | ||
3370 | spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; | ||
3371 | spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; | ||
3372 | if (spec->multiout.dig_out_nid) { | ||
3373 | if (codec->vendor_id >= 0x11d4989a) { | ||
3374 | spec->mixers[spec->num_mixers++] = | ||
3375 | ad1989_spdif_out_mixers; | ||
3376 | spec->init_verbs[spec->num_init_verbs++] = | ||
3377 | ad1989_spdif_init_verbs; | ||
3378 | codec->slave_dig_outs = ad1989b_slave_dig_outs; | ||
3379 | } else { | ||
3380 | spec->mixers[spec->num_mixers++] = | ||
3381 | ad1988_spdif_out_mixers; | ||
3382 | spec->init_verbs[spec->num_init_verbs++] = | ||
3383 | ad1988_spdif_init_verbs; | ||
3384 | } | ||
3385 | } | ||
3386 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) { | ||
3387 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; | ||
3388 | spec->init_verbs[spec->num_init_verbs++] = | ||
3389 | ad1988_spdif_in_init_verbs; | ||
3390 | } | ||
3391 | |||
3392 | codec->patch_ops = ad198x_patch_ops; | ||
3393 | switch (board_config) { | ||
3394 | case AD1988_LAPTOP: | ||
3395 | case AD1988_LAPTOP_DIG: | ||
3396 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; | ||
3397 | break; | ||
3398 | } | ||
3399 | #ifdef CONFIG_PM | ||
3400 | spec->loopback.amplist = ad1988_loopbacks; | ||
3401 | #endif | ||
3402 | spec->vmaster_nid = 0x04; | ||
3403 | |||
3404 | codec->no_trigger_sense = 1; | ||
3405 | codec->no_sticky_stream = 1; | ||
3406 | |||
3407 | return 0; | ||
3408 | } | ||
3409 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3410 | #define patch_ad1988 ad1988_parse_auto_config | ||
3411 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3412 | |||
3413 | 892 | ||
3414 | /* | 893 | /* |
3415 | * AD1884 / AD1984 | 894 | * AD1884 / AD1984 |
@@ -3423,167 +902,19 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3423 | * | 902 | * |
3424 | * AD1984 = AD1884 + two digital mic-ins | 903 | * AD1984 = AD1884 + two digital mic-ins |
3425 | * | 904 | * |
3426 | * FIXME: | 905 | * AD1883 / AD1884A / AD1984A / AD1984B |
3427 | * For simplicity, we share the single DAC for both HP and line-outs | 906 | * |
3428 | * right now. The inidividual playbacks could be easily implemented, | 907 | * port-B (0x14) - front mic-in |
3429 | * but no build-up framework is given, so far. | 908 | * port-E (0x1c) - rear mic-in |
3430 | */ | 909 | * port-F (0x16) - CD / ext out |
3431 | 910 | * port-C (0x15) - rear line-in | |
3432 | #ifdef ENABLE_AD_STATIC_QUIRKS | 911 | * port-D (0x12) - rear line-out |
3433 | static const hda_nid_t ad1884_dac_nids[1] = { | 912 | * port-A (0x11) - front hp-out |
3434 | 0x04, | 913 | * |
3435 | }; | 914 | * AD1984A = AD1884A + digital-mic |
3436 | 915 | * AD1883 = equivalent with AD1984A | |
3437 | static const hda_nid_t ad1884_adc_nids[2] = { | 916 | * AD1984B = AD1984A + extra SPDIF-out |
3438 | 0x08, 0x09, | ||
3439 | }; | ||
3440 | |||
3441 | static const hda_nid_t ad1884_capsrc_nids[2] = { | ||
3442 | 0x0c, 0x0d, | ||
3443 | }; | ||
3444 | |||
3445 | #define AD1884_SPDIF_OUT 0x02 | ||
3446 | |||
3447 | static const struct hda_input_mux ad1884_capture_source = { | ||
3448 | .num_items = 4, | ||
3449 | .items = { | ||
3450 | { "Front Mic", 0x0 }, | ||
3451 | { "Mic", 0x1 }, | ||
3452 | { "CD", 0x2 }, | ||
3453 | { "Mix", 0x3 }, | ||
3454 | }, | ||
3455 | }; | ||
3456 | |||
3457 | static const struct snd_kcontrol_new ad1884_base_mixers[] = { | ||
3458 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3459 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | ||
3460 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3461 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3462 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3463 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3464 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3465 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3466 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3467 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3468 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||
3469 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||
3470 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3471 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3472 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3473 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3474 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3475 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3476 | { | ||
3477 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3478 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3479 | * So call somewhat different.. | ||
3480 | */ | ||
3481 | /* .name = "Capture Source", */ | ||
3482 | .name = "Input Source", | ||
3483 | .count = 2, | ||
3484 | .info = ad198x_mux_enum_info, | ||
3485 | .get = ad198x_mux_enum_get, | ||
3486 | .put = ad198x_mux_enum_put, | ||
3487 | }, | ||
3488 | /* SPDIF controls */ | ||
3489 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3490 | { | ||
3491 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3492 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3493 | /* identical with ad1983 */ | ||
3494 | .info = ad1983_spdif_route_info, | ||
3495 | .get = ad1983_spdif_route_get, | ||
3496 | .put = ad1983_spdif_route_put, | ||
3497 | }, | ||
3498 | { } /* end */ | ||
3499 | }; | ||
3500 | |||
3501 | static const struct snd_kcontrol_new ad1984_dmic_mixers[] = { | ||
3502 | HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT), | ||
3503 | HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT), | ||
3504 | HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0, | ||
3505 | HDA_INPUT), | ||
3506 | HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0, | ||
3507 | HDA_INPUT), | ||
3508 | { } /* end */ | ||
3509 | }; | ||
3510 | |||
3511 | /* | ||
3512 | * initialization verbs | ||
3513 | */ | 917 | */ |
3514 | static const struct hda_verb ad1884_init_verbs[] = { | ||
3515 | /* DACs; mute as default */ | ||
3516 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3517 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3518 | /* Port-A (HP) mixer */ | ||
3519 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3520 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3521 | /* Port-A pin */ | ||
3522 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3523 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3524 | /* HP selector - select DAC2 */ | ||
3525 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3526 | /* Port-D (Line-out) mixer */ | ||
3527 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3528 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3529 | /* Port-D pin */ | ||
3530 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3531 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3532 | /* Mono-out mixer */ | ||
3533 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3534 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3535 | /* Mono-out pin */ | ||
3536 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3537 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3538 | /* Mono selector */ | ||
3539 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3540 | /* Port-B (front mic) pin */ | ||
3541 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3542 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3543 | /* Port-C (rear mic) pin */ | ||
3544 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3545 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3546 | /* Analog mixer; mute as default */ | ||
3547 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3548 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3549 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
3550 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
3551 | /* Analog Mix output amp */ | ||
3552 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
3553 | /* SPDIF output selector */ | ||
3554 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
3555 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
3556 | { } /* end */ | ||
3557 | }; | ||
3558 | |||
3559 | #ifdef CONFIG_PM | ||
3560 | static const struct hda_amp_list ad1884_loopbacks[] = { | ||
3561 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
3562 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
3563 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
3564 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
3565 | { } /* end */ | ||
3566 | }; | ||
3567 | #endif | ||
3568 | |||
3569 | static const char * const ad1884_slave_vols[] = { | ||
3570 | "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD", | ||
3571 | "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958", | ||
3572 | NULL | ||
3573 | }; | ||
3574 | |||
3575 | enum { | ||
3576 | AD1884_AUTO, | ||
3577 | AD1884_BASIC, | ||
3578 | AD1884_MODELS | ||
3579 | }; | ||
3580 | |||
3581 | static const char * const ad1884_models[AD1884_MODELS] = { | ||
3582 | [AD1884_AUTO] = "auto", | ||
3583 | [AD1884_BASIC] = "basic", | ||
3584 | }; | ||
3585 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3586 | |||
3587 | 918 | ||
3588 | /* set the upper-limit for mixer amp to 0dB for avoiding the possible | 919 | /* set the upper-limit for mixer amp to 0dB for avoiding the possible |
3589 | * damage by overloading | 920 | * damage by overloading |
@@ -3599,14 +930,34 @@ static void ad1884_fixup_amp_override(struct hda_codec *codec, | |||
3599 | (1 << AC_AMPCAP_MUTE_SHIFT)); | 930 | (1 << AC_AMPCAP_MUTE_SHIFT)); |
3600 | } | 931 | } |
3601 | 932 | ||
933 | /* toggle GPIO1 according to the mute state */ | ||
934 | static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled) | ||
935 | { | ||
936 | struct hda_codec *codec = private_data; | ||
937 | struct ad198x_spec *spec = codec->spec; | ||
938 | |||
939 | if (spec->eapd_nid) | ||
940 | ad_vmaster_eapd_hook(private_data, enabled); | ||
941 | snd_hda_codec_update_cache(codec, 0x01, 0, | ||
942 | AC_VERB_SET_GPIO_DATA, | ||
943 | enabled ? 0x00 : 0x02); | ||
944 | } | ||
945 | |||
3602 | static void ad1884_fixup_hp_eapd(struct hda_codec *codec, | 946 | static void ad1884_fixup_hp_eapd(struct hda_codec *codec, |
3603 | const struct hda_fixup *fix, int action) | 947 | const struct hda_fixup *fix, int action) |
3604 | { | 948 | { |
3605 | struct ad198x_spec *spec = codec->spec; | 949 | struct ad198x_spec *spec = codec->spec; |
950 | static const struct hda_verb gpio_init_verbs[] = { | ||
951 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
952 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
953 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, | ||
954 | {}, | ||
955 | }; | ||
3606 | 956 | ||
3607 | switch (action) { | 957 | switch (action) { |
3608 | case HDA_FIXUP_ACT_PRE_PROBE: | 958 | case HDA_FIXUP_ACT_PRE_PROBE: |
3609 | spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; | 959 | spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook; |
960 | snd_hda_sequence_write_cache(codec, gpio_init_verbs); | ||
3610 | break; | 961 | break; |
3611 | case HDA_FIXUP_ACT_PROBE: | 962 | case HDA_FIXUP_ACT_PROBE: |
3612 | if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) | 963 | if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) |
@@ -3617,9 +968,18 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec, | |||
3617 | } | 968 | } |
3618 | } | 969 | } |
3619 | 970 | ||
971 | /* set magic COEFs for dmic */ | ||
972 | static const struct hda_verb ad1884_dmic_init_verbs[] = { | ||
973 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
974 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
975 | {} | ||
976 | }; | ||
977 | |||
3620 | enum { | 978 | enum { |
3621 | AD1884_FIXUP_AMP_OVERRIDE, | 979 | AD1884_FIXUP_AMP_OVERRIDE, |
3622 | AD1884_FIXUP_HP_EAPD, | 980 | AD1884_FIXUP_HP_EAPD, |
981 | AD1884_FIXUP_DMIC_COEF, | ||
982 | AD1884_FIXUP_HP_TOUCHSMART, | ||
3623 | }; | 983 | }; |
3624 | 984 | ||
3625 | static const struct hda_fixup ad1884_fixups[] = { | 985 | static const struct hda_fixup ad1884_fixups[] = { |
@@ -3633,15 +993,27 @@ static const struct hda_fixup ad1884_fixups[] = { | |||
3633 | .chained = true, | 993 | .chained = true, |
3634 | .chain_id = AD1884_FIXUP_AMP_OVERRIDE, | 994 | .chain_id = AD1884_FIXUP_AMP_OVERRIDE, |
3635 | }, | 995 | }, |
996 | [AD1884_FIXUP_DMIC_COEF] = { | ||
997 | .type = HDA_FIXUP_VERBS, | ||
998 | .v.verbs = ad1884_dmic_init_verbs, | ||
999 | }, | ||
1000 | [AD1884_FIXUP_HP_TOUCHSMART] = { | ||
1001 | .type = HDA_FIXUP_VERBS, | ||
1002 | .v.verbs = ad1884_dmic_init_verbs, | ||
1003 | .chained = true, | ||
1004 | .chain_id = AD1884_FIXUP_HP_EAPD, | ||
1005 | }, | ||
3636 | }; | 1006 | }; |
3637 | 1007 | ||
3638 | static const struct snd_pci_quirk ad1884_fixup_tbl[] = { | 1008 | static const struct snd_pci_quirk ad1884_fixup_tbl[] = { |
1009 | SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART), | ||
3639 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), | 1010 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), |
1011 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF), | ||
3640 | {} | 1012 | {} |
3641 | }; | 1013 | }; |
3642 | 1014 | ||
3643 | 1015 | ||
3644 | static int ad1884_parse_auto_config(struct hda_codec *codec) | 1016 | static int patch_ad1884(struct hda_codec *codec) |
3645 | { | 1017 | { |
3646 | struct ad198x_spec *spec; | 1018 | struct ad198x_spec *spec; |
3647 | int err; | 1019 | int err; |
@@ -3674,1170 +1046,6 @@ static int ad1884_parse_auto_config(struct hda_codec *codec) | |||
3674 | return err; | 1046 | return err; |
3675 | } | 1047 | } |
3676 | 1048 | ||
3677 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3678 | static int patch_ad1884_basic(struct hda_codec *codec) | ||
3679 | { | ||
3680 | struct ad198x_spec *spec; | ||
3681 | int err; | ||
3682 | |||
3683 | err = alloc_ad_spec(codec); | ||
3684 | if (err < 0) | ||
3685 | return err; | ||
3686 | spec = codec->spec; | ||
3687 | |||
3688 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
3689 | if (err < 0) { | ||
3690 | ad198x_free(codec); | ||
3691 | return err; | ||
3692 | } | ||
3693 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
3694 | |||
3695 | spec->multiout.max_channels = 2; | ||
3696 | spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids); | ||
3697 | spec->multiout.dac_nids = ad1884_dac_nids; | ||
3698 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | ||
3699 | spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids); | ||
3700 | spec->adc_nids = ad1884_adc_nids; | ||
3701 | spec->capsrc_nids = ad1884_capsrc_nids; | ||
3702 | spec->input_mux = &ad1884_capture_source; | ||
3703 | spec->num_mixers = 1; | ||
3704 | spec->mixers[0] = ad1884_base_mixers; | ||
3705 | spec->num_init_verbs = 1; | ||
3706 | spec->init_verbs[0] = ad1884_init_verbs; | ||
3707 | spec->spdif_route = 0; | ||
3708 | #ifdef CONFIG_PM | ||
3709 | spec->loopback.amplist = ad1884_loopbacks; | ||
3710 | #endif | ||
3711 | spec->vmaster_nid = 0x04; | ||
3712 | /* we need to cover all playback volumes */ | ||
3713 | spec->slave_vols = ad1884_slave_vols; | ||
3714 | /* slaves may contain input volumes, so we can't raise to 0dB blindly */ | ||
3715 | spec->avoid_init_slave_vol = 1; | ||
3716 | |||
3717 | codec->patch_ops = ad198x_patch_ops; | ||
3718 | |||
3719 | codec->no_trigger_sense = 1; | ||
3720 | codec->no_sticky_stream = 1; | ||
3721 | |||
3722 | return 0; | ||
3723 | } | ||
3724 | |||
3725 | static int patch_ad1884(struct hda_codec *codec) | ||
3726 | { | ||
3727 | int board_config; | ||
3728 | |||
3729 | board_config = snd_hda_check_board_config(codec, AD1884_MODELS, | ||
3730 | ad1884_models, NULL); | ||
3731 | if (board_config < 0) { | ||
3732 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3733 | codec->chip_name); | ||
3734 | board_config = AD1884_AUTO; | ||
3735 | } | ||
3736 | |||
3737 | if (board_config == AD1884_AUTO) | ||
3738 | return ad1884_parse_auto_config(codec); | ||
3739 | else | ||
3740 | return patch_ad1884_basic(codec); | ||
3741 | } | ||
3742 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3743 | #define patch_ad1884 ad1884_parse_auto_config | ||
3744 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3745 | |||
3746 | |||
3747 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3748 | /* | ||
3749 | * Lenovo Thinkpad T61/X61 | ||
3750 | */ | ||
3751 | static const struct hda_input_mux ad1984_thinkpad_capture_source = { | ||
3752 | .num_items = 4, | ||
3753 | .items = { | ||
3754 | { "Mic", 0x0 }, | ||
3755 | { "Internal Mic", 0x1 }, | ||
3756 | { "Mix", 0x3 }, | ||
3757 | { "Dock Mic", 0x4 }, | ||
3758 | }, | ||
3759 | }; | ||
3760 | |||
3761 | |||
3762 | /* | ||
3763 | * Dell Precision T3400 | ||
3764 | */ | ||
3765 | static const struct hda_input_mux ad1984_dell_desktop_capture_source = { | ||
3766 | .num_items = 3, | ||
3767 | .items = { | ||
3768 | { "Front Mic", 0x0 }, | ||
3769 | { "Line-In", 0x1 }, | ||
3770 | { "Mix", 0x3 }, | ||
3771 | }, | ||
3772 | }; | ||
3773 | |||
3774 | |||
3775 | static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | ||
3776 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3777 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | ||
3778 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3779 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3780 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3781 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3782 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3783 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3784 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
3785 | HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
3786 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
3787 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
3788 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3789 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3790 | HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
3791 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3792 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3793 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3794 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3795 | { | ||
3796 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3797 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3798 | * So call somewhat different.. | ||
3799 | */ | ||
3800 | /* .name = "Capture Source", */ | ||
3801 | .name = "Input Source", | ||
3802 | .count = 2, | ||
3803 | .info = ad198x_mux_enum_info, | ||
3804 | .get = ad198x_mux_enum_get, | ||
3805 | .put = ad198x_mux_enum_put, | ||
3806 | }, | ||
3807 | /* SPDIF controls */ | ||
3808 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3809 | { | ||
3810 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3811 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3812 | /* identical with ad1983 */ | ||
3813 | .info = ad1983_spdif_route_info, | ||
3814 | .get = ad1983_spdif_route_get, | ||
3815 | .put = ad1983_spdif_route_put, | ||
3816 | }, | ||
3817 | { } /* end */ | ||
3818 | }; | ||
3819 | |||
3820 | /* additional verbs */ | ||
3821 | static const struct hda_verb ad1984_thinkpad_init_verbs[] = { | ||
3822 | /* Port-E (docking station mic) pin */ | ||
3823 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3824 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3825 | /* docking mic boost */ | ||
3826 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3827 | /* Analog PC Beeper - allow firmware/ACPI beeps */ | ||
3828 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a}, | ||
3829 | /* Analog mixer - docking mic; mute as default */ | ||
3830 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
3831 | /* enable EAPD bit */ | ||
3832 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
3833 | { } /* end */ | ||
3834 | }; | ||
3835 | |||
3836 | /* | ||
3837 | * Dell Precision T3400 | ||
3838 | */ | ||
3839 | static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { | ||
3840 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3841 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3842 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3843 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3844 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3845 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3846 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3847 | HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3848 | HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3849 | HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3850 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3851 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3852 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3853 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3854 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3855 | { | ||
3856 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3857 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3858 | * So call somewhat different.. | ||
3859 | */ | ||
3860 | /* .name = "Capture Source", */ | ||
3861 | .name = "Input Source", | ||
3862 | .count = 2, | ||
3863 | .info = ad198x_mux_enum_info, | ||
3864 | .get = ad198x_mux_enum_get, | ||
3865 | .put = ad198x_mux_enum_put, | ||
3866 | }, | ||
3867 | { } /* end */ | ||
3868 | }; | ||
3869 | |||
3870 | /* Digial MIC ADC NID 0x05 + 0x06 */ | ||
3871 | static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, | ||
3872 | struct hda_codec *codec, | ||
3873 | unsigned int stream_tag, | ||
3874 | unsigned int format, | ||
3875 | struct snd_pcm_substream *substream) | ||
3876 | { | ||
3877 | snd_hda_codec_setup_stream(codec, 0x05 + substream->number, | ||
3878 | stream_tag, 0, format); | ||
3879 | return 0; | ||
3880 | } | ||
3881 | |||
3882 | static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, | ||
3883 | struct hda_codec *codec, | ||
3884 | struct snd_pcm_substream *substream) | ||
3885 | { | ||
3886 | snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number); | ||
3887 | return 0; | ||
3888 | } | ||
3889 | |||
3890 | static const struct hda_pcm_stream ad1984_pcm_dmic_capture = { | ||
3891 | .substreams = 2, | ||
3892 | .channels_min = 2, | ||
3893 | .channels_max = 2, | ||
3894 | .nid = 0x05, | ||
3895 | .ops = { | ||
3896 | .prepare = ad1984_pcm_dmic_prepare, | ||
3897 | .cleanup = ad1984_pcm_dmic_cleanup | ||
3898 | }, | ||
3899 | }; | ||
3900 | |||
3901 | static int ad1984_build_pcms(struct hda_codec *codec) | ||
3902 | { | ||
3903 | struct ad198x_spec *spec = codec->spec; | ||
3904 | struct hda_pcm *info; | ||
3905 | int err; | ||
3906 | |||
3907 | err = ad198x_build_pcms(codec); | ||
3908 | if (err < 0) | ||
3909 | return err; | ||
3910 | |||
3911 | info = spec->pcm_rec + codec->num_pcms; | ||
3912 | codec->num_pcms++; | ||
3913 | info->name = "AD1984 Digital Mic"; | ||
3914 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture; | ||
3915 | return 0; | ||
3916 | } | ||
3917 | |||
3918 | /* models */ | ||
3919 | enum { | ||
3920 | AD1984_AUTO, | ||
3921 | AD1984_BASIC, | ||
3922 | AD1984_THINKPAD, | ||
3923 | AD1984_DELL_DESKTOP, | ||
3924 | AD1984_MODELS | ||
3925 | }; | ||
3926 | |||
3927 | static const char * const ad1984_models[AD1984_MODELS] = { | ||
3928 | [AD1984_AUTO] = "auto", | ||
3929 | [AD1984_BASIC] = "basic", | ||
3930 | [AD1984_THINKPAD] = "thinkpad", | ||
3931 | [AD1984_DELL_DESKTOP] = "dell_desktop", | ||
3932 | }; | ||
3933 | |||
3934 | static const struct snd_pci_quirk ad1984_cfg_tbl[] = { | ||
3935 | /* Lenovo Thinkpad T61/X61 */ | ||
3936 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), | ||
3937 | SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), | ||
3938 | SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP), | ||
3939 | {} | ||
3940 | }; | ||
3941 | |||
3942 | static int patch_ad1984(struct hda_codec *codec) | ||
3943 | { | ||
3944 | struct ad198x_spec *spec; | ||
3945 | int board_config, err; | ||
3946 | |||
3947 | board_config = snd_hda_check_board_config(codec, AD1984_MODELS, | ||
3948 | ad1984_models, ad1984_cfg_tbl); | ||
3949 | if (board_config < 0) { | ||
3950 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3951 | codec->chip_name); | ||
3952 | board_config = AD1984_AUTO; | ||
3953 | } | ||
3954 | |||
3955 | if (board_config == AD1984_AUTO) | ||
3956 | return ad1884_parse_auto_config(codec); | ||
3957 | |||
3958 | err = patch_ad1884_basic(codec); | ||
3959 | if (err < 0) | ||
3960 | return err; | ||
3961 | spec = codec->spec; | ||
3962 | |||
3963 | switch (board_config) { | ||
3964 | case AD1984_BASIC: | ||
3965 | /* additional digital mics */ | ||
3966 | spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers; | ||
3967 | codec->patch_ops.build_pcms = ad1984_build_pcms; | ||
3968 | break; | ||
3969 | case AD1984_THINKPAD: | ||
3970 | if (codec->subsystem_id == 0x17aa20fb) { | ||
3971 | /* Thinpad X300 does not have the ability to do SPDIF, | ||
3972 | or attach to docking station to use SPDIF */ | ||
3973 | spec->multiout.dig_out_nid = 0; | ||
3974 | } else | ||
3975 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | ||
3976 | spec->input_mux = &ad1984_thinkpad_capture_source; | ||
3977 | spec->mixers[0] = ad1984_thinkpad_mixers; | ||
3978 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; | ||
3979 | spec->analog_beep = 1; | ||
3980 | break; | ||
3981 | case AD1984_DELL_DESKTOP: | ||
3982 | spec->multiout.dig_out_nid = 0; | ||
3983 | spec->input_mux = &ad1984_dell_desktop_capture_source; | ||
3984 | spec->mixers[0] = ad1984_dell_desktop_mixers; | ||
3985 | break; | ||
3986 | } | ||
3987 | return 0; | ||
3988 | } | ||
3989 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3990 | #define patch_ad1984 ad1884_parse_auto_config | ||
3991 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3992 | |||
3993 | |||
3994 | /* | ||
3995 | * AD1883 / AD1884A / AD1984A / AD1984B | ||
3996 | * | ||
3997 | * port-B (0x14) - front mic-in | ||
3998 | * port-E (0x1c) - rear mic-in | ||
3999 | * port-F (0x16) - CD / ext out | ||
4000 | * port-C (0x15) - rear line-in | ||
4001 | * port-D (0x12) - rear line-out | ||
4002 | * port-A (0x11) - front hp-out | ||
4003 | * | ||
4004 | * AD1984A = AD1884A + digital-mic | ||
4005 | * AD1883 = equivalent with AD1984A | ||
4006 | * AD1984B = AD1984A + extra SPDIF-out | ||
4007 | * | ||
4008 | * FIXME: | ||
4009 | * We share the single DAC for both HP and line-outs (see AD1884/1984). | ||
4010 | */ | ||
4011 | |||
4012 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
4013 | static const hda_nid_t ad1884a_dac_nids[1] = { | ||
4014 | 0x03, | ||
4015 | }; | ||
4016 | |||
4017 | #define ad1884a_adc_nids ad1884_adc_nids | ||
4018 | #define ad1884a_capsrc_nids ad1884_capsrc_nids | ||
4019 | |||
4020 | #define AD1884A_SPDIF_OUT 0x02 | ||
4021 | |||
4022 | static const struct hda_input_mux ad1884a_capture_source = { | ||
4023 | .num_items = 5, | ||
4024 | .items = { | ||
4025 | { "Front Mic", 0x0 }, | ||
4026 | { "Mic", 0x4 }, | ||
4027 | { "Line", 0x1 }, | ||
4028 | { "CD", 0x2 }, | ||
4029 | { "Mix", 0x3 }, | ||
4030 | }, | ||
4031 | }; | ||
4032 | |||
4033 | static const struct snd_kcontrol_new ad1884a_base_mixers[] = { | ||
4034 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4035 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4036 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
4037 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4038 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4039 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4040 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4041 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4042 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4043 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4044 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4045 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4046 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4047 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4048 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||
4049 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||
4050 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4051 | HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4052 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4053 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4054 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4055 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4056 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4057 | { | ||
4058 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4059 | /* The multiple "Capture Source" controls confuse alsamixer | ||
4060 | * So call somewhat different.. | ||
4061 | */ | ||
4062 | /* .name = "Capture Source", */ | ||
4063 | .name = "Input Source", | ||
4064 | .count = 2, | ||
4065 | .info = ad198x_mux_enum_info, | ||
4066 | .get = ad198x_mux_enum_get, | ||
4067 | .put = ad198x_mux_enum_put, | ||
4068 | }, | ||
4069 | /* SPDIF controls */ | ||
4070 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
4071 | { | ||
4072 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4073 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
4074 | /* identical with ad1983 */ | ||
4075 | .info = ad1983_spdif_route_info, | ||
4076 | .get = ad1983_spdif_route_get, | ||
4077 | .put = ad1983_spdif_route_put, | ||
4078 | }, | ||
4079 | { } /* end */ | ||
4080 | }; | ||
4081 | |||
4082 | /* | ||
4083 | * initialization verbs | ||
4084 | */ | ||
4085 | static const struct hda_verb ad1884a_init_verbs[] = { | ||
4086 | /* DACs; unmute as default */ | ||
4087 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4088 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4089 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4090 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4091 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4092 | /* Port-A pin */ | ||
4093 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4094 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4095 | /* Port-D (Line-out) mixer - route only from analog mixer */ | ||
4096 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4097 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4098 | /* Port-D pin */ | ||
4099 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4100 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4101 | /* Mono-out mixer - route only from analog mixer */ | ||
4102 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4103 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4104 | /* Mono-out pin */ | ||
4105 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4106 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4107 | /* Port-B (front mic) pin */ | ||
4108 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4109 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4110 | /* Port-C (rear line-in) pin */ | ||
4111 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4112 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4113 | /* Port-E (rear mic) pin */ | ||
4114 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4115 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4116 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */ | ||
4117 | /* Port-F (CD) pin */ | ||
4118 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4119 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4120 | /* Analog mixer; mute as default */ | ||
4121 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4122 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4123 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4124 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4125 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */ | ||
4126 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4127 | /* Analog Mix output amp */ | ||
4128 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4129 | /* capture sources */ | ||
4130 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4131 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4132 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4133 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4134 | /* SPDIF output amp */ | ||
4135 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
4136 | { } /* end */ | ||
4137 | }; | ||
4138 | |||
4139 | #ifdef CONFIG_PM | ||
4140 | static const struct hda_amp_list ad1884a_loopbacks[] = { | ||
4141 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
4142 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
4143 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
4144 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
4145 | { } /* end */ | ||
4146 | }; | ||
4147 | #endif | ||
4148 | |||
4149 | /* | ||
4150 | * Laptop model | ||
4151 | * | ||
4152 | * Port A: Headphone jack | ||
4153 | * Port B: MIC jack | ||
4154 | * Port C: Internal MIC | ||
4155 | * Port D: Dock Line Out (if enabled) | ||
4156 | * Port E: Dock Line In (if enabled) | ||
4157 | * Port F: Internal speakers | ||
4158 | */ | ||
4159 | |||
4160 | static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, | ||
4161 | struct snd_ctl_elem_value *ucontrol) | ||
4162 | { | ||
4163 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4164 | int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
4165 | int mute = (!ucontrol->value.integer.value[0] && | ||
4166 | !ucontrol->value.integer.value[1]); | ||
4167 | /* toggle GPIO1 according to the mute state */ | ||
4168 | snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
4169 | mute ? 0x02 : 0x0); | ||
4170 | return ret; | ||
4171 | } | ||
4172 | |||
4173 | static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | ||
4174 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4175 | { | ||
4176 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4177 | .name = "Master Playback Switch", | ||
4178 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4179 | .info = snd_hda_mixer_amp_switch_info, | ||
4180 | .get = snd_hda_mixer_amp_switch_get, | ||
4181 | .put = ad1884a_mobile_master_sw_put, | ||
4182 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4183 | }, | ||
4184 | HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4185 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4186 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4187 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4188 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4189 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4190 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4191 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4192 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4193 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4194 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4195 | HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4196 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4197 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4198 | { } /* end */ | ||
4199 | }; | ||
4200 | |||
4201 | static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | ||
4202 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4203 | /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | ||
4204 | { | ||
4205 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4206 | .name = "Master Playback Switch", | ||
4207 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4208 | .info = snd_hda_mixer_amp_switch_info, | ||
4209 | .get = snd_hda_mixer_amp_switch_get, | ||
4210 | .put = ad1884a_mobile_master_sw_put, | ||
4211 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4212 | }, | ||
4213 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4214 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4215 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT), | ||
4216 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT), | ||
4217 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4218 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4219 | { } /* end */ | ||
4220 | }; | ||
4221 | |||
4222 | /* mute internal speaker if HP is plugged */ | ||
4223 | static void ad1884a_hp_automute(struct hda_codec *codec) | ||
4224 | { | ||
4225 | unsigned int present; | ||
4226 | |||
4227 | present = snd_hda_jack_detect(codec, 0x11); | ||
4228 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
4229 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4230 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
4231 | present ? 0x00 : 0x02); | ||
4232 | } | ||
4233 | |||
4234 | /* switch to external mic if plugged */ | ||
4235 | static void ad1884a_hp_automic(struct hda_codec *codec) | ||
4236 | { | ||
4237 | unsigned int present; | ||
4238 | |||
4239 | present = snd_hda_jack_detect(codec, 0x14); | ||
4240 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, | ||
4241 | present ? 0 : 1); | ||
4242 | } | ||
4243 | |||
4244 | #define AD1884A_HP_EVENT 0x37 | ||
4245 | #define AD1884A_MIC_EVENT 0x36 | ||
4246 | |||
4247 | /* unsolicited event for HP jack sensing */ | ||
4248 | static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4249 | { | ||
4250 | switch (res >> 26) { | ||
4251 | case AD1884A_HP_EVENT: | ||
4252 | ad1884a_hp_automute(codec); | ||
4253 | break; | ||
4254 | case AD1884A_MIC_EVENT: | ||
4255 | ad1884a_hp_automic(codec); | ||
4256 | break; | ||
4257 | } | ||
4258 | } | ||
4259 | |||
4260 | /* initialize jack-sensing, too */ | ||
4261 | static int ad1884a_hp_init(struct hda_codec *codec) | ||
4262 | { | ||
4263 | ad198x_init(codec); | ||
4264 | ad1884a_hp_automute(codec); | ||
4265 | ad1884a_hp_automic(codec); | ||
4266 | return 0; | ||
4267 | } | ||
4268 | |||
4269 | /* mute internal speaker if HP or docking HP is plugged */ | ||
4270 | static void ad1884a_laptop_automute(struct hda_codec *codec) | ||
4271 | { | ||
4272 | unsigned int present; | ||
4273 | |||
4274 | present = snd_hda_jack_detect(codec, 0x11); | ||
4275 | if (!present) | ||
4276 | present = snd_hda_jack_detect(codec, 0x12); | ||
4277 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
4278 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4279 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
4280 | present ? 0x00 : 0x02); | ||
4281 | } | ||
4282 | |||
4283 | /* switch to external mic if plugged */ | ||
4284 | static void ad1884a_laptop_automic(struct hda_codec *codec) | ||
4285 | { | ||
4286 | unsigned int idx; | ||
4287 | |||
4288 | if (snd_hda_jack_detect(codec, 0x14)) | ||
4289 | idx = 0; | ||
4290 | else if (snd_hda_jack_detect(codec, 0x1c)) | ||
4291 | idx = 4; | ||
4292 | else | ||
4293 | idx = 1; | ||
4294 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx); | ||
4295 | } | ||
4296 | |||
4297 | /* unsolicited event for HP jack sensing */ | ||
4298 | static void ad1884a_laptop_unsol_event(struct hda_codec *codec, | ||
4299 | unsigned int res) | ||
4300 | { | ||
4301 | switch (res >> 26) { | ||
4302 | case AD1884A_HP_EVENT: | ||
4303 | ad1884a_laptop_automute(codec); | ||
4304 | break; | ||
4305 | case AD1884A_MIC_EVENT: | ||
4306 | ad1884a_laptop_automic(codec); | ||
4307 | break; | ||
4308 | } | ||
4309 | } | ||
4310 | |||
4311 | /* initialize jack-sensing, too */ | ||
4312 | static int ad1884a_laptop_init(struct hda_codec *codec) | ||
4313 | { | ||
4314 | ad198x_init(codec); | ||
4315 | ad1884a_laptop_automute(codec); | ||
4316 | ad1884a_laptop_automic(codec); | ||
4317 | return 0; | ||
4318 | } | ||
4319 | |||
4320 | /* additional verbs for laptop model */ | ||
4321 | static const struct hda_verb ad1884a_laptop_verbs[] = { | ||
4322 | /* Port-A (HP) pin - always unmuted */ | ||
4323 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4324 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4325 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4326 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4327 | /* Port-F (int speaker) pin */ | ||
4328 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4329 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4330 | /* required for compaq 6530s/6531s speaker output */ | ||
4331 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4332 | /* Port-C pin - internal mic-in */ | ||
4333 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4334 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4335 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4336 | /* Port-D (docking line-out) pin - default unmuted */ | ||
4337 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4338 | /* analog mix */ | ||
4339 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4340 | /* unsolicited event for pin-sense */ | ||
4341 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4342 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4343 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4344 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4345 | /* allow to touch GPIO1 (for mute control) */ | ||
4346 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4347 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4348 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4349 | { } /* end */ | ||
4350 | }; | ||
4351 | |||
4352 | static const struct hda_verb ad1884a_mobile_verbs[] = { | ||
4353 | /* DACs; unmute as default */ | ||
4354 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4355 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4356 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4357 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4358 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4359 | /* Port-A pin */ | ||
4360 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4361 | /* Port-A (HP) pin - always unmuted */ | ||
4362 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4363 | /* Port-B (mic jack) pin */ | ||
4364 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4365 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4366 | /* Port-C (int mic) pin */ | ||
4367 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4368 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4369 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4370 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4371 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4372 | /* Port-F pin */ | ||
4373 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4374 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4375 | /* Analog mixer; mute as default */ | ||
4376 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4377 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4378 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4379 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4380 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4381 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4382 | /* Analog Mix output amp */ | ||
4383 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4384 | /* capture sources */ | ||
4385 | /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ | ||
4386 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4387 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4388 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4389 | /* unsolicited event for pin-sense */ | ||
4390 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4391 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4392 | /* allow to touch GPIO1 (for mute control) */ | ||
4393 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4394 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4395 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4396 | { } /* end */ | ||
4397 | }; | ||
4398 | |||
4399 | /* | ||
4400 | * Thinkpad X300 | ||
4401 | * 0x11 - HP | ||
4402 | * 0x12 - speaker | ||
4403 | * 0x14 - mic-in | ||
4404 | * 0x17 - built-in mic | ||
4405 | */ | ||
4406 | |||
4407 | static const struct hda_verb ad1984a_thinkpad_verbs[] = { | ||
4408 | /* HP unmute */ | ||
4409 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4410 | /* analog mix */ | ||
4411 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4412 | /* turn on EAPD */ | ||
4413 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
4414 | /* unsolicited event for pin-sense */ | ||
4415 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4416 | /* internal mic - dmic */ | ||
4417 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4418 | /* set magic COEFs for dmic */ | ||
4419 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
4420 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
4421 | { } /* end */ | ||
4422 | }; | ||
4423 | |||
4424 | static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { | ||
4425 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4426 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4427 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4428 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4429 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4430 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4431 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4432 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), | ||
4433 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4434 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4435 | { | ||
4436 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4437 | .name = "Capture Source", | ||
4438 | .info = ad198x_mux_enum_info, | ||
4439 | .get = ad198x_mux_enum_get, | ||
4440 | .put = ad198x_mux_enum_put, | ||
4441 | }, | ||
4442 | { } /* end */ | ||
4443 | }; | ||
4444 | |||
4445 | static const struct hda_input_mux ad1984a_thinkpad_capture_source = { | ||
4446 | .num_items = 3, | ||
4447 | .items = { | ||
4448 | { "Mic", 0x0 }, | ||
4449 | { "Internal Mic", 0x5 }, | ||
4450 | { "Mix", 0x3 }, | ||
4451 | }, | ||
4452 | }; | ||
4453 | |||
4454 | /* mute internal speaker if HP is plugged */ | ||
4455 | static void ad1984a_thinkpad_automute(struct hda_codec *codec) | ||
4456 | { | ||
4457 | unsigned int present; | ||
4458 | |||
4459 | present = snd_hda_jack_detect(codec, 0x11); | ||
4460 | snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, | ||
4461 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4462 | } | ||
4463 | |||
4464 | /* unsolicited event for HP jack sensing */ | ||
4465 | static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec, | ||
4466 | unsigned int res) | ||
4467 | { | ||
4468 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
4469 | return; | ||
4470 | ad1984a_thinkpad_automute(codec); | ||
4471 | } | ||
4472 | |||
4473 | /* initialize jack-sensing, too */ | ||
4474 | static int ad1984a_thinkpad_init(struct hda_codec *codec) | ||
4475 | { | ||
4476 | ad198x_init(codec); | ||
4477 | ad1984a_thinkpad_automute(codec); | ||
4478 | return 0; | ||
4479 | } | ||
4480 | |||
4481 | /* | ||
4482 | * Precision R5500 | ||
4483 | * 0x12 - HP/line-out | ||
4484 | * 0x13 - speaker (mono) | ||
4485 | * 0x15 - mic-in | ||
4486 | */ | ||
4487 | |||
4488 | static const struct hda_verb ad1984a_precision_verbs[] = { | ||
4489 | /* Unmute main output path */ | ||
4490 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4491 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ | ||
4492 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */ | ||
4493 | /* Analog mixer; mute as default */ | ||
4494 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4495 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4496 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4497 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4498 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4499 | /* Select mic as input */ | ||
4500 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
4501 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */ | ||
4502 | /* Configure as mic */ | ||
4503 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4504 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4505 | /* HP unmute */ | ||
4506 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4507 | /* turn on EAPD */ | ||
4508 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
4509 | /* unsolicited event for pin-sense */ | ||
4510 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4511 | { } /* end */ | ||
4512 | }; | ||
4513 | |||
4514 | static const struct snd_kcontrol_new ad1984a_precision_mixers[] = { | ||
4515 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4516 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4517 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4518 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4519 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4520 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4521 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4522 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4523 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
4524 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4525 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4526 | { } /* end */ | ||
4527 | }; | ||
4528 | |||
4529 | |||
4530 | /* mute internal speaker if HP is plugged */ | ||
4531 | static void ad1984a_precision_automute(struct hda_codec *codec) | ||
4532 | { | ||
4533 | unsigned int present; | ||
4534 | |||
4535 | present = snd_hda_jack_detect(codec, 0x12); | ||
4536 | snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, | ||
4537 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4538 | } | ||
4539 | |||
4540 | |||
4541 | /* unsolicited event for HP jack sensing */ | ||
4542 | static void ad1984a_precision_unsol_event(struct hda_codec *codec, | ||
4543 | unsigned int res) | ||
4544 | { | ||
4545 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
4546 | return; | ||
4547 | ad1984a_precision_automute(codec); | ||
4548 | } | ||
4549 | |||
4550 | /* initialize jack-sensing, too */ | ||
4551 | static int ad1984a_precision_init(struct hda_codec *codec) | ||
4552 | { | ||
4553 | ad198x_init(codec); | ||
4554 | ad1984a_precision_automute(codec); | ||
4555 | return 0; | ||
4556 | } | ||
4557 | |||
4558 | |||
4559 | /* | ||
4560 | * HP Touchsmart | ||
4561 | * port-A (0x11) - front hp-out | ||
4562 | * port-B (0x14) - unused | ||
4563 | * port-C (0x15) - unused | ||
4564 | * port-D (0x12) - rear line out | ||
4565 | * port-E (0x1c) - front mic-in | ||
4566 | * port-F (0x16) - Internal speakers | ||
4567 | * digital-mic (0x17) - Internal mic | ||
4568 | */ | ||
4569 | |||
4570 | static const struct hda_verb ad1984a_touchsmart_verbs[] = { | ||
4571 | /* DACs; unmute as default */ | ||
4572 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4573 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4574 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4575 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4576 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4577 | /* Port-A pin */ | ||
4578 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4579 | /* Port-A (HP) pin - always unmuted */ | ||
4580 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4581 | /* Port-E (int speaker) mixer - route only from analog mixer */ | ||
4582 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03}, | ||
4583 | /* Port-E pin */ | ||
4584 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4585 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4586 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4587 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4588 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4589 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4590 | /* Port-F pin */ | ||
4591 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4592 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4593 | /* Analog mixer; mute as default */ | ||
4594 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4595 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4596 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4597 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4598 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4599 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4600 | /* Analog Mix output amp */ | ||
4601 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4602 | /* capture sources */ | ||
4603 | /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ | ||
4604 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4605 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4606 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4607 | /* unsolicited event for pin-sense */ | ||
4608 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4609 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4610 | /* allow to touch GPIO1 (for mute control) */ | ||
4611 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4612 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4613 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4614 | /* internal mic - dmic */ | ||
4615 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4616 | /* set magic COEFs for dmic */ | ||
4617 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
4618 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
4619 | { } /* end */ | ||
4620 | }; | ||
4621 | |||
4622 | static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | ||
4623 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4624 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | ||
4625 | { | ||
4626 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4627 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4628 | .name = "Master Playback Switch", | ||
4629 | .info = snd_hda_mixer_amp_switch_info, | ||
4630 | .get = snd_hda_mixer_amp_switch_get, | ||
4631 | .put = ad1884a_mobile_master_sw_put, | ||
4632 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4633 | }, | ||
4634 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4635 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4636 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4637 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4638 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4639 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), | ||
4640 | { } /* end */ | ||
4641 | }; | ||
4642 | |||
4643 | /* switch to external mic if plugged */ | ||
4644 | static void ad1984a_touchsmart_automic(struct hda_codec *codec) | ||
4645 | { | ||
4646 | if (snd_hda_jack_detect(codec, 0x1c)) | ||
4647 | snd_hda_codec_write(codec, 0x0c, 0, | ||
4648 | AC_VERB_SET_CONNECT_SEL, 0x4); | ||
4649 | else | ||
4650 | snd_hda_codec_write(codec, 0x0c, 0, | ||
4651 | AC_VERB_SET_CONNECT_SEL, 0x5); | ||
4652 | } | ||
4653 | |||
4654 | |||
4655 | /* unsolicited event for HP jack sensing */ | ||
4656 | static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec, | ||
4657 | unsigned int res) | ||
4658 | { | ||
4659 | switch (res >> 26) { | ||
4660 | case AD1884A_HP_EVENT: | ||
4661 | ad1884a_hp_automute(codec); | ||
4662 | break; | ||
4663 | case AD1884A_MIC_EVENT: | ||
4664 | ad1984a_touchsmart_automic(codec); | ||
4665 | break; | ||
4666 | } | ||
4667 | } | ||
4668 | |||
4669 | /* initialize jack-sensing, too */ | ||
4670 | static int ad1984a_touchsmart_init(struct hda_codec *codec) | ||
4671 | { | ||
4672 | ad198x_init(codec); | ||
4673 | ad1884a_hp_automute(codec); | ||
4674 | ad1984a_touchsmart_automic(codec); | ||
4675 | return 0; | ||
4676 | } | ||
4677 | |||
4678 | |||
4679 | /* | ||
4680 | */ | ||
4681 | |||
4682 | enum { | ||
4683 | AD1884A_AUTO, | ||
4684 | AD1884A_DESKTOP, | ||
4685 | AD1884A_LAPTOP, | ||
4686 | AD1884A_MOBILE, | ||
4687 | AD1884A_THINKPAD, | ||
4688 | AD1984A_TOUCHSMART, | ||
4689 | AD1984A_PRECISION, | ||
4690 | AD1884A_MODELS | ||
4691 | }; | ||
4692 | |||
4693 | static const char * const ad1884a_models[AD1884A_MODELS] = { | ||
4694 | [AD1884A_AUTO] = "auto", | ||
4695 | [AD1884A_DESKTOP] = "desktop", | ||
4696 | [AD1884A_LAPTOP] = "laptop", | ||
4697 | [AD1884A_MOBILE] = "mobile", | ||
4698 | [AD1884A_THINKPAD] = "thinkpad", | ||
4699 | [AD1984A_TOUCHSMART] = "touchsmart", | ||
4700 | [AD1984A_PRECISION] = "precision", | ||
4701 | }; | ||
4702 | |||
4703 | static const struct snd_pci_quirk ad1884a_cfg_tbl[] = { | ||
4704 | SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), | ||
4705 | SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), | ||
4706 | SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), | ||
4707 | SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), | ||
4708 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE), | ||
4709 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP), | ||
4710 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), | ||
4711 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), | ||
4712 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), | ||
4713 | SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), | ||
4714 | SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART), | ||
4715 | {} | ||
4716 | }; | ||
4717 | |||
4718 | static int patch_ad1884a(struct hda_codec *codec) | ||
4719 | { | ||
4720 | struct ad198x_spec *spec; | ||
4721 | int err, board_config; | ||
4722 | |||
4723 | board_config = snd_hda_check_board_config(codec, AD1884A_MODELS, | ||
4724 | ad1884a_models, | ||
4725 | ad1884a_cfg_tbl); | ||
4726 | if (board_config < 0) { | ||
4727 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
4728 | codec->chip_name); | ||
4729 | board_config = AD1884A_AUTO; | ||
4730 | } | ||
4731 | |||
4732 | if (board_config == AD1884A_AUTO) | ||
4733 | return ad1884_parse_auto_config(codec); | ||
4734 | |||
4735 | err = alloc_ad_spec(codec); | ||
4736 | if (err < 0) | ||
4737 | return err; | ||
4738 | spec = codec->spec; | ||
4739 | |||
4740 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
4741 | if (err < 0) { | ||
4742 | ad198x_free(codec); | ||
4743 | return err; | ||
4744 | } | ||
4745 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
4746 | |||
4747 | spec->multiout.max_channels = 2; | ||
4748 | spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids); | ||
4749 | spec->multiout.dac_nids = ad1884a_dac_nids; | ||
4750 | spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT; | ||
4751 | spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids); | ||
4752 | spec->adc_nids = ad1884a_adc_nids; | ||
4753 | spec->capsrc_nids = ad1884a_capsrc_nids; | ||
4754 | spec->input_mux = &ad1884a_capture_source; | ||
4755 | spec->num_mixers = 1; | ||
4756 | spec->mixers[0] = ad1884a_base_mixers; | ||
4757 | spec->num_init_verbs = 1; | ||
4758 | spec->init_verbs[0] = ad1884a_init_verbs; | ||
4759 | spec->spdif_route = 0; | ||
4760 | #ifdef CONFIG_PM | ||
4761 | spec->loopback.amplist = ad1884a_loopbacks; | ||
4762 | #endif | ||
4763 | codec->patch_ops = ad198x_patch_ops; | ||
4764 | |||
4765 | /* override some parameters */ | ||
4766 | switch (board_config) { | ||
4767 | case AD1884A_LAPTOP: | ||
4768 | spec->mixers[0] = ad1884a_laptop_mixers; | ||
4769 | spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; | ||
4770 | spec->multiout.dig_out_nid = 0; | ||
4771 | codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event; | ||
4772 | codec->patch_ops.init = ad1884a_laptop_init; | ||
4773 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4774 | * possible damage by overloading | ||
4775 | */ | ||
4776 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4777 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4778 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4779 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4780 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4781 | break; | ||
4782 | case AD1884A_MOBILE: | ||
4783 | spec->mixers[0] = ad1884a_mobile_mixers; | ||
4784 | spec->init_verbs[0] = ad1884a_mobile_verbs; | ||
4785 | spec->multiout.dig_out_nid = 0; | ||
4786 | codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; | ||
4787 | codec->patch_ops.init = ad1884a_hp_init; | ||
4788 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4789 | * possible damage by overloading | ||
4790 | */ | ||
4791 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4792 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4793 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4794 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4795 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4796 | break; | ||
4797 | case AD1884A_THINKPAD: | ||
4798 | spec->mixers[0] = ad1984a_thinkpad_mixers; | ||
4799 | spec->init_verbs[spec->num_init_verbs++] = | ||
4800 | ad1984a_thinkpad_verbs; | ||
4801 | spec->multiout.dig_out_nid = 0; | ||
4802 | spec->input_mux = &ad1984a_thinkpad_capture_source; | ||
4803 | codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; | ||
4804 | codec->patch_ops.init = ad1984a_thinkpad_init; | ||
4805 | break; | ||
4806 | case AD1984A_PRECISION: | ||
4807 | spec->mixers[0] = ad1984a_precision_mixers; | ||
4808 | spec->init_verbs[spec->num_init_verbs++] = | ||
4809 | ad1984a_precision_verbs; | ||
4810 | spec->multiout.dig_out_nid = 0; | ||
4811 | codec->patch_ops.unsol_event = ad1984a_precision_unsol_event; | ||
4812 | codec->patch_ops.init = ad1984a_precision_init; | ||
4813 | break; | ||
4814 | case AD1984A_TOUCHSMART: | ||
4815 | spec->mixers[0] = ad1984a_touchsmart_mixers; | ||
4816 | spec->init_verbs[0] = ad1984a_touchsmart_verbs; | ||
4817 | spec->multiout.dig_out_nid = 0; | ||
4818 | codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event; | ||
4819 | codec->patch_ops.init = ad1984a_touchsmart_init; | ||
4820 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4821 | * possible damage by overloading | ||
4822 | */ | ||
4823 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4824 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4825 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4826 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4827 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4828 | break; | ||
4829 | } | ||
4830 | |||
4831 | codec->no_trigger_sense = 1; | ||
4832 | codec->no_sticky_stream = 1; | ||
4833 | |||
4834 | return 0; | ||
4835 | } | ||
4836 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
4837 | #define patch_ad1884a ad1884_parse_auto_config | ||
4838 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
4839 | |||
4840 | |||
4841 | /* | 1049 | /* |
4842 | * AD1882 / AD1882A | 1050 | * AD1882 / AD1882A |
4843 | * | 1051 | * |
@@ -4850,299 +1058,7 @@ static int patch_ad1884a(struct hda_codec *codec) | |||
4850 | * port-G - rear clfe-out (6stack) | 1058 | * port-G - rear clfe-out (6stack) |
4851 | */ | 1059 | */ |
4852 | 1060 | ||
4853 | #ifdef ENABLE_AD_STATIC_QUIRKS | 1061 | static int patch_ad1882(struct hda_codec *codec) |
4854 | static const hda_nid_t ad1882_dac_nids[3] = { | ||
4855 | 0x04, 0x03, 0x05 | ||
4856 | }; | ||
4857 | |||
4858 | static const hda_nid_t ad1882_adc_nids[2] = { | ||
4859 | 0x08, 0x09, | ||
4860 | }; | ||
4861 | |||
4862 | static const hda_nid_t ad1882_capsrc_nids[2] = { | ||
4863 | 0x0c, 0x0d, | ||
4864 | }; | ||
4865 | |||
4866 | #define AD1882_SPDIF_OUT 0x02 | ||
4867 | |||
4868 | /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */ | ||
4869 | static const struct hda_input_mux ad1882_capture_source = { | ||
4870 | .num_items = 5, | ||
4871 | .items = { | ||
4872 | { "Front Mic", 0x1 }, | ||
4873 | { "Mic", 0x4 }, | ||
4874 | { "Line", 0x2 }, | ||
4875 | { "CD", 0x3 }, | ||
4876 | { "Mix", 0x7 }, | ||
4877 | }, | ||
4878 | }; | ||
4879 | |||
4880 | /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */ | ||
4881 | static const struct hda_input_mux ad1882a_capture_source = { | ||
4882 | .num_items = 5, | ||
4883 | .items = { | ||
4884 | { "Front Mic", 0x1 }, | ||
4885 | { "Mic", 0x4}, | ||
4886 | { "Line", 0x2 }, | ||
4887 | { "Digital Mic", 0x06 }, | ||
4888 | { "Mix", 0x7 }, | ||
4889 | }, | ||
4890 | }; | ||
4891 | |||
4892 | static const struct snd_kcontrol_new ad1882_base_mixers[] = { | ||
4893 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
4894 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
4895 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
4896 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
4897 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
4898 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4899 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4900 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4901 | |||
4902 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
4903 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
4904 | HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT), | ||
4905 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4906 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4907 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4908 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4909 | { | ||
4910 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4911 | /* The multiple "Capture Source" controls confuse alsamixer | ||
4912 | * So call somewhat different.. | ||
4913 | */ | ||
4914 | /* .name = "Capture Source", */ | ||
4915 | .name = "Input Source", | ||
4916 | .count = 2, | ||
4917 | .info = ad198x_mux_enum_info, | ||
4918 | .get = ad198x_mux_enum_get, | ||
4919 | .put = ad198x_mux_enum_put, | ||
4920 | }, | ||
4921 | /* SPDIF controls */ | ||
4922 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
4923 | { | ||
4924 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4925 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
4926 | /* identical with ad1983 */ | ||
4927 | .info = ad1983_spdif_route_info, | ||
4928 | .get = ad1983_spdif_route_get, | ||
4929 | .put = ad1983_spdif_route_put, | ||
4930 | }, | ||
4931 | { } /* end */ | ||
4932 | }; | ||
4933 | |||
4934 | static const struct snd_kcontrol_new ad1882_loopback_mixers[] = { | ||
4935 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4936 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4937 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4938 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4939 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4940 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4941 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), | ||
4942 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), | ||
4943 | { } /* end */ | ||
4944 | }; | ||
4945 | |||
4946 | static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = { | ||
4947 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4948 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4949 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4950 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4951 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4952 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4953 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), | ||
4954 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), | ||
4955 | HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT), | ||
4956 | { } /* end */ | ||
4957 | }; | ||
4958 | |||
4959 | static const struct snd_kcontrol_new ad1882_3stack_mixers[] = { | ||
4960 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
4961 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT), | ||
4962 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT), | ||
4963 | { | ||
4964 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4965 | .name = "Channel Mode", | ||
4966 | .info = ad198x_ch_mode_info, | ||
4967 | .get = ad198x_ch_mode_get, | ||
4968 | .put = ad198x_ch_mode_put, | ||
4969 | }, | ||
4970 | { } /* end */ | ||
4971 | }; | ||
4972 | |||
4973 | /* simple auto-mute control for AD1882 3-stack board */ | ||
4974 | #define AD1882_HP_EVENT 0x01 | ||
4975 | |||
4976 | static void ad1882_3stack_automute(struct hda_codec *codec) | ||
4977 | { | ||
4978 | bool mute = snd_hda_jack_detect(codec, 0x11); | ||
4979 | snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
4980 | mute ? 0 : PIN_OUT); | ||
4981 | } | ||
4982 | |||
4983 | static int ad1882_3stack_automute_init(struct hda_codec *codec) | ||
4984 | { | ||
4985 | ad198x_init(codec); | ||
4986 | ad1882_3stack_automute(codec); | ||
4987 | return 0; | ||
4988 | } | ||
4989 | |||
4990 | static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4991 | { | ||
4992 | switch (res >> 26) { | ||
4993 | case AD1882_HP_EVENT: | ||
4994 | ad1882_3stack_automute(codec); | ||
4995 | break; | ||
4996 | } | ||
4997 | } | ||
4998 | |||
4999 | static const struct snd_kcontrol_new ad1882_6stack_mixers[] = { | ||
5000 | HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
5001 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), | ||
5002 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT), | ||
5003 | { } /* end */ | ||
5004 | }; | ||
5005 | |||
5006 | static const struct hda_verb ad1882_ch2_init[] = { | ||
5007 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
5008 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5009 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5010 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5011 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5012 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5013 | { } /* end */ | ||
5014 | }; | ||
5015 | |||
5016 | static const struct hda_verb ad1882_ch4_init[] = { | ||
5017 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5018 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5019 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5020 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5021 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5022 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5023 | { } /* end */ | ||
5024 | }; | ||
5025 | |||
5026 | static const struct hda_verb ad1882_ch6_init[] = { | ||
5027 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5028 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5029 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5030 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5031 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5032 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5033 | { } /* end */ | ||
5034 | }; | ||
5035 | |||
5036 | static const struct hda_channel_mode ad1882_modes[3] = { | ||
5037 | { 2, ad1882_ch2_init }, | ||
5038 | { 4, ad1882_ch4_init }, | ||
5039 | { 6, ad1882_ch6_init }, | ||
5040 | }; | ||
5041 | |||
5042 | /* | ||
5043 | * initialization verbs | ||
5044 | */ | ||
5045 | static const struct hda_verb ad1882_init_verbs[] = { | ||
5046 | /* DACs; mute as default */ | ||
5047 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5048 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5049 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5050 | /* Port-A (HP) mixer */ | ||
5051 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5052 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5053 | /* Port-A pin */ | ||
5054 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5055 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5056 | /* HP selector - select DAC2 */ | ||
5057 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
5058 | /* Port-D (Line-out) mixer */ | ||
5059 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5060 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5061 | /* Port-D pin */ | ||
5062 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5063 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5064 | /* Mono-out mixer */ | ||
5065 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5066 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5067 | /* Mono-out pin */ | ||
5068 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5069 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5070 | /* Port-B (front mic) pin */ | ||
5071 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5072 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5073 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ | ||
5074 | /* Port-C (line-in) pin */ | ||
5075 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
5076 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5077 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ | ||
5078 | /* Port-C mixer - mute as input */ | ||
5079 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5080 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5081 | /* Port-E (mic-in) pin */ | ||
5082 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5083 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5084 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ | ||
5085 | /* Port-E mixer - mute as input */ | ||
5086 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5087 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5088 | /* Port-F (surround) */ | ||
5089 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5090 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5091 | /* Port-G (CLFE) */ | ||
5092 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5093 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5094 | /* Analog mixer; mute as default */ | ||
5095 | /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */ | ||
5096 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5097 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5098 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5099 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5100 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5101 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
5102 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
5103 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
5104 | /* Analog Mix output amp */ | ||
5105 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
5106 | /* SPDIF output selector */ | ||
5107 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
5108 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
5109 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
5110 | { } /* end */ | ||
5111 | }; | ||
5112 | |||
5113 | static const struct hda_verb ad1882_3stack_automute_verbs[] = { | ||
5114 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT}, | ||
5115 | { } /* end */ | ||
5116 | }; | ||
5117 | |||
5118 | #ifdef CONFIG_PM | ||
5119 | static const struct hda_amp_list ad1882_loopbacks[] = { | ||
5120 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
5121 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
5122 | { 0x20, HDA_INPUT, 4 }, /* Line */ | ||
5123 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
5124 | { } /* end */ | ||
5125 | }; | ||
5126 | #endif | ||
5127 | |||
5128 | /* models */ | ||
5129 | enum { | ||
5130 | AD1882_AUTO, | ||
5131 | AD1882_3STACK, | ||
5132 | AD1882_6STACK, | ||
5133 | AD1882_3STACK_AUTOMUTE, | ||
5134 | AD1882_MODELS | ||
5135 | }; | ||
5136 | |||
5137 | static const char * const ad1882_models[AD1986A_MODELS] = { | ||
5138 | [AD1882_AUTO] = "auto", | ||
5139 | [AD1882_3STACK] = "3stack", | ||
5140 | [AD1882_6STACK] = "6stack", | ||
5141 | [AD1882_3STACK_AUTOMUTE] = "3stack-automute", | ||
5142 | }; | ||
5143 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
5144 | |||
5145 | static int ad1882_parse_auto_config(struct hda_codec *codec) | ||
5146 | { | 1062 | { |
5147 | struct ad198x_spec *spec; | 1063 | struct ad198x_spec *spec; |
5148 | int err; | 1064 | int err; |
@@ -5169,110 +1085,20 @@ static int ad1882_parse_auto_config(struct hda_codec *codec) | |||
5169 | return err; | 1085 | return err; |
5170 | } | 1086 | } |
5171 | 1087 | ||
5172 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
5173 | static int patch_ad1882(struct hda_codec *codec) | ||
5174 | { | ||
5175 | struct ad198x_spec *spec; | ||
5176 | int err, board_config; | ||
5177 | |||
5178 | board_config = snd_hda_check_board_config(codec, AD1882_MODELS, | ||
5179 | ad1882_models, NULL); | ||
5180 | if (board_config < 0) { | ||
5181 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
5182 | codec->chip_name); | ||
5183 | board_config = AD1882_AUTO; | ||
5184 | } | ||
5185 | |||
5186 | if (board_config == AD1882_AUTO) | ||
5187 | return ad1882_parse_auto_config(codec); | ||
5188 | |||
5189 | err = alloc_ad_spec(codec); | ||
5190 | if (err < 0) | ||
5191 | return err; | ||
5192 | spec = codec->spec; | ||
5193 | |||
5194 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
5195 | if (err < 0) { | ||
5196 | ad198x_free(codec); | ||
5197 | return err; | ||
5198 | } | ||
5199 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
5200 | |||
5201 | spec->multiout.max_channels = 6; | ||
5202 | spec->multiout.num_dacs = 3; | ||
5203 | spec->multiout.dac_nids = ad1882_dac_nids; | ||
5204 | spec->multiout.dig_out_nid = AD1882_SPDIF_OUT; | ||
5205 | spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids); | ||
5206 | spec->adc_nids = ad1882_adc_nids; | ||
5207 | spec->capsrc_nids = ad1882_capsrc_nids; | ||
5208 | if (codec->vendor_id == 0x11d41882) | ||
5209 | spec->input_mux = &ad1882_capture_source; | ||
5210 | else | ||
5211 | spec->input_mux = &ad1882a_capture_source; | ||
5212 | spec->num_mixers = 2; | ||
5213 | spec->mixers[0] = ad1882_base_mixers; | ||
5214 | if (codec->vendor_id == 0x11d41882) | ||
5215 | spec->mixers[1] = ad1882_loopback_mixers; | ||
5216 | else | ||
5217 | spec->mixers[1] = ad1882a_loopback_mixers; | ||
5218 | spec->num_init_verbs = 1; | ||
5219 | spec->init_verbs[0] = ad1882_init_verbs; | ||
5220 | spec->spdif_route = 0; | ||
5221 | #ifdef CONFIG_PM | ||
5222 | spec->loopback.amplist = ad1882_loopbacks; | ||
5223 | #endif | ||
5224 | spec->vmaster_nid = 0x04; | ||
5225 | |||
5226 | codec->patch_ops = ad198x_patch_ops; | ||
5227 | |||
5228 | /* override some parameters */ | ||
5229 | switch (board_config) { | ||
5230 | default: | ||
5231 | case AD1882_3STACK: | ||
5232 | case AD1882_3STACK_AUTOMUTE: | ||
5233 | spec->num_mixers = 3; | ||
5234 | spec->mixers[2] = ad1882_3stack_mixers; | ||
5235 | spec->channel_mode = ad1882_modes; | ||
5236 | spec->num_channel_mode = ARRAY_SIZE(ad1882_modes); | ||
5237 | spec->need_dac_fix = 1; | ||
5238 | spec->multiout.max_channels = 2; | ||
5239 | spec->multiout.num_dacs = 1; | ||
5240 | if (board_config != AD1882_3STACK) { | ||
5241 | spec->init_verbs[spec->num_init_verbs++] = | ||
5242 | ad1882_3stack_automute_verbs; | ||
5243 | codec->patch_ops.unsol_event = ad1882_3stack_unsol_event; | ||
5244 | codec->patch_ops.init = ad1882_3stack_automute_init; | ||
5245 | } | ||
5246 | break; | ||
5247 | case AD1882_6STACK: | ||
5248 | spec->num_mixers = 3; | ||
5249 | spec->mixers[2] = ad1882_6stack_mixers; | ||
5250 | break; | ||
5251 | } | ||
5252 | |||
5253 | codec->no_trigger_sense = 1; | ||
5254 | codec->no_sticky_stream = 1; | ||
5255 | |||
5256 | return 0; | ||
5257 | } | ||
5258 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
5259 | #define patch_ad1882 ad1882_parse_auto_config | ||
5260 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
5261 | |||
5262 | 1088 | ||
5263 | /* | 1089 | /* |
5264 | * patch entries | 1090 | * patch entries |
5265 | */ | 1091 | */ |
5266 | static const struct hda_codec_preset snd_hda_preset_analog[] = { | 1092 | static const struct hda_codec_preset snd_hda_preset_analog[] = { |
5267 | { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, | 1093 | { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 }, |
5268 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, | 1094 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, |
5269 | { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, | 1095 | { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 }, |
5270 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, | 1096 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, |
5271 | { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a }, | 1097 | { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 }, |
5272 | { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a }, | 1098 | { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 }, |
5273 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, | 1099 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, |
5274 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, | 1100 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, |
5275 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 }, | 1101 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 }, |
5276 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, | 1102 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, |
5277 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, | 1103 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, |
5278 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, | 1104 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index de00ce166470..4edd2d0f9a3c 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -66,6 +66,8 @@ struct conexant_spec { | |||
66 | hda_nid_t eapds[4]; | 66 | hda_nid_t eapds[4]; |
67 | bool dynamic_eapd; | 67 | bool dynamic_eapd; |
68 | 68 | ||
69 | unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ | ||
70 | |||
69 | #ifdef ENABLE_CXT_STATIC_QUIRKS | 71 | #ifdef ENABLE_CXT_STATIC_QUIRKS |
70 | const struct snd_kcontrol_new *mixers[5]; | 72 | const struct snd_kcontrol_new *mixers[5]; |
71 | int num_mixers; | 73 | int num_mixers; |
@@ -3200,6 +3202,9 @@ static int cx_auto_init(struct hda_codec *codec) | |||
3200 | snd_hda_gen_init(codec); | 3202 | snd_hda_gen_init(codec); |
3201 | if (!spec->dynamic_eapd) | 3203 | if (!spec->dynamic_eapd) |
3202 | cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); | 3204 | cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); |
3205 | |||
3206 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); | ||
3207 | |||
3203 | return 0; | 3208 | return 0; |
3204 | } | 3209 | } |
3205 | 3210 | ||
@@ -3224,6 +3229,8 @@ enum { | |||
3224 | CXT_PINCFG_LEMOTE_A1205, | 3229 | CXT_PINCFG_LEMOTE_A1205, |
3225 | CXT_FIXUP_STEREO_DMIC, | 3230 | CXT_FIXUP_STEREO_DMIC, |
3226 | CXT_FIXUP_INC_MIC_BOOST, | 3231 | CXT_FIXUP_INC_MIC_BOOST, |
3232 | CXT_FIXUP_HEADPHONE_MIC_PIN, | ||
3233 | CXT_FIXUP_HEADPHONE_MIC, | ||
3227 | }; | 3234 | }; |
3228 | 3235 | ||
3229 | static void cxt_fixup_stereo_dmic(struct hda_codec *codec, | 3236 | static void cxt_fixup_stereo_dmic(struct hda_codec *codec, |
@@ -3246,6 +3253,59 @@ static void cxt5066_increase_mic_boost(struct hda_codec *codec, | |||
3246 | (0 << AC_AMPCAP_MUTE_SHIFT)); | 3253 | (0 << AC_AMPCAP_MUTE_SHIFT)); |
3247 | } | 3254 | } |
3248 | 3255 | ||
3256 | static void cxt_update_headset_mode(struct hda_codec *codec) | ||
3257 | { | ||
3258 | /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */ | ||
3259 | int i; | ||
3260 | bool mic_mode = false; | ||
3261 | struct conexant_spec *spec = codec->spec; | ||
3262 | struct auto_pin_cfg *cfg = &spec->gen.autocfg; | ||
3263 | |||
3264 | hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; | ||
3265 | |||
3266 | for (i = 0; i < cfg->num_inputs; i++) | ||
3267 | if (cfg->inputs[i].pin == mux_pin) { | ||
3268 | mic_mode = !!cfg->inputs[i].is_headphone_mic; | ||
3269 | break; | ||
3270 | } | ||
3271 | |||
3272 | if (mic_mode) { | ||
3273 | snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */ | ||
3274 | spec->gen.hp_jack_present = false; | ||
3275 | } else { | ||
3276 | snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */ | ||
3277 | spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]); | ||
3278 | } | ||
3279 | |||
3280 | snd_hda_gen_update_outputs(codec); | ||
3281 | } | ||
3282 | |||
3283 | static void cxt_update_headset_mode_hook(struct hda_codec *codec, | ||
3284 | struct snd_ctl_elem_value *ucontrol) | ||
3285 | { | ||
3286 | cxt_update_headset_mode(codec); | ||
3287 | } | ||
3288 | |||
3289 | static void cxt_fixup_headphone_mic(struct hda_codec *codec, | ||
3290 | const struct hda_fixup *fix, int action) | ||
3291 | { | ||
3292 | struct conexant_spec *spec = codec->spec; | ||
3293 | |||
3294 | switch (action) { | ||
3295 | case HDA_FIXUP_ACT_PRE_PROBE: | ||
3296 | spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC; | ||
3297 | break; | ||
3298 | case HDA_FIXUP_ACT_PROBE: | ||
3299 | spec->gen.cap_sync_hook = cxt_update_headset_mode_hook; | ||
3300 | spec->gen.automute_hook = cxt_update_headset_mode; | ||
3301 | break; | ||
3302 | case HDA_FIXUP_ACT_INIT: | ||
3303 | cxt_update_headset_mode(codec); | ||
3304 | break; | ||
3305 | } | ||
3306 | } | ||
3307 | |||
3308 | |||
3249 | /* ThinkPad X200 & co with cxt5051 */ | 3309 | /* ThinkPad X200 & co with cxt5051 */ |
3250 | static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { | 3310 | static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { |
3251 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ | 3311 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ |
@@ -3302,6 +3362,19 @@ static const struct hda_fixup cxt_fixups[] = { | |||
3302 | .type = HDA_FIXUP_FUNC, | 3362 | .type = HDA_FIXUP_FUNC, |
3303 | .v.func = cxt5066_increase_mic_boost, | 3363 | .v.func = cxt5066_increase_mic_boost, |
3304 | }, | 3364 | }, |
3365 | [CXT_FIXUP_HEADPHONE_MIC_PIN] = { | ||
3366 | .type = HDA_FIXUP_PINS, | ||
3367 | .chained = true, | ||
3368 | .chain_id = CXT_FIXUP_HEADPHONE_MIC, | ||
3369 | .v.pins = (const struct hda_pintbl[]) { | ||
3370 | { 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ | ||
3371 | { } | ||
3372 | } | ||
3373 | }, | ||
3374 | [CXT_FIXUP_HEADPHONE_MIC] = { | ||
3375 | .type = HDA_FIXUP_FUNC, | ||
3376 | .v.func = cxt_fixup_headphone_mic, | ||
3377 | }, | ||
3305 | }; | 3378 | }; |
3306 | 3379 | ||
3307 | static const struct snd_pci_quirk cxt5051_fixups[] = { | 3380 | static const struct snd_pci_quirk cxt5051_fixups[] = { |
@@ -3311,6 +3384,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = { | |||
3311 | 3384 | ||
3312 | static const struct snd_pci_quirk cxt5066_fixups[] = { | 3385 | static const struct snd_pci_quirk cxt5066_fixups[] = { |
3313 | SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), | 3386 | SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), |
3387 | SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), | ||
3314 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), | 3388 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), |
3315 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), | 3389 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), |
3316 | SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), | 3390 | SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), |
@@ -3395,7 +3469,8 @@ static int patch_conexant_auto(struct hda_codec *codec) | |||
3395 | 3469 | ||
3396 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | 3470 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); |
3397 | 3471 | ||
3398 | err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); | 3472 | err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, |
3473 | spec->parse_flags); | ||
3399 | if (err < 0) | 3474 | if (err < 0) |
3400 | goto error; | 3475 | goto error; |
3401 | 3476 | ||
@@ -3416,6 +3491,8 @@ static int patch_conexant_auto(struct hda_codec *codec) | |||
3416 | codec->bus->allow_bus_reset = 1; | 3491 | codec->bus->allow_bus_reset = 1; |
3417 | } | 3492 | } |
3418 | 3493 | ||
3494 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); | ||
3495 | |||
3419 | return 0; | 3496 | return 0; |
3420 | 3497 | ||
3421 | error: | 3498 | error: |
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 9f3586276871..9a58893d52a7 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -67,6 +67,8 @@ struct hdmi_spec_per_pin { | |||
67 | struct delayed_work work; | 67 | struct delayed_work work; |
68 | struct snd_kcontrol *eld_ctl; | 68 | struct snd_kcontrol *eld_ctl; |
69 | int repoll_count; | 69 | int repoll_count; |
70 | bool setup; /* the stream has been set up by prepare callback */ | ||
71 | int channels; /* current number of channels */ | ||
70 | bool non_pcm; | 72 | bool non_pcm; |
71 | bool chmap_set; /* channel-map override by ALSA API? */ | 73 | bool chmap_set; /* channel-map override by ALSA API? */ |
72 | unsigned char chmap[8]; /* ALSA API channel-map */ | 74 | unsigned char chmap[8]; /* ALSA API channel-map */ |
@@ -551,6 +553,17 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) | |||
551 | } | 553 | } |
552 | } | 554 | } |
553 | 555 | ||
556 | if (!ca) { | ||
557 | /* if there was no match, select the regular ALSA channel | ||
558 | * allocation with the matching number of channels */ | ||
559 | for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { | ||
560 | if (channels == channel_allocations[i].channels) { | ||
561 | ca = channel_allocations[i].ca_index; | ||
562 | break; | ||
563 | } | ||
564 | } | ||
565 | } | ||
566 | |||
554 | snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf)); | 567 | snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf)); |
555 | snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", | 568 | snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", |
556 | ca, channels, buf); | 569 | ca, channels, buf); |
@@ -868,18 +881,19 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, | |||
868 | return true; | 881 | return true; |
869 | } | 882 | } |
870 | 883 | ||
871 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, | 884 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, |
872 | bool non_pcm, | 885 | struct hdmi_spec_per_pin *per_pin, |
873 | struct snd_pcm_substream *substream) | 886 | bool non_pcm) |
874 | { | 887 | { |
875 | struct hdmi_spec *spec = codec->spec; | ||
876 | struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); | ||
877 | hda_nid_t pin_nid = per_pin->pin_nid; | 888 | hda_nid_t pin_nid = per_pin->pin_nid; |
878 | int channels = substream->runtime->channels; | 889 | int channels = per_pin->channels; |
879 | struct hdmi_eld *eld; | 890 | struct hdmi_eld *eld; |
880 | int ca; | 891 | int ca; |
881 | union audio_infoframe ai; | 892 | union audio_infoframe ai; |
882 | 893 | ||
894 | if (!channels) | ||
895 | return; | ||
896 | |||
883 | eld = &per_pin->sink_eld; | 897 | eld = &per_pin->sink_eld; |
884 | if (!eld->monitor_present) | 898 | if (!eld->monitor_present) |
885 | return; | 899 | return; |
@@ -959,6 +973,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
959 | int pin_nid; | 973 | int pin_nid; |
960 | int pin_idx; | 974 | int pin_idx; |
961 | struct hda_jack_tbl *jack; | 975 | struct hda_jack_tbl *jack; |
976 | int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; | ||
962 | 977 | ||
963 | jack = snd_hda_jack_tbl_get_from_tag(codec, tag); | 978 | jack = snd_hda_jack_tbl_get_from_tag(codec, tag); |
964 | if (!jack) | 979 | if (!jack) |
@@ -967,8 +982,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
967 | jack->jack_dirty = 1; | 982 | jack->jack_dirty = 1; |
968 | 983 | ||
969 | _snd_printd(SND_PR_VERBOSE, | 984 | _snd_printd(SND_PR_VERBOSE, |
970 | "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", | 985 | "HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n", |
971 | codec->addr, pin_nid, | 986 | codec->addr, pin_nid, dev_entry, !!(res & AC_UNSOL_RES_IA), |
972 | !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); | 987 | !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); |
973 | 988 | ||
974 | pin_idx = pin_nid_to_pin_index(spec, pin_nid); | 989 | pin_idx = pin_nid_to_pin_index(spec, pin_nid); |
@@ -1329,6 +1344,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) | |||
1329 | eld_changed = true; | 1344 | eld_changed = true; |
1330 | } | 1345 | } |
1331 | if (update_eld) { | 1346 | if (update_eld) { |
1347 | bool old_eld_valid = pin_eld->eld_valid; | ||
1332 | pin_eld->eld_valid = eld->eld_valid; | 1348 | pin_eld->eld_valid = eld->eld_valid; |
1333 | eld_changed = pin_eld->eld_size != eld->eld_size || | 1349 | eld_changed = pin_eld->eld_size != eld->eld_size || |
1334 | memcmp(pin_eld->eld_buffer, eld->eld_buffer, | 1350 | memcmp(pin_eld->eld_buffer, eld->eld_buffer, |
@@ -1338,6 +1354,18 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) | |||
1338 | eld->eld_size); | 1354 | eld->eld_size); |
1339 | pin_eld->eld_size = eld->eld_size; | 1355 | pin_eld->eld_size = eld->eld_size; |
1340 | pin_eld->info = eld->info; | 1356 | pin_eld->info = eld->info; |
1357 | |||
1358 | /* Haswell-specific workaround: re-setup when the transcoder is | ||
1359 | * changed during the stream playback | ||
1360 | */ | ||
1361 | if (codec->vendor_id == 0x80862807 && | ||
1362 | eld->eld_valid && !old_eld_valid && per_pin->setup) { | ||
1363 | snd_hda_codec_write(codec, pin_nid, 0, | ||
1364 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1365 | AMP_OUT_UNMUTE); | ||
1366 | hdmi_setup_audio_infoframe(codec, per_pin, | ||
1367 | per_pin->non_pcm); | ||
1368 | } | ||
1341 | } | 1369 | } |
1342 | mutex_unlock(&pin_eld->lock); | 1370 | mutex_unlock(&pin_eld->lock); |
1343 | 1371 | ||
@@ -1510,14 +1538,17 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
1510 | hda_nid_t cvt_nid = hinfo->nid; | 1538 | hda_nid_t cvt_nid = hinfo->nid; |
1511 | struct hdmi_spec *spec = codec->spec; | 1539 | struct hdmi_spec *spec = codec->spec; |
1512 | int pin_idx = hinfo_to_pin_index(spec, hinfo); | 1540 | int pin_idx = hinfo_to_pin_index(spec, hinfo); |
1513 | hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid; | 1541 | struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); |
1542 | hda_nid_t pin_nid = per_pin->pin_nid; | ||
1514 | bool non_pcm; | 1543 | bool non_pcm; |
1515 | 1544 | ||
1516 | non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); | 1545 | non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); |
1546 | per_pin->channels = substream->runtime->channels; | ||
1547 | per_pin->setup = true; | ||
1517 | 1548 | ||
1518 | hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); | 1549 | hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); |
1519 | 1550 | ||
1520 | hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream); | 1551 | hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); |
1521 | 1552 | ||
1522 | return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); | 1553 | return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); |
1523 | } | 1554 | } |
@@ -1557,6 +1588,9 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, | |||
1557 | snd_hda_spdif_ctls_unassign(codec, pin_idx); | 1588 | snd_hda_spdif_ctls_unassign(codec, pin_idx); |
1558 | per_pin->chmap_set = false; | 1589 | per_pin->chmap_set = false; |
1559 | memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); | 1590 | memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); |
1591 | |||
1592 | per_pin->setup = false; | ||
1593 | per_pin->channels = 0; | ||
1560 | } | 1594 | } |
1561 | 1595 | ||
1562 | return 0; | 1596 | return 0; |
@@ -1692,8 +1726,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, | |||
1692 | per_pin->chmap_set = true; | 1726 | per_pin->chmap_set = true; |
1693 | memcpy(per_pin->chmap, chmap, sizeof(chmap)); | 1727 | memcpy(per_pin->chmap, chmap, sizeof(chmap)); |
1694 | if (prepared) | 1728 | if (prepared) |
1695 | hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm, | 1729 | hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); |
1696 | substream); | ||
1697 | 1730 | ||
1698 | return 0; | 1731 | return 0; |
1699 | } | 1732 | } |
@@ -1992,8 +2025,10 @@ static int patch_generic_hdmi(struct hda_codec *codec) | |||
1992 | return -EINVAL; | 2025 | return -EINVAL; |
1993 | } | 2026 | } |
1994 | codec->patch_ops = generic_hdmi_patch_ops; | 2027 | codec->patch_ops = generic_hdmi_patch_ops; |
1995 | if (codec->vendor_id == 0x80862807) | 2028 | if (codec->vendor_id == 0x80862807) { |
1996 | codec->patch_ops.set_power_state = haswell_set_power_state; | 2029 | codec->patch_ops.set_power_state = haswell_set_power_state; |
2030 | codec->dp_mst = true; | ||
2031 | } | ||
1997 | 2032 | ||
1998 | generic_hdmi_init_per_pins(codec); | 2033 | generic_hdmi_init_per_pins(codec); |
1999 | 2034 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 389db4c2801b..9e9378cde8fa 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -282,6 +282,7 @@ static void alc_eapd_shutup(struct hda_codec *codec) | |||
282 | { | 282 | { |
283 | alc_auto_setup_eapd(codec, false); | 283 | alc_auto_setup_eapd(codec, false); |
284 | msleep(200); | 284 | msleep(200); |
285 | snd_hda_shutup_pins(codec); | ||
285 | } | 286 | } |
286 | 287 | ||
287 | /* generic EAPD initialization */ | 288 | /* generic EAPD initialization */ |
@@ -826,7 +827,8 @@ static inline void alc_shutup(struct hda_codec *codec) | |||
826 | 827 | ||
827 | if (spec && spec->shutup) | 828 | if (spec && spec->shutup) |
828 | spec->shutup(codec); | 829 | spec->shutup(codec); |
829 | snd_hda_shutup_pins(codec); | 830 | else |
831 | snd_hda_shutup_pins(codec); | ||
830 | } | 832 | } |
831 | 833 | ||
832 | #define alc_free snd_hda_gen_free | 834 | #define alc_free snd_hda_gen_free |
@@ -1853,8 +1855,10 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec, | |||
1853 | const struct hda_fixup *fix, int action) | 1855 | const struct hda_fixup *fix, int action) |
1854 | { | 1856 | { |
1855 | struct alc_spec *spec = codec->spec; | 1857 | struct alc_spec *spec = codec->spec; |
1856 | if (action == HDA_FIXUP_ACT_PRE_PROBE) | 1858 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { |
1857 | spec->gen.no_primary_hp = 1; | 1859 | spec->gen.no_primary_hp = 1; |
1860 | spec->gen.no_multi_io = 1; | ||
1861 | } | ||
1858 | } | 1862 | } |
1859 | 1863 | ||
1860 | static const struct hda_fixup alc882_fixups[] = { | 1864 | static const struct hda_fixup alc882_fixups[] = { |
@@ -2533,6 +2537,7 @@ enum { | |||
2533 | ALC269_TYPE_ALC269VD, | 2537 | ALC269_TYPE_ALC269VD, |
2534 | ALC269_TYPE_ALC280, | 2538 | ALC269_TYPE_ALC280, |
2535 | ALC269_TYPE_ALC282, | 2539 | ALC269_TYPE_ALC282, |
2540 | ALC269_TYPE_ALC283, | ||
2536 | ALC269_TYPE_ALC284, | 2541 | ALC269_TYPE_ALC284, |
2537 | ALC269_TYPE_ALC286, | 2542 | ALC269_TYPE_ALC286, |
2538 | }; | 2543 | }; |
@@ -2558,6 +2563,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
2558 | case ALC269_TYPE_ALC269VB: | 2563 | case ALC269_TYPE_ALC269VB: |
2559 | case ALC269_TYPE_ALC269VD: | 2564 | case ALC269_TYPE_ALC269VD: |
2560 | case ALC269_TYPE_ALC282: | 2565 | case ALC269_TYPE_ALC282: |
2566 | case ALC269_TYPE_ALC283: | ||
2561 | case ALC269_TYPE_ALC286: | 2567 | case ALC269_TYPE_ALC286: |
2562 | ssids = alc269_ssids; | 2568 | ssids = alc269_ssids; |
2563 | break; | 2569 | break; |
@@ -2583,15 +2589,81 @@ static void alc269_shutup(struct hda_codec *codec) | |||
2583 | { | 2589 | { |
2584 | struct alc_spec *spec = codec->spec; | 2590 | struct alc_spec *spec = codec->spec; |
2585 | 2591 | ||
2586 | if (spec->codec_variant != ALC269_TYPE_ALC269VB) | ||
2587 | return; | ||
2588 | |||
2589 | if (spec->codec_variant == ALC269_TYPE_ALC269VB) | 2592 | if (spec->codec_variant == ALC269_TYPE_ALC269VB) |
2590 | alc269vb_toggle_power_output(codec, 0); | 2593 | alc269vb_toggle_power_output(codec, 0); |
2591 | if (spec->codec_variant == ALC269_TYPE_ALC269VB && | 2594 | if (spec->codec_variant == ALC269_TYPE_ALC269VB && |
2592 | (alc_get_coef0(codec) & 0x00ff) == 0x018) { | 2595 | (alc_get_coef0(codec) & 0x00ff) == 0x018) { |
2593 | msleep(150); | 2596 | msleep(150); |
2594 | } | 2597 | } |
2598 | snd_hda_shutup_pins(codec); | ||
2599 | } | ||
2600 | |||
2601 | static void alc283_init(struct hda_codec *codec) | ||
2602 | { | ||
2603 | struct alc_spec *spec = codec->spec; | ||
2604 | hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; | ||
2605 | bool hp_pin_sense; | ||
2606 | int val; | ||
2607 | |||
2608 | if (!hp_pin) | ||
2609 | return; | ||
2610 | hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); | ||
2611 | |||
2612 | /* Index 0x43 Direct Drive HP AMP LPM Control 1 */ | ||
2613 | /* Headphone capless set to high power mode */ | ||
2614 | alc_write_coef_idx(codec, 0x43, 0x9004); | ||
2615 | |||
2616 | snd_hda_codec_write(codec, hp_pin, 0, | ||
2617 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
2618 | |||
2619 | if (hp_pin_sense) | ||
2620 | msleep(85); | ||
2621 | |||
2622 | snd_hda_codec_write(codec, hp_pin, 0, | ||
2623 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
2624 | |||
2625 | if (hp_pin_sense) | ||
2626 | msleep(85); | ||
2627 | /* Index 0x46 Combo jack auto switch control 2 */ | ||
2628 | /* 3k pull low control for Headset jack. */ | ||
2629 | val = alc_read_coef_idx(codec, 0x46); | ||
2630 | alc_write_coef_idx(codec, 0x46, val & ~(3 << 12)); | ||
2631 | /* Headphone capless set to normal mode */ | ||
2632 | alc_write_coef_idx(codec, 0x43, 0x9614); | ||
2633 | } | ||
2634 | |||
2635 | static void alc283_shutup(struct hda_codec *codec) | ||
2636 | { | ||
2637 | struct alc_spec *spec = codec->spec; | ||
2638 | hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; | ||
2639 | bool hp_pin_sense; | ||
2640 | int val; | ||
2641 | |||
2642 | if (!hp_pin) { | ||
2643 | alc269_shutup(codec); | ||
2644 | return; | ||
2645 | } | ||
2646 | |||
2647 | hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); | ||
2648 | |||
2649 | alc_write_coef_idx(codec, 0x43, 0x9004); | ||
2650 | |||
2651 | snd_hda_codec_write(codec, hp_pin, 0, | ||
2652 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
2653 | |||
2654 | if (hp_pin_sense) | ||
2655 | msleep(85); | ||
2656 | |||
2657 | snd_hda_codec_write(codec, hp_pin, 0, | ||
2658 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); | ||
2659 | |||
2660 | val = alc_read_coef_idx(codec, 0x46); | ||
2661 | alc_write_coef_idx(codec, 0x46, val | (3 << 12)); | ||
2662 | |||
2663 | if (hp_pin_sense) | ||
2664 | msleep(85); | ||
2665 | snd_hda_shutup_pins(codec); | ||
2666 | alc_write_coef_idx(codec, 0x43, 0x9614); | ||
2595 | } | 2667 | } |
2596 | 2668 | ||
2597 | static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg, | 2669 | static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg, |
@@ -2722,6 +2794,7 @@ static int alc269_resume(struct hda_codec *codec) | |||
2722 | hda_call_check_power_status(codec, 0x01); | 2794 | hda_call_check_power_status(codec, 0x01); |
2723 | if (spec->has_alc5505_dsp) | 2795 | if (spec->has_alc5505_dsp) |
2724 | alc5505_dsp_resume(codec); | 2796 | alc5505_dsp_resume(codec); |
2797 | |||
2725 | return 0; | 2798 | return 0; |
2726 | } | 2799 | } |
2727 | #endif /* CONFIG_PM */ | 2800 | #endif /* CONFIG_PM */ |
@@ -3261,6 +3334,28 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, | |||
3261 | alc_fixup_headset_mode(codec, fix, action); | 3334 | alc_fixup_headset_mode(codec, fix, action); |
3262 | } | 3335 | } |
3263 | 3336 | ||
3337 | /* Returns the nid of the external mic input pin, or 0 if it cannot be found. */ | ||
3338 | static int find_ext_mic_pin(struct hda_codec *codec) | ||
3339 | { | ||
3340 | struct alc_spec *spec = codec->spec; | ||
3341 | struct auto_pin_cfg *cfg = &spec->gen.autocfg; | ||
3342 | hda_nid_t nid; | ||
3343 | unsigned int defcfg; | ||
3344 | int i; | ||
3345 | |||
3346 | for (i = 0; i < cfg->num_inputs; i++) { | ||
3347 | if (cfg->inputs[i].type != AUTO_PIN_MIC) | ||
3348 | continue; | ||
3349 | nid = cfg->inputs[i].pin; | ||
3350 | defcfg = snd_hda_codec_get_pincfg(codec, nid); | ||
3351 | if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) | ||
3352 | continue; | ||
3353 | return nid; | ||
3354 | } | ||
3355 | |||
3356 | return 0; | ||
3357 | } | ||
3358 | |||
3264 | static void alc271_hp_gate_mic_jack(struct hda_codec *codec, | 3359 | static void alc271_hp_gate_mic_jack(struct hda_codec *codec, |
3265 | const struct hda_fixup *fix, | 3360 | const struct hda_fixup *fix, |
3266 | int action) | 3361 | int action) |
@@ -3268,11 +3363,12 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec, | |||
3268 | struct alc_spec *spec = codec->spec; | 3363 | struct alc_spec *spec = codec->spec; |
3269 | 3364 | ||
3270 | if (action == HDA_FIXUP_ACT_PROBE) { | 3365 | if (action == HDA_FIXUP_ACT_PROBE) { |
3271 | if (snd_BUG_ON(!spec->gen.am_entry[1].pin || | 3366 | int mic_pin = find_ext_mic_pin(codec); |
3272 | !spec->gen.autocfg.hp_pins[0])) | 3367 | int hp_pin = spec->gen.autocfg.hp_pins[0]; |
3368 | |||
3369 | if (snd_BUG_ON(!mic_pin || !hp_pin)) | ||
3273 | return; | 3370 | return; |
3274 | snd_hda_jack_set_gating_jack(codec, spec->gen.am_entry[1].pin, | 3371 | snd_hda_jack_set_gating_jack(codec, mic_pin, hp_pin); |
3275 | spec->gen.autocfg.hp_pins[0]); | ||
3276 | } | 3372 | } |
3277 | } | 3373 | } |
3278 | 3374 | ||
@@ -3308,6 +3404,45 @@ static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec, | |||
3308 | } | 3404 | } |
3309 | } | 3405 | } |
3310 | 3406 | ||
3407 | static void alc283_hp_automute_hook(struct hda_codec *codec, | ||
3408 | struct hda_jack_tbl *jack) | ||
3409 | { | ||
3410 | struct alc_spec *spec = codec->spec; | ||
3411 | int vref; | ||
3412 | |||
3413 | msleep(200); | ||
3414 | snd_hda_gen_hp_automute(codec, jack); | ||
3415 | |||
3416 | vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0; | ||
3417 | |||
3418 | msleep(600); | ||
3419 | snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3420 | vref); | ||
3421 | } | ||
3422 | |||
3423 | static void alc283_chromebook_caps(struct hda_codec *codec) | ||
3424 | { | ||
3425 | snd_hda_override_wcaps(codec, 0x03, 0); | ||
3426 | } | ||
3427 | |||
3428 | static void alc283_fixup_chromebook(struct hda_codec *codec, | ||
3429 | const struct hda_fixup *fix, int action) | ||
3430 | { | ||
3431 | struct alc_spec *spec = codec->spec; | ||
3432 | int val; | ||
3433 | |||
3434 | switch (action) { | ||
3435 | case HDA_FIXUP_ACT_PRE_PROBE: | ||
3436 | alc283_chromebook_caps(codec); | ||
3437 | spec->gen.hp_automute_hook = alc283_hp_automute_hook; | ||
3438 | /* MIC2-VREF control */ | ||
3439 | /* Set to manual mode */ | ||
3440 | val = alc_read_coef_idx(codec, 0x06); | ||
3441 | alc_write_coef_idx(codec, 0x06, val & ~0x000c); | ||
3442 | break; | ||
3443 | } | ||
3444 | } | ||
3445 | |||
3311 | enum { | 3446 | enum { |
3312 | ALC269_FIXUP_SONY_VAIO, | 3447 | ALC269_FIXUP_SONY_VAIO, |
3313 | ALC275_FIXUP_SONY_VAIO_GPIO2, | 3448 | ALC275_FIXUP_SONY_VAIO_GPIO2, |
@@ -3344,6 +3479,7 @@ enum { | |||
3344 | ALC269_FIXUP_ACER_AC700, | 3479 | ALC269_FIXUP_ACER_AC700, |
3345 | ALC269_FIXUP_LIMIT_INT_MIC_BOOST, | 3480 | ALC269_FIXUP_LIMIT_INT_MIC_BOOST, |
3346 | ALC269VB_FIXUP_ORDISSIMO_EVE2, | 3481 | ALC269VB_FIXUP_ORDISSIMO_EVE2, |
3482 | ALC283_FIXUP_CHROME_BOOK, | ||
3347 | }; | 3483 | }; |
3348 | 3484 | ||
3349 | static const struct hda_fixup alc269_fixups[] = { | 3485 | static const struct hda_fixup alc269_fixups[] = { |
@@ -3595,11 +3731,20 @@ static const struct hda_fixup alc269_fixups[] = { | |||
3595 | { } | 3731 | { } |
3596 | }, | 3732 | }, |
3597 | }, | 3733 | }, |
3734 | [ALC283_FIXUP_CHROME_BOOK] = { | ||
3735 | .type = HDA_FIXUP_FUNC, | ||
3736 | .v.func = alc283_fixup_chromebook, | ||
3737 | }, | ||
3598 | }; | 3738 | }; |
3599 | 3739 | ||
3600 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { | 3740 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { |
3601 | SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), | 3741 | SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), |
3602 | SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), | 3742 | SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), |
3743 | SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), | ||
3744 | SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), | ||
3745 | SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), | ||
3746 | SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), | ||
3747 | SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), | ||
3603 | SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), | 3748 | SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), |
3604 | SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), | 3749 | SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), |
3605 | SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), | 3750 | SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), |
@@ -3637,6 +3782,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
3637 | SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), | 3782 | SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), |
3638 | SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 3783 | SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
3639 | SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 3784 | SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
3785 | SND_PCI_QUIRK(0x103c, 0x21ed, "HP Falco Chromebook", ALC283_FIXUP_CHROME_BOOK), | ||
3640 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), | 3786 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), |
3641 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 3787 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
3642 | SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 3788 | SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
@@ -3655,11 +3801,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
3655 | SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), | 3801 | SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), |
3656 | SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), | 3802 | SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), |
3657 | SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), | 3803 | SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), |
3658 | SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), | ||
3659 | SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), | ||
3660 | SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), | ||
3661 | SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), | ||
3662 | SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), | ||
3663 | SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), | 3804 | SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), |
3664 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), | 3805 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), |
3665 | SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), | 3806 | SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), |
@@ -3670,8 +3811,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
3670 | SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), | 3811 | SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), |
3671 | SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), | 3812 | SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), |
3672 | SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), | 3813 | SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), |
3673 | SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), | ||
3674 | SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), | 3814 | SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), |
3815 | SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), | ||
3816 | SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3817 | SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3818 | SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3819 | SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3820 | SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3821 | SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3822 | SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3823 | SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3675 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), | 3824 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), |
3676 | SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), | 3825 | SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), |
3677 | SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ | 3826 | SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ |
@@ -3840,11 +3989,15 @@ static int patch_alc269(struct hda_codec *codec) | |||
3840 | case 0x10ec0290: | 3989 | case 0x10ec0290: |
3841 | spec->codec_variant = ALC269_TYPE_ALC280; | 3990 | spec->codec_variant = ALC269_TYPE_ALC280; |
3842 | break; | 3991 | break; |
3843 | case 0x10ec0233: | ||
3844 | case 0x10ec0282: | 3992 | case 0x10ec0282: |
3845 | case 0x10ec0283: | ||
3846 | spec->codec_variant = ALC269_TYPE_ALC282; | 3993 | spec->codec_variant = ALC269_TYPE_ALC282; |
3847 | break; | 3994 | break; |
3995 | case 0x10ec0233: | ||
3996 | case 0x10ec0283: | ||
3997 | spec->codec_variant = ALC269_TYPE_ALC283; | ||
3998 | spec->shutup = alc283_shutup; | ||
3999 | spec->init_hook = alc283_init; | ||
4000 | break; | ||
3848 | case 0x10ec0284: | 4001 | case 0x10ec0284: |
3849 | case 0x10ec0292: | 4002 | case 0x10ec0292: |
3850 | spec->codec_variant = ALC269_TYPE_ALC284; | 4003 | spec->codec_variant = ALC269_TYPE_ALC284; |
@@ -3872,7 +4025,8 @@ static int patch_alc269(struct hda_codec *codec) | |||
3872 | codec->patch_ops.suspend = alc269_suspend; | 4025 | codec->patch_ops.suspend = alc269_suspend; |
3873 | codec->patch_ops.resume = alc269_resume; | 4026 | codec->patch_ops.resume = alc269_resume; |
3874 | #endif | 4027 | #endif |
3875 | spec->shutup = alc269_shutup; | 4028 | if (!spec->shutup) |
4029 | spec->shutup = alc269_shutup; | ||
3876 | 4030 | ||
3877 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); | 4031 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); |
3878 | 4032 | ||
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6d1924c19abf..fba0cef1c47f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -158,6 +158,7 @@ enum { | |||
158 | STAC_D965_VERBS, | 158 | STAC_D965_VERBS, |
159 | STAC_DELL_3ST, | 159 | STAC_DELL_3ST, |
160 | STAC_DELL_BIOS, | 160 | STAC_DELL_BIOS, |
161 | STAC_DELL_BIOS_AMIC, | ||
161 | STAC_DELL_BIOS_SPDIF, | 162 | STAC_DELL_BIOS_SPDIF, |
162 | STAC_927X_DELL_DMIC, | 163 | STAC_927X_DELL_DMIC, |
163 | STAC_927X_VOLKNOB, | 164 | STAC_927X_VOLKNOB, |
@@ -3231,8 +3232,6 @@ static const struct hda_fixup stac927x_fixups[] = { | |||
3231 | [STAC_DELL_BIOS] = { | 3232 | [STAC_DELL_BIOS] = { |
3232 | .type = HDA_FIXUP_PINS, | 3233 | .type = HDA_FIXUP_PINS, |
3233 | .v.pins = (const struct hda_pintbl[]) { | 3234 | .v.pins = (const struct hda_pintbl[]) { |
3234 | /* configure the analog microphone on some laptops */ | ||
3235 | { 0x0c, 0x90a79130 }, | ||
3236 | /* correct the front output jack as a hp out */ | 3235 | /* correct the front output jack as a hp out */ |
3237 | { 0x0f, 0x0221101f }, | 3236 | { 0x0f, 0x0221101f }, |
3238 | /* correct the front input jack as a mic */ | 3237 | /* correct the front input jack as a mic */ |
@@ -3242,6 +3241,16 @@ static const struct hda_fixup stac927x_fixups[] = { | |||
3242 | .chained = true, | 3241 | .chained = true, |
3243 | .chain_id = STAC_927X_DELL_DMIC, | 3242 | .chain_id = STAC_927X_DELL_DMIC, |
3244 | }, | 3243 | }, |
3244 | [STAC_DELL_BIOS_AMIC] = { | ||
3245 | .type = HDA_FIXUP_PINS, | ||
3246 | .v.pins = (const struct hda_pintbl[]) { | ||
3247 | /* configure the analog microphone on some laptops */ | ||
3248 | { 0x0c, 0x90a79130 }, | ||
3249 | {} | ||
3250 | }, | ||
3251 | .chained = true, | ||
3252 | .chain_id = STAC_DELL_BIOS, | ||
3253 | }, | ||
3245 | [STAC_DELL_BIOS_SPDIF] = { | 3254 | [STAC_DELL_BIOS_SPDIF] = { |
3246 | .type = HDA_FIXUP_PINS, | 3255 | .type = HDA_FIXUP_PINS, |
3247 | .v.pins = (const struct hda_pintbl[]) { | 3256 | .v.pins = (const struct hda_pintbl[]) { |
@@ -3270,6 +3279,7 @@ static const struct hda_model_fixup stac927x_models[] = { | |||
3270 | { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" }, | 3279 | { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" }, |
3271 | { .id = STAC_DELL_3ST, .name = "dell-3stack" }, | 3280 | { .id = STAC_DELL_3ST, .name = "dell-3stack" }, |
3272 | { .id = STAC_DELL_BIOS, .name = "dell-bios" }, | 3281 | { .id = STAC_DELL_BIOS, .name = "dell-bios" }, |
3282 | { .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" }, | ||
3273 | { .id = STAC_927X_VOLKNOB, .name = "volknob" }, | 3283 | { .id = STAC_927X_VOLKNOB, .name = "volknob" }, |
3274 | {} | 3284 | {} |
3275 | }; | 3285 | }; |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index e2481baddc70..0bc20ef5687a 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -207,9 +207,9 @@ static void vt1708_stop_hp_work(struct hda_codec *codec) | |||
207 | return; | 207 | return; |
208 | if (spec->hp_work_active) { | 208 | if (spec->hp_work_active) { |
209 | snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1); | 209 | snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1); |
210 | codec->jackpoll_interval = 0; | ||
210 | cancel_delayed_work_sync(&codec->jackpoll_work); | 211 | cancel_delayed_work_sync(&codec->jackpoll_work); |
211 | spec->hp_work_active = false; | 212 | spec->hp_work_active = false; |
212 | codec->jackpoll_interval = 0; | ||
213 | } | 213 | } |
214 | } | 214 | } |
215 | 215 | ||
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 2a8ad9d1a2ae..bb9ebc5543d7 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/vmalloc.h> | ||
31 | 32 | ||
32 | #include <sound/core.h> | 33 | #include <sound/core.h> |
33 | #include <sound/info.h> | 34 | #include <sound/info.h> |
@@ -198,6 +199,31 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard."); | |||
198 | #define RME96_AD1852_VOL_BITS 14 | 199 | #define RME96_AD1852_VOL_BITS 14 |
199 | #define RME96_AD1855_VOL_BITS 10 | 200 | #define RME96_AD1855_VOL_BITS 10 |
200 | 201 | ||
202 | /* Defines for snd_rme96_trigger */ | ||
203 | #define RME96_TB_START_PLAYBACK 1 | ||
204 | #define RME96_TB_START_CAPTURE 2 | ||
205 | #define RME96_TB_STOP_PLAYBACK 4 | ||
206 | #define RME96_TB_STOP_CAPTURE 8 | ||
207 | #define RME96_TB_RESET_PLAYPOS 16 | ||
208 | #define RME96_TB_RESET_CAPTUREPOS 32 | ||
209 | #define RME96_TB_CLEAR_PLAYBACK_IRQ 64 | ||
210 | #define RME96_TB_CLEAR_CAPTURE_IRQ 128 | ||
211 | #define RME96_RESUME_PLAYBACK (RME96_TB_START_PLAYBACK) | ||
212 | #define RME96_RESUME_CAPTURE (RME96_TB_START_CAPTURE) | ||
213 | #define RME96_RESUME_BOTH (RME96_RESUME_PLAYBACK \ | ||
214 | | RME96_RESUME_CAPTURE) | ||
215 | #define RME96_START_PLAYBACK (RME96_TB_START_PLAYBACK \ | ||
216 | | RME96_TB_RESET_PLAYPOS) | ||
217 | #define RME96_START_CAPTURE (RME96_TB_START_CAPTURE \ | ||
218 | | RME96_TB_RESET_CAPTUREPOS) | ||
219 | #define RME96_START_BOTH (RME96_START_PLAYBACK \ | ||
220 | | RME96_START_CAPTURE) | ||
221 | #define RME96_STOP_PLAYBACK (RME96_TB_STOP_PLAYBACK \ | ||
222 | | RME96_TB_CLEAR_PLAYBACK_IRQ) | ||
223 | #define RME96_STOP_CAPTURE (RME96_TB_STOP_CAPTURE \ | ||
224 | | RME96_TB_CLEAR_CAPTURE_IRQ) | ||
225 | #define RME96_STOP_BOTH (RME96_STOP_PLAYBACK \ | ||
226 | | RME96_STOP_CAPTURE) | ||
201 | 227 | ||
202 | struct rme96 { | 228 | struct rme96 { |
203 | spinlock_t lock; | 229 | spinlock_t lock; |
@@ -214,6 +240,13 @@ struct rme96 { | |||
214 | 240 | ||
215 | u8 rev; /* card revision number */ | 241 | u8 rev; /* card revision number */ |
216 | 242 | ||
243 | #ifdef CONFIG_PM | ||
244 | u32 playback_pointer; | ||
245 | u32 capture_pointer; | ||
246 | void *playback_suspend_buffer; | ||
247 | void *capture_suspend_buffer; | ||
248 | #endif | ||
249 | |||
217 | struct snd_pcm_substream *playback_substream; | 250 | struct snd_pcm_substream *playback_substream; |
218 | struct snd_pcm_substream *capture_substream; | 251 | struct snd_pcm_substream *capture_substream; |
219 | 252 | ||
@@ -344,6 +377,8 @@ static struct snd_pcm_hardware snd_rme96_playback_spdif_info = | |||
344 | { | 377 | { |
345 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | | 378 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | |
346 | SNDRV_PCM_INFO_MMAP_VALID | | 379 | SNDRV_PCM_INFO_MMAP_VALID | |
380 | SNDRV_PCM_INFO_SYNC_START | | ||
381 | SNDRV_PCM_INFO_RESUME | | ||
347 | SNDRV_PCM_INFO_INTERLEAVED | | 382 | SNDRV_PCM_INFO_INTERLEAVED | |
348 | SNDRV_PCM_INFO_PAUSE), | 383 | SNDRV_PCM_INFO_PAUSE), |
349 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 384 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
@@ -373,6 +408,8 @@ static struct snd_pcm_hardware snd_rme96_capture_spdif_info = | |||
373 | { | 408 | { |
374 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | | 409 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | |
375 | SNDRV_PCM_INFO_MMAP_VALID | | 410 | SNDRV_PCM_INFO_MMAP_VALID | |
411 | SNDRV_PCM_INFO_SYNC_START | | ||
412 | SNDRV_PCM_INFO_RESUME | | ||
376 | SNDRV_PCM_INFO_INTERLEAVED | | 413 | SNDRV_PCM_INFO_INTERLEAVED | |
377 | SNDRV_PCM_INFO_PAUSE), | 414 | SNDRV_PCM_INFO_PAUSE), |
378 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 415 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
@@ -402,6 +439,8 @@ static struct snd_pcm_hardware snd_rme96_playback_adat_info = | |||
402 | { | 439 | { |
403 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | | 440 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | |
404 | SNDRV_PCM_INFO_MMAP_VALID | | 441 | SNDRV_PCM_INFO_MMAP_VALID | |
442 | SNDRV_PCM_INFO_SYNC_START | | ||
443 | SNDRV_PCM_INFO_RESUME | | ||
405 | SNDRV_PCM_INFO_INTERLEAVED | | 444 | SNDRV_PCM_INFO_INTERLEAVED | |
406 | SNDRV_PCM_INFO_PAUSE), | 445 | SNDRV_PCM_INFO_PAUSE), |
407 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 446 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
@@ -427,6 +466,8 @@ static struct snd_pcm_hardware snd_rme96_capture_adat_info = | |||
427 | { | 466 | { |
428 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | | 467 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | |
429 | SNDRV_PCM_INFO_MMAP_VALID | | 468 | SNDRV_PCM_INFO_MMAP_VALID | |
469 | SNDRV_PCM_INFO_SYNC_START | | ||
470 | SNDRV_PCM_INFO_RESUME | | ||
430 | SNDRV_PCM_INFO_INTERLEAVED | | 471 | SNDRV_PCM_INFO_INTERLEAVED | |
431 | SNDRV_PCM_INFO_PAUSE), | 472 | SNDRV_PCM_INFO_PAUSE), |
432 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 473 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
@@ -1045,54 +1086,35 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream, | |||
1045 | } | 1086 | } |
1046 | 1087 | ||
1047 | static void | 1088 | static void |
1048 | snd_rme96_playback_start(struct rme96 *rme96, | 1089 | snd_rme96_trigger(struct rme96 *rme96, |
1049 | int from_pause) | 1090 | int op) |
1050 | { | 1091 | { |
1051 | if (!from_pause) { | 1092 | if (op & RME96_TB_RESET_PLAYPOS) |
1052 | writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); | 1093 | writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); |
1053 | } | 1094 | if (op & RME96_TB_RESET_CAPTUREPOS) |
1054 | |||
1055 | rme96->wcreg |= RME96_WCR_START; | ||
1056 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1057 | } | ||
1058 | |||
1059 | static void | ||
1060 | snd_rme96_capture_start(struct rme96 *rme96, | ||
1061 | int from_pause) | ||
1062 | { | ||
1063 | if (!from_pause) { | ||
1064 | writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); | 1095 | writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); |
1065 | } | 1096 | if (op & RME96_TB_CLEAR_PLAYBACK_IRQ) { |
1066 | 1097 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | |
1067 | rme96->wcreg |= RME96_WCR_START_2; | 1098 | if (rme96->rcreg & RME96_RCR_IRQ) |
1099 | writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ); | ||
1100 | } | ||
1101 | if (op & RME96_TB_CLEAR_CAPTURE_IRQ) { | ||
1102 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1103 | if (rme96->rcreg & RME96_RCR_IRQ_2) | ||
1104 | writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ); | ||
1105 | } | ||
1106 | if (op & RME96_TB_START_PLAYBACK) | ||
1107 | rme96->wcreg |= RME96_WCR_START; | ||
1108 | if (op & RME96_TB_STOP_PLAYBACK) | ||
1109 | rme96->wcreg &= ~RME96_WCR_START; | ||
1110 | if (op & RME96_TB_START_CAPTURE) | ||
1111 | rme96->wcreg |= RME96_WCR_START_2; | ||
1112 | if (op & RME96_TB_STOP_CAPTURE) | ||
1113 | rme96->wcreg &= ~RME96_WCR_START_2; | ||
1068 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); | 1114 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); |
1069 | } | 1115 | } |
1070 | 1116 | ||
1071 | static void | ||
1072 | snd_rme96_playback_stop(struct rme96 *rme96) | ||
1073 | { | ||
1074 | /* | ||
1075 | * Check if there is an unconfirmed IRQ, if so confirm it, or else | ||
1076 | * the hardware will not stop generating interrupts | ||
1077 | */ | ||
1078 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1079 | if (rme96->rcreg & RME96_RCR_IRQ) { | ||
1080 | writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ); | ||
1081 | } | ||
1082 | rme96->wcreg &= ~RME96_WCR_START; | ||
1083 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1084 | } | ||
1085 | 1117 | ||
1086 | static void | ||
1087 | snd_rme96_capture_stop(struct rme96 *rme96) | ||
1088 | { | ||
1089 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1090 | if (rme96->rcreg & RME96_RCR_IRQ_2) { | ||
1091 | writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ); | ||
1092 | } | ||
1093 | rme96->wcreg &= ~RME96_WCR_START_2; | ||
1094 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1095 | } | ||
1096 | 1118 | ||
1097 | static irqreturn_t | 1119 | static irqreturn_t |
1098 | snd_rme96_interrupt(int irq, | 1120 | snd_rme96_interrupt(int irq, |
@@ -1155,6 +1177,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) | |||
1155 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1177 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1156 | struct snd_pcm_runtime *runtime = substream->runtime; | 1178 | struct snd_pcm_runtime *runtime = substream->runtime; |
1157 | 1179 | ||
1180 | snd_pcm_set_sync(substream); | ||
1158 | spin_lock_irq(&rme96->lock); | 1181 | spin_lock_irq(&rme96->lock); |
1159 | if (rme96->playback_substream != NULL) { | 1182 | if (rme96->playback_substream != NULL) { |
1160 | spin_unlock_irq(&rme96->lock); | 1183 | spin_unlock_irq(&rme96->lock); |
@@ -1191,6 +1214,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream) | |||
1191 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1214 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1192 | struct snd_pcm_runtime *runtime = substream->runtime; | 1215 | struct snd_pcm_runtime *runtime = substream->runtime; |
1193 | 1216 | ||
1217 | snd_pcm_set_sync(substream); | ||
1194 | runtime->hw = snd_rme96_capture_spdif_info; | 1218 | runtime->hw = snd_rme96_capture_spdif_info; |
1195 | if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && | 1219 | if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && |
1196 | (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) | 1220 | (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) |
@@ -1222,6 +1246,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream) | |||
1222 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1246 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1223 | struct snd_pcm_runtime *runtime = substream->runtime; | 1247 | struct snd_pcm_runtime *runtime = substream->runtime; |
1224 | 1248 | ||
1249 | snd_pcm_set_sync(substream); | ||
1225 | spin_lock_irq(&rme96->lock); | 1250 | spin_lock_irq(&rme96->lock); |
1226 | if (rme96->playback_substream != NULL) { | 1251 | if (rme96->playback_substream != NULL) { |
1227 | spin_unlock_irq(&rme96->lock); | 1252 | spin_unlock_irq(&rme96->lock); |
@@ -1253,6 +1278,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream) | |||
1253 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1278 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1254 | struct snd_pcm_runtime *runtime = substream->runtime; | 1279 | struct snd_pcm_runtime *runtime = substream->runtime; |
1255 | 1280 | ||
1281 | snd_pcm_set_sync(substream); | ||
1256 | runtime->hw = snd_rme96_capture_adat_info; | 1282 | runtime->hw = snd_rme96_capture_adat_info; |
1257 | if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { | 1283 | if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { |
1258 | /* makes no sense to use analog input. Note that analog | 1284 | /* makes no sense to use analog input. Note that analog |
@@ -1288,7 +1314,7 @@ snd_rme96_playback_close(struct snd_pcm_substream *substream) | |||
1288 | 1314 | ||
1289 | spin_lock_irq(&rme96->lock); | 1315 | spin_lock_irq(&rme96->lock); |
1290 | if (RME96_ISPLAYING(rme96)) { | 1316 | if (RME96_ISPLAYING(rme96)) { |
1291 | snd_rme96_playback_stop(rme96); | 1317 | snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK); |
1292 | } | 1318 | } |
1293 | rme96->playback_substream = NULL; | 1319 | rme96->playback_substream = NULL; |
1294 | rme96->playback_periodsize = 0; | 1320 | rme96->playback_periodsize = 0; |
@@ -1309,7 +1335,7 @@ snd_rme96_capture_close(struct snd_pcm_substream *substream) | |||
1309 | 1335 | ||
1310 | spin_lock_irq(&rme96->lock); | 1336 | spin_lock_irq(&rme96->lock); |
1311 | if (RME96_ISRECORDING(rme96)) { | 1337 | if (RME96_ISRECORDING(rme96)) { |
1312 | snd_rme96_capture_stop(rme96); | 1338 | snd_rme96_trigger(rme96, RME96_STOP_CAPTURE); |
1313 | } | 1339 | } |
1314 | rme96->capture_substream = NULL; | 1340 | rme96->capture_substream = NULL; |
1315 | rme96->capture_periodsize = 0; | 1341 | rme96->capture_periodsize = 0; |
@@ -1324,7 +1350,7 @@ snd_rme96_playback_prepare(struct snd_pcm_substream *substream) | |||
1324 | 1350 | ||
1325 | spin_lock_irq(&rme96->lock); | 1351 | spin_lock_irq(&rme96->lock); |
1326 | if (RME96_ISPLAYING(rme96)) { | 1352 | if (RME96_ISPLAYING(rme96)) { |
1327 | snd_rme96_playback_stop(rme96); | 1353 | snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK); |
1328 | } | 1354 | } |
1329 | writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); | 1355 | writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); |
1330 | spin_unlock_irq(&rme96->lock); | 1356 | spin_unlock_irq(&rme96->lock); |
@@ -1338,7 +1364,7 @@ snd_rme96_capture_prepare(struct snd_pcm_substream *substream) | |||
1338 | 1364 | ||
1339 | spin_lock_irq(&rme96->lock); | 1365 | spin_lock_irq(&rme96->lock); |
1340 | if (RME96_ISRECORDING(rme96)) { | 1366 | if (RME96_ISRECORDING(rme96)) { |
1341 | snd_rme96_capture_stop(rme96); | 1367 | snd_rme96_trigger(rme96, RME96_STOP_CAPTURE); |
1342 | } | 1368 | } |
1343 | writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); | 1369 | writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); |
1344 | spin_unlock_irq(&rme96->lock); | 1370 | spin_unlock_irq(&rme96->lock); |
@@ -1350,41 +1376,55 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream, | |||
1350 | int cmd) | 1376 | int cmd) |
1351 | { | 1377 | { |
1352 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1378 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1379 | struct snd_pcm_substream *s; | ||
1380 | bool sync; | ||
1381 | |||
1382 | snd_pcm_group_for_each_entry(s, substream) { | ||
1383 | if (snd_pcm_substream_chip(s) == rme96) | ||
1384 | snd_pcm_trigger_done(s, substream); | ||
1385 | } | ||
1386 | |||
1387 | sync = (rme96->playback_substream && rme96->capture_substream) && | ||
1388 | (rme96->playback_substream->group == | ||
1389 | rme96->capture_substream->group); | ||
1353 | 1390 | ||
1354 | switch (cmd) { | 1391 | switch (cmd) { |
1355 | case SNDRV_PCM_TRIGGER_START: | 1392 | case SNDRV_PCM_TRIGGER_START: |
1356 | if (!RME96_ISPLAYING(rme96)) { | 1393 | if (!RME96_ISPLAYING(rme96)) { |
1357 | if (substream != rme96->playback_substream) { | 1394 | if (substream != rme96->playback_substream) |
1358 | return -EBUSY; | 1395 | return -EBUSY; |
1359 | } | 1396 | snd_rme96_trigger(rme96, sync ? RME96_START_BOTH |
1360 | snd_rme96_playback_start(rme96, 0); | 1397 | : RME96_START_PLAYBACK); |
1361 | } | 1398 | } |
1362 | break; | 1399 | break; |
1363 | 1400 | ||
1401 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1364 | case SNDRV_PCM_TRIGGER_STOP: | 1402 | case SNDRV_PCM_TRIGGER_STOP: |
1365 | if (RME96_ISPLAYING(rme96)) { | 1403 | if (RME96_ISPLAYING(rme96)) { |
1366 | if (substream != rme96->playback_substream) { | 1404 | if (substream != rme96->playback_substream) |
1367 | return -EBUSY; | 1405 | return -EBUSY; |
1368 | } | 1406 | snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH |
1369 | snd_rme96_playback_stop(rme96); | 1407 | : RME96_STOP_PLAYBACK); |
1370 | } | 1408 | } |
1371 | break; | 1409 | break; |
1372 | 1410 | ||
1373 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1411 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1374 | if (RME96_ISPLAYING(rme96)) { | 1412 | if (RME96_ISPLAYING(rme96)) |
1375 | snd_rme96_playback_stop(rme96); | 1413 | snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH |
1376 | } | 1414 | : RME96_STOP_PLAYBACK); |
1377 | break; | 1415 | break; |
1378 | 1416 | ||
1417 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1379 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1418 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1380 | if (!RME96_ISPLAYING(rme96)) { | 1419 | if (!RME96_ISPLAYING(rme96)) |
1381 | snd_rme96_playback_start(rme96, 1); | 1420 | snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH |
1382 | } | 1421 | : RME96_RESUME_PLAYBACK); |
1383 | break; | 1422 | break; |
1384 | 1423 | ||
1385 | default: | 1424 | default: |
1386 | return -EINVAL; | 1425 | return -EINVAL; |
1387 | } | 1426 | } |
1427 | |||
1388 | return 0; | 1428 | return 0; |
1389 | } | 1429 | } |
1390 | 1430 | ||
@@ -1393,38 +1433,51 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream, | |||
1393 | int cmd) | 1433 | int cmd) |
1394 | { | 1434 | { |
1395 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1435 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1436 | struct snd_pcm_substream *s; | ||
1437 | bool sync; | ||
1438 | |||
1439 | snd_pcm_group_for_each_entry(s, substream) { | ||
1440 | if (snd_pcm_substream_chip(s) == rme96) | ||
1441 | snd_pcm_trigger_done(s, substream); | ||
1442 | } | ||
1443 | |||
1444 | sync = (rme96->playback_substream && rme96->capture_substream) && | ||
1445 | (rme96->playback_substream->group == | ||
1446 | rme96->capture_substream->group); | ||
1396 | 1447 | ||
1397 | switch (cmd) { | 1448 | switch (cmd) { |
1398 | case SNDRV_PCM_TRIGGER_START: | 1449 | case SNDRV_PCM_TRIGGER_START: |
1399 | if (!RME96_ISRECORDING(rme96)) { | 1450 | if (!RME96_ISRECORDING(rme96)) { |
1400 | if (substream != rme96->capture_substream) { | 1451 | if (substream != rme96->capture_substream) |
1401 | return -EBUSY; | 1452 | return -EBUSY; |
1402 | } | 1453 | snd_rme96_trigger(rme96, sync ? RME96_START_BOTH |
1403 | snd_rme96_capture_start(rme96, 0); | 1454 | : RME96_START_CAPTURE); |
1404 | } | 1455 | } |
1405 | break; | 1456 | break; |
1406 | 1457 | ||
1458 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1407 | case SNDRV_PCM_TRIGGER_STOP: | 1459 | case SNDRV_PCM_TRIGGER_STOP: |
1408 | if (RME96_ISRECORDING(rme96)) { | 1460 | if (RME96_ISRECORDING(rme96)) { |
1409 | if (substream != rme96->capture_substream) { | 1461 | if (substream != rme96->capture_substream) |
1410 | return -EBUSY; | 1462 | return -EBUSY; |
1411 | } | 1463 | snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH |
1412 | snd_rme96_capture_stop(rme96); | 1464 | : RME96_STOP_CAPTURE); |
1413 | } | 1465 | } |
1414 | break; | 1466 | break; |
1415 | 1467 | ||
1416 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1468 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1417 | if (RME96_ISRECORDING(rme96)) { | 1469 | if (RME96_ISRECORDING(rme96)) |
1418 | snd_rme96_capture_stop(rme96); | 1470 | snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH |
1419 | } | 1471 | : RME96_STOP_CAPTURE); |
1420 | break; | 1472 | break; |
1421 | 1473 | ||
1474 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1422 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1475 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1423 | if (!RME96_ISRECORDING(rme96)) { | 1476 | if (!RME96_ISRECORDING(rme96)) |
1424 | snd_rme96_capture_start(rme96, 1); | 1477 | snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH |
1425 | } | 1478 | : RME96_RESUME_CAPTURE); |
1426 | break; | 1479 | break; |
1427 | 1480 | ||
1428 | default: | 1481 | default: |
1429 | return -EINVAL; | 1482 | return -EINVAL; |
1430 | } | 1483 | } |
@@ -1505,8 +1558,7 @@ snd_rme96_free(void *private_data) | |||
1505 | return; | 1558 | return; |
1506 | } | 1559 | } |
1507 | if (rme96->irq >= 0) { | 1560 | if (rme96->irq >= 0) { |
1508 | snd_rme96_playback_stop(rme96); | 1561 | snd_rme96_trigger(rme96, RME96_STOP_BOTH); |
1509 | snd_rme96_capture_stop(rme96); | ||
1510 | rme96->areg &= ~RME96_AR_DAC_EN; | 1562 | rme96->areg &= ~RME96_AR_DAC_EN; |
1511 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); | 1563 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); |
1512 | free_irq(rme96->irq, (void *)rme96); | 1564 | free_irq(rme96->irq, (void *)rme96); |
@@ -1520,6 +1572,10 @@ snd_rme96_free(void *private_data) | |||
1520 | pci_release_regions(rme96->pci); | 1572 | pci_release_regions(rme96->pci); |
1521 | rme96->port = 0; | 1573 | rme96->port = 0; |
1522 | } | 1574 | } |
1575 | #ifdef CONFIG_PM | ||
1576 | vfree(rme96->playback_suspend_buffer); | ||
1577 | vfree(rme96->capture_suspend_buffer); | ||
1578 | #endif | ||
1523 | pci_disable_device(rme96->pci); | 1579 | pci_disable_device(rme96->pci); |
1524 | } | 1580 | } |
1525 | 1581 | ||
@@ -1606,8 +1662,7 @@ snd_rme96_create(struct rme96 *rme96) | |||
1606 | rme96->capture_periodsize = 0; | 1662 | rme96->capture_periodsize = 0; |
1607 | 1663 | ||
1608 | /* make sure playback/capture is stopped, if by some reason active */ | 1664 | /* make sure playback/capture is stopped, if by some reason active */ |
1609 | snd_rme96_playback_stop(rme96); | 1665 | snd_rme96_trigger(rme96, RME96_STOP_BOTH); |
1610 | snd_rme96_capture_stop(rme96); | ||
1611 | 1666 | ||
1612 | /* set default values in registers */ | 1667 | /* set default values in registers */ |
1613 | rme96->wcreg = | 1668 | rme96->wcreg = |
@@ -2319,6 +2374,87 @@ snd_rme96_create_switches(struct snd_card *card, | |||
2319 | * Card initialisation | 2374 | * Card initialisation |
2320 | */ | 2375 | */ |
2321 | 2376 | ||
2377 | #ifdef CONFIG_PM | ||
2378 | |||
2379 | static int | ||
2380 | snd_rme96_suspend(struct pci_dev *pci, | ||
2381 | pm_message_t state) | ||
2382 | { | ||
2383 | struct snd_card *card = pci_get_drvdata(pci); | ||
2384 | struct rme96 *rme96 = card->private_data; | ||
2385 | |||
2386 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
2387 | snd_pcm_suspend(rme96->playback_substream); | ||
2388 | snd_pcm_suspend(rme96->capture_substream); | ||
2389 | |||
2390 | /* save capture & playback pointers */ | ||
2391 | rme96->playback_pointer = readl(rme96->iobase + RME96_IO_GET_PLAY_POS) | ||
2392 | & RME96_RCR_AUDIO_ADDR_MASK; | ||
2393 | rme96->capture_pointer = readl(rme96->iobase + RME96_IO_GET_REC_POS) | ||
2394 | & RME96_RCR_AUDIO_ADDR_MASK; | ||
2395 | |||
2396 | /* save playback and capture buffers */ | ||
2397 | memcpy_fromio(rme96->playback_suspend_buffer, | ||
2398 | rme96->iobase + RME96_IO_PLAY_BUFFER, RME96_BUFFER_SIZE); | ||
2399 | memcpy_fromio(rme96->capture_suspend_buffer, | ||
2400 | rme96->iobase + RME96_IO_REC_BUFFER, RME96_BUFFER_SIZE); | ||
2401 | |||
2402 | /* disable the DAC */ | ||
2403 | rme96->areg &= ~RME96_AR_DAC_EN; | ||
2404 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); | ||
2405 | |||
2406 | pci_disable_device(pci); | ||
2407 | pci_save_state(pci); | ||
2408 | |||
2409 | return 0; | ||
2410 | } | ||
2411 | |||
2412 | static int | ||
2413 | snd_rme96_resume(struct pci_dev *pci) | ||
2414 | { | ||
2415 | struct snd_card *card = pci_get_drvdata(pci); | ||
2416 | struct rme96 *rme96 = card->private_data; | ||
2417 | |||
2418 | pci_restore_state(pci); | ||
2419 | if (pci_enable_device(pci) < 0) { | ||
2420 | printk(KERN_ERR "rme96: pci_enable_device failed, disabling device\n"); | ||
2421 | snd_card_disconnect(card); | ||
2422 | return -EIO; | ||
2423 | } | ||
2424 | |||
2425 | /* reset playback and record buffer pointers */ | ||
2426 | writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS | ||
2427 | + rme96->playback_pointer); | ||
2428 | writel(0, rme96->iobase + RME96_IO_SET_REC_POS | ||
2429 | + rme96->capture_pointer); | ||
2430 | |||
2431 | /* restore playback and capture buffers */ | ||
2432 | memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER, | ||
2433 | rme96->playback_suspend_buffer, RME96_BUFFER_SIZE); | ||
2434 | memcpy_toio(rme96->iobase + RME96_IO_REC_BUFFER, | ||
2435 | rme96->capture_suspend_buffer, RME96_BUFFER_SIZE); | ||
2436 | |||
2437 | /* reset the ADC */ | ||
2438 | writel(rme96->areg | RME96_AR_PD2, | ||
2439 | rme96->iobase + RME96_IO_ADDITIONAL_REG); | ||
2440 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); | ||
2441 | |||
2442 | /* reset and enable DAC, restore analog volume */ | ||
2443 | snd_rme96_reset_dac(rme96); | ||
2444 | rme96->areg |= RME96_AR_DAC_EN; | ||
2445 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); | ||
2446 | if (RME96_HAS_ANALOG_OUT(rme96)) { | ||
2447 | usleep_range(3000, 10000); | ||
2448 | snd_rme96_apply_dac_volume(rme96); | ||
2449 | } | ||
2450 | |||
2451 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
2452 | |||
2453 | return 0; | ||
2454 | } | ||
2455 | |||
2456 | #endif | ||
2457 | |||
2322 | static void snd_rme96_card_free(struct snd_card *card) | 2458 | static void snd_rme96_card_free(struct snd_card *card) |
2323 | { | 2459 | { |
2324 | snd_rme96_free(card->private_data); | 2460 | snd_rme96_free(card->private_data); |
@@ -2355,6 +2491,23 @@ snd_rme96_probe(struct pci_dev *pci, | |||
2355 | return err; | 2491 | return err; |
2356 | } | 2492 | } |
2357 | 2493 | ||
2494 | #ifdef CONFIG_PM | ||
2495 | rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); | ||
2496 | if (!rme96->playback_suspend_buffer) { | ||
2497 | snd_printk(KERN_ERR | ||
2498 | "Failed to allocate playback suspend buffer!\n"); | ||
2499 | snd_card_free(card); | ||
2500 | return -ENOMEM; | ||
2501 | } | ||
2502 | rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); | ||
2503 | if (!rme96->capture_suspend_buffer) { | ||
2504 | snd_printk(KERN_ERR | ||
2505 | "Failed to allocate capture suspend buffer!\n"); | ||
2506 | snd_card_free(card); | ||
2507 | return -ENOMEM; | ||
2508 | } | ||
2509 | #endif | ||
2510 | |||
2358 | strcpy(card->driver, "Digi96"); | 2511 | strcpy(card->driver, "Digi96"); |
2359 | switch (rme96->pci->device) { | 2512 | switch (rme96->pci->device) { |
2360 | case PCI_DEVICE_ID_RME_DIGI96: | 2513 | case PCI_DEVICE_ID_RME_DIGI96: |
@@ -2397,6 +2550,10 @@ static struct pci_driver rme96_driver = { | |||
2397 | .id_table = snd_rme96_ids, | 2550 | .id_table = snd_rme96_ids, |
2398 | .probe = snd_rme96_probe, | 2551 | .probe = snd_rme96_probe, |
2399 | .remove = snd_rme96_remove, | 2552 | .remove = snd_rme96_remove, |
2553 | #ifdef CONFIG_PM | ||
2554 | .suspend = snd_rme96_suspend, | ||
2555 | .resume = snd_rme96_resume, | ||
2556 | #endif | ||
2400 | }; | 2557 | }; |
2401 | 2558 | ||
2402 | module_pci_driver(rme96_driver); | 2559 | module_pci_driver(rme96_driver); |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index bd501931ee23..3cde55b753e2 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
@@ -38,6 +38,97 @@ | |||
38 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 38 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
39 | * | 39 | * |
40 | */ | 40 | */ |
41 | |||
42 | /* ************* Register Documentation ******************************************************* | ||
43 | * | ||
44 | * Work in progress! Documentation is based on the code in this file. | ||
45 | * | ||
46 | * --------- HDSPM_controlRegister --------- | ||
47 | * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte | ||
48 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
49 | * :3322.2222:2222.1111:1111.1100:0000.0000: bit number | ||
50 | * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 | ||
51 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
52 | * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit | ||
53 | * : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits | ||
54 | * : . : . : . : . x: HDSPM_Start / enables audio IO | ||
55 | * : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave | ||
56 | * : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency | ||
57 | * : . : . : . : . : 0:64, 1:128, 2:256, 3:512, | ||
58 | * : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192 | ||
59 | * :x . : . : . x:xx . : HDSPM_FrequencyMask | ||
60 | * : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=?? | ||
61 | * : . : . : . x: . : <MADI> HDSPM_DoubleSpeed | ||
62 | * :x . : . : . : . : <MADI> HDSPM_QuadSpeed | ||
63 | * : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask : | ||
64 | * : . : . x: . : . : HDSPM_SyncRef0 | ||
65 | * : . : . x : . : . : HDSPM_SyncRef1 | ||
66 | * : . : . : x . : . : <AES32> HDSPM_SyncRef2 | ||
67 | * : . x : . : . : . : <AES32> HDSPM_SyncRef3 | ||
68 | * : . : . 10: . : . : <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn | ||
69 | * : . 3 : . 10: 2 . : . : <AES32> 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn? | ||
70 | * : . x : . : . : . : <MADIe> HDSPe_FLOAT_FORMAT | ||
71 | * : . : . : x . : . : <MADI> HDSPM_InputSelect0 : 0=optical,1=coax | ||
72 | * : . : . :x . : . : <MADI> HDSPM_InputSelect1 | ||
73 | * : . : .x : . : . : <MADI> HDSPM_clr_tms | ||
74 | * : . : . : . x : . : <MADI> HDSPM_TX_64ch | ||
75 | * : . : . : . x : . : <AES32> HDSPM_Emphasis | ||
76 | * : . : . : .x : . : <MADI> HDSPM_AutoInp | ||
77 | * : . : . x : . : . : <MADI> HDSPM_SMUX | ||
78 | * : . : .x : . : . : <MADI> HDSPM_clr_tms | ||
79 | * : . : x. : . : . : <MADI> HDSPM_taxi_reset | ||
80 | * : . x: . : . : . : <MADI> HDSPM_LineOut | ||
81 | * : . x: . : . : . : <AES32> ?????????????????? | ||
82 | * : . : x. : . : . : <AES32> HDSPM_WCK48 | ||
83 | * : . : . : .x : . : <AES32> HDSPM_Dolby | ||
84 | * : . : x . : . : . : HDSPM_Midi0InterruptEnable | ||
85 | * : . :x . : . : . : HDSPM_Midi1InterruptEnable | ||
86 | * : . : x . : . : . : HDSPM_Midi2InterruptEnable | ||
87 | * : . x : . : . : . : <MADI> HDSPM_Midi3InterruptEnable | ||
88 | * : . x : . : . : . : <AES32> HDSPM_DS_DoubleWire | ||
89 | * : .x : . : . : . : <AES32> HDSPM_QS_DoubleWire | ||
90 | * : x. : . : . : . : <AES32> HDSPM_QS_QuadWire | ||
91 | * : . : . : . x : . : <AES32> HDSPM_Professional | ||
92 | * : x . : . : . : . : HDSPM_wclk_sel | ||
93 | * : . : . : . : . : | ||
94 | * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte | ||
95 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
96 | * :3322.2222:2222.1111:1111.1100:0000.0000: bit number | ||
97 | * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 | ||
98 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
99 | * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit | ||
100 | * | ||
101 | * | ||
102 | * | ||
103 | * AIO / RayDAT only | ||
104 | * | ||
105 | * ------------ HDSPM_WR_SETTINGS ---------- | ||
106 | * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte | ||
107 | * :1098.7654:3210.9876:5432.1098:7654.3210: | ||
108 | * :||||.||||:||||.||||:||||.||||:||||.||||: bit number | ||
109 | * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 | ||
110 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
111 | * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit | ||
112 | * : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave | ||
113 | * : . : . : . : . x : HDSPM_c0_SyncRef0 | ||
114 | * : . : . : . : . x : HDSPM_c0_SyncRef1 | ||
115 | * : . : . : . : .x : HDSPM_c0_SyncRef2 | ||
116 | * : . : . : . : x. : HDSPM_c0_SyncRef3 | ||
117 | * : . : . : . : 3.210 : HDSPM_c0_SyncRefMask: | ||
118 | * : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4, | ||
119 | * : . : . : . : . : 9:TCO, 10:SyncIn | ||
120 | * : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT, | ||
121 | * : . : . : . : . : 9:TCO, 10:SyncIn | ||
122 | * : . : . : . : . : | ||
123 | * : . : . : . : . : | ||
124 | * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte | ||
125 | * :1098.7654:3210.9876:5432.1098:7654.3210: | ||
126 | * :||||.||||:||||.||||:||||.||||:||||.||||: bit number | ||
127 | * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 | ||
128 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
129 | * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit | ||
130 | * | ||
131 | */ | ||
41 | #include <linux/init.h> | 132 | #include <linux/init.h> |
42 | #include <linux/delay.h> | 133 | #include <linux/delay.h> |
43 | #include <linux/interrupt.h> | 134 | #include <linux/interrupt.h> |
@@ -95,7 +186,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
95 | #define HDSPM_controlRegister 64 | 186 | #define HDSPM_controlRegister 64 |
96 | #define HDSPM_interruptConfirmation 96 | 187 | #define HDSPM_interruptConfirmation 96 |
97 | #define HDSPM_control2Reg 256 /* not in specs ???????? */ | 188 | #define HDSPM_control2Reg 256 /* not in specs ???????? */ |
98 | #define HDSPM_freqReg 256 /* for AES32 */ | 189 | #define HDSPM_freqReg 256 /* for setting arbitrary clock values (DDS feature) */ |
99 | #define HDSPM_midiDataOut0 352 /* just believe in old code */ | 190 | #define HDSPM_midiDataOut0 352 /* just believe in old code */ |
100 | #define HDSPM_midiDataOut1 356 | 191 | #define HDSPM_midiDataOut1 356 |
101 | #define HDSPM_eeprom_wr 384 /* for AES32 */ | 192 | #define HDSPM_eeprom_wr 384 /* for AES32 */ |
@@ -258,6 +349,25 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
258 | 349 | ||
259 | #define HDSPM_wclk_sel (1<<30) | 350 | #define HDSPM_wclk_sel (1<<30) |
260 | 351 | ||
352 | /* additional control register bits for AIO*/ | ||
353 | #define HDSPM_c0_Wck48 0x20 /* also RayDAT */ | ||
354 | #define HDSPM_c0_Input0 0x1000 | ||
355 | #define HDSPM_c0_Input1 0x2000 | ||
356 | #define HDSPM_c0_Spdif_Opt 0x4000 | ||
357 | #define HDSPM_c0_Pro 0x8000 | ||
358 | #define HDSPM_c0_clr_tms 0x10000 | ||
359 | #define HDSPM_c0_AEB1 0x20000 | ||
360 | #define HDSPM_c0_AEB2 0x40000 | ||
361 | #define HDSPM_c0_LineOut 0x80000 | ||
362 | #define HDSPM_c0_AD_GAIN0 0x100000 | ||
363 | #define HDSPM_c0_AD_GAIN1 0x200000 | ||
364 | #define HDSPM_c0_DA_GAIN0 0x400000 | ||
365 | #define HDSPM_c0_DA_GAIN1 0x800000 | ||
366 | #define HDSPM_c0_PH_GAIN0 0x1000000 | ||
367 | #define HDSPM_c0_PH_GAIN1 0x2000000 | ||
368 | #define HDSPM_c0_Sym6db 0x4000000 | ||
369 | |||
370 | |||
261 | /* --- bit helper defines */ | 371 | /* --- bit helper defines */ |
262 | #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) | 372 | #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) |
263 | #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ | 373 | #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ |
@@ -341,11 +451,11 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
341 | #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ | 451 | #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ |
342 | #define HDSPM_madiSync (1<<18) /* MADI is in sync */ | 452 | #define HDSPM_madiSync (1<<18) /* MADI is in sync */ |
343 | 453 | ||
344 | #define HDSPM_tcoLock 0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */ | 454 | #define HDSPM_tcoLockMadi 0x00000020 /* Optional TCO locked status for HDSPe MADI*/ |
345 | #define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status */ | 455 | #define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/ |
346 | 456 | ||
347 | #define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */ | 457 | #define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */ |
348 | #define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */ | 458 | #define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */ |
349 | 459 | ||
350 | #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ | 460 | #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ |
351 | /* since 64byte accurate, last 6 bits are not used */ | 461 | /* since 64byte accurate, last 6 bits are not used */ |
@@ -363,7 +473,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
363 | * Interrupt | 473 | * Interrupt |
364 | */ | 474 | */ |
365 | #define HDSPM_tco_detect 0x08000000 | 475 | #define HDSPM_tco_detect 0x08000000 |
366 | #define HDSPM_tco_lock 0x20000000 | 476 | #define HDSPM_tcoLockAes 0x20000000 /* Optional TCO locked status for HDSPe AES */ |
367 | 477 | ||
368 | #define HDSPM_s2_tco_detect 0x00000040 | 478 | #define HDSPM_s2_tco_detect 0x00000040 |
369 | #define HDSPM_s2_AEBO_D 0x00000080 | 479 | #define HDSPM_s2_AEBO_D 0x00000080 |
@@ -461,7 +571,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
461 | #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 | 571 | #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 |
462 | #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 | 572 | #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 |
463 | #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 | 573 | #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 |
464 | #define HDSPM_AES32_AUTOSYNC_FROM_NONE 9 | 574 | #define HDSPM_AES32_AUTOSYNC_FROM_TCO 9 |
575 | #define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10 | ||
576 | #define HDSPM_AES32_AUTOSYNC_FROM_NONE 11 | ||
465 | 577 | ||
466 | /* status2 */ | 578 | /* status2 */ |
467 | /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ | 579 | /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ |
@@ -537,36 +649,39 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
537 | /* names for speed modes */ | 649 | /* names for speed modes */ |
538 | static char *hdspm_speed_names[] = { "single", "double", "quad" }; | 650 | static char *hdspm_speed_names[] = { "single", "double", "quad" }; |
539 | 651 | ||
540 | static char *texts_autosync_aes_tco[] = { "Word Clock", | 652 | static const char *const texts_autosync_aes_tco[] = { "Word Clock", |
541 | "AES1", "AES2", "AES3", "AES4", | 653 | "AES1", "AES2", "AES3", "AES4", |
542 | "AES5", "AES6", "AES7", "AES8", | 654 | "AES5", "AES6", "AES7", "AES8", |
543 | "TCO" }; | 655 | "TCO", "Sync In" |
544 | static char *texts_autosync_aes[] = { "Word Clock", | 656 | }; |
657 | static const char *const texts_autosync_aes[] = { "Word Clock", | ||
545 | "AES1", "AES2", "AES3", "AES4", | 658 | "AES1", "AES2", "AES3", "AES4", |
546 | "AES5", "AES6", "AES7", "AES8" }; | 659 | "AES5", "AES6", "AES7", "AES8", |
547 | static char *texts_autosync_madi_tco[] = { "Word Clock", | 660 | "Sync In" |
661 | }; | ||
662 | static const char *const texts_autosync_madi_tco[] = { "Word Clock", | ||
548 | "MADI", "TCO", "Sync In" }; | 663 | "MADI", "TCO", "Sync In" }; |
549 | static char *texts_autosync_madi[] = { "Word Clock", | 664 | static const char *const texts_autosync_madi[] = { "Word Clock", |
550 | "MADI", "Sync In" }; | 665 | "MADI", "Sync In" }; |
551 | 666 | ||
552 | static char *texts_autosync_raydat_tco[] = { | 667 | static const char *const texts_autosync_raydat_tco[] = { |
553 | "Word Clock", | 668 | "Word Clock", |
554 | "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", | 669 | "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", |
555 | "AES", "SPDIF", "TCO", "Sync In" | 670 | "AES", "SPDIF", "TCO", "Sync In" |
556 | }; | 671 | }; |
557 | static char *texts_autosync_raydat[] = { | 672 | static const char *const texts_autosync_raydat[] = { |
558 | "Word Clock", | 673 | "Word Clock", |
559 | "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", | 674 | "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", |
560 | "AES", "SPDIF", "Sync In" | 675 | "AES", "SPDIF", "Sync In" |
561 | }; | 676 | }; |
562 | static char *texts_autosync_aio_tco[] = { | 677 | static const char *const texts_autosync_aio_tco[] = { |
563 | "Word Clock", | 678 | "Word Clock", |
564 | "ADAT", "AES", "SPDIF", "TCO", "Sync In" | 679 | "ADAT", "AES", "SPDIF", "TCO", "Sync In" |
565 | }; | 680 | }; |
566 | static char *texts_autosync_aio[] = { "Word Clock", | 681 | static const char *const texts_autosync_aio[] = { "Word Clock", |
567 | "ADAT", "AES", "SPDIF", "Sync In" }; | 682 | "ADAT", "AES", "SPDIF", "Sync In" }; |
568 | 683 | ||
569 | static char *texts_freq[] = { | 684 | static const char *const texts_freq[] = { |
570 | "No Lock", | 685 | "No Lock", |
571 | "32 kHz", | 686 | "32 kHz", |
572 | "44.1 kHz", | 687 | "44.1 kHz", |
@@ -629,7 +744,8 @@ static char *texts_ports_aio_in_ss[] = { | |||
629 | "AES.L", "AES.R", | 744 | "AES.L", "AES.R", |
630 | "SPDIF.L", "SPDIF.R", | 745 | "SPDIF.L", "SPDIF.R", |
631 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", | 746 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", |
632 | "ADAT.7", "ADAT.8" | 747 | "ADAT.7", "ADAT.8", |
748 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
633 | }; | 749 | }; |
634 | 750 | ||
635 | static char *texts_ports_aio_out_ss[] = { | 751 | static char *texts_ports_aio_out_ss[] = { |
@@ -638,14 +754,16 @@ static char *texts_ports_aio_out_ss[] = { | |||
638 | "SPDIF.L", "SPDIF.R", | 754 | "SPDIF.L", "SPDIF.R", |
639 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", | 755 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", |
640 | "ADAT.7", "ADAT.8", | 756 | "ADAT.7", "ADAT.8", |
641 | "Phone.L", "Phone.R" | 757 | "Phone.L", "Phone.R", |
758 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
642 | }; | 759 | }; |
643 | 760 | ||
644 | static char *texts_ports_aio_in_ds[] = { | 761 | static char *texts_ports_aio_in_ds[] = { |
645 | "Analogue.L", "Analogue.R", | 762 | "Analogue.L", "Analogue.R", |
646 | "AES.L", "AES.R", | 763 | "AES.L", "AES.R", |
647 | "SPDIF.L", "SPDIF.R", | 764 | "SPDIF.L", "SPDIF.R", |
648 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" | 765 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", |
766 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
649 | }; | 767 | }; |
650 | 768 | ||
651 | static char *texts_ports_aio_out_ds[] = { | 769 | static char *texts_ports_aio_out_ds[] = { |
@@ -653,14 +771,16 @@ static char *texts_ports_aio_out_ds[] = { | |||
653 | "AES.L", "AES.R", | 771 | "AES.L", "AES.R", |
654 | "SPDIF.L", "SPDIF.R", | 772 | "SPDIF.L", "SPDIF.R", |
655 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", | 773 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", |
656 | "Phone.L", "Phone.R" | 774 | "Phone.L", "Phone.R", |
775 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
657 | }; | 776 | }; |
658 | 777 | ||
659 | static char *texts_ports_aio_in_qs[] = { | 778 | static char *texts_ports_aio_in_qs[] = { |
660 | "Analogue.L", "Analogue.R", | 779 | "Analogue.L", "Analogue.R", |
661 | "AES.L", "AES.R", | 780 | "AES.L", "AES.R", |
662 | "SPDIF.L", "SPDIF.R", | 781 | "SPDIF.L", "SPDIF.R", |
663 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" | 782 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", |
783 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
664 | }; | 784 | }; |
665 | 785 | ||
666 | static char *texts_ports_aio_out_qs[] = { | 786 | static char *texts_ports_aio_out_qs[] = { |
@@ -668,7 +788,8 @@ static char *texts_ports_aio_out_qs[] = { | |||
668 | "AES.L", "AES.R", | 788 | "AES.L", "AES.R", |
669 | "SPDIF.L", "SPDIF.R", | 789 | "SPDIF.L", "SPDIF.R", |
670 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", | 790 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", |
671 | "Phone.L", "Phone.R" | 791 | "Phone.L", "Phone.R", |
792 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
672 | }; | 793 | }; |
673 | 794 | ||
674 | static char *texts_ports_aes32[] = { | 795 | static char *texts_ports_aes32[] = { |
@@ -745,8 +866,8 @@ static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = { | |||
745 | 8, 9, /* aes in, */ | 866 | 8, 9, /* aes in, */ |
746 | 10, 11, /* spdif in */ | 867 | 10, 11, /* spdif in */ |
747 | 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ | 868 | 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ |
748 | -1, -1, | 869 | 2, 3, 4, 5, /* AEB */ |
749 | -1, -1, -1, -1, -1, -1, -1, -1, | 870 | -1, -1, -1, -1, -1, -1, |
750 | -1, -1, -1, -1, -1, -1, -1, -1, | 871 | -1, -1, -1, -1, -1, -1, -1, -1, |
751 | -1, -1, -1, -1, -1, -1, -1, -1, | 872 | -1, -1, -1, -1, -1, -1, -1, -1, |
752 | -1, -1, -1, -1, -1, -1, -1, -1, | 873 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -760,7 +881,8 @@ static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = { | |||
760 | 10, 11, /* spdif out */ | 881 | 10, 11, /* spdif out */ |
761 | 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ | 882 | 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ |
762 | 6, 7, /* phone out */ | 883 | 6, 7, /* phone out */ |
763 | -1, -1, -1, -1, -1, -1, -1, -1, | 884 | 2, 3, 4, 5, /* AEB */ |
885 | -1, -1, -1, -1, | ||
764 | -1, -1, -1, -1, -1, -1, -1, -1, | 886 | -1, -1, -1, -1, -1, -1, -1, -1, |
765 | -1, -1, -1, -1, -1, -1, -1, -1, | 887 | -1, -1, -1, -1, -1, -1, -1, -1, |
766 | -1, -1, -1, -1, -1, -1, -1, -1, | 888 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -773,7 +895,8 @@ static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = { | |||
773 | 8, 9, /* aes in */ | 895 | 8, 9, /* aes in */ |
774 | 10, 11, /* spdif in */ | 896 | 10, 11, /* spdif in */ |
775 | 12, 14, 16, 18, /* adat in */ | 897 | 12, 14, 16, 18, /* adat in */ |
776 | -1, -1, -1, -1, -1, -1, | 898 | 2, 3, 4, 5, /* AEB */ |
899 | -1, -1, | ||
777 | -1, -1, -1, -1, -1, -1, -1, -1, | 900 | -1, -1, -1, -1, -1, -1, -1, -1, |
778 | -1, -1, -1, -1, -1, -1, -1, -1, | 901 | -1, -1, -1, -1, -1, -1, -1, -1, |
779 | -1, -1, -1, -1, -1, -1, -1, -1, | 902 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -788,7 +911,7 @@ static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = { | |||
788 | 10, 11, /* spdif out */ | 911 | 10, 11, /* spdif out */ |
789 | 12, 14, 16, 18, /* adat out */ | 912 | 12, 14, 16, 18, /* adat out */ |
790 | 6, 7, /* phone out */ | 913 | 6, 7, /* phone out */ |
791 | -1, -1, -1, -1, | 914 | 2, 3, 4, 5, /* AEB */ |
792 | -1, -1, -1, -1, -1, -1, -1, -1, | 915 | -1, -1, -1, -1, -1, -1, -1, -1, |
793 | -1, -1, -1, -1, -1, -1, -1, -1, | 916 | -1, -1, -1, -1, -1, -1, -1, -1, |
794 | -1, -1, -1, -1, -1, -1, -1, -1, | 917 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -802,7 +925,8 @@ static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = { | |||
802 | 8, 9, /* aes in */ | 925 | 8, 9, /* aes in */ |
803 | 10, 11, /* spdif in */ | 926 | 10, 11, /* spdif in */ |
804 | 12, 16, /* adat in */ | 927 | 12, 16, /* adat in */ |
805 | -1, -1, -1, -1, -1, -1, -1, -1, | 928 | 2, 3, 4, 5, /* AEB */ |
929 | -1, -1, -1, -1, | ||
806 | -1, -1, -1, -1, -1, -1, -1, -1, | 930 | -1, -1, -1, -1, -1, -1, -1, -1, |
807 | -1, -1, -1, -1, -1, -1, -1, -1, | 931 | -1, -1, -1, -1, -1, -1, -1, -1, |
808 | -1, -1, -1, -1, -1, -1, -1, -1, | 932 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -817,7 +941,8 @@ static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = { | |||
817 | 10, 11, /* spdif out */ | 941 | 10, 11, /* spdif out */ |
818 | 12, 16, /* adat out */ | 942 | 12, 16, /* adat out */ |
819 | 6, 7, /* phone out */ | 943 | 6, 7, /* phone out */ |
820 | -1, -1, -1, -1, -1, -1, | 944 | 2, 3, 4, 5, /* AEB */ |
945 | -1, -1, | ||
821 | -1, -1, -1, -1, -1, -1, -1, -1, | 946 | -1, -1, -1, -1, -1, -1, -1, -1, |
822 | -1, -1, -1, -1, -1, -1, -1, -1, | 947 | -1, -1, -1, -1, -1, -1, -1, -1, |
823 | -1, -1, -1, -1, -1, -1, -1, -1, | 948 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -856,11 +981,11 @@ struct hdspm_midi { | |||
856 | }; | 981 | }; |
857 | 982 | ||
858 | struct hdspm_tco { | 983 | struct hdspm_tco { |
859 | int input; | 984 | int input; /* 0: LTC, 1:Video, 2: WC*/ |
860 | int framerate; | 985 | int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */ |
861 | int wordclock; | 986 | int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */ |
862 | int samplerate; | 987 | int samplerate; /* 0=44.1, 1=48, 2= freq from app */ |
863 | int pull; | 988 | int pull; /* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/ |
864 | int term; /* 0 = off, 1 = on */ | 989 | int term; /* 0 = off, 1 = on */ |
865 | }; | 990 | }; |
866 | 991 | ||
@@ -879,7 +1004,7 @@ struct hdspm { | |||
879 | 1004 | ||
880 | u32 control_register; /* cached value */ | 1005 | u32 control_register; /* cached value */ |
881 | u32 control2_register; /* cached value */ | 1006 | u32 control2_register; /* cached value */ |
882 | u32 settings_register; | 1007 | u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */ |
883 | 1008 | ||
884 | struct hdspm_midi midi[4]; | 1009 | struct hdspm_midi midi[4]; |
885 | struct tasklet_struct midi_tasklet; | 1010 | struct tasklet_struct midi_tasklet; |
@@ -941,7 +1066,7 @@ struct hdspm { | |||
941 | 1066 | ||
942 | struct hdspm_tco *tco; /* NULL if no TCO detected */ | 1067 | struct hdspm_tco *tco; /* NULL if no TCO detected */ |
943 | 1068 | ||
944 | char **texts_autosync; | 1069 | const char *const *texts_autosync; |
945 | int texts_autosync_items; | 1070 | int texts_autosync_items; |
946 | 1071 | ||
947 | cycles_t last_interrupt; | 1072 | cycles_t last_interrupt; |
@@ -976,12 +1101,24 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); | |||
976 | static inline int hdspm_get_pll_freq(struct hdspm *hdspm); | 1101 | static inline int hdspm_get_pll_freq(struct hdspm *hdspm); |
977 | static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); | 1102 | static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); |
978 | static int hdspm_autosync_ref(struct hdspm *hdspm); | 1103 | static int hdspm_autosync_ref(struct hdspm *hdspm); |
1104 | static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out); | ||
979 | static int snd_hdspm_set_defaults(struct hdspm *hdspm); | 1105 | static int snd_hdspm_set_defaults(struct hdspm *hdspm); |
980 | static int hdspm_system_clock_mode(struct hdspm *hdspm); | 1106 | static int hdspm_system_clock_mode(struct hdspm *hdspm); |
981 | static void hdspm_set_sgbuf(struct hdspm *hdspm, | 1107 | static void hdspm_set_sgbuf(struct hdspm *hdspm, |
982 | struct snd_pcm_substream *substream, | 1108 | struct snd_pcm_substream *substream, |
983 | unsigned int reg, int channels); | 1109 | unsigned int reg, int channels); |
984 | 1110 | ||
1111 | static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx); | ||
1112 | static int hdspm_wc_sync_check(struct hdspm *hdspm); | ||
1113 | static int hdspm_tco_sync_check(struct hdspm *hdspm); | ||
1114 | static int hdspm_sync_in_sync_check(struct hdspm *hdspm); | ||
1115 | |||
1116 | static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index); | ||
1117 | static int hdspm_get_tco_sample_rate(struct hdspm *hdspm); | ||
1118 | static int hdspm_get_wc_sample_rate(struct hdspm *hdspm); | ||
1119 | |||
1120 | |||
1121 | |||
985 | static inline int HDSPM_bit2freq(int n) | 1122 | static inline int HDSPM_bit2freq(int n) |
986 | { | 1123 | { |
987 | static const int bit2freq_tab[] = { | 1124 | static const int bit2freq_tab[] = { |
@@ -992,6 +1129,12 @@ static inline int HDSPM_bit2freq(int n) | |||
992 | return bit2freq_tab[n]; | 1129 | return bit2freq_tab[n]; |
993 | } | 1130 | } |
994 | 1131 | ||
1132 | static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm) | ||
1133 | { | ||
1134 | return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type)); | ||
1135 | } | ||
1136 | |||
1137 | |||
995 | /* Write/read to/from HDSPM with Adresses in Bytes | 1138 | /* Write/read to/from HDSPM with Adresses in Bytes |
996 | not words but only 32Bit writes are allowed */ | 1139 | not words but only 32Bit writes are allowed */ |
997 | 1140 | ||
@@ -1107,14 +1250,11 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) | |||
1107 | else if (hdspm->control_register & | 1250 | else if (hdspm->control_register & |
1108 | HDSPM_DoubleSpeed) | 1251 | HDSPM_DoubleSpeed) |
1109 | return rate * 2; | 1252 | return rate * 2; |
1110 | }; | 1253 | } |
1111 | return rate; | 1254 | return rate; |
1112 | } | 1255 | } |
1113 | 1256 | ||
1114 | static int hdspm_tco_sync_check(struct hdspm *hdspm); | 1257 | /* check for external sample rate, returns the sample rate in Hz*/ |
1115 | static int hdspm_sync_in_sync_check(struct hdspm *hdspm); | ||
1116 | |||
1117 | /* check for external sample rate */ | ||
1118 | static int hdspm_external_sample_rate(struct hdspm *hdspm) | 1258 | static int hdspm_external_sample_rate(struct hdspm *hdspm) |
1119 | { | 1259 | { |
1120 | unsigned int status, status2, timecode; | 1260 | unsigned int status, status2, timecode; |
@@ -1127,17 +1267,36 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) | |||
1127 | timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); | 1267 | timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); |
1128 | 1268 | ||
1129 | syncref = hdspm_autosync_ref(hdspm); | 1269 | syncref = hdspm_autosync_ref(hdspm); |
1270 | switch (syncref) { | ||
1271 | case HDSPM_AES32_AUTOSYNC_FROM_WORD: | ||
1272 | /* Check WC sync and get sample rate */ | ||
1273 | if (hdspm_wc_sync_check(hdspm)) | ||
1274 | return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm)); | ||
1275 | break; | ||
1130 | 1276 | ||
1131 | if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && | 1277 | case HDSPM_AES32_AUTOSYNC_FROM_AES1: |
1132 | status & HDSPM_AES32_wcLock) | 1278 | case HDSPM_AES32_AUTOSYNC_FROM_AES2: |
1133 | return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); | 1279 | case HDSPM_AES32_AUTOSYNC_FROM_AES3: |
1280 | case HDSPM_AES32_AUTOSYNC_FROM_AES4: | ||
1281 | case HDSPM_AES32_AUTOSYNC_FROM_AES5: | ||
1282 | case HDSPM_AES32_AUTOSYNC_FROM_AES6: | ||
1283 | case HDSPM_AES32_AUTOSYNC_FROM_AES7: | ||
1284 | case HDSPM_AES32_AUTOSYNC_FROM_AES8: | ||
1285 | /* Check AES sync and get sample rate */ | ||
1286 | if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)) | ||
1287 | return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm, | ||
1288 | syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)); | ||
1289 | break; | ||
1134 | 1290 | ||
1135 | if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && | 1291 | |
1136 | syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && | 1292 | case HDSPM_AES32_AUTOSYNC_FROM_TCO: |
1137 | status2 & (HDSPM_LockAES >> | 1293 | /* Check TCO sync and get sample rate */ |
1138 | (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))) | 1294 | if (hdspm_tco_sync_check(hdspm)) |
1139 | return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF); | 1295 | return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm)); |
1140 | return 0; | 1296 | break; |
1297 | default: | ||
1298 | return 0; | ||
1299 | } /* end switch(syncref) */ | ||
1141 | break; | 1300 | break; |
1142 | 1301 | ||
1143 | case MADIface: | 1302 | case MADIface: |
@@ -2129,6 +2288,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) | |||
2129 | status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); | 2288 | status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); |
2130 | return (status >> 16) & 0xF; | 2289 | return (status >> 16) & 0xF; |
2131 | break; | 2290 | break; |
2291 | case AES32: | ||
2292 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
2293 | return (status >> HDSPM_AES32_wcFreq_bit) & 0xF; | ||
2132 | default: | 2294 | default: |
2133 | break; | 2295 | break; |
2134 | } | 2296 | } |
@@ -2152,6 +2314,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) | |||
2152 | status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); | 2314 | status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); |
2153 | return (status >> 20) & 0xF; | 2315 | return (status >> 20) & 0xF; |
2154 | break; | 2316 | break; |
2317 | case AES32: | ||
2318 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
2319 | return (status >> 1) & 0xF; | ||
2155 | default: | 2320 | default: |
2156 | break; | 2321 | break; |
2157 | } | 2322 | } |
@@ -2183,6 +2348,23 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) | |||
2183 | return 0; | 2348 | return 0; |
2184 | } | 2349 | } |
2185 | 2350 | ||
2351 | /** | ||
2352 | * Returns the AES sample rate class for the given card. | ||
2353 | **/ | ||
2354 | static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) | ||
2355 | { | ||
2356 | int timecode; | ||
2357 | |||
2358 | switch (hdspm->io_type) { | ||
2359 | case AES32: | ||
2360 | timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); | ||
2361 | return (timecode >> (4*index)) & 0xF; | ||
2362 | break; | ||
2363 | default: | ||
2364 | break; | ||
2365 | } | ||
2366 | return 0; | ||
2367 | } | ||
2186 | 2368 | ||
2187 | /** | 2369 | /** |
2188 | * Returns the sample rate class for input source <idx> for | 2370 | * Returns the sample rate class for input source <idx> for |
@@ -2196,15 +2378,23 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) | |||
2196 | } | 2378 | } |
2197 | 2379 | ||
2198 | #define ENUMERATED_CTL_INFO(info, texts) \ | 2380 | #define ENUMERATED_CTL_INFO(info, texts) \ |
2199 | { \ | 2381 | snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts) |
2200 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \ | 2382 | |
2201 | uinfo->count = 1; \ | ||
2202 | uinfo->value.enumerated.items = ARRAY_SIZE(texts); \ | ||
2203 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \ | ||
2204 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; \ | ||
2205 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \ | ||
2206 | } | ||
2207 | 2383 | ||
2384 | /* Helper function to query the external sample rate and return the | ||
2385 | * corresponding enum to be returned to userspace. | ||
2386 | */ | ||
2387 | static int hdspm_external_rate_to_enum(struct hdspm *hdspm) | ||
2388 | { | ||
2389 | int rate = hdspm_external_sample_rate(hdspm); | ||
2390 | int i, selected_rate = 0; | ||
2391 | for (i = 1; i < 10; i++) | ||
2392 | if (HDSPM_bit2freq(i) == rate) { | ||
2393 | selected_rate = i; | ||
2394 | break; | ||
2395 | } | ||
2396 | return selected_rate; | ||
2397 | } | ||
2208 | 2398 | ||
2209 | 2399 | ||
2210 | #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ | 2400 | #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ |
@@ -2270,7 +2460,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, | |||
2270 | default: | 2460 | default: |
2271 | ucontrol->value.enumerated.item[0] = | 2461 | ucontrol->value.enumerated.item[0] = |
2272 | hdspm_get_s1_sample_rate(hdspm, | 2462 | hdspm_get_s1_sample_rate(hdspm, |
2273 | ucontrol->id.index-1); | 2463 | kcontrol->private_value-1); |
2274 | } | 2464 | } |
2275 | break; | 2465 | break; |
2276 | 2466 | ||
@@ -2289,28 +2479,24 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, | |||
2289 | ucontrol->value.enumerated.item[0] = | 2479 | ucontrol->value.enumerated.item[0] = |
2290 | hdspm_get_sync_in_sample_rate(hdspm); | 2480 | hdspm_get_sync_in_sample_rate(hdspm); |
2291 | break; | 2481 | break; |
2482 | case 11: /* External Rate */ | ||
2483 | ucontrol->value.enumerated.item[0] = | ||
2484 | hdspm_external_rate_to_enum(hdspm); | ||
2485 | break; | ||
2292 | default: /* AES1 to AES8 */ | 2486 | default: /* AES1 to AES8 */ |
2293 | ucontrol->value.enumerated.item[0] = | 2487 | ucontrol->value.enumerated.item[0] = |
2294 | hdspm_get_s1_sample_rate(hdspm, | 2488 | hdspm_get_aes_sample_rate(hdspm, |
2295 | kcontrol->private_value-1); | 2489 | kcontrol->private_value - |
2490 | HDSPM_AES32_AUTOSYNC_FROM_AES1); | ||
2296 | break; | 2491 | break; |
2297 | } | 2492 | } |
2298 | break; | 2493 | break; |
2299 | 2494 | ||
2300 | case MADI: | 2495 | case MADI: |
2301 | case MADIface: | 2496 | case MADIface: |
2302 | { | 2497 | ucontrol->value.enumerated.item[0] = |
2303 | int rate = hdspm_external_sample_rate(hdspm); | 2498 | hdspm_external_rate_to_enum(hdspm); |
2304 | int i, selected_rate = 0; | ||
2305 | for (i = 1; i < 10; i++) | ||
2306 | if (HDSPM_bit2freq(i) == rate) { | ||
2307 | selected_rate = i; | ||
2308 | break; | ||
2309 | } | ||
2310 | ucontrol->value.enumerated.item[0] = selected_rate; | ||
2311 | } | ||
2312 | break; | 2499 | break; |
2313 | |||
2314 | default: | 2500 | default: |
2315 | break; | 2501 | break; |
2316 | } | 2502 | } |
@@ -2359,33 +2545,17 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm) | |||
2359 | **/ | 2545 | **/ |
2360 | static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) | 2546 | static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) |
2361 | { | 2547 | { |
2362 | switch (hdspm->io_type) { | 2548 | hdspm_set_toggle_setting(hdspm, |
2363 | case AIO: | 2549 | (hdspm_is_raydat_or_aio(hdspm)) ? |
2364 | case RayDAT: | 2550 | HDSPM_c0Master : HDSPM_ClockModeMaster, |
2365 | if (0 == mode) | 2551 | (0 == mode)); |
2366 | hdspm->settings_register |= HDSPM_c0Master; | ||
2367 | else | ||
2368 | hdspm->settings_register &= ~HDSPM_c0Master; | ||
2369 | |||
2370 | hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); | ||
2371 | break; | ||
2372 | |||
2373 | default: | ||
2374 | if (0 == mode) | ||
2375 | hdspm->control_register |= HDSPM_ClockModeMaster; | ||
2376 | else | ||
2377 | hdspm->control_register &= ~HDSPM_ClockModeMaster; | ||
2378 | |||
2379 | hdspm_write(hdspm, HDSPM_controlRegister, | ||
2380 | hdspm->control_register); | ||
2381 | } | ||
2382 | } | 2552 | } |
2383 | 2553 | ||
2384 | 2554 | ||
2385 | static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, | 2555 | static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, |
2386 | struct snd_ctl_elem_info *uinfo) | 2556 | struct snd_ctl_elem_info *uinfo) |
2387 | { | 2557 | { |
2388 | static char *texts[] = { "Master", "AutoSync" }; | 2558 | static const char *const texts[] = { "Master", "AutoSync" }; |
2389 | ENUMERATED_CTL_INFO(uinfo, texts); | 2559 | ENUMERATED_CTL_INFO(uinfo, texts); |
2390 | return 0; | 2560 | return 0; |
2391 | } | 2561 | } |
@@ -2809,16 +2979,7 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, | |||
2809 | { | 2979 | { |
2810 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | 2980 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); |
2811 | 2981 | ||
2812 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2982 | snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync); |
2813 | uinfo->count = 1; | ||
2814 | uinfo->value.enumerated.items = hdspm->texts_autosync_items; | ||
2815 | |||
2816 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2817 | uinfo->value.enumerated.item = | ||
2818 | uinfo->value.enumerated.items - 1; | ||
2819 | |||
2820 | strcpy(uinfo->value.enumerated.name, | ||
2821 | hdspm->texts_autosync[uinfo->value.enumerated.item]); | ||
2822 | 2983 | ||
2823 | return 0; | 2984 | return 0; |
2824 | } | 2985 | } |
@@ -2873,19 +3034,20 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, | |||
2873 | 3034 | ||
2874 | static int hdspm_autosync_ref(struct hdspm *hdspm) | 3035 | static int hdspm_autosync_ref(struct hdspm *hdspm) |
2875 | { | 3036 | { |
3037 | /* This looks at the autosync selected sync reference */ | ||
2876 | if (AES32 == hdspm->io_type) { | 3038 | if (AES32 == hdspm->io_type) { |
3039 | |||
2877 | unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); | 3040 | unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); |
2878 | unsigned int syncref = | 3041 | unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; |
2879 | (status >> HDSPM_AES32_syncref_bit) & 0xF; | 3042 | if ((syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD) && |
2880 | if (syncref == 0) | 3043 | (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN)) { |
2881 | return HDSPM_AES32_AUTOSYNC_FROM_WORD; | ||
2882 | if (syncref <= 8) | ||
2883 | return syncref; | 3044 | return syncref; |
3045 | } | ||
2884 | return HDSPM_AES32_AUTOSYNC_FROM_NONE; | 3046 | return HDSPM_AES32_AUTOSYNC_FROM_NONE; |
3047 | |||
2885 | } else if (MADI == hdspm->io_type) { | 3048 | } else if (MADI == hdspm->io_type) { |
2886 | /* This looks at the autosync selected sync reference */ | ||
2887 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
2888 | 3049 | ||
3050 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
2889 | switch (status2 & HDSPM_SelSyncRefMask) { | 3051 | switch (status2 & HDSPM_SelSyncRefMask) { |
2890 | case HDSPM_SelSyncRef_WORD: | 3052 | case HDSPM_SelSyncRef_WORD: |
2891 | return HDSPM_AUTOSYNC_FROM_WORD; | 3053 | return HDSPM_AUTOSYNC_FROM_WORD; |
@@ -2898,7 +3060,7 @@ static int hdspm_autosync_ref(struct hdspm *hdspm) | |||
2898 | case HDSPM_SelSyncRef_NVALID: | 3060 | case HDSPM_SelSyncRef_NVALID: |
2899 | return HDSPM_AUTOSYNC_FROM_NONE; | 3061 | return HDSPM_AUTOSYNC_FROM_NONE; |
2900 | default: | 3062 | default: |
2901 | return 0; | 3063 | return HDSPM_AUTOSYNC_FROM_NONE; |
2902 | } | 3064 | } |
2903 | 3065 | ||
2904 | } | 3066 | } |
@@ -2912,31 +3074,15 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, | |||
2912 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | 3074 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); |
2913 | 3075 | ||
2914 | if (AES32 == hdspm->io_type) { | 3076 | if (AES32 == hdspm->io_type) { |
2915 | static char *texts[] = { "WordClock", "AES1", "AES2", "AES3", | 3077 | static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3", |
2916 | "AES4", "AES5", "AES6", "AES7", "AES8", "None"}; | 3078 | "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"}; |
2917 | 3079 | ||
2918 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 3080 | ENUMERATED_CTL_INFO(uinfo, texts); |
2919 | uinfo->count = 1; | ||
2920 | uinfo->value.enumerated.items = 10; | ||
2921 | if (uinfo->value.enumerated.item >= | ||
2922 | uinfo->value.enumerated.items) | ||
2923 | uinfo->value.enumerated.item = | ||
2924 | uinfo->value.enumerated.items - 1; | ||
2925 | strcpy(uinfo->value.enumerated.name, | ||
2926 | texts[uinfo->value.enumerated.item]); | ||
2927 | } else if (MADI == hdspm->io_type) { | 3081 | } else if (MADI == hdspm->io_type) { |
2928 | static char *texts[] = {"Word Clock", "MADI", "TCO", | 3082 | static const char *const texts[] = {"Word Clock", "MADI", "TCO", |
2929 | "Sync In", "None" }; | 3083 | "Sync In", "None" }; |
2930 | 3084 | ||
2931 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 3085 | ENUMERATED_CTL_INFO(uinfo, texts); |
2932 | uinfo->count = 1; | ||
2933 | uinfo->value.enumerated.items = 5; | ||
2934 | if (uinfo->value.enumerated.item >= | ||
2935 | uinfo->value.enumerated.items) | ||
2936 | uinfo->value.enumerated.item = | ||
2937 | uinfo->value.enumerated.items - 1; | ||
2938 | strcpy(uinfo->value.enumerated.name, | ||
2939 | texts[uinfo->value.enumerated.item]); | ||
2940 | } | 3086 | } |
2941 | return 0; | 3087 | return 0; |
2942 | } | 3088 | } |
@@ -2964,7 +3110,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, | |||
2964 | static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, | 3110 | static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, |
2965 | struct snd_ctl_elem_info *uinfo) | 3111 | struct snd_ctl_elem_info *uinfo) |
2966 | { | 3112 | { |
2967 | static char *texts[] = {"No video", "NTSC", "PAL"}; | 3113 | static const char *const texts[] = {"No video", "NTSC", "PAL"}; |
2968 | ENUMERATED_CTL_INFO(uinfo, texts); | 3114 | ENUMERATED_CTL_INFO(uinfo, texts); |
2969 | return 0; | 3115 | return 0; |
2970 | } | 3116 | } |
@@ -3010,7 +3156,7 @@ static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol, | |||
3010 | static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, | 3156 | static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, |
3011 | struct snd_ctl_elem_info *uinfo) | 3157 | struct snd_ctl_elem_info *uinfo) |
3012 | { | 3158 | { |
3013 | static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", | 3159 | static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", |
3014 | "30 fps"}; | 3160 | "30 fps"}; |
3015 | ENUMERATED_CTL_INFO(uinfo, texts); | 3161 | ENUMERATED_CTL_INFO(uinfo, texts); |
3016 | return 0; | 3162 | return 0; |
@@ -3027,19 +3173,19 @@ static int hdspm_tco_ltc_frames(struct hdspm *hdspm) | |||
3027 | HDSPM_TCO1_LTC_Format_MSB)) { | 3173 | HDSPM_TCO1_LTC_Format_MSB)) { |
3028 | case 0: | 3174 | case 0: |
3029 | /* 24 fps */ | 3175 | /* 24 fps */ |
3030 | ret = 1; | 3176 | ret = fps_24; |
3031 | break; | 3177 | break; |
3032 | case HDSPM_TCO1_LTC_Format_LSB: | 3178 | case HDSPM_TCO1_LTC_Format_LSB: |
3033 | /* 25 fps */ | 3179 | /* 25 fps */ |
3034 | ret = 2; | 3180 | ret = fps_25; |
3035 | break; | 3181 | break; |
3036 | case HDSPM_TCO1_LTC_Format_MSB: | 3182 | case HDSPM_TCO1_LTC_Format_MSB: |
3037 | /* 25 fps */ | 3183 | /* 29.97 fps */ |
3038 | ret = 3; | 3184 | ret = fps_2997; |
3039 | break; | 3185 | break; |
3040 | default: | 3186 | default: |
3041 | /* 30 fps */ | 3187 | /* 30 fps */ |
3042 | ret = 4; | 3188 | ret = fps_30; |
3043 | break; | 3189 | break; |
3044 | } | 3190 | } |
3045 | } | 3191 | } |
@@ -3067,16 +3213,35 @@ static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol, | |||
3067 | 3213 | ||
3068 | static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) | 3214 | static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) |
3069 | { | 3215 | { |
3070 | return (hdspm->control_register & regmask) ? 1 : 0; | 3216 | u32 reg; |
3217 | |||
3218 | if (hdspm_is_raydat_or_aio(hdspm)) | ||
3219 | reg = hdspm->settings_register; | ||
3220 | else | ||
3221 | reg = hdspm->control_register; | ||
3222 | |||
3223 | return (reg & regmask) ? 1 : 0; | ||
3071 | } | 3224 | } |
3072 | 3225 | ||
3073 | static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) | 3226 | static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) |
3074 | { | 3227 | { |
3228 | u32 *reg; | ||
3229 | u32 target_reg; | ||
3230 | |||
3231 | if (hdspm_is_raydat_or_aio(hdspm)) { | ||
3232 | reg = &(hdspm->settings_register); | ||
3233 | target_reg = HDSPM_WR_SETTINGS; | ||
3234 | } else { | ||
3235 | reg = &(hdspm->control_register); | ||
3236 | target_reg = HDSPM_controlRegister; | ||
3237 | } | ||
3238 | |||
3075 | if (out) | 3239 | if (out) |
3076 | hdspm->control_register |= regmask; | 3240 | *reg |= regmask; |
3077 | else | 3241 | else |
3078 | hdspm->control_register &= ~regmask; | 3242 | *reg &= ~regmask; |
3079 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | 3243 | |
3244 | hdspm_write(hdspm, target_reg, *reg); | ||
3080 | 3245 | ||
3081 | return 0; | 3246 | return 0; |
3082 | } | 3247 | } |
@@ -3141,7 +3306,7 @@ static int hdspm_set_input_select(struct hdspm * hdspm, int out) | |||
3141 | static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, | 3306 | static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, |
3142 | struct snd_ctl_elem_info *uinfo) | 3307 | struct snd_ctl_elem_info *uinfo) |
3143 | { | 3308 | { |
3144 | static char *texts[] = { "optical", "coaxial" }; | 3309 | static const char *const texts[] = { "optical", "coaxial" }; |
3145 | ENUMERATED_CTL_INFO(uinfo, texts); | 3310 | ENUMERATED_CTL_INFO(uinfo, texts); |
3146 | return 0; | 3311 | return 0; |
3147 | } | 3312 | } |
@@ -3203,7 +3368,7 @@ static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) | |||
3203 | static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, | 3368 | static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, |
3204 | struct snd_ctl_elem_info *uinfo) | 3369 | struct snd_ctl_elem_info *uinfo) |
3205 | { | 3370 | { |
3206 | static char *texts[] = { "Single", "Double" }; | 3371 | static const char *const texts[] = { "Single", "Double" }; |
3207 | ENUMERATED_CTL_INFO(uinfo, texts); | 3372 | ENUMERATED_CTL_INFO(uinfo, texts); |
3208 | return 0; | 3373 | return 0; |
3209 | } | 3374 | } |
@@ -3276,7 +3441,7 @@ static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) | |||
3276 | static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, | 3441 | static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, |
3277 | struct snd_ctl_elem_info *uinfo) | 3442 | struct snd_ctl_elem_info *uinfo) |
3278 | { | 3443 | { |
3279 | static char *texts[] = { "Single", "Double", "Quad" }; | 3444 | static const char *const texts[] = { "Single", "Double", "Quad" }; |
3280 | ENUMERATED_CTL_INFO(uinfo, texts); | 3445 | ENUMERATED_CTL_INFO(uinfo, texts); |
3281 | return 0; | 3446 | return 0; |
3282 | } | 3447 | } |
@@ -3313,6 +3478,84 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, | |||
3313 | return change; | 3478 | return change; |
3314 | } | 3479 | } |
3315 | 3480 | ||
3481 | #define HDSPM_CONTROL_TRISTATE(xname, xindex) \ | ||
3482 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
3483 | .name = xname, \ | ||
3484 | .private_value = xindex, \ | ||
3485 | .info = snd_hdspm_info_tristate, \ | ||
3486 | .get = snd_hdspm_get_tristate, \ | ||
3487 | .put = snd_hdspm_put_tristate \ | ||
3488 | } | ||
3489 | |||
3490 | static int hdspm_tristate(struct hdspm *hdspm, u32 regmask) | ||
3491 | { | ||
3492 | u32 reg = hdspm->settings_register & (regmask * 3); | ||
3493 | return reg / regmask; | ||
3494 | } | ||
3495 | |||
3496 | static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask) | ||
3497 | { | ||
3498 | hdspm->settings_register &= ~(regmask * 3); | ||
3499 | hdspm->settings_register |= (regmask * mode); | ||
3500 | hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); | ||
3501 | |||
3502 | return 0; | ||
3503 | } | ||
3504 | |||
3505 | static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol, | ||
3506 | struct snd_ctl_elem_info *uinfo) | ||
3507 | { | ||
3508 | u32 regmask = kcontrol->private_value; | ||
3509 | |||
3510 | static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" }; | ||
3511 | static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; | ||
3512 | |||
3513 | switch (regmask) { | ||
3514 | case HDSPM_c0_Input0: | ||
3515 | ENUMERATED_CTL_INFO(uinfo, texts_spdif); | ||
3516 | break; | ||
3517 | default: | ||
3518 | ENUMERATED_CTL_INFO(uinfo, texts_levels); | ||
3519 | break; | ||
3520 | } | ||
3521 | return 0; | ||
3522 | } | ||
3523 | |||
3524 | static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol, | ||
3525 | struct snd_ctl_elem_value *ucontrol) | ||
3526 | { | ||
3527 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
3528 | u32 regmask = kcontrol->private_value; | ||
3529 | |||
3530 | spin_lock_irq(&hdspm->lock); | ||
3531 | ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask); | ||
3532 | spin_unlock_irq(&hdspm->lock); | ||
3533 | return 0; | ||
3534 | } | ||
3535 | |||
3536 | static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol, | ||
3537 | struct snd_ctl_elem_value *ucontrol) | ||
3538 | { | ||
3539 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
3540 | u32 regmask = kcontrol->private_value; | ||
3541 | int change; | ||
3542 | int val; | ||
3543 | |||
3544 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
3545 | return -EBUSY; | ||
3546 | val = ucontrol->value.integer.value[0]; | ||
3547 | if (val < 0) | ||
3548 | val = 0; | ||
3549 | if (val > 2) | ||
3550 | val = 2; | ||
3551 | |||
3552 | spin_lock_irq(&hdspm->lock); | ||
3553 | change = val != hdspm_tristate(hdspm, regmask); | ||
3554 | hdspm_set_tristate(hdspm, val, regmask); | ||
3555 | spin_unlock_irq(&hdspm->lock); | ||
3556 | return change; | ||
3557 | } | ||
3558 | |||
3316 | #define HDSPM_MADI_SPEEDMODE(xname, xindex) \ | 3559 | #define HDSPM_MADI_SPEEDMODE(xname, xindex) \ |
3317 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 3560 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
3318 | .name = xname, \ | 3561 | .name = xname, \ |
@@ -3352,7 +3595,7 @@ static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode) | |||
3352 | static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, | 3595 | static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, |
3353 | struct snd_ctl_elem_info *uinfo) | 3596 | struct snd_ctl_elem_info *uinfo) |
3354 | { | 3597 | { |
3355 | static char *texts[] = { "Single", "Double", "Quad" }; | 3598 | static const char *const texts[] = { "Single", "Double", "Quad" }; |
3356 | ENUMERATED_CTL_INFO(uinfo, texts); | 3599 | ENUMERATED_CTL_INFO(uinfo, texts); |
3357 | return 0; | 3600 | return 0; |
3358 | } | 3601 | } |
@@ -3587,7 +3830,7 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, | |||
3587 | static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, | 3830 | static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, |
3588 | struct snd_ctl_elem_info *uinfo) | 3831 | struct snd_ctl_elem_info *uinfo) |
3589 | { | 3832 | { |
3590 | static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" }; | 3833 | static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" }; |
3591 | ENUMERATED_CTL_INFO(uinfo, texts); | 3834 | ENUMERATED_CTL_INFO(uinfo, texts); |
3592 | return 0; | 3835 | return 0; |
3593 | } | 3836 | } |
@@ -3595,7 +3838,7 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, | |||
3595 | static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, | 3838 | static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, |
3596 | struct snd_ctl_elem_info *uinfo) | 3839 | struct snd_ctl_elem_info *uinfo) |
3597 | { | 3840 | { |
3598 | static char *texts[] = { "No Lock", "Lock" }; | 3841 | static const char *const texts[] = { "No Lock", "Lock" }; |
3599 | ENUMERATED_CTL_INFO(uinfo, texts); | 3842 | ENUMERATED_CTL_INFO(uinfo, texts); |
3600 | return 0; | 3843 | return 0; |
3601 | } | 3844 | } |
@@ -3745,9 +3988,18 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm) | |||
3745 | if (hdspm->tco) { | 3988 | if (hdspm->tco) { |
3746 | switch (hdspm->io_type) { | 3989 | switch (hdspm->io_type) { |
3747 | case MADI: | 3990 | case MADI: |
3991 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
3992 | if (status & HDSPM_tcoLockMadi) { | ||
3993 | if (status & HDSPM_tcoSync) | ||
3994 | return 2; | ||
3995 | else | ||
3996 | return 1; | ||
3997 | } | ||
3998 | return 0; | ||
3999 | break; | ||
3748 | case AES32: | 4000 | case AES32: |
3749 | status = hdspm_read(hdspm, HDSPM_statusRegister); | 4001 | status = hdspm_read(hdspm, HDSPM_statusRegister); |
3750 | if (status & HDSPM_tcoLock) { | 4002 | if (status & HDSPM_tcoLockAes) { |
3751 | if (status & HDSPM_tcoSync) | 4003 | if (status & HDSPM_tcoSync) |
3752 | return 2; | 4004 | return 2; |
3753 | else | 4005 | else |
@@ -3807,7 +4059,8 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, | |||
3807 | case 5: /* SYNC IN */ | 4059 | case 5: /* SYNC IN */ |
3808 | val = hdspm_sync_in_sync_check(hdspm); break; | 4060 | val = hdspm_sync_in_sync_check(hdspm); break; |
3809 | default: | 4061 | default: |
3810 | val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); | 4062 | val = hdspm_s1_sync_check(hdspm, |
4063 | kcontrol->private_value-1); | ||
3811 | } | 4064 | } |
3812 | break; | 4065 | break; |
3813 | 4066 | ||
@@ -3975,7 +4228,8 @@ static void hdspm_tco_write(struct hdspm *hdspm) | |||
3975 | static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, | 4228 | static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, |
3976 | struct snd_ctl_elem_info *uinfo) | 4229 | struct snd_ctl_elem_info *uinfo) |
3977 | { | 4230 | { |
3978 | static char *texts[] = { "44.1 kHz", "48 kHz" }; | 4231 | /* TODO freq from app could be supported here, see tco->samplerate */ |
4232 | static const char *const texts[] = { "44.1 kHz", "48 kHz" }; | ||
3979 | ENUMERATED_CTL_INFO(uinfo, texts); | 4233 | ENUMERATED_CTL_INFO(uinfo, texts); |
3980 | return 0; | 4234 | return 0; |
3981 | } | 4235 | } |
@@ -4021,7 +4275,8 @@ static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol, | |||
4021 | static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, | 4275 | static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, |
4022 | struct snd_ctl_elem_info *uinfo) | 4276 | struct snd_ctl_elem_info *uinfo) |
4023 | { | 4277 | { |
4024 | static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" }; | 4278 | static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %", |
4279 | "+ 4 %", "- 4 %" }; | ||
4025 | ENUMERATED_CTL_INFO(uinfo, texts); | 4280 | ENUMERATED_CTL_INFO(uinfo, texts); |
4026 | return 0; | 4281 | return 0; |
4027 | } | 4282 | } |
@@ -4066,7 +4321,7 @@ static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol, | |||
4066 | static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, | 4321 | static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, |
4067 | struct snd_ctl_elem_info *uinfo) | 4322 | struct snd_ctl_elem_info *uinfo) |
4068 | { | 4323 | { |
4069 | static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; | 4324 | static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; |
4070 | ENUMERATED_CTL_INFO(uinfo, texts); | 4325 | ENUMERATED_CTL_INFO(uinfo, texts); |
4071 | return 0; | 4326 | return 0; |
4072 | } | 4327 | } |
@@ -4112,7 +4367,7 @@ static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol, | |||
4112 | static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, | 4367 | static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, |
4113 | struct snd_ctl_elem_info *uinfo) | 4368 | struct snd_ctl_elem_info *uinfo) |
4114 | { | 4369 | { |
4115 | static char *texts[] = { "24 fps", "25 fps", "29.97fps", | 4370 | static const char *const texts[] = { "24 fps", "25 fps", "29.97fps", |
4116 | "29.97 dfps", "30 fps", "30 dfps" }; | 4371 | "29.97 dfps", "30 fps", "30 dfps" }; |
4117 | ENUMERATED_CTL_INFO(uinfo, texts); | 4372 | ENUMERATED_CTL_INFO(uinfo, texts); |
4118 | return 0; | 4373 | return 0; |
@@ -4159,7 +4414,7 @@ static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol, | |||
4159 | static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, | 4414 | static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, |
4160 | struct snd_ctl_elem_info *uinfo) | 4415 | struct snd_ctl_elem_info *uinfo) |
4161 | { | 4416 | { |
4162 | static char *texts[] = { "LTC", "Video", "WCK" }; | 4417 | static const char *const texts[] = { "LTC", "Video", "WCK" }; |
4163 | ENUMERATED_CTL_INFO(uinfo, texts); | 4418 | ENUMERATED_CTL_INFO(uinfo, texts); |
4164 | return 0; | 4419 | return 0; |
4165 | } | 4420 | } |
@@ -4284,7 +4539,6 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { | |||
4284 | HDSPM_INTERNAL_CLOCK("Internal Clock", 0), | 4539 | HDSPM_INTERNAL_CLOCK("Internal Clock", 0), |
4285 | HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), | 4540 | HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), |
4286 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), | 4541 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), |
4287 | HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), | ||
4288 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), | 4542 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), |
4289 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), | 4543 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), |
4290 | HDSPM_SYNC_CHECK("WC SyncCheck", 0), | 4544 | HDSPM_SYNC_CHECK("WC SyncCheck", 0), |
@@ -4298,7 +4552,16 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { | |||
4298 | HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), | 4552 | HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), |
4299 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), | 4553 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), |
4300 | HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), | 4554 | HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), |
4301 | HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5) | 4555 | HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5), |
4556 | HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0), | ||
4557 | HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt), | ||
4558 | HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), | ||
4559 | HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1), | ||
4560 | HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db), | ||
4561 | HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48), | ||
4562 | HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0), | ||
4563 | HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0), | ||
4564 | HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0) | ||
4302 | 4565 | ||
4303 | /* | 4566 | /* |
4304 | HDSPM_INPUT_SELECT("Input Select", 0), | 4567 | HDSPM_INPUT_SELECT("Input Select", 0), |
@@ -4335,7 +4598,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = { | |||
4335 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), | 4598 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), |
4336 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), | 4599 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), |
4337 | HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), | 4600 | HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), |
4338 | HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8) | 4601 | HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8), |
4602 | HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), | ||
4603 | HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) | ||
4339 | }; | 4604 | }; |
4340 | 4605 | ||
4341 | static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { | 4606 | static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { |
@@ -4345,7 +4610,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { | |||
4345 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), | 4610 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), |
4346 | HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), | 4611 | HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), |
4347 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), | 4612 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), |
4348 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), | 4613 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11), |
4349 | HDSPM_SYNC_CHECK("WC Sync Check", 0), | 4614 | HDSPM_SYNC_CHECK("WC Sync Check", 0), |
4350 | HDSPM_SYNC_CHECK("AES1 Sync Check", 1), | 4615 | HDSPM_SYNC_CHECK("AES1 Sync Check", 1), |
4351 | HDSPM_SYNC_CHECK("AES2 Sync Check", 2), | 4616 | HDSPM_SYNC_CHECK("AES2 Sync Check", 2), |
@@ -4501,77 +4766,22 @@ static int snd_hdspm_create_controls(struct snd_card *card, | |||
4501 | ------------------------------------------------------------*/ | 4766 | ------------------------------------------------------------*/ |
4502 | 4767 | ||
4503 | static void | 4768 | static void |
4504 | snd_hdspm_proc_read_madi(struct snd_info_entry * entry, | 4769 | snd_hdspm_proc_read_tco(struct snd_info_entry *entry, |
4505 | struct snd_info_buffer *buffer) | 4770 | struct snd_info_buffer *buffer) |
4506 | { | 4771 | { |
4507 | struct hdspm *hdspm = entry->private_data; | 4772 | struct hdspm *hdspm = entry->private_data; |
4508 | unsigned int status, status2, control, freq; | 4773 | unsigned int status, control; |
4509 | |||
4510 | char *pref_sync_ref; | ||
4511 | char *autosync_ref; | ||
4512 | char *system_clock_mode; | ||
4513 | char *insel; | ||
4514 | int x, x2; | ||
4515 | |||
4516 | /* TCO stuff */ | ||
4517 | int a, ltc, frames, seconds, minutes, hours; | 4774 | int a, ltc, frames, seconds, minutes, hours; |
4518 | unsigned int period; | 4775 | unsigned int period; |
4519 | u64 freq_const = 0; | 4776 | u64 freq_const = 0; |
4520 | u32 rate; | 4777 | u32 rate; |
4521 | 4778 | ||
4779 | snd_iprintf(buffer, "--- TCO ---\n"); | ||
4780 | |||
4522 | status = hdspm_read(hdspm, HDSPM_statusRegister); | 4781 | status = hdspm_read(hdspm, HDSPM_statusRegister); |
4523 | status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
4524 | control = hdspm->control_register; | 4782 | control = hdspm->control_register; |
4525 | freq = hdspm_read(hdspm, HDSPM_timecodeRegister); | ||
4526 | 4783 | ||
4527 | snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", | ||
4528 | hdspm->card_name, hdspm->card->number + 1, | ||
4529 | hdspm->firmware_rev, | ||
4530 | (status2 & HDSPM_version0) | | ||
4531 | (status2 & HDSPM_version1) | (status2 & | ||
4532 | HDSPM_version2)); | ||
4533 | 4784 | ||
4534 | snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", | ||
4535 | (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, | ||
4536 | hdspm->serial); | ||
4537 | |||
4538 | snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", | ||
4539 | hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); | ||
4540 | |||
4541 | snd_iprintf(buffer, "--- System ---\n"); | ||
4542 | |||
4543 | snd_iprintf(buffer, | ||
4544 | "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", | ||
4545 | status & HDSPM_audioIRQPending, | ||
4546 | (status & HDSPM_midi0IRQPending) ? 1 : 0, | ||
4547 | (status & HDSPM_midi1IRQPending) ? 1 : 0, | ||
4548 | hdspm->irq_count); | ||
4549 | snd_iprintf(buffer, | ||
4550 | "HW pointer: id = %d, rawptr = %d (%d->%d) " | ||
4551 | "estimated= %ld (bytes)\n", | ||
4552 | ((status & HDSPM_BufferID) ? 1 : 0), | ||
4553 | (status & HDSPM_BufferPositionMask), | ||
4554 | (status & HDSPM_BufferPositionMask) % | ||
4555 | (2 * (int)hdspm->period_bytes), | ||
4556 | ((status & HDSPM_BufferPositionMask) - 64) % | ||
4557 | (2 * (int)hdspm->period_bytes), | ||
4558 | (long) hdspm_hw_pointer(hdspm) * 4); | ||
4559 | |||
4560 | snd_iprintf(buffer, | ||
4561 | "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", | ||
4562 | hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, | ||
4563 | hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, | ||
4564 | hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, | ||
4565 | hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); | ||
4566 | snd_iprintf(buffer, | ||
4567 | "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", | ||
4568 | hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, | ||
4569 | hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); | ||
4570 | snd_iprintf(buffer, | ||
4571 | "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " | ||
4572 | "status2=0x%x\n", | ||
4573 | hdspm->control_register, hdspm->control2_register, | ||
4574 | status, status2); | ||
4575 | if (status & HDSPM_tco_detect) { | 4785 | if (status & HDSPM_tco_detect) { |
4576 | snd_iprintf(buffer, "TCO module detected.\n"); | 4786 | snd_iprintf(buffer, "TCO module detected.\n"); |
4577 | a = hdspm_read(hdspm, HDSPM_RD_TCO+4); | 4787 | a = hdspm_read(hdspm, HDSPM_RD_TCO+4); |
@@ -4665,6 +4875,75 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, | |||
4665 | } else { | 4875 | } else { |
4666 | snd_iprintf(buffer, "No TCO module detected.\n"); | 4876 | snd_iprintf(buffer, "No TCO module detected.\n"); |
4667 | } | 4877 | } |
4878 | } | ||
4879 | |||
4880 | static void | ||
4881 | snd_hdspm_proc_read_madi(struct snd_info_entry *entry, | ||
4882 | struct snd_info_buffer *buffer) | ||
4883 | { | ||
4884 | struct hdspm *hdspm = entry->private_data; | ||
4885 | unsigned int status, status2, control, freq; | ||
4886 | |||
4887 | char *pref_sync_ref; | ||
4888 | char *autosync_ref; | ||
4889 | char *system_clock_mode; | ||
4890 | char *insel; | ||
4891 | int x, x2; | ||
4892 | |||
4893 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
4894 | status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
4895 | control = hdspm->control_register; | ||
4896 | freq = hdspm_read(hdspm, HDSPM_timecodeRegister); | ||
4897 | |||
4898 | snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", | ||
4899 | hdspm->card_name, hdspm->card->number + 1, | ||
4900 | hdspm->firmware_rev, | ||
4901 | (status2 & HDSPM_version0) | | ||
4902 | (status2 & HDSPM_version1) | (status2 & | ||
4903 | HDSPM_version2)); | ||
4904 | |||
4905 | snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", | ||
4906 | (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, | ||
4907 | hdspm->serial); | ||
4908 | |||
4909 | snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", | ||
4910 | hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); | ||
4911 | |||
4912 | snd_iprintf(buffer, "--- System ---\n"); | ||
4913 | |||
4914 | snd_iprintf(buffer, | ||
4915 | "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", | ||
4916 | status & HDSPM_audioIRQPending, | ||
4917 | (status & HDSPM_midi0IRQPending) ? 1 : 0, | ||
4918 | (status & HDSPM_midi1IRQPending) ? 1 : 0, | ||
4919 | hdspm->irq_count); | ||
4920 | snd_iprintf(buffer, | ||
4921 | "HW pointer: id = %d, rawptr = %d (%d->%d) " | ||
4922 | "estimated= %ld (bytes)\n", | ||
4923 | ((status & HDSPM_BufferID) ? 1 : 0), | ||
4924 | (status & HDSPM_BufferPositionMask), | ||
4925 | (status & HDSPM_BufferPositionMask) % | ||
4926 | (2 * (int)hdspm->period_bytes), | ||
4927 | ((status & HDSPM_BufferPositionMask) - 64) % | ||
4928 | (2 * (int)hdspm->period_bytes), | ||
4929 | (long) hdspm_hw_pointer(hdspm) * 4); | ||
4930 | |||
4931 | snd_iprintf(buffer, | ||
4932 | "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", | ||
4933 | hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, | ||
4934 | hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, | ||
4935 | hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, | ||
4936 | hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); | ||
4937 | snd_iprintf(buffer, | ||
4938 | "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", | ||
4939 | hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, | ||
4940 | hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); | ||
4941 | snd_iprintf(buffer, | ||
4942 | "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " | ||
4943 | "status2=0x%x\n", | ||
4944 | hdspm->control_register, hdspm->control2_register, | ||
4945 | status, status2); | ||
4946 | |||
4668 | 4947 | ||
4669 | snd_iprintf(buffer, "--- Settings ---\n"); | 4948 | snd_iprintf(buffer, "--- Settings ---\n"); |
4670 | 4949 | ||
@@ -4768,6 +5047,9 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, | |||
4768 | (status & HDSPM_RX_64ch) ? "64 channels" : | 5047 | (status & HDSPM_RX_64ch) ? "64 channels" : |
4769 | "56 channels"); | 5048 | "56 channels"); |
4770 | 5049 | ||
5050 | /* call readout function for TCO specific status */ | ||
5051 | snd_hdspm_proc_read_tco(entry, buffer); | ||
5052 | |||
4771 | snd_iprintf(buffer, "\n"); | 5053 | snd_iprintf(buffer, "\n"); |
4772 | } | 5054 | } |
4773 | 5055 | ||
@@ -4909,11 +5191,18 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, | |||
4909 | autosync_ref = "AES7"; break; | 5191 | autosync_ref = "AES7"; break; |
4910 | case HDSPM_AES32_AUTOSYNC_FROM_AES8: | 5192 | case HDSPM_AES32_AUTOSYNC_FROM_AES8: |
4911 | autosync_ref = "AES8"; break; | 5193 | autosync_ref = "AES8"; break; |
5194 | case HDSPM_AES32_AUTOSYNC_FROM_TCO: | ||
5195 | autosync_ref = "TCO"; break; | ||
5196 | case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN: | ||
5197 | autosync_ref = "Sync In"; break; | ||
4912 | default: | 5198 | default: |
4913 | autosync_ref = "---"; break; | 5199 | autosync_ref = "---"; break; |
4914 | } | 5200 | } |
4915 | snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); | 5201 | snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); |
4916 | 5202 | ||
5203 | /* call readout function for TCO specific status */ | ||
5204 | snd_hdspm_proc_read_tco(entry, buffer); | ||
5205 | |||
4917 | snd_iprintf(buffer, "\n"); | 5206 | snd_iprintf(buffer, "\n"); |
4918 | } | 5207 | } |
4919 | 5208 | ||
@@ -5097,7 +5386,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) | |||
5097 | 5386 | ||
5098 | case AES32: | 5387 | case AES32: |
5099 | hdspm->control_register = | 5388 | hdspm->control_register = |
5100 | HDSPM_ClockModeMaster | /* Master Cloack Mode on */ | 5389 | HDSPM_ClockModeMaster | /* Master Clock Mode on */ |
5101 | hdspm_encode_latency(7) | /* latency max=8192samples */ | 5390 | hdspm_encode_latency(7) | /* latency max=8192samples */ |
5102 | HDSPM_SyncRef0 | /* AES1 is syncclock */ | 5391 | HDSPM_SyncRef0 | /* AES1 is syncclock */ |
5103 | HDSPM_LineOut | /* Analog output in */ | 5392 | HDSPM_LineOut | /* Analog output in */ |
@@ -5123,9 +5412,8 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) | |||
5123 | 5412 | ||
5124 | all_in_all_mixer(hdspm, 0 * UNITY_GAIN); | 5413 | all_in_all_mixer(hdspm, 0 * UNITY_GAIN); |
5125 | 5414 | ||
5126 | if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) { | 5415 | if (hdspm_is_raydat_or_aio(hdspm)) |
5127 | hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); | 5416 | hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); |
5128 | } | ||
5129 | 5417 | ||
5130 | /* set a default rate so that the channel map is set up. */ | 5418 | /* set a default rate so that the channel map is set up. */ |
5131 | hdspm_set_rate(hdspm, 48000, 1); | 5419 | hdspm_set_rate(hdspm, 48000, 1); |
@@ -5371,6 +5659,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, | |||
5371 | */ | 5659 | */ |
5372 | 5660 | ||
5373 | 5661 | ||
5662 | /* For AES cards, the float format bit is the same as the | ||
5663 | * preferred sync reference. Since we don't want to break | ||
5664 | * sync settings, we have to skip the remaining part of this | ||
5665 | * function. | ||
5666 | */ | ||
5667 | if (hdspm->io_type == AES32) { | ||
5668 | return 0; | ||
5669 | } | ||
5670 | |||
5671 | |||
5374 | /* Switch to native float format if requested */ | 5672 | /* Switch to native float format if requested */ |
5375 | if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { | 5673 | if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { |
5376 | if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) | 5674 | if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) |
@@ -6013,7 +6311,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, | |||
6013 | ltc.format = fps_2997; | 6311 | ltc.format = fps_2997; |
6014 | break; | 6312 | break; |
6015 | default: | 6313 | default: |
6016 | ltc.format = 30; | 6314 | ltc.format = fps_30; |
6017 | break; | 6315 | break; |
6018 | } | 6316 | } |
6019 | if (i & HDSPM_TCO1_set_drop_frame_flag) { | 6317 | if (i & HDSPM_TCO1_set_drop_frame_flag) { |
@@ -6479,10 +6777,6 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6479 | break; | 6777 | break; |
6480 | 6778 | ||
6481 | case AIO: | 6779 | case AIO: |
6482 | if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { | ||
6483 | snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n"); | ||
6484 | } | ||
6485 | |||
6486 | hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; | 6780 | hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; |
6487 | hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; | 6781 | hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; |
6488 | hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; | 6782 | hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; |
@@ -6490,6 +6784,20 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6490 | hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; | 6784 | hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; |
6491 | hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; | 6785 | hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; |
6492 | 6786 | ||
6787 | if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { | ||
6788 | snd_printk(KERN_INFO "HDSPM: AEB input board found\n"); | ||
6789 | hdspm->ss_in_channels += 4; | ||
6790 | hdspm->ds_in_channels += 4; | ||
6791 | hdspm->qs_in_channels += 4; | ||
6792 | } | ||
6793 | |||
6794 | if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) { | ||
6795 | snd_printk(KERN_INFO "HDSPM: AEB output board found\n"); | ||
6796 | hdspm->ss_out_channels += 4; | ||
6797 | hdspm->ds_out_channels += 4; | ||
6798 | hdspm->qs_out_channels += 4; | ||
6799 | } | ||
6800 | |||
6493 | hdspm->channel_map_out_ss = channel_map_aio_out_ss; | 6801 | hdspm->channel_map_out_ss = channel_map_aio_out_ss; |
6494 | hdspm->channel_map_out_ds = channel_map_aio_out_ds; | 6802 | hdspm->channel_map_out_ds = channel_map_aio_out_ds; |
6495 | hdspm->channel_map_out_qs = channel_map_aio_out_qs; | 6803 | hdspm->channel_map_out_qs = channel_map_aio_out_qs; |
@@ -6558,6 +6866,7 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6558 | break; | 6866 | break; |
6559 | 6867 | ||
6560 | case MADI: | 6868 | case MADI: |
6869 | case AES32: | ||
6561 | if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { | 6870 | if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { |
6562 | hdspm->midiPorts++; | 6871 | hdspm->midiPorts++; |
6563 | hdspm->tco = kzalloc(sizeof(struct hdspm_tco), | 6872 | hdspm->tco = kzalloc(sizeof(struct hdspm_tco), |
@@ -6565,7 +6874,7 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6565 | if (NULL != hdspm->tco) { | 6874 | if (NULL != hdspm->tco) { |
6566 | hdspm_tco_write(hdspm); | 6875 | hdspm_tco_write(hdspm); |
6567 | } | 6876 | } |
6568 | snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n"); | 6877 | snd_printk(KERN_INFO "HDSPM: MADI/AES TCO module found\n"); |
6569 | } else { | 6878 | } else { |
6570 | hdspm->tco = NULL; | 6879 | hdspm->tco = NULL; |
6571 | } | 6880 | } |
@@ -6580,10 +6889,12 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6580 | case AES32: | 6889 | case AES32: |
6581 | if (hdspm->tco) { | 6890 | if (hdspm->tco) { |
6582 | hdspm->texts_autosync = texts_autosync_aes_tco; | 6891 | hdspm->texts_autosync = texts_autosync_aes_tco; |
6583 | hdspm->texts_autosync_items = 10; | 6892 | hdspm->texts_autosync_items = |
6893 | ARRAY_SIZE(texts_autosync_aes_tco); | ||
6584 | } else { | 6894 | } else { |
6585 | hdspm->texts_autosync = texts_autosync_aes; | 6895 | hdspm->texts_autosync = texts_autosync_aes; |
6586 | hdspm->texts_autosync_items = 9; | 6896 | hdspm->texts_autosync_items = |
6897 | ARRAY_SIZE(texts_autosync_aes); | ||
6587 | } | 6898 | } |
6588 | break; | 6899 | break; |
6589 | 6900 | ||
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..0ecf356027f6 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, IER, 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..a57643d6402f 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); |
@@ -411,7 +408,6 @@ static int ep93xx_i2s_probe(struct platform_device *pdev) | |||
411 | return 0; | 408 | return 0; |
412 | 409 | ||
413 | fail_put_lrclk: | 410 | fail_put_lrclk: |
414 | dev_set_drvdata(&pdev->dev, NULL); | ||
415 | clk_put(info->lrclk); | 411 | clk_put(info->lrclk); |
416 | fail_put_sclk: | 412 | fail_put_sclk: |
417 | clk_put(info->sclk); | 413 | clk_put(info->sclk); |
@@ -426,7 +422,6 @@ static int ep93xx_i2s_remove(struct platform_device *pdev) | |||
426 | struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev); | 422 | struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev); |
427 | 423 | ||
428 | snd_soc_unregister_component(&pdev->dev); | 424 | snd_soc_unregister_component(&pdev->dev); |
429 | dev_set_drvdata(&pdev->dev, NULL); | ||
430 | clk_put(info->lrclk); | 425 | clk_put(info->lrclk); |
431 | clk_put(info->sclk); | 426 | clk_put(info->sclk); |
432 | clk_put(info->mclk); | 427 | clk_put(info->mclk); |
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/dmic.c b/sound/soc/codecs/dmic.c index 66967ba6f757..b2090b2a5e2d 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c | |||
@@ -50,20 +50,11 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
50 | {"DMIC AIF", NULL, "DMic"}, | 50 | {"DMIC AIF", NULL, "DMic"}, |
51 | }; | 51 | }; |
52 | 52 | ||
53 | static int dmic_probe(struct snd_soc_codec *codec) | ||
54 | { | ||
55 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
56 | |||
57 | snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets, | ||
58 | ARRAY_SIZE(dmic_dapm_widgets)); | ||
59 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); | ||
60 | snd_soc_dapm_new_widgets(dapm); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static struct snd_soc_codec_driver soc_dmic = { | 53 | static struct snd_soc_codec_driver soc_dmic = { |
66 | .probe = dmic_probe, | 54 | .dapm_widgets = dmic_dapm_widgets, |
55 | .num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets), | ||
56 | .dapm_routes = intercon, | ||
57 | .num_dapm_routes = ARRAY_SIZE(intercon), | ||
67 | }; | 58 | }; |
68 | 59 | ||
69 | static int dmic_dev_probe(struct platform_device *pdev) | 60 | static int dmic_dev_probe(struct platform_device *pdev) |
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..c26a8f814b18 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c | |||
@@ -50,8 +50,6 @@ static const struct regmap_range_cfg rt5640_ranges[] = { | |||
50 | 50 | ||
51 | static struct reg_default init_list[] = { | 51 | static struct reg_default init_list[] = { |
52 | {RT5640_PR_BASE + 0x3d, 0x3600}, | 52 | {RT5640_PR_BASE + 0x3d, 0x3600}, |
53 | {RT5640_PR_BASE + 0x1c, 0x0D21}, | ||
54 | {RT5640_PR_BASE + 0x1b, 0x0000}, | ||
55 | {RT5640_PR_BASE + 0x12, 0x0aa8}, | 53 | {RT5640_PR_BASE + 0x12, 0x0aa8}, |
56 | {RT5640_PR_BASE + 0x14, 0x0aaa}, | 54 | {RT5640_PR_BASE + 0x14, 0x0aaa}, |
57 | {RT5640_PR_BASE + 0x20, 0x6110}, | 55 | {RT5640_PR_BASE + 0x20, 0x6110}, |
@@ -384,15 +382,11 @@ static const SOC_ENUM_SINGLE_DECL( | |||
384 | 382 | ||
385 | static const struct snd_kcontrol_new rt5640_snd_controls[] = { | 383 | static const struct snd_kcontrol_new rt5640_snd_controls[] = { |
386 | /* Speaker Output Volume */ | 384 | /* Speaker Output Volume */ |
387 | SOC_DOUBLE("Speaker Playback Switch", RT5640_SPK_VOL, | ||
388 | RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1), | ||
389 | SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL, | 385 | SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL, |
390 | RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1), | 386 | RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1), |
391 | SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL, | 387 | SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL, |
392 | RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv), | 388 | RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv), |
393 | /* Headphone Output Volume */ | 389 | /* Headphone Output Volume */ |
394 | SOC_DOUBLE("HP Playback Switch", RT5640_HP_VOL, | ||
395 | RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1), | ||
396 | SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL, | 390 | SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL, |
397 | RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1), | 391 | RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1), |
398 | SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL, | 392 | SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL, |
@@ -737,28 +731,21 @@ static const struct snd_kcontrol_new rt5640_mono_mix[] = { | |||
737 | RT5640_M_BST1_MM_SFT, 1, 1), | 731 | RT5640_M_BST1_MM_SFT, 1, 1), |
738 | }; | 732 | }; |
739 | 733 | ||
740 | /* INL/R source */ | 734 | static const struct snd_kcontrol_new spk_l_enable_control = |
741 | static const char * const rt5640_inl_src[] = { | 735 | SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL, |
742 | "IN2P", "MONOP" | 736 | RT5640_L_MUTE_SFT, 1, 1); |
743 | }; | ||
744 | 737 | ||
745 | static const SOC_ENUM_SINGLE_DECL( | 738 | static const struct snd_kcontrol_new spk_r_enable_control = |
746 | rt5640_inl_enum, RT5640_INL_INR_VOL, | 739 | SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL, |
747 | RT5640_INL_SEL_SFT, rt5640_inl_src); | 740 | RT5640_R_MUTE_SFT, 1, 1); |
748 | 741 | ||
749 | static const struct snd_kcontrol_new rt5640_inl_mux = | 742 | static const struct snd_kcontrol_new hp_l_enable_control = |
750 | SOC_DAPM_ENUM("INL source", rt5640_inl_enum); | 743 | SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL, |
744 | RT5640_L_MUTE_SFT, 1, 1); | ||
751 | 745 | ||
752 | static const char * const rt5640_inr_src[] = { | 746 | static const struct snd_kcontrol_new hp_r_enable_control = |
753 | "IN2N", "MONON" | 747 | SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL, |
754 | }; | 748 | RT5640_R_MUTE_SFT, 1, 1); |
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 | 749 | ||
763 | /* Stereo ADC source */ | 750 | /* Stereo ADC source */ |
764 | static const char * const rt5640_stereo_adc1_src[] = { | 751 | static const char * const rt5640_stereo_adc1_src[] = { |
@@ -891,33 +878,6 @@ static const SOC_ENUM_SINGLE_DECL( | |||
891 | static const struct snd_kcontrol_new rt5640_sdi_mux = | 878 | static const struct snd_kcontrol_new rt5640_sdi_mux = |
892 | SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); | 879 | SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); |
893 | 880 | ||
894 | static int spk_event(struct snd_soc_dapm_widget *w, | ||
895 | struct snd_kcontrol *kcontrol, int event) | ||
896 | { | ||
897 | struct snd_soc_codec *codec = w->codec; | ||
898 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); | ||
899 | |||
900 | switch (event) { | ||
901 | case SND_SOC_DAPM_POST_PMU: | ||
902 | regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1, | ||
903 | 0x0001, 0x0001); | ||
904 | regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c, | ||
905 | 0xf000, 0xf000); | ||
906 | break; | ||
907 | |||
908 | case SND_SOC_DAPM_PRE_PMD: | ||
909 | regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c, | ||
910 | 0xf000, 0x0000); | ||
911 | regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1, | ||
912 | 0x0001, 0x0000); | ||
913 | break; | ||
914 | |||
915 | default: | ||
916 | return 0; | ||
917 | } | ||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w, | 881 | static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w, |
922 | struct snd_kcontrol *kcontrol, int event) | 882 | struct snd_kcontrol *kcontrol, int event) |
923 | { | 883 | { |
@@ -966,6 +926,117 @@ static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w, | |||
966 | return 0; | 926 | return 0; |
967 | } | 927 | } |
968 | 928 | ||
929 | void hp_amp_power_on(struct snd_soc_codec *codec) | ||
930 | { | ||
931 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); | ||
932 | |||
933 | /* depop parameters */ | ||
934 | regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + | ||
935 | RT5640_CHPUMP_INT_REG1, 0x0700, 0x0200); | ||
936 | regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2, | ||
937 | RT5640_DEPOP_MASK, RT5640_DEPOP_MAN); | ||
938 | regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1, | ||
939 | RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CB_MASK, | ||
940 | RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU); | ||
941 | regmap_write(rt5640->regmap, RT5640_PR_BASE + RT5640_HP_DCC_INT1, | ||
942 | 0x9f00); | ||
943 | /* headphone amp power on */ | ||
944 | regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1, | ||
945 | RT5640_PWR_FV1 | RT5640_PWR_FV2, 0); | ||
946 | regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1, | ||
947 | RT5640_PWR_HA, | ||
948 | RT5640_PWR_HA); | ||
949 | usleep_range(10000, 15000); | ||
950 | regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1, | ||
951 | RT5640_PWR_FV1 | RT5640_PWR_FV2 , | ||
952 | RT5640_PWR_FV1 | RT5640_PWR_FV2); | ||
953 | } | ||
954 | |||
955 | static void rt5640_pmu_depop(struct snd_soc_codec *codec) | ||
956 | { | ||
957 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); | ||
958 | |||
959 | regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2, | ||
960 | RT5640_DEPOP_MASK | RT5640_DIG_DP_MASK, | ||
961 | RT5640_DEPOP_AUTO | RT5640_DIG_DP_EN); | ||
962 | regmap_update_bits(rt5640->regmap, RT5640_CHARGE_PUMP, | ||
963 | RT5640_PM_HP_MASK, RT5640_PM_HP_HV); | ||
964 | |||
965 | regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M3, | ||
966 | RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK, | ||
967 | (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) | | ||
968 | (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) | | ||
969 | (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT)); | ||
970 | |||
971 | regmap_write(rt5640->regmap, RT5640_PR_BASE + | ||
972 | RT5640_MAMP_INT_REG2, 0x1c00); | ||
973 | regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1, | ||
974 | RT5640_HP_CP_MASK | RT5640_HP_SG_MASK, | ||
975 | RT5640_HP_CP_PD | RT5640_HP_SG_EN); | ||
976 | regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + | ||
977 | RT5640_CHPUMP_INT_REG1, 0x0700, 0x0400); | ||
978 | } | ||
979 | |||
980 | static int rt5640_hp_event(struct snd_soc_dapm_widget *w, | ||
981 | struct snd_kcontrol *kcontrol, int event) | ||
982 | { | ||
983 | struct snd_soc_codec *codec = w->codec; | ||
984 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); | ||
985 | |||
986 | switch (event) { | ||
987 | case SND_SOC_DAPM_POST_PMU: | ||
988 | rt5640_pmu_depop(codec); | ||
989 | rt5640->hp_mute = 0; | ||
990 | break; | ||
991 | |||
992 | case SND_SOC_DAPM_PRE_PMD: | ||
993 | rt5640->hp_mute = 1; | ||
994 | usleep_range(70000, 75000); | ||
995 | break; | ||
996 | |||
997 | default: | ||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w, | ||
1005 | struct snd_kcontrol *kcontrol, int event) | ||
1006 | { | ||
1007 | struct snd_soc_codec *codec = w->codec; | ||
1008 | |||
1009 | switch (event) { | ||
1010 | case SND_SOC_DAPM_POST_PMU: | ||
1011 | hp_amp_power_on(codec); | ||
1012 | break; | ||
1013 | default: | ||
1014 | return 0; | ||
1015 | } | ||
1016 | |||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w, | ||
1021 | struct snd_kcontrol *kcontrol, int event) | ||
1022 | { | ||
1023 | struct snd_soc_codec *codec = w->codec; | ||
1024 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); | ||
1025 | |||
1026 | switch (event) { | ||
1027 | case SND_SOC_DAPM_POST_PMU: | ||
1028 | if (!rt5640->hp_mute) | ||
1029 | usleep_range(80000, 85000); | ||
1030 | |||
1031 | break; | ||
1032 | |||
1033 | default: | ||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | return 0; | ||
1038 | } | ||
1039 | |||
969 | static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { | 1040 | static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { |
970 | SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2, | 1041 | SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2, |
971 | RT5640_PWR_PLL_BIT, 0, NULL, 0), | 1042 | RT5640_PWR_PLL_BIT, 0, NULL, 0), |
@@ -1005,9 +1076,6 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { | |||
1005 | RT5640_PWR_IN_L_BIT, 0, NULL, 0), | 1076 | RT5640_PWR_IN_L_BIT, 0, NULL, 0), |
1006 | SND_SOC_DAPM_PGA("INR VOL", RT5640_PWR_VOL, | 1077 | SND_SOC_DAPM_PGA("INR VOL", RT5640_PWR_VOL, |
1007 | RT5640_PWR_IN_R_BIT, 0, NULL, 0), | 1078 | 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 */ | 1079 | /* REC Mixer */ |
1012 | SND_SOC_DAPM_MIXER("RECMIXL", RT5640_PWR_MIXER, RT5640_PWR_RM_L_BIT, 0, | 1080 | 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)), | 1081 | rt5640_rec_l_mix, ARRAY_SIZE(rt5640_rec_l_mix)), |
@@ -1158,15 +1226,28 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { | |||
1158 | rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)), | 1226 | rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)), |
1159 | SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, | 1227 | SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, |
1160 | RT5640_PWR_MA_BIT, 0, NULL, 0), | 1228 | RT5640_PWR_MA_BIT, 0, NULL, 0), |
1161 | SND_SOC_DAPM_SUPPLY("Improve HP Amp Drv", RT5640_PWR_ANLG1, | 1229 | SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM, |
1162 | SND_SOC_NOPM, 0, NULL, 0), | 1230 | 0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU), |
1163 | SND_SOC_DAPM_PGA("HP L Amp", RT5640_PWR_ANLG1, | 1231 | SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, |
1232 | rt5640_hp_event, | ||
1233 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
1234 | SND_SOC_DAPM_SUPPLY("HP L Amp", RT5640_PWR_ANLG1, | ||
1164 | RT5640_PWR_HP_L_BIT, 0, NULL, 0), | 1235 | RT5640_PWR_HP_L_BIT, 0, NULL, 0), |
1165 | SND_SOC_DAPM_PGA("HP R Amp", RT5640_PWR_ANLG1, | 1236 | SND_SOC_DAPM_SUPPLY("HP R Amp", RT5640_PWR_ANLG1, |
1166 | RT5640_PWR_HP_R_BIT, 0, NULL, 0), | 1237 | RT5640_PWR_HP_R_BIT, 0, NULL, 0), |
1167 | SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1, | 1238 | SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1, |
1168 | SND_SOC_NOPM, 0, spk_event, | 1239 | RT5640_PWR_CLS_D_BIT, 0, NULL, 0), |
1169 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | 1240 | |
1241 | /* Output Switch */ | ||
1242 | SND_SOC_DAPM_SWITCH("Speaker L Playback", SND_SOC_NOPM, 0, 0, | ||
1243 | &spk_l_enable_control), | ||
1244 | SND_SOC_DAPM_SWITCH("Speaker R Playback", SND_SOC_NOPM, 0, 0, | ||
1245 | &spk_r_enable_control), | ||
1246 | SND_SOC_DAPM_SWITCH("HP L Playback", SND_SOC_NOPM, 0, 0, | ||
1247 | &hp_l_enable_control), | ||
1248 | SND_SOC_DAPM_SWITCH("HP R Playback", SND_SOC_NOPM, 0, 0, | ||
1249 | &hp_r_enable_control), | ||
1250 | SND_SOC_DAPM_POST("HP Post", rt5640_hp_post_event), | ||
1170 | /* Output Lines */ | 1251 | /* Output Lines */ |
1171 | SND_SOC_DAPM_OUTPUT("SPOLP"), | 1252 | SND_SOC_DAPM_OUTPUT("SPOLP"), |
1172 | SND_SOC_DAPM_OUTPUT("SPOLN"), | 1253 | SND_SOC_DAPM_OUTPUT("SPOLN"), |
@@ -1407,9 +1488,11 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { | |||
1407 | {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"}, | 1488 | {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"}, |
1408 | {"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"}, | 1489 | {"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"}, |
1409 | {"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"}, | 1490 | {"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"}, |
1491 | {"HPO MIX L", NULL, "HP L Amp"}, | ||
1410 | {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"}, | 1492 | {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"}, |
1411 | {"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"}, | 1493 | {"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"}, |
1412 | {"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"}, | 1494 | {"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"}, |
1495 | {"HPO MIX R", NULL, "HP R Amp"}, | ||
1413 | 1496 | ||
1414 | {"LOUT MIX", "DAC L1 Switch", "DAC L1"}, | 1497 | {"LOUT MIX", "DAC L1 Switch", "DAC L1"}, |
1415 | {"LOUT MIX", "DAC R1 Switch", "DAC R1"}, | 1498 | {"LOUT MIX", "DAC R1 Switch", "DAC R1"}, |
@@ -1422,13 +1505,15 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { | |||
1422 | {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"}, | 1505 | {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"}, |
1423 | {"Mono MIX", "BST1 Switch", "BST1"}, | 1506 | {"Mono MIX", "BST1 Switch", "BST1"}, |
1424 | 1507 | ||
1425 | {"HP L Amp", NULL, "HPO MIX L"}, | 1508 | {"HP Amp", NULL, "HPO MIX L"}, |
1426 | {"HP R Amp", NULL, "HPO MIX R"}, | 1509 | {"HP Amp", NULL, "HPO MIX R"}, |
1427 | 1510 | ||
1428 | {"SPOLP", NULL, "SPOL MIX"}, | 1511 | {"Speaker L Playback", "Switch", "SPOL MIX"}, |
1429 | {"SPOLN", NULL, "SPOL MIX"}, | 1512 | {"Speaker R Playback", "Switch", "SPOR MIX"}, |
1430 | {"SPORP", NULL, "SPOR MIX"}, | 1513 | {"SPOLP", NULL, "Speaker L Playback"}, |
1431 | {"SPORN", NULL, "SPOR MIX"}, | 1514 | {"SPOLN", NULL, "Speaker L Playback"}, |
1515 | {"SPORP", NULL, "Speaker R Playback"}, | ||
1516 | {"SPORN", NULL, "Speaker R Playback"}, | ||
1432 | 1517 | ||
1433 | {"SPOLP", NULL, "Improve SPK Amp Drv"}, | 1518 | {"SPOLP", NULL, "Improve SPK Amp Drv"}, |
1434 | {"SPOLN", NULL, "Improve SPK Amp Drv"}, | 1519 | {"SPOLN", NULL, "Improve SPK Amp Drv"}, |
@@ -1438,8 +1523,10 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { | |||
1438 | {"HPOL", NULL, "Improve HP Amp Drv"}, | 1523 | {"HPOL", NULL, "Improve HP Amp Drv"}, |
1439 | {"HPOR", NULL, "Improve HP Amp Drv"}, | 1524 | {"HPOR", NULL, "Improve HP Amp Drv"}, |
1440 | 1525 | ||
1441 | {"HPOL", NULL, "HP L Amp"}, | 1526 | {"HP L Playback", "Switch", "HP Amp"}, |
1442 | {"HPOR", NULL, "HP R Amp"}, | 1527 | {"HP R Playback", "Switch", "HP Amp"}, |
1528 | {"HPOL", NULL, "HP L Playback"}, | ||
1529 | {"HPOR", NULL, "HP R Playback"}, | ||
1443 | {"LOUTL", NULL, "LOUT MIX"}, | 1530 | {"LOUTL", NULL, "LOUT MIX"}, |
1444 | {"LOUTR", NULL, "LOUT MIX"}, | 1531 | {"LOUTR", NULL, "LOUT MIX"}, |
1445 | {"MONOP", NULL, "Mono MIX"}, | 1532 | {"MONOP", NULL, "Mono MIX"}, |
@@ -1818,17 +1905,13 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec, | |||
1818 | RT5640_PWR_BG | RT5640_PWR_VREF2, | 1905 | RT5640_PWR_BG | RT5640_PWR_VREF2, |
1819 | RT5640_PWR_VREF1 | RT5640_PWR_MB | | 1906 | RT5640_PWR_VREF1 | RT5640_PWR_MB | |
1820 | RT5640_PWR_BG | RT5640_PWR_VREF2); | 1907 | RT5640_PWR_BG | RT5640_PWR_VREF2); |
1821 | mdelay(10); | 1908 | usleep_range(10000, 15000); |
1822 | snd_soc_update_bits(codec, RT5640_PWR_ANLG1, | 1909 | snd_soc_update_bits(codec, RT5640_PWR_ANLG1, |
1823 | RT5640_PWR_FV1 | RT5640_PWR_FV2, | 1910 | RT5640_PWR_FV1 | RT5640_PWR_FV2, |
1824 | RT5640_PWR_FV1 | RT5640_PWR_FV2); | 1911 | RT5640_PWR_FV1 | RT5640_PWR_FV2); |
1825 | regcache_sync(rt5640->regmap); | 1912 | regcache_sync(rt5640->regmap); |
1826 | snd_soc_update_bits(codec, RT5640_DUMMY1, | 1913 | snd_soc_update_bits(codec, RT5640_DUMMY1, |
1827 | 0x0301, 0x0301); | 1914 | 0x0301, 0x0301); |
1828 | snd_soc_update_bits(codec, RT5640_DEPOP_M1, | ||
1829 | 0x001d, 0x0019); | ||
1830 | snd_soc_update_bits(codec, RT5640_DEPOP_M2, | ||
1831 | 0x2000, 0x2000); | ||
1832 | snd_soc_update_bits(codec, RT5640_MICBIAS, | 1915 | snd_soc_update_bits(codec, RT5640_MICBIAS, |
1833 | 0x0030, 0x0030); | 1916 | 0x0030, 0x0030); |
1834 | } | 1917 | } |
@@ -1872,8 +1955,6 @@ static int rt5640_probe(struct snd_soc_codec *codec) | |||
1872 | rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1955 | rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1873 | 1956 | ||
1874 | snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301); | 1957 | snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301); |
1875 | snd_soc_update_bits(codec, RT5640_DEPOP_M1, 0x001d, 0x0019); | ||
1876 | snd_soc_update_bits(codec, RT5640_DEPOP_M2, 0x2000, 0x2000); | ||
1877 | snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030); | 1958 | snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030); |
1878 | snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00); | 1959 | snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00); |
1879 | 1960 | ||
@@ -2095,6 +2176,8 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, | |||
2095 | regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, | 2176 | regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, |
2096 | RT5640_IN_DF2, RT5640_IN_DF2); | 2177 | RT5640_IN_DF2, RT5640_IN_DF2); |
2097 | 2178 | ||
2179 | rt5640->hp_mute = 1; | ||
2180 | |||
2098 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, | 2181 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, |
2099 | rt5640_dai, ARRAY_SIZE(rt5640_dai)); | 2182 | rt5640_dai, ARRAY_SIZE(rt5640_dai)); |
2100 | if (ret < 0) | 2183 | if (ret < 0) |
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index c48286d7118f..5e8df25a13f3 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h | |||
@@ -145,6 +145,8 @@ | |||
145 | 145 | ||
146 | 146 | ||
147 | /* Index of Codec Private Register definition */ | 147 | /* Index of Codec Private Register definition */ |
148 | #define RT5640_CHPUMP_INT_REG1 0x24 | ||
149 | #define RT5640_MAMP_INT_REG2 0x37 | ||
148 | #define RT5640_3D_SPK 0x63 | 150 | #define RT5640_3D_SPK 0x63 |
149 | #define RT5640_WND_1 0x6c | 151 | #define RT5640_WND_1 0x6c |
150 | #define RT5640_WND_2 0x6d | 152 | #define RT5640_WND_2 0x6d |
@@ -153,6 +155,7 @@ | |||
153 | #define RT5640_WND_5 0x70 | 155 | #define RT5640_WND_5 0x70 |
154 | #define RT5640_WND_8 0x73 | 156 | #define RT5640_WND_8 0x73 |
155 | #define RT5640_DIP_SPK_INF 0x75 | 157 | #define RT5640_DIP_SPK_INF 0x75 |
158 | #define RT5640_HP_DCC_INT1 0x77 | ||
156 | #define RT5640_EQ_BW_LOP 0xa0 | 159 | #define RT5640_EQ_BW_LOP 0xa0 |
157 | #define RT5640_EQ_GN_LOP 0xa1 | 160 | #define RT5640_EQ_GN_LOP 0xa1 |
158 | #define RT5640_EQ_FC_BP1 0xa2 | 161 | #define RT5640_EQ_FC_BP1 0xa2 |
@@ -1201,6 +1204,14 @@ | |||
1201 | #define RT5640_CP_FQ2_SFT 4 | 1204 | #define RT5640_CP_FQ2_SFT 4 |
1202 | #define RT5640_CP_FQ3_MASK (0x7) | 1205 | #define RT5640_CP_FQ3_MASK (0x7) |
1203 | #define RT5640_CP_FQ3_SFT 0 | 1206 | #define RT5640_CP_FQ3_SFT 0 |
1207 | #define RT5640_CP_FQ_1_5_KHZ 0 | ||
1208 | #define RT5640_CP_FQ_3_KHZ 1 | ||
1209 | #define RT5640_CP_FQ_6_KHZ 2 | ||
1210 | #define RT5640_CP_FQ_12_KHZ 3 | ||
1211 | #define RT5640_CP_FQ_24_KHZ 4 | ||
1212 | #define RT5640_CP_FQ_48_KHZ 5 | ||
1213 | #define RT5640_CP_FQ_96_KHZ 6 | ||
1214 | #define RT5640_CP_FQ_192_KHZ 7 | ||
1204 | 1215 | ||
1205 | /* HPOUT charge pump (0x91) */ | 1216 | /* HPOUT charge pump (0x91) */ |
1206 | #define RT5640_OSW_L_MASK (0x1 << 11) | 1217 | #define RT5640_OSW_L_MASK (0x1 << 11) |
@@ -2087,6 +2098,7 @@ struct rt5640_priv { | |||
2087 | int pll_out; | 2098 | int pll_out; |
2088 | 2099 | ||
2089 | int dmic_en; | 2100 | int dmic_en; |
2101 | bool hp_mute; | ||
2090 | }; | 2102 | }; |
2091 | 2103 | ||
2092 | #endif | 2104 | #endif |
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/ssm2602.c b/sound/soc/codecs/ssm2602.c index f8d30e5f6371..492644e67ace 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -561,8 +561,9 @@ static int ssm2602_suspend(struct snd_soc_codec *codec) | |||
561 | 561 | ||
562 | static int ssm2602_resume(struct snd_soc_codec *codec) | 562 | static int ssm2602_resume(struct snd_soc_codec *codec) |
563 | { | 563 | { |
564 | snd_soc_cache_sync(codec); | 564 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
565 | 565 | ||
566 | regcache_sync(ssm2602->regmap); | ||
566 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 567 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
567 | 568 | ||
568 | return 0; | 569 | return 0; |
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/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 17df4e32feac..2ed57d4aa445 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c | |||
@@ -338,18 +338,6 @@ static inline int aic32x4_get_divs(int mclk, int rate) | |||
338 | return -EINVAL; | 338 | return -EINVAL; |
339 | } | 339 | } |
340 | 340 | ||
341 | static int aic32x4_add_widgets(struct snd_soc_codec *codec) | ||
342 | { | ||
343 | snd_soc_dapm_new_controls(&codec->dapm, aic32x4_dapm_widgets, | ||
344 | ARRAY_SIZE(aic32x4_dapm_widgets)); | ||
345 | |||
346 | snd_soc_dapm_add_routes(&codec->dapm, aic32x4_dapm_routes, | ||
347 | ARRAY_SIZE(aic32x4_dapm_routes)); | ||
348 | |||
349 | snd_soc_dapm_new_widgets(&codec->dapm); | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 341 | static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
354 | int clk_id, unsigned int freq, int dir) | 342 | int clk_id, unsigned int freq, int dir) |
355 | { | 343 | { |
@@ -683,9 +671,6 @@ static int aic32x4_probe(struct snd_soc_codec *codec) | |||
683 | } | 671 | } |
684 | 672 | ||
685 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 673 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
686 | snd_soc_add_codec_controls(codec, aic32x4_snd_controls, | ||
687 | ARRAY_SIZE(aic32x4_snd_controls)); | ||
688 | aic32x4_add_widgets(codec); | ||
689 | 674 | ||
690 | /* | 675 | /* |
691 | * Workaround: for an unknown reason, the ADC needs to be powered up | 676 | * Workaround: for an unknown reason, the ADC needs to be powered up |
@@ -714,6 +699,13 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { | |||
714 | .suspend = aic32x4_suspend, | 699 | .suspend = aic32x4_suspend, |
715 | .resume = aic32x4_resume, | 700 | .resume = aic32x4_resume, |
716 | .set_bias_level = aic32x4_set_bias_level, | 701 | .set_bias_level = aic32x4_set_bias_level, |
702 | |||
703 | .controls = aic32x4_snd_controls, | ||
704 | .num_controls = ARRAY_SIZE(aic32x4_snd_controls), | ||
705 | .dapm_widgets = aic32x4_dapm_widgets, | ||
706 | .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets), | ||
707 | .dapm_routes = aic32x4_dapm_routes, | ||
708 | .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), | ||
717 | }; | 709 | }; |
718 | 710 | ||
719 | static int aic32x4_i2c_probe(struct i2c_client *i2c, | 711 | static int aic32x4_i2c_probe(struct i2c_client *i2c, |
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..4dfa8dceeabf 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" |
@@ -1202,7 +1202,6 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec) | |||
1202 | break; | 1202 | break; |
1203 | } | 1203 | } |
1204 | 1204 | ||
1205 | snd_soc_dapm_new_widgets(dapm); | ||
1206 | return 0; | 1205 | return 0; |
1207 | } | 1206 | } |
1208 | 1207 | ||
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..11d80f3b6137 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; |
@@ -3175,7 +3174,7 @@ static ssize_t wm8962_beep_set(struct device *dev, | |||
3175 | long int time; | 3174 | long int time; |
3176 | int ret; | 3175 | int ret; |
3177 | 3176 | ||
3178 | ret = strict_strtol(buf, 10, &time); | 3177 | ret = kstrtol(buf, 10, &time); |
3179 | if (ret != 0) | 3178 | if (ret != 0) |
3180 | return ret; | 3179 | return ret; |
3181 | 3180 | ||
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/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 70eb37a5dd16..25c31f1655f6 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c | |||
@@ -421,13 +421,11 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
421 | dw_i2s_dai, 1); | 421 | dw_i2s_dai, 1); |
422 | if (ret != 0) { | 422 | if (ret != 0) { |
423 | dev_err(&pdev->dev, "not able to register dai\n"); | 423 | dev_err(&pdev->dev, "not able to register dai\n"); |
424 | goto err_set_drvdata; | 424 | goto err_clk_disable; |
425 | } | 425 | } |
426 | 426 | ||
427 | return 0; | 427 | return 0; |
428 | 428 | ||
429 | err_set_drvdata: | ||
430 | dev_set_drvdata(&pdev->dev, NULL); | ||
431 | err_clk_disable: | 429 | err_clk_disable: |
432 | clk_disable(dev->clk); | 430 | clk_disable(dev->clk); |
433 | err_clk_put: | 431 | err_clk_put: |
@@ -440,7 +438,6 @@ static int dw_i2s_remove(struct platform_device *pdev) | |||
440 | struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); | 438 | struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); |
441 | 439 | ||
442 | snd_soc_unregister_component(&pdev->dev); | 440 | snd_soc_unregister_component(&pdev->dev); |
443 | dev_set_drvdata(&pdev->dev, NULL); | ||
444 | 441 | ||
445 | clk_put(dev->clk); | 442 | clk_put(dev->clk); |
446 | 443 | ||
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index aa438546c912..704e246f5b1e 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,23 @@ 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 | ||
196 | config SND_SOC_IMX_SPDIF | ||
197 | tristate "SoC Audio support for i.MX boards with S/PDIF" | ||
198 | select SND_SOC_IMX_PCM_DMA | ||
199 | select SND_SOC_FSL_SPDIF | ||
200 | select SND_SOC_SPDIF | ||
201 | help | ||
202 | SoC Audio support for i.MX boards with S/PDIF | ||
203 | Say Y if you want to add support for SoC audio on an i.MX board with | ||
204 | a S/DPDIF. | ||
205 | |||
195 | config SND_SOC_IMX_MC13783 | 206 | config SND_SOC_IMX_MC13783 |
196 | tristate "SoC Audio support for I.MX boards with mc13783" | 207 | tristate "SoC Audio support for I.MX boards with mc13783" |
197 | depends on MFD_MC13783 | 208 | depends on MFD_MC13783 && ARM |
198 | select SND_SOC_IMX_SSI | 209 | select SND_SOC_IMX_SSI |
199 | select SND_SOC_IMX_AUDMUX | 210 | select SND_SOC_IMX_AUDMUX |
200 | select SND_SOC_MC13783 | 211 | select SND_SOC_MC13783 |
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index d4b4aa8b5649..8db705b0fdf9 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 | ||
@@ -43,6 +45,7 @@ snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o | |||
43 | snd-soc-wm1133-ev1-objs := wm1133-ev1.o | 45 | snd-soc-wm1133-ev1-objs := wm1133-ev1.o |
44 | snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o | 46 | snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o |
45 | snd-soc-imx-wm8962-objs := imx-wm8962.o | 47 | snd-soc-imx-wm8962-objs := imx-wm8962.o |
48 | snd-soc-imx-spdif-objs := imx-spdif.o | ||
46 | snd-soc-imx-mc13783-objs := imx-mc13783.o | 49 | snd-soc-imx-mc13783-objs := imx-mc13783.o |
47 | 50 | ||
48 | obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o | 51 | obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o |
@@ -51,4 +54,5 @@ obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o | |||
51 | obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o | 54 | obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o |
52 | obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o | 55 | obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o |
53 | obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o | 56 | obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o |
57 | obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o | ||
54 | obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o | 58 | obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o |
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c new file mode 100644 index 000000000000..3920c3e849ce --- /dev/null +++ b/sound/soc/fsl/fsl_spdif.c | |||
@@ -0,0 +1,1225 @@ | |||
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 | static 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 | static 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 | * FSL SPDIF IEC958 controller(mixer) functions | ||
559 | * | ||
560 | * Channel status get/put control | ||
561 | * User bit value get/put control | ||
562 | * Valid bit value get control | ||
563 | * DPLL lock status get control | ||
564 | * User bit sync mode selection control | ||
565 | */ | ||
566 | |||
567 | static int fsl_spdif_info(struct snd_kcontrol *kcontrol, | ||
568 | struct snd_ctl_elem_info *uinfo) | ||
569 | { | ||
570 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
571 | uinfo->count = 1; | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | static int fsl_spdif_pb_get(struct snd_kcontrol *kcontrol, | ||
577 | struct snd_ctl_elem_value *uvalue) | ||
578 | { | ||
579 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
580 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
581 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
582 | |||
583 | uvalue->value.iec958.status[0] = ctrl->ch_status[0]; | ||
584 | uvalue->value.iec958.status[1] = ctrl->ch_status[1]; | ||
585 | uvalue->value.iec958.status[2] = ctrl->ch_status[2]; | ||
586 | uvalue->value.iec958.status[3] = ctrl->ch_status[3]; | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static int fsl_spdif_pb_put(struct snd_kcontrol *kcontrol, | ||
592 | struct snd_ctl_elem_value *uvalue) | ||
593 | { | ||
594 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
595 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
596 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
597 | |||
598 | ctrl->ch_status[0] = uvalue->value.iec958.status[0]; | ||
599 | ctrl->ch_status[1] = uvalue->value.iec958.status[1]; | ||
600 | ctrl->ch_status[2] = uvalue->value.iec958.status[2]; | ||
601 | ctrl->ch_status[3] = uvalue->value.iec958.status[3]; | ||
602 | |||
603 | spdif_write_channel_status(spdif_priv); | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | /* Get channel status from SPDIF_RX_CCHAN register */ | ||
609 | static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol, | ||
610 | struct snd_ctl_elem_value *ucontrol) | ||
611 | { | ||
612 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
613 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
614 | struct regmap *regmap = spdif_priv->regmap; | ||
615 | u32 cstatus, val; | ||
616 | |||
617 | regmap_read(regmap, REG_SPDIF_SIS, &val); | ||
618 | if (!(val & INT_CNEW)) { | ||
619 | return -EAGAIN; | ||
620 | } | ||
621 | |||
622 | regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus); | ||
623 | ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF; | ||
624 | ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF; | ||
625 | ucontrol->value.iec958.status[2] = cstatus & 0xFF; | ||
626 | |||
627 | regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus); | ||
628 | ucontrol->value.iec958.status[3] = (cstatus >> 16) & 0xFF; | ||
629 | ucontrol->value.iec958.status[4] = (cstatus >> 8) & 0xFF; | ||
630 | ucontrol->value.iec958.status[5] = cstatus & 0xFF; | ||
631 | |||
632 | /* Clear intr */ | ||
633 | regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW); | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | /* | ||
639 | * Get User bits (subcode) from chip value which readed out | ||
640 | * in UChannel register. | ||
641 | */ | ||
642 | static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol, | ||
643 | struct snd_ctl_elem_value *ucontrol) | ||
644 | { | ||
645 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
646 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
647 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
648 | unsigned long flags; | ||
649 | int ret = 0; | ||
650 | |||
651 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | ||
652 | if (ctrl->ready_buf) { | ||
653 | int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE; | ||
654 | memcpy(&ucontrol->value.iec958.subcode[0], | ||
655 | &ctrl->subcode[idx], SPDIF_UBITS_SIZE); | ||
656 | } else { | ||
657 | ret = -EAGAIN; | ||
658 | } | ||
659 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | ||
660 | |||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | /* Q-subcode infomation. The byte size is SPDIF_UBITS_SIZE/8 */ | ||
665 | static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol, | ||
666 | struct snd_ctl_elem_info *uinfo) | ||
667 | { | ||
668 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
669 | uinfo->count = SPDIF_QSUB_SIZE; | ||
670 | |||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | /* Get Q subcode from chip value which readed out in QChannel register */ | ||
675 | static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, | ||
676 | struct snd_ctl_elem_value *ucontrol) | ||
677 | { | ||
678 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
679 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
680 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
681 | unsigned long flags; | ||
682 | int ret = 0; | ||
683 | |||
684 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | ||
685 | if (ctrl->ready_buf) { | ||
686 | int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE; | ||
687 | memcpy(&ucontrol->value.bytes.data[0], | ||
688 | &ctrl->qsub[idx], SPDIF_QSUB_SIZE); | ||
689 | } else { | ||
690 | ret = -EAGAIN; | ||
691 | } | ||
692 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | ||
693 | |||
694 | return ret; | ||
695 | } | ||
696 | |||
697 | /* Valid bit infomation */ | ||
698 | static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol, | ||
699 | struct snd_ctl_elem_info *uinfo) | ||
700 | { | ||
701 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
702 | uinfo->count = 1; | ||
703 | uinfo->value.integer.min = 0; | ||
704 | uinfo->value.integer.max = 1; | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | /* Get valid good bit from interrupt status register */ | ||
710 | static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, | ||
711 | struct snd_ctl_elem_value *ucontrol) | ||
712 | { | ||
713 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
714 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
715 | struct regmap *regmap = spdif_priv->regmap; | ||
716 | u32 val; | ||
717 | |||
718 | val = regmap_read(regmap, REG_SPDIF_SIS, &val); | ||
719 | ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; | ||
720 | regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | /* DPLL lock infomation */ | ||
726 | static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, | ||
727 | struct snd_ctl_elem_info *uinfo) | ||
728 | { | ||
729 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
730 | uinfo->count = 1; | ||
731 | uinfo->value.integer.min = 16000; | ||
732 | uinfo->value.integer.max = 96000; | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static u32 gainsel_multi[GAINSEL_MULTI_MAX] = { | ||
738 | 24, 16, 12, 8, 6, 4, 3, | ||
739 | }; | ||
740 | |||
741 | /* Get RX data clock rate given the SPDIF bus_clk */ | ||
742 | static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv, | ||
743 | enum spdif_gainsel gainsel) | ||
744 | { | ||
745 | struct regmap *regmap = spdif_priv->regmap; | ||
746 | struct platform_device *pdev = spdif_priv->pdev; | ||
747 | u64 tmpval64, busclk_freq = 0; | ||
748 | u32 freqmeas, phaseconf; | ||
749 | u8 clksrc; | ||
750 | |||
751 | regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas); | ||
752 | regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf); | ||
753 | |||
754 | clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf; | ||
755 | if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) { | ||
756 | /* Get bus clock from system */ | ||
757 | busclk_freq = clk_get_rate(spdif_priv->rxclk); | ||
758 | } | ||
759 | |||
760 | /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */ | ||
761 | tmpval64 = (u64) busclk_freq * freqmeas; | ||
762 | do_div(tmpval64, gainsel_multi[gainsel] * 1024); | ||
763 | do_div(tmpval64, 128 * 1024); | ||
764 | |||
765 | dev_dbg(&pdev->dev, "FreqMeas: %d\n", freqmeas); | ||
766 | dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq); | ||
767 | dev_dbg(&pdev->dev, "RxRate: %lld\n", tmpval64); | ||
768 | |||
769 | return (int)tmpval64; | ||
770 | } | ||
771 | |||
772 | /* | ||
773 | * Get DPLL lock or not info from stable interrupt status register. | ||
774 | * User application must use this control to get locked, | ||
775 | * then can do next PCM operation | ||
776 | */ | ||
777 | static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol, | ||
778 | struct snd_ctl_elem_value *ucontrol) | ||
779 | { | ||
780 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
781 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
782 | int rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL); | ||
783 | |||
784 | if (spdif_priv->dpll_locked) | ||
785 | ucontrol->value.integer.value[0] = rate; | ||
786 | else | ||
787 | ucontrol->value.integer.value[0] = 0; | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | /* User bit sync mode info */ | ||
793 | static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol, | ||
794 | struct snd_ctl_elem_info *uinfo) | ||
795 | { | ||
796 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
797 | uinfo->count = 1; | ||
798 | uinfo->value.integer.min = 0; | ||
799 | uinfo->value.integer.max = 1; | ||
800 | |||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | /* | ||
805 | * User bit sync mode: | ||
806 | * 1 CD User channel subcode | ||
807 | * 0 Non-CD data | ||
808 | */ | ||
809 | static int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol, | ||
810 | struct snd_ctl_elem_value *ucontrol) | ||
811 | { | ||
812 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
813 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
814 | struct regmap *regmap = spdif_priv->regmap; | ||
815 | u32 val; | ||
816 | |||
817 | regmap_read(regmap, REG_SPDIF_SRCD, &val); | ||
818 | ucontrol->value.integer.value[0] = (val & SRCD_CD_USER) != 0; | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | |||
823 | /* | ||
824 | * User bit sync mode: | ||
825 | * 1 CD User channel subcode | ||
826 | * 0 Non-CD data | ||
827 | */ | ||
828 | static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol, | ||
829 | struct snd_ctl_elem_value *ucontrol) | ||
830 | { | ||
831 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
832 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
833 | struct regmap *regmap = spdif_priv->regmap; | ||
834 | u32 val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET; | ||
835 | |||
836 | regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val); | ||
837 | |||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | /* FSL SPDIF IEC958 controller defines */ | ||
842 | static struct snd_kcontrol_new fsl_spdif_ctrls[] = { | ||
843 | /* Status cchanel controller */ | ||
844 | { | ||
845 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
846 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | ||
847 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
848 | SNDRV_CTL_ELEM_ACCESS_WRITE | | ||
849 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
850 | .info = fsl_spdif_info, | ||
851 | .get = fsl_spdif_pb_get, | ||
852 | .put = fsl_spdif_pb_put, | ||
853 | }, | ||
854 | { | ||
855 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
856 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | ||
857 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
858 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
859 | .info = fsl_spdif_info, | ||
860 | .get = fsl_spdif_capture_get, | ||
861 | }, | ||
862 | /* User bits controller */ | ||
863 | { | ||
864 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
865 | .name = "IEC958 Subcode Capture Default", | ||
866 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
867 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
868 | .info = fsl_spdif_info, | ||
869 | .get = fsl_spdif_subcode_get, | ||
870 | }, | ||
871 | { | ||
872 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
873 | .name = "IEC958 Q-subcode Capture Default", | ||
874 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
875 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
876 | .info = fsl_spdif_qinfo, | ||
877 | .get = fsl_spdif_qget, | ||
878 | }, | ||
879 | /* Valid bit error controller */ | ||
880 | { | ||
881 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
882 | .name = "IEC958 V-Bit Errors", | ||
883 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
884 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
885 | .info = fsl_spdif_vbit_info, | ||
886 | .get = fsl_spdif_vbit_get, | ||
887 | }, | ||
888 | /* DPLL lock info get controller */ | ||
889 | { | ||
890 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
891 | .name = "RX Sample Rate", | ||
892 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
893 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
894 | .info = fsl_spdif_rxrate_info, | ||
895 | .get = fsl_spdif_rxrate_get, | ||
896 | }, | ||
897 | /* User bit sync mode set/get controller */ | ||
898 | { | ||
899 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
900 | .name = "IEC958 USyncMode CDText", | ||
901 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
902 | SNDRV_CTL_ELEM_ACCESS_WRITE | | ||
903 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
904 | .info = fsl_spdif_usync_info, | ||
905 | .get = fsl_spdif_usync_get, | ||
906 | .put = fsl_spdif_usync_put, | ||
907 | }, | ||
908 | }; | ||
909 | |||
910 | static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) | ||
911 | { | ||
912 | struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); | ||
913 | |||
914 | dai->playback_dma_data = &spdif_private->dma_params_tx; | ||
915 | dai->capture_dma_data = &spdif_private->dma_params_rx; | ||
916 | |||
917 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static struct snd_soc_dai_driver fsl_spdif_dai = { | ||
923 | .probe = &fsl_spdif_dai_probe, | ||
924 | .playback = { | ||
925 | .channels_min = 2, | ||
926 | .channels_max = 2, | ||
927 | .rates = FSL_SPDIF_RATES_PLAYBACK, | ||
928 | .formats = FSL_SPDIF_FORMATS_PLAYBACK, | ||
929 | }, | ||
930 | .capture = { | ||
931 | .channels_min = 2, | ||
932 | .channels_max = 2, | ||
933 | .rates = FSL_SPDIF_RATES_CAPTURE, | ||
934 | .formats = FSL_SPDIF_FORMATS_CAPTURE, | ||
935 | }, | ||
936 | .ops = &fsl_spdif_dai_ops, | ||
937 | }; | ||
938 | |||
939 | static const struct snd_soc_component_driver fsl_spdif_component = { | ||
940 | .name = "fsl-spdif", | ||
941 | }; | ||
942 | |||
943 | /* FSL SPDIF REGMAP */ | ||
944 | |||
945 | static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg) | ||
946 | { | ||
947 | switch (reg) { | ||
948 | case REG_SPDIF_SCR: | ||
949 | case REG_SPDIF_SRCD: | ||
950 | case REG_SPDIF_SRPC: | ||
951 | case REG_SPDIF_SIE: | ||
952 | case REG_SPDIF_SIS: | ||
953 | case REG_SPDIF_SRL: | ||
954 | case REG_SPDIF_SRR: | ||
955 | case REG_SPDIF_SRCSH: | ||
956 | case REG_SPDIF_SRCSL: | ||
957 | case REG_SPDIF_SRU: | ||
958 | case REG_SPDIF_SRQ: | ||
959 | case REG_SPDIF_STCSCH: | ||
960 | case REG_SPDIF_STCSCL: | ||
961 | case REG_SPDIF_SRFM: | ||
962 | case REG_SPDIF_STC: | ||
963 | return true; | ||
964 | default: | ||
965 | return false; | ||
966 | }; | ||
967 | } | ||
968 | |||
969 | static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) | ||
970 | { | ||
971 | switch (reg) { | ||
972 | case REG_SPDIF_SCR: | ||
973 | case REG_SPDIF_SRCD: | ||
974 | case REG_SPDIF_SRPC: | ||
975 | case REG_SPDIF_SIE: | ||
976 | case REG_SPDIF_SIC: | ||
977 | case REG_SPDIF_STL: | ||
978 | case REG_SPDIF_STR: | ||
979 | case REG_SPDIF_STCSCH: | ||
980 | case REG_SPDIF_STCSCL: | ||
981 | case REG_SPDIF_STC: | ||
982 | return true; | ||
983 | default: | ||
984 | return false; | ||
985 | }; | ||
986 | } | ||
987 | |||
988 | static const struct regmap_config fsl_spdif_regmap_config = { | ||
989 | .reg_bits = 32, | ||
990 | .reg_stride = 4, | ||
991 | .val_bits = 32, | ||
992 | |||
993 | .max_register = REG_SPDIF_STC, | ||
994 | .readable_reg = fsl_spdif_readable_reg, | ||
995 | .writeable_reg = fsl_spdif_writeable_reg, | ||
996 | }; | ||
997 | |||
998 | static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, | ||
999 | struct clk *clk, u64 savesub, | ||
1000 | enum spdif_txrate index) | ||
1001 | { | ||
1002 | const u32 rate[] = { 32000, 44100, 48000 }; | ||
1003 | u64 rate_ideal, rate_actual, sub; | ||
1004 | u32 div, arate; | ||
1005 | |||
1006 | for (div = 1; div <= 128; div++) { | ||
1007 | rate_ideal = rate[index] * (div + 1) * 64; | ||
1008 | rate_actual = clk_round_rate(clk, rate_ideal); | ||
1009 | |||
1010 | arate = rate_actual / 64; | ||
1011 | arate /= div; | ||
1012 | |||
1013 | if (arate == rate[index]) { | ||
1014 | /* We are lucky */ | ||
1015 | savesub = 0; | ||
1016 | spdif_priv->txclk_div[index] = div; | ||
1017 | break; | ||
1018 | } else if (arate / rate[index] == 1) { | ||
1019 | /* A little bigger than expect */ | ||
1020 | sub = (arate - rate[index]) * 100000; | ||
1021 | do_div(sub, rate[index]); | ||
1022 | if (sub < savesub) { | ||
1023 | savesub = sub; | ||
1024 | spdif_priv->txclk_div[index] = div; | ||
1025 | } | ||
1026 | } else if (rate[index] / arate == 1) { | ||
1027 | /* A little smaller than expect */ | ||
1028 | sub = (rate[index] - arate) * 100000; | ||
1029 | do_div(sub, rate[index]); | ||
1030 | if (sub < savesub) { | ||
1031 | savesub = sub; | ||
1032 | spdif_priv->txclk_div[index] = div; | ||
1033 | } | ||
1034 | } | ||
1035 | } | ||
1036 | |||
1037 | return savesub; | ||
1038 | } | ||
1039 | |||
1040 | static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, | ||
1041 | enum spdif_txrate index) | ||
1042 | { | ||
1043 | const u32 rate[] = { 32000, 44100, 48000 }; | ||
1044 | struct platform_device *pdev = spdif_priv->pdev; | ||
1045 | struct device *dev = &pdev->dev; | ||
1046 | u64 savesub = 100000, ret; | ||
1047 | struct clk *clk; | ||
1048 | char tmp[16]; | ||
1049 | int i; | ||
1050 | |||
1051 | for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { | ||
1052 | sprintf(tmp, "rxtx%d", i); | ||
1053 | clk = devm_clk_get(&pdev->dev, tmp); | ||
1054 | if (IS_ERR(clk)) { | ||
1055 | dev_err(dev, "no rxtx%d clock in devicetree\n", i); | ||
1056 | return PTR_ERR(clk); | ||
1057 | } | ||
1058 | if (!clk_get_rate(clk)) | ||
1059 | continue; | ||
1060 | |||
1061 | ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index); | ||
1062 | if (savesub == ret) | ||
1063 | continue; | ||
1064 | |||
1065 | savesub = ret; | ||
1066 | spdif_priv->txclk[index] = clk; | ||
1067 | spdif_priv->txclk_src[index] = i; | ||
1068 | |||
1069 | /* To quick catch a divisor, we allow a 0.1% deviation */ | ||
1070 | if (savesub < 100) | ||
1071 | break; | ||
1072 | } | ||
1073 | |||
1074 | dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n", | ||
1075 | spdif_priv->txclk_src[index], rate[index]); | ||
1076 | dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate\n", | ||
1077 | spdif_priv->txclk_div[index], rate[index]); | ||
1078 | |||
1079 | return 0; | ||
1080 | } | ||
1081 | |||
1082 | static int fsl_spdif_probe(struct platform_device *pdev) | ||
1083 | { | ||
1084 | struct device_node *np = pdev->dev.of_node; | ||
1085 | struct fsl_spdif_priv *spdif_priv; | ||
1086 | struct spdif_mixer_control *ctrl; | ||
1087 | struct resource *res; | ||
1088 | void __iomem *regs; | ||
1089 | int irq, ret, i; | ||
1090 | |||
1091 | if (!np) | ||
1092 | return -ENODEV; | ||
1093 | |||
1094 | spdif_priv = devm_kzalloc(&pdev->dev, | ||
1095 | sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1, | ||
1096 | GFP_KERNEL); | ||
1097 | if (!spdif_priv) | ||
1098 | return -ENOMEM; | ||
1099 | |||
1100 | strcpy(spdif_priv->name, np->name); | ||
1101 | |||
1102 | spdif_priv->pdev = pdev; | ||
1103 | |||
1104 | /* Initialize this copy of the CPU DAI driver structure */ | ||
1105 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); | ||
1106 | spdif_priv->cpu_dai_drv.name = spdif_priv->name; | ||
1107 | |||
1108 | /* Get the addresses and IRQ */ | ||
1109 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1110 | if (IS_ERR(res)) { | ||
1111 | dev_err(&pdev->dev, "could not determine device resources\n"); | ||
1112 | return PTR_ERR(res); | ||
1113 | } | ||
1114 | |||
1115 | regs = devm_ioremap_resource(&pdev->dev, res); | ||
1116 | if (IS_ERR(regs)) | ||
1117 | return PTR_ERR(regs); | ||
1118 | |||
1119 | spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, | ||
1120 | "core", regs, &fsl_spdif_regmap_config); | ||
1121 | if (IS_ERR(spdif_priv->regmap)) { | ||
1122 | dev_err(&pdev->dev, "regmap init failed\n"); | ||
1123 | return PTR_ERR(spdif_priv->regmap); | ||
1124 | } | ||
1125 | |||
1126 | irq = platform_get_irq(pdev, 0); | ||
1127 | if (irq < 0) { | ||
1128 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); | ||
1129 | return irq; | ||
1130 | } | ||
1131 | |||
1132 | ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, | ||
1133 | spdif_priv->name, spdif_priv); | ||
1134 | if (ret) { | ||
1135 | dev_err(&pdev->dev, "could not claim irq %u\n", irq); | ||
1136 | return ret; | ||
1137 | } | ||
1138 | |||
1139 | /* Select clock source for rx/tx clock */ | ||
1140 | spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1"); | ||
1141 | if (IS_ERR(spdif_priv->rxclk)) { | ||
1142 | dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n"); | ||
1143 | return PTR_ERR(spdif_priv->rxclk); | ||
1144 | } | ||
1145 | spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC; | ||
1146 | |||
1147 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) { | ||
1148 | ret = fsl_spdif_probe_txclk(spdif_priv, i); | ||
1149 | if (ret) | ||
1150 | return ret; | ||
1151 | } | ||
1152 | |||
1153 | /* Initial spinlock for control data */ | ||
1154 | ctrl = &spdif_priv->fsl_spdif_control; | ||
1155 | spin_lock_init(&ctrl->ctl_lock); | ||
1156 | |||
1157 | /* Init tx channel status default value */ | ||
1158 | ctrl->ch_status[0] = | ||
1159 | IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_5015; | ||
1160 | ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID; | ||
1161 | ctrl->ch_status[2] = 0x00; | ||
1162 | ctrl->ch_status[3] = | ||
1163 | IEC958_AES3_CON_FS_44100 | IEC958_AES3_CON_CLOCK_1000PPM; | ||
1164 | |||
1165 | spdif_priv->dpll_locked = false; | ||
1166 | |||
1167 | spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML; | ||
1168 | spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML; | ||
1169 | spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL; | ||
1170 | spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL; | ||
1171 | |||
1172 | /* Register with ASoC */ | ||
1173 | dev_set_drvdata(&pdev->dev, spdif_priv); | ||
1174 | |||
1175 | ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component, | ||
1176 | &spdif_priv->cpu_dai_drv, 1); | ||
1177 | if (ret) { | ||
1178 | dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); | ||
1179 | return ret; | ||
1180 | } | ||
1181 | |||
1182 | ret = imx_pcm_dma_init(pdev); | ||
1183 | if (ret) { | ||
1184 | dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); | ||
1185 | goto error_component; | ||
1186 | } | ||
1187 | |||
1188 | return ret; | ||
1189 | |||
1190 | error_component: | ||
1191 | snd_soc_unregister_component(&pdev->dev); | ||
1192 | |||
1193 | return ret; | ||
1194 | } | ||
1195 | |||
1196 | static int fsl_spdif_remove(struct platform_device *pdev) | ||
1197 | { | ||
1198 | imx_pcm_dma_exit(pdev); | ||
1199 | snd_soc_unregister_component(&pdev->dev); | ||
1200 | |||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | static const struct of_device_id fsl_spdif_dt_ids[] = { | ||
1205 | { .compatible = "fsl,imx35-spdif", }, | ||
1206 | {} | ||
1207 | }; | ||
1208 | MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); | ||
1209 | |||
1210 | static struct platform_driver fsl_spdif_driver = { | ||
1211 | .driver = { | ||
1212 | .name = "fsl-spdif-dai", | ||
1213 | .owner = THIS_MODULE, | ||
1214 | .of_match_table = fsl_spdif_dt_ids, | ||
1215 | }, | ||
1216 | .probe = fsl_spdif_probe, | ||
1217 | .remove = fsl_spdif_remove, | ||
1218 | }; | ||
1219 | |||
1220 | module_platform_driver(fsl_spdif_driver); | ||
1221 | |||
1222 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
1223 | MODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver"); | ||
1224 | MODULE_LICENSE("GPL v2"); | ||
1225 | 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..c6b743978d5e 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: |
@@ -853,27 +1114,15 @@ error_dai: | |||
853 | snd_soc_unregister_component(&pdev->dev); | 1114 | snd_soc_unregister_component(&pdev->dev); |
854 | 1115 | ||
855 | error_dev: | 1116 | error_dev: |
856 | dev_set_drvdata(&pdev->dev, NULL); | ||
857 | device_remove_file(&pdev->dev, dev_attr); | 1117 | device_remove_file(&pdev->dev, dev_attr); |
858 | 1118 | ||
859 | error_clk: | 1119 | error_clk: |
860 | if (ssi_private->ssi_on_imx) { | 1120 | if (ssi_private->ssi_on_imx) |
861 | clk_disable_unprepare(ssi_private->clk); | 1121 | 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 | 1122 | ||
868 | error_irqmap: | 1123 | error_irqmap: |
869 | irq_dispose_mapping(ssi_private->irq); | 1124 | irq_dispose_mapping(ssi_private->irq); |
870 | 1125 | ||
871 | error_iomap: | ||
872 | iounmap(ssi_private->ssi); | ||
873 | |||
874 | error_kmalloc: | ||
875 | kfree(ssi_private); | ||
876 | |||
877 | return ret; | 1126 | return ret; |
878 | } | 1127 | } |
879 | 1128 | ||
@@ -883,20 +1132,15 @@ static int fsl_ssi_remove(struct platform_device *pdev) | |||
883 | 1132 | ||
884 | if (!ssi_private->new_binding) | 1133 | if (!ssi_private->new_binding) |
885 | platform_device_unregister(ssi_private->pdev); | 1134 | platform_device_unregister(ssi_private->pdev); |
886 | if (ssi_private->ssi_on_imx) { | 1135 | if (ssi_private->ssi_on_imx) |
887 | imx_pcm_dma_exit(pdev); | 1136 | 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); | 1137 | snd_soc_unregister_component(&pdev->dev); |
1138 | dev_set_drvdata(&pdev->dev, NULL); | ||
892 | device_remove_file(&pdev->dev, &ssi_private->dev_attr); | 1139 | device_remove_file(&pdev->dev, &ssi_private->dev_attr); |
893 | 1140 | if (ssi_private->ssi_on_imx) | |
894 | free_irq(ssi_private->irq, ssi_private); | 1141 | clk_disable_unprepare(ssi_private->clk); |
895 | irq_dispose_mapping(ssi_private->irq); | 1142 | irq_dispose_mapping(ssi_private->irq); |
896 | 1143 | ||
897 | kfree(ssi_private); | ||
898 | dev_set_drvdata(&pdev->dev, NULL); | ||
899 | |||
900 | return 0; | 1144 | return 0; |
901 | } | 1145 | } |
902 | 1146 | ||
@@ -919,6 +1163,7 @@ static struct platform_driver fsl_ssi_driver = { | |||
919 | 1163 | ||
920 | module_platform_driver(fsl_ssi_driver); | 1164 | module_platform_driver(fsl_ssi_driver); |
921 | 1165 | ||
1166 | MODULE_ALIAS("platform:fsl-ssi-dai"); | ||
922 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | 1167 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); |
923 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); | 1168 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); |
924 | MODULE_LICENSE("GPL v2"); | 1169 | 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-spdif.c b/sound/soc/fsl/imx-spdif.c new file mode 100644 index 000000000000..816013b0ebba --- /dev/null +++ b/sound/soc/fsl/imx-spdif.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/of_platform.h> | ||
14 | #include <sound/soc.h> | ||
15 | |||
16 | struct imx_spdif_data { | ||
17 | struct snd_soc_dai_link dai[2]; | ||
18 | struct snd_soc_card card; | ||
19 | struct platform_device *txdev; | ||
20 | struct platform_device *rxdev; | ||
21 | }; | ||
22 | |||
23 | static int imx_spdif_audio_probe(struct platform_device *pdev) | ||
24 | { | ||
25 | struct device_node *spdif_np, *np = pdev->dev.of_node; | ||
26 | struct imx_spdif_data *data; | ||
27 | int ret = 0, num_links = 0; | ||
28 | |||
29 | spdif_np = of_parse_phandle(np, "spdif-controller", 0); | ||
30 | if (!spdif_np) { | ||
31 | dev_err(&pdev->dev, "failed to find spdif-controller\n"); | ||
32 | ret = -EINVAL; | ||
33 | goto end; | ||
34 | } | ||
35 | |||
36 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | ||
37 | if (!data) { | ||
38 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
39 | ret = -ENOMEM; | ||
40 | goto end; | ||
41 | } | ||
42 | |||
43 | if (of_property_read_bool(np, "spdif-out")) { | ||
44 | data->dai[num_links].name = "S/PDIF TX"; | ||
45 | data->dai[num_links].stream_name = "S/PDIF PCM Playback"; | ||
46 | data->dai[num_links].codec_dai_name = "dit-hifi"; | ||
47 | data->dai[num_links].codec_name = "spdif-dit"; | ||
48 | data->dai[num_links].cpu_of_node = spdif_np; | ||
49 | data->dai[num_links].platform_of_node = spdif_np; | ||
50 | num_links++; | ||
51 | |||
52 | data->txdev = platform_device_register_simple("spdif-dit", -1, NULL, 0); | ||
53 | if (IS_ERR(data->txdev)) { | ||
54 | ret = PTR_ERR(data->txdev); | ||
55 | dev_err(&pdev->dev, "register dit failed: %d\n", ret); | ||
56 | goto end; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | if (of_property_read_bool(np, "spdif-in")) { | ||
61 | data->dai[num_links].name = "S/PDIF RX"; | ||
62 | data->dai[num_links].stream_name = "S/PDIF PCM Capture"; | ||
63 | data->dai[num_links].codec_dai_name = "dir-hifi"; | ||
64 | data->dai[num_links].codec_name = "spdif-dir"; | ||
65 | data->dai[num_links].cpu_of_node = spdif_np; | ||
66 | data->dai[num_links].platform_of_node = spdif_np; | ||
67 | num_links++; | ||
68 | |||
69 | data->rxdev = platform_device_register_simple("spdif-dir", -1, NULL, 0); | ||
70 | if (IS_ERR(data->rxdev)) { | ||
71 | ret = PTR_ERR(data->rxdev); | ||
72 | dev_err(&pdev->dev, "register dir failed: %d\n", ret); | ||
73 | goto error_dit; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | if (!num_links) { | ||
78 | dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n"); | ||
79 | goto error_dir; | ||
80 | } | ||
81 | |||
82 | data->card.dev = &pdev->dev; | ||
83 | data->card.num_links = num_links; | ||
84 | data->card.dai_link = data->dai; | ||
85 | |||
86 | ret = snd_soc_of_parse_card_name(&data->card, "model"); | ||
87 | if (ret) | ||
88 | goto error_dir; | ||
89 | |||
90 | ret = snd_soc_register_card(&data->card); | ||
91 | if (ret) { | ||
92 | dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret); | ||
93 | goto error_dir; | ||
94 | } | ||
95 | |||
96 | platform_set_drvdata(pdev, data); | ||
97 | |||
98 | goto end; | ||
99 | |||
100 | error_dir: | ||
101 | if (data->rxdev) | ||
102 | platform_device_unregister(data->rxdev); | ||
103 | error_dit: | ||
104 | if (data->txdev) | ||
105 | platform_device_unregister(data->txdev); | ||
106 | end: | ||
107 | if (spdif_np) | ||
108 | of_node_put(spdif_np); | ||
109 | |||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | static int imx_spdif_audio_remove(struct platform_device *pdev) | ||
114 | { | ||
115 | struct imx_spdif_data *data = platform_get_drvdata(pdev); | ||
116 | |||
117 | if (data->rxdev) | ||
118 | platform_device_unregister(data->rxdev); | ||
119 | if (data->txdev) | ||
120 | platform_device_unregister(data->txdev); | ||
121 | |||
122 | snd_soc_unregister_card(&data->card); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static const struct of_device_id imx_spdif_dt_ids[] = { | ||
128 | { .compatible = "fsl,imx-audio-spdif", }, | ||
129 | { /* sentinel */ } | ||
130 | }; | ||
131 | MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids); | ||
132 | |||
133 | static struct platform_driver imx_spdif_driver = { | ||
134 | .driver = { | ||
135 | .name = "imx-spdif", | ||
136 | .owner = THIS_MODULE, | ||
137 | .of_match_table = imx_spdif_dt_ids, | ||
138 | }, | ||
139 | .probe = imx_spdif_audio_probe, | ||
140 | .remove = imx_spdif_audio_remove, | ||
141 | }; | ||
142 | |||
143 | module_platform_driver(imx_spdif_driver); | ||
144 | |||
145 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
146 | MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver"); | ||
147 | MODULE_LICENSE("GPL v2"); | ||
148 | MODULE_ALIAS("platform:imx-spdif"); | ||
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/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355a8542..8c49147db84c 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -105,6 +105,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev) | |||
105 | static struct platform_driver asoc_simple_card = { | 105 | static struct platform_driver asoc_simple_card = { |
106 | .driver = { | 106 | .driver = { |
107 | .name = "asoc-simple-card", | 107 | .name = "asoc-simple-card", |
108 | .owner = THIS_MODULE, | ||
108 | }, | 109 | }, |
109 | .probe = asoc_simple_card_probe, | 110 | .probe = asoc_simple_card_probe, |
110 | .remove = asoc_simple_card_remove, | 111 | .remove = asoc_simple_card_remove, |
@@ -112,6 +113,7 @@ static struct platform_driver asoc_simple_card = { | |||
112 | 113 | ||
113 | module_platform_driver(asoc_simple_card); | 114 | module_platform_driver(asoc_simple_card); |
114 | 115 | ||
116 | MODULE_ALIAS("platform:asoc-simple-card"); | ||
115 | MODULE_LICENSE("GPL"); | 117 | MODULE_LICENSE("GPL"); |
116 | MODULE_DESCRIPTION("ASoC Simple Sound Card"); | 118 | MODULE_DESCRIPTION("ASoC Simple Sound Card"); |
117 | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); | 119 | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); |
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig index c62d715235e2..78ed4a42ad21 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 and Dove chips" |
3 | depends on ARCH_KIRKWOOD | 3 | depends on ARCH_KIRKWOOD || ARCH_DOVE || 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..7fce340ab3ef 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c | |||
@@ -22,13 +22,12 @@ | |||
22 | #include <sound/pcm_params.h> | 22 | #include <sound/pcm_params.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <linux/platform_data/asoc-kirkwood.h> | 24 | #include <linux/platform_data/asoc-kirkwood.h> |
25 | #include <linux/of.h> | ||
26 | |||
25 | #include "kirkwood.h" | 27 | #include "kirkwood.h" |
26 | 28 | ||
27 | #define DRV_NAME "kirkwood-i2s" | 29 | #define DRV_NAME "mvebu-audio" |
28 | 30 | ||
29 | #define KIRKWOOD_I2S_RATES \ | ||
30 | (SNDRV_PCM_RATE_44100 | \ | ||
31 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | ||
32 | #define KIRKWOOD_I2S_FORMATS \ | 31 | #define KIRKWOOD_I2S_FORMATS \ |
33 | (SNDRV_PCM_FMTBIT_S16_LE | \ | 32 | (SNDRV_PCM_FMTBIT_S16_LE | \ |
34 | SNDRV_PCM_FMTBIT_S24_LE | \ | 33 | SNDRV_PCM_FMTBIT_S24_LE | \ |
@@ -105,14 +104,16 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai, | |||
105 | uint32_t clks_ctrl; | 104 | uint32_t clks_ctrl; |
106 | 105 | ||
107 | if (rate == 44100 || rate == 48000 || rate == 96000) { | 106 | if (rate == 44100 || rate == 48000 || rate == 96000) { |
108 | /* use internal dco for supported rates */ | 107 | /* use internal dco for the supported rates |
108 | * defined in kirkwood_i2s_dai */ | ||
109 | dev_dbg(dai->dev, "%s: dco set rate = %lu\n", | 109 | dev_dbg(dai->dev, "%s: dco set rate = %lu\n", |
110 | __func__, rate); | 110 | __func__, rate); |
111 | kirkwood_set_dco(priv->io, rate); | 111 | kirkwood_set_dco(priv->io, rate); |
112 | 112 | ||
113 | clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO; | 113 | clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO; |
114 | } else if (!IS_ERR(priv->extclk)) { | 114 | } else { |
115 | /* use optional external clk for other rates */ | 115 | /* use the external clock for the other rates |
116 | * defined in kirkwood_i2s_dai_extclk */ | ||
116 | dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n", | 117 | dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n", |
117 | __func__, rate, 256 * rate); | 118 | __func__, rate, 256 * rate); |
118 | clk_set_rate(priv->extclk, 256 * rate); | 119 | clk_set_rate(priv->extclk, 256 * rate); |
@@ -199,8 +200,7 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
199 | ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF; | 200 | ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF; |
200 | 201 | ||
201 | priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK | | 202 | priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK | |
202 | KIRKWOOD_PLAYCTL_I2S_EN | | 203 | KIRKWOOD_PLAYCTL_ENABLE_MASK | |
203 | KIRKWOOD_PLAYCTL_SPDIF_EN | | ||
204 | KIRKWOOD_PLAYCTL_SIZE_MASK); | 204 | KIRKWOOD_PLAYCTL_SIZE_MASK); |
205 | priv->ctl_play |= ctl_play; | 205 | priv->ctl_play |= ctl_play; |
206 | } else { | 206 | } else { |
@@ -244,8 +244,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
244 | case SNDRV_PCM_TRIGGER_START: | 244 | case SNDRV_PCM_TRIGGER_START: |
245 | /* configure */ | 245 | /* configure */ |
246 | ctl = priv->ctl_play; | 246 | ctl = priv->ctl_play; |
247 | value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN | | 247 | value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK; |
248 | KIRKWOOD_PLAYCTL_SPDIF_EN); | ||
249 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | 248 | writel(value, priv->io + KIRKWOOD_PLAYCTL); |
250 | 249 | ||
251 | /* enable interrupts */ | 250 | /* enable interrupts */ |
@@ -267,7 +266,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
267 | writel(value, priv->io + KIRKWOOD_INT_MASK); | 266 | writel(value, priv->io + KIRKWOOD_INT_MASK); |
268 | 267 | ||
269 | /* disable all playbacks */ | 268 | /* disable all playbacks */ |
270 | ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); | 269 | ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK; |
271 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 270 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
272 | break; | 271 | break; |
273 | 272 | ||
@@ -387,7 +386,7 @@ static int kirkwood_i2s_probe(struct snd_soc_dai *dai) | |||
387 | 386 | ||
388 | /* disable playback/record */ | 387 | /* disable playback/record */ |
389 | value = readl(priv->io + KIRKWOOD_PLAYCTL); | 388 | value = readl(priv->io + KIRKWOOD_PLAYCTL); |
390 | value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN); | 389 | value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK; |
391 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | 390 | writel(value, priv->io + KIRKWOOD_PLAYCTL); |
392 | 391 | ||
393 | value = readl(priv->io + KIRKWOOD_RECCTL); | 392 | value = readl(priv->io + KIRKWOOD_RECCTL); |
@@ -398,11 +397,6 @@ static int kirkwood_i2s_probe(struct snd_soc_dai *dai) | |||
398 | 397 | ||
399 | } | 398 | } |
400 | 399 | ||
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 = { | 400 | static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { |
407 | .startup = kirkwood_i2s_startup, | 401 | .startup = kirkwood_i2s_startup, |
408 | .trigger = kirkwood_i2s_trigger, | 402 | .trigger = kirkwood_i2s_trigger, |
@@ -413,17 +407,18 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { | |||
413 | 407 | ||
414 | static struct snd_soc_dai_driver kirkwood_i2s_dai = { | 408 | static struct snd_soc_dai_driver kirkwood_i2s_dai = { |
415 | .probe = kirkwood_i2s_probe, | 409 | .probe = kirkwood_i2s_probe, |
416 | .remove = kirkwood_i2s_remove, | ||
417 | .playback = { | 410 | .playback = { |
418 | .channels_min = 1, | 411 | .channels_min = 1, |
419 | .channels_max = 2, | 412 | .channels_max = 2, |
420 | .rates = KIRKWOOD_I2S_RATES, | 413 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | |
414 | SNDRV_PCM_RATE_96000, | ||
421 | .formats = KIRKWOOD_I2S_FORMATS, | 415 | .formats = KIRKWOOD_I2S_FORMATS, |
422 | }, | 416 | }, |
423 | .capture = { | 417 | .capture = { |
424 | .channels_min = 1, | 418 | .channels_min = 1, |
425 | .channels_max = 2, | 419 | .channels_max = 2, |
426 | .rates = KIRKWOOD_I2S_RATES, | 420 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | |
421 | SNDRV_PCM_RATE_96000, | ||
427 | .formats = KIRKWOOD_I2S_FORMATS, | 422 | .formats = KIRKWOOD_I2S_FORMATS, |
428 | }, | 423 | }, |
429 | .ops = &kirkwood_i2s_dai_ops, | 424 | .ops = &kirkwood_i2s_dai_ops, |
@@ -431,7 +426,6 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = { | |||
431 | 426 | ||
432 | static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { | 427 | static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { |
433 | .probe = kirkwood_i2s_probe, | 428 | .probe = kirkwood_i2s_probe, |
434 | .remove = kirkwood_i2s_remove, | ||
435 | .playback = { | 429 | .playback = { |
436 | .channels_min = 1, | 430 | .channels_min = 1, |
437 | .channels_max = 2, | 431 | .channels_max = 2, |
@@ -461,6 +455,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
461 | struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai; | 455 | struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai; |
462 | struct kirkwood_dma_data *priv; | 456 | struct kirkwood_dma_data *priv; |
463 | struct resource *mem; | 457 | struct resource *mem; |
458 | struct device_node *np = pdev->dev.of_node; | ||
464 | int err; | 459 | int err; |
465 | 460 | ||
466 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | 461 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
@@ -481,14 +476,16 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
481 | return -ENXIO; | 476 | return -ENXIO; |
482 | } | 477 | } |
483 | 478 | ||
484 | if (!data) { | 479 | if (np) { |
485 | dev_err(&pdev->dev, "no platform data ?!\n"); | 480 | priv->burst = 128; /* might be 32 or 128 */ |
481 | } else if (data) { | ||
482 | priv->burst = data->burst; | ||
483 | } else { | ||
484 | dev_err(&pdev->dev, "no DT nor platform data ?!\n"); | ||
486 | return -EINVAL; | 485 | return -EINVAL; |
487 | } | 486 | } |
488 | 487 | ||
489 | priv->burst = data->burst; | 488 | priv->clk = devm_clk_get(&pdev->dev, np ? "internal" : NULL); |
490 | |||
491 | priv->clk = devm_clk_get(&pdev->dev, NULL); | ||
492 | if (IS_ERR(priv->clk)) { | 489 | if (IS_ERR(priv->clk)) { |
493 | dev_err(&pdev->dev, "no clock\n"); | 490 | dev_err(&pdev->dev, "no clock\n"); |
494 | return PTR_ERR(priv->clk); | 491 | return PTR_ERR(priv->clk); |
@@ -498,10 +495,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
498 | if (err < 0) | 495 | if (err < 0) |
499 | return err; | 496 | return err; |
500 | 497 | ||
501 | priv->extclk = clk_get(&pdev->dev, "extclk"); | 498 | priv->extclk = devm_clk_get(&pdev->dev, "extclk"); |
502 | if (!IS_ERR(priv->extclk)) { | 499 | if (!IS_ERR(priv->extclk)) { |
503 | if (priv->extclk == priv->clk) { | 500 | if (priv->extclk == priv->clk) { |
504 | clk_put(priv->extclk); | 501 | devm_clk_put(&pdev->dev, priv->extclk); |
505 | priv->extclk = ERR_PTR(-EINVAL); | 502 | priv->extclk = ERR_PTR(-EINVAL); |
506 | } else { | 503 | } else { |
507 | dev_info(&pdev->dev, "found external clock\n"); | 504 | dev_info(&pdev->dev, "found external clock\n"); |
@@ -515,7 +512,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
515 | priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24; | 512 | priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24; |
516 | 513 | ||
517 | /* Select the burst size */ | 514 | /* Select the burst size */ |
518 | if (data->burst == 32) { | 515 | if (priv->burst == 32) { |
519 | priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32; | 516 | priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32; |
520 | priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32; | 517 | priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32; |
521 | } else { | 518 | } else { |
@@ -525,14 +522,22 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
525 | 522 | ||
526 | err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, | 523 | err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, |
527 | soc_dai, 1); | 524 | soc_dai, 1); |
528 | if (!err) | 525 | if (err) { |
529 | return 0; | 526 | dev_err(&pdev->dev, "snd_soc_register_component failed\n"); |
530 | dev_err(&pdev->dev, "snd_soc_register_component failed\n"); | 527 | goto err_component; |
528 | } | ||
531 | 529 | ||
532 | if (!IS_ERR(priv->extclk)) { | 530 | err = snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform); |
533 | clk_disable_unprepare(priv->extclk); | 531 | if (err) { |
534 | clk_put(priv->extclk); | 532 | dev_err(&pdev->dev, "snd_soc_register_platform failed\n"); |
533 | goto err_platform; | ||
535 | } | 534 | } |
535 | return 0; | ||
536 | err_platform: | ||
537 | snd_soc_unregister_component(&pdev->dev); | ||
538 | err_component: | ||
539 | if (!IS_ERR(priv->extclk)) | ||
540 | clk_disable_unprepare(priv->extclk); | ||
536 | clk_disable_unprepare(priv->clk); | 541 | clk_disable_unprepare(priv->clk); |
537 | 542 | ||
538 | return err; | 543 | return err; |
@@ -542,23 +547,31 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev) | |||
542 | { | 547 | { |
543 | struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); | 548 | struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); |
544 | 549 | ||
550 | snd_soc_unregister_platform(&pdev->dev); | ||
545 | snd_soc_unregister_component(&pdev->dev); | 551 | snd_soc_unregister_component(&pdev->dev); |
546 | 552 | ||
547 | if (!IS_ERR(priv->extclk)) { | 553 | if (!IS_ERR(priv->extclk)) |
548 | clk_disable_unprepare(priv->extclk); | 554 | clk_disable_unprepare(priv->extclk); |
549 | clk_put(priv->extclk); | ||
550 | } | ||
551 | clk_disable_unprepare(priv->clk); | 555 | clk_disable_unprepare(priv->clk); |
552 | 556 | ||
553 | return 0; | 557 | return 0; |
554 | } | 558 | } |
555 | 559 | ||
560 | #ifdef CONFIG_OF | ||
561 | static struct of_device_id mvebu_audio_of_match[] = { | ||
562 | { .compatible = "marvell,mvebu-audio" }, | ||
563 | { } | ||
564 | }; | ||
565 | MODULE_DEVICE_TABLE(of, mvebu_audio_of_match); | ||
566 | #endif | ||
567 | |||
556 | static struct platform_driver kirkwood_i2s_driver = { | 568 | static struct platform_driver kirkwood_i2s_driver = { |
557 | .probe = kirkwood_i2s_dev_probe, | 569 | .probe = kirkwood_i2s_dev_probe, |
558 | .remove = kirkwood_i2s_dev_remove, | 570 | .remove = kirkwood_i2s_dev_remove, |
559 | .driver = { | 571 | .driver = { |
560 | .name = DRV_NAME, | 572 | .name = DRV_NAME, |
561 | .owner = THIS_MODULE, | 573 | .owner = THIS_MODULE, |
574 | .of_match_table = of_match_ptr(mvebu_audio_of_match), | ||
562 | }, | 575 | }, |
563 | }; | 576 | }; |
564 | 577 | ||
@@ -568,4 +581,4 @@ module_platform_driver(kirkwood_i2s_driver); | |||
568 | MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>"); | 581 | MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>"); |
569 | MODULE_DESCRIPTION("Kirkwood I2S SoC Interface"); | 582 | MODULE_DESCRIPTION("Kirkwood I2S SoC Interface"); |
570 | MODULE_LICENSE("GPL"); | 583 | MODULE_LICENSE("GPL"); |
571 | MODULE_ALIAS("platform:kirkwood-i2s"); | 584 | 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..4bb273786ff3 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 | } |
@@ -91,11 +105,13 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = { | |||
91 | .stream_name = "HiFi Playback", | 105 | .stream_name = "HiFi Playback", |
92 | .codec_dai_name = "sgtl5000", | 106 | .codec_dai_name = "sgtl5000", |
93 | .ops = &mxs_sgtl5000_hifi_ops, | 107 | .ops = &mxs_sgtl5000_hifi_ops, |
108 | .playback_only = true, | ||
94 | }, { | 109 | }, { |
95 | .name = "HiFi Rx", | 110 | .name = "HiFi Rx", |
96 | .stream_name = "HiFi Capture", | 111 | .stream_name = "HiFi Capture", |
97 | .codec_dai_name = "sgtl5000", | 112 | .codec_dai_name = "sgtl5000", |
98 | .ops = &mxs_sgtl5000_hifi_ops, | 113 | .ops = &mxs_sgtl5000_hifi_ops, |
114 | .capture_only = true, | ||
99 | }, | 115 | }, |
100 | }; | 116 | }; |
101 | 117 | ||
@@ -154,8 +170,10 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) | |||
154 | * should be >= 8MHz and <= 27M. | 170 | * should be >= 8MHz and <= 27M. |
155 | */ | 171 | */ |
156 | ret = mxs_saif_get_mclk(0, 44100 * 256, 44100); | 172 | ret = mxs_saif_get_mclk(0, 44100 * 256, 44100); |
157 | if (ret) | 173 | if (ret) { |
174 | dev_err(&pdev->dev, "failed to get mclk\n"); | ||
158 | return ret; | 175 | return ret; |
176 | } | ||
159 | 177 | ||
160 | card->dev = &pdev->dev; | 178 | card->dev = &pdev->dev; |
161 | platform_set_drvdata(pdev, card); | 179 | 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/mcbsp.c b/sound/soc/omap/mcbsp.c index 361e4c03646e..83433fdea32a 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c | |||
@@ -781,7 +781,7 @@ static ssize_t prop##_store(struct device *dev, \ | |||
781 | unsigned long val; \ | 781 | unsigned long val; \ |
782 | int status; \ | 782 | int status; \ |
783 | \ | 783 | \ |
784 | status = strict_strtoul(buf, 0, &val); \ | 784 | status = kstrtoul(buf, 0, &val); \ |
785 | if (status) \ | 785 | if (status) \ |
786 | return status; \ | 786 | return status; \ |
787 | \ | 787 | \ |
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..9338d11e9216 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c | |||
@@ -90,6 +90,13 @@ static void dma_enqueue(struct snd_pcm_substream *substream) | |||
90 | dma_info.period = prtd->dma_period; | 90 | dma_info.period = prtd->dma_period; |
91 | dma_info.len = prtd->dma_period*limit; | 91 | dma_info.len = prtd->dma_period*limit; |
92 | 92 | ||
93 | if (dma_info.cap == DMA_CYCLIC) { | ||
94 | dma_info.buf = pos; | ||
95 | prtd->params->ops->prepare(prtd->params->ch, &dma_info); | ||
96 | prtd->dma_loaded += limit; | ||
97 | return; | ||
98 | } | ||
99 | |||
93 | while (prtd->dma_loaded < limit) { | 100 | while (prtd->dma_loaded < limit) { |
94 | pr_debug("dma_loaded: %d\n", prtd->dma_loaded); | 101 | pr_debug("dma_loaded: %d\n", prtd->dma_loaded); |
95 | 102 | ||
@@ -176,6 +183,10 @@ static int dma_hw_params(struct snd_pcm_substream *substream, | |||
176 | prtd->params->ch = prtd->params->ops->request( | 183 | prtd->params->ch = prtd->params->ops->request( |
177 | prtd->params->channel, &req, rtd->cpu_dai->dev, | 184 | prtd->params->channel, &req, rtd->cpu_dai->dev, |
178 | prtd->params->ch_name); | 185 | prtd->params->ch_name); |
186 | if (!prtd->params->ch) { | ||
187 | pr_err("Failed to allocate DMA channel\n"); | ||
188 | return -ENXIO; | ||
189 | } | ||
179 | prtd->params->ops->config(prtd->params->ch, &config); | 190 | prtd->params->ops->config(prtd->params->ch, &config); |
180 | } | 191 | } |
181 | 192 | ||
@@ -433,17 +444,17 @@ static struct snd_soc_platform_driver samsung_asoc_platform = { | |||
433 | .pcm_free = dma_free_dma_buffers, | 444 | .pcm_free = dma_free_dma_buffers, |
434 | }; | 445 | }; |
435 | 446 | ||
436 | int asoc_dma_platform_register(struct device *dev) | 447 | int samsung_asoc_dma_platform_register(struct device *dev) |
437 | { | 448 | { |
438 | return snd_soc_register_platform(dev, &samsung_asoc_platform); | 449 | return snd_soc_register_platform(dev, &samsung_asoc_platform); |
439 | } | 450 | } |
440 | EXPORT_SYMBOL_GPL(asoc_dma_platform_register); | 451 | EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register); |
441 | 452 | ||
442 | void asoc_dma_platform_unregister(struct device *dev) | 453 | void samsung_asoc_dma_platform_unregister(struct device *dev) |
443 | { | 454 | { |
444 | snd_soc_unregister_platform(dev); | 455 | snd_soc_unregister_platform(dev); |
445 | } | 456 | } |
446 | EXPORT_SYMBOL_GPL(asoc_dma_platform_unregister); | 457 | EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister); |
447 | 458 | ||
448 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | 459 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); |
449 | MODULE_DESCRIPTION("Samsung ASoC DMA Driver"); | 460 | 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/fsi.c b/sound/soc/sh/fsi.c index 30390260bb67..b33ca7cd085b 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -235,6 +235,8 @@ struct fsi_stream { | |||
235 | struct sh_dmae_slave slave; /* see fsi_handler_init() */ | 235 | struct sh_dmae_slave slave; /* see fsi_handler_init() */ |
236 | struct work_struct work; | 236 | struct work_struct work; |
237 | dma_addr_t dma; | 237 | dma_addr_t dma; |
238 | int loop_cnt; | ||
239 | int additional_pos; | ||
238 | }; | 240 | }; |
239 | 241 | ||
240 | struct fsi_clk { | 242 | struct fsi_clk { |
@@ -1289,6 +1291,8 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) | |||
1289 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | | 1291 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | |
1290 | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); | 1292 | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); |
1291 | 1293 | ||
1294 | io->loop_cnt = 2; /* push 1st, 2nd period first, then 3rd, 4th... */ | ||
1295 | io->additional_pos = 0; | ||
1292 | io->dma = dma_map_single(dai->dev, runtime->dma_area, | 1296 | io->dma = dma_map_single(dai->dev, runtime->dma_area, |
1293 | snd_pcm_lib_buffer_bytes(io->substream), dir); | 1297 | snd_pcm_lib_buffer_bytes(io->substream), dir); |
1294 | return 0; | 1298 | return 0; |
@@ -1305,11 +1309,15 @@ static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io) | |||
1305 | return 0; | 1309 | return 0; |
1306 | } | 1310 | } |
1307 | 1311 | ||
1308 | static dma_addr_t fsi_dma_get_area(struct fsi_stream *io) | 1312 | static dma_addr_t fsi_dma_get_area(struct fsi_stream *io, int additional) |
1309 | { | 1313 | { |
1310 | struct snd_pcm_runtime *runtime = io->substream->runtime; | 1314 | struct snd_pcm_runtime *runtime = io->substream->runtime; |
1315 | int period = io->period_pos + additional; | ||
1311 | 1316 | ||
1312 | return io->dma + samples_to_bytes(runtime, io->buff_sample_pos); | 1317 | if (period >= runtime->periods) |
1318 | period = 0; | ||
1319 | |||
1320 | return io->dma + samples_to_bytes(runtime, period * io->period_samples); | ||
1313 | } | 1321 | } |
1314 | 1322 | ||
1315 | static void fsi_dma_complete(void *data) | 1323 | static void fsi_dma_complete(void *data) |
@@ -1321,7 +1329,7 @@ static void fsi_dma_complete(void *data) | |||
1321 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? | 1329 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? |
1322 | DMA_TO_DEVICE : DMA_FROM_DEVICE; | 1330 | DMA_TO_DEVICE : DMA_FROM_DEVICE; |
1323 | 1331 | ||
1324 | dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io), | 1332 | dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io, 0), |
1325 | samples_to_bytes(runtime, io->period_samples), dir); | 1333 | samples_to_bytes(runtime, io->period_samples), dir); |
1326 | 1334 | ||
1327 | io->buff_sample_pos += io->period_samples; | 1335 | io->buff_sample_pos += io->period_samples; |
@@ -1347,7 +1355,7 @@ static void fsi_dma_do_work(struct work_struct *work) | |||
1347 | struct snd_pcm_runtime *runtime; | 1355 | struct snd_pcm_runtime *runtime; |
1348 | enum dma_data_direction dir; | 1356 | enum dma_data_direction dir; |
1349 | int is_play = fsi_stream_is_play(fsi, io); | 1357 | int is_play = fsi_stream_is_play(fsi, io); |
1350 | int len; | 1358 | int len, i; |
1351 | dma_addr_t buf; | 1359 | dma_addr_t buf; |
1352 | 1360 | ||
1353 | if (!fsi_stream_is_working(fsi, io)) | 1361 | if (!fsi_stream_is_working(fsi, io)) |
@@ -1357,26 +1365,33 @@ static void fsi_dma_do_work(struct work_struct *work) | |||
1357 | runtime = io->substream->runtime; | 1365 | runtime = io->substream->runtime; |
1358 | dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 1366 | dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |
1359 | len = samples_to_bytes(runtime, io->period_samples); | 1367 | len = samples_to_bytes(runtime, io->period_samples); |
1360 | buf = fsi_dma_get_area(io); | ||
1361 | 1368 | ||
1362 | dma_sync_single_for_device(dai->dev, buf, len, dir); | 1369 | for (i = 0; i < io->loop_cnt; i++) { |
1370 | buf = fsi_dma_get_area(io, io->additional_pos); | ||
1363 | 1371 | ||
1364 | desc = dmaengine_prep_slave_single(io->chan, buf, len, dir, | 1372 | dma_sync_single_for_device(dai->dev, buf, len, dir); |
1365 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
1366 | if (!desc) { | ||
1367 | dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); | ||
1368 | return; | ||
1369 | } | ||
1370 | 1373 | ||
1371 | desc->callback = fsi_dma_complete; | 1374 | desc = dmaengine_prep_slave_single(io->chan, buf, len, dir, |
1372 | desc->callback_param = io; | 1375 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
1376 | if (!desc) { | ||
1377 | dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); | ||
1378 | return; | ||
1379 | } | ||
1373 | 1380 | ||
1374 | if (dmaengine_submit(desc) < 0) { | 1381 | desc->callback = fsi_dma_complete; |
1375 | dev_err(dai->dev, "tx_submit() fail\n"); | 1382 | desc->callback_param = io; |
1376 | return; | 1383 | |
1384 | if (dmaengine_submit(desc) < 0) { | ||
1385 | dev_err(dai->dev, "tx_submit() fail\n"); | ||
1386 | return; | ||
1387 | } | ||
1388 | |||
1389 | dma_async_issue_pending(io->chan); | ||
1390 | |||
1391 | io->additional_pos = 1; | ||
1377 | } | 1392 | } |
1378 | 1393 | ||
1379 | dma_async_issue_pending(io->chan); | 1394 | io->loop_cnt = 1; |
1380 | 1395 | ||
1381 | /* | 1396 | /* |
1382 | * FIXME | 1397 | * FIXME |
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..4d0561312f3b 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) |
@@ -192,7 +203,7 @@ static ssize_t pmdown_time_set(struct device *dev, | |||
192 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); | 203 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); |
193 | int ret; | 204 | int ret; |
194 | 205 | ||
195 | ret = strict_strtol(buf, 10, &rtd->pmdown_time); | 206 | ret = kstrtol(buf, 10, &rtd->pmdown_time); |
196 | if (ret) | 207 | if (ret) |
197 | return ret; | 208 | return ret; |
198 | 209 | ||
@@ -237,6 +248,7 @@ static ssize_t codec_reg_write_file(struct file *file, | |||
237 | char *start = buf; | 248 | char *start = buf; |
238 | unsigned long reg, value; | 249 | unsigned long reg, value; |
239 | struct snd_soc_codec *codec = file->private_data; | 250 | struct snd_soc_codec *codec = file->private_data; |
251 | int ret; | ||
240 | 252 | ||
241 | buf_size = min(count, (sizeof(buf)-1)); | 253 | buf_size = min(count, (sizeof(buf)-1)); |
242 | if (copy_from_user(buf, user_buf, buf_size)) | 254 | if (copy_from_user(buf, user_buf, buf_size)) |
@@ -248,8 +260,9 @@ static ssize_t codec_reg_write_file(struct file *file, | |||
248 | reg = simple_strtoul(start, &start, 16); | 260 | reg = simple_strtoul(start, &start, 16); |
249 | while (*start == ' ') | 261 | while (*start == ' ') |
250 | start++; | 262 | start++; |
251 | if (strict_strtoul(start, 16, &value)) | 263 | ret = kstrtoul(start, 16, &value); |
252 | return -EINVAL; | 264 | if (ret) |
265 | return ret; | ||
253 | 266 | ||
254 | /* Userspace has been fiddling around behind the kernel's back */ | 267 | /* Userspace has been fiddling around behind the kernel's back */ |
255 | add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE); | 268 | add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE); |
@@ -530,6 +543,15 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) | |||
530 | } | 543 | } |
531 | #endif | 544 | #endif |
532 | 545 | ||
546 | static void codec2codec_close_delayed_work(struct work_struct *work) | ||
547 | { | ||
548 | /* Currently nothing to do for c2c links | ||
549 | * Since c2c links are internal nodes in the DAPM graph and | ||
550 | * don't interface with the outside world or application layer | ||
551 | * we don't have to do any special handling on close. | ||
552 | */ | ||
553 | } | ||
554 | |||
533 | #ifdef CONFIG_PM_SLEEP | 555 | #ifdef CONFIG_PM_SLEEP |
534 | /* powers down audio subsystem for suspend */ | 556 | /* powers down audio subsystem for suspend */ |
535 | int snd_soc_suspend(struct device *dev) | 557 | int snd_soc_suspend(struct device *dev) |
@@ -1223,9 +1245,6 @@ static int soc_post_component_init(struct snd_soc_card *card, | |||
1223 | } | 1245 | } |
1224 | rtd->card = card; | 1246 | rtd->card = card; |
1225 | 1247 | ||
1226 | /* Make sure all DAPM widgets are instantiated */ | ||
1227 | snd_soc_dapm_new_widgets(&codec->dapm); | ||
1228 | |||
1229 | /* machine controls, routes and widgets are not prefixed */ | 1248 | /* machine controls, routes and widgets are not prefixed */ |
1230 | temp = codec->name_prefix; | 1249 | temp = codec->name_prefix; |
1231 | codec->name_prefix = NULL; | 1250 | codec->name_prefix = NULL; |
@@ -1428,6 +1447,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1428 | return ret; | 1447 | return ret; |
1429 | } | 1448 | } |
1430 | } else { | 1449 | } else { |
1450 | INIT_DELAYED_WORK(&rtd->delayed_work, | ||
1451 | codec2codec_close_delayed_work); | ||
1452 | |||
1431 | /* link the DAI widgets */ | 1453 | /* link the DAI widgets */ |
1432 | play_w = codec_dai->playback_widget; | 1454 | play_w = codec_dai->playback_widget; |
1433 | capture_w = cpu_dai->capture_widget; | 1455 | capture_w = cpu_dai->capture_widget; |
@@ -1718,8 +1740,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1718 | snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, | 1740 | snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, |
1719 | card->num_dapm_routes); | 1741 | card->num_dapm_routes); |
1720 | 1742 | ||
1721 | snd_soc_dapm_new_widgets(&card->dapm); | ||
1722 | |||
1723 | for (i = 0; i < card->num_links; i++) { | 1743 | for (i = 0; i < card->num_links; i++) { |
1724 | dai_link = &card->dai_link[i]; | 1744 | dai_link = &card->dai_link[i]; |
1725 | dai_fmt = dai_link->dai_fmt; | 1745 | dai_fmt = dai_link->dai_fmt; |
@@ -1798,12 +1818,12 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1798 | } | 1818 | } |
1799 | } | 1819 | } |
1800 | 1820 | ||
1801 | snd_soc_dapm_new_widgets(&card->dapm); | ||
1802 | |||
1803 | if (card->fully_routed) | 1821 | if (card->fully_routed) |
1804 | list_for_each_entry(codec, &card->codec_dev_list, card_list) | 1822 | list_for_each_entry(codec, &card->codec_dev_list, card_list) |
1805 | snd_soc_dapm_auto_nc_codec_pins(codec); | 1823 | snd_soc_dapm_auto_nc_codec_pins(codec); |
1806 | 1824 | ||
1825 | snd_soc_dapm_new_widgets(card); | ||
1826 | |||
1807 | ret = snd_card_register(card->snd_card); | 1827 | ret = snd_card_register(card->snd_card); |
1808 | if (ret < 0) { | 1828 | if (ret < 0) { |
1809 | dev_err(card->dev, "ASoC: failed to register soundcard %d\n", | 1829 | dev_err(card->dev, "ASoC: failed to register soundcard %d\n", |
@@ -2080,6 +2100,117 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | |||
2080 | } | 2100 | } |
2081 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | 2101 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); |
2082 | 2102 | ||
2103 | static struct snd_ac97_reset_cfg snd_ac97_rst_cfg; | ||
2104 | |||
2105 | static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97) | ||
2106 | { | ||
2107 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
2108 | |||
2109 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset); | ||
2110 | |||
2111 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1); | ||
2112 | |||
2113 | udelay(10); | ||
2114 | |||
2115 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
2116 | |||
2117 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
2118 | msleep(2); | ||
2119 | } | ||
2120 | |||
2121 | static void snd_soc_ac97_reset(struct snd_ac97 *ac97) | ||
2122 | { | ||
2123 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
2124 | |||
2125 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset); | ||
2126 | |||
2127 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
2128 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0); | ||
2129 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0); | ||
2130 | |||
2131 | udelay(10); | ||
2132 | |||
2133 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1); | ||
2134 | |||
2135 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
2136 | msleep(2); | ||
2137 | } | ||
2138 | |||
2139 | static int snd_soc_ac97_parse_pinctl(struct device *dev, | ||
2140 | struct snd_ac97_reset_cfg *cfg) | ||
2141 | { | ||
2142 | struct pinctrl *p; | ||
2143 | struct pinctrl_state *state; | ||
2144 | int gpio; | ||
2145 | int ret; | ||
2146 | |||
2147 | p = devm_pinctrl_get(dev); | ||
2148 | if (IS_ERR(p)) { | ||
2149 | dev_err(dev, "Failed to get pinctrl\n"); | ||
2150 | return PTR_RET(p); | ||
2151 | } | ||
2152 | cfg->pctl = p; | ||
2153 | |||
2154 | state = pinctrl_lookup_state(p, "ac97-reset"); | ||
2155 | if (IS_ERR(state)) { | ||
2156 | dev_err(dev, "Can't find pinctrl state ac97-reset\n"); | ||
2157 | return PTR_RET(state); | ||
2158 | } | ||
2159 | cfg->pstate_reset = state; | ||
2160 | |||
2161 | state = pinctrl_lookup_state(p, "ac97-warm-reset"); | ||
2162 | if (IS_ERR(state)) { | ||
2163 | dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); | ||
2164 | return PTR_RET(state); | ||
2165 | } | ||
2166 | cfg->pstate_warm_reset = state; | ||
2167 | |||
2168 | state = pinctrl_lookup_state(p, "ac97-running"); | ||
2169 | if (IS_ERR(state)) { | ||
2170 | dev_err(dev, "Can't find pinctrl state ac97-running\n"); | ||
2171 | return PTR_RET(state); | ||
2172 | } | ||
2173 | cfg->pstate_run = state; | ||
2174 | |||
2175 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0); | ||
2176 | if (gpio < 0) { | ||
2177 | dev_err(dev, "Can't find ac97-sync gpio\n"); | ||
2178 | return gpio; | ||
2179 | } | ||
2180 | ret = devm_gpio_request(dev, gpio, "AC97 link sync"); | ||
2181 | if (ret) { | ||
2182 | dev_err(dev, "Failed requesting ac97-sync gpio\n"); | ||
2183 | return ret; | ||
2184 | } | ||
2185 | cfg->gpio_sync = gpio; | ||
2186 | |||
2187 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1); | ||
2188 | if (gpio < 0) { | ||
2189 | dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio); | ||
2190 | return gpio; | ||
2191 | } | ||
2192 | ret = devm_gpio_request(dev, gpio, "AC97 link sdata"); | ||
2193 | if (ret) { | ||
2194 | dev_err(dev, "Failed requesting ac97-sdata gpio\n"); | ||
2195 | return ret; | ||
2196 | } | ||
2197 | cfg->gpio_sdata = gpio; | ||
2198 | |||
2199 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); | ||
2200 | if (gpio < 0) { | ||
2201 | dev_err(dev, "Can't find ac97-reset gpio\n"); | ||
2202 | return gpio; | ||
2203 | } | ||
2204 | ret = devm_gpio_request(dev, gpio, "AC97 link reset"); | ||
2205 | if (ret) { | ||
2206 | dev_err(dev, "Failed requesting ac97-reset gpio\n"); | ||
2207 | return ret; | ||
2208 | } | ||
2209 | cfg->gpio_reset = gpio; | ||
2210 | |||
2211 | return 0; | ||
2212 | } | ||
2213 | |||
2083 | struct snd_ac97_bus_ops *soc_ac97_ops; | 2214 | struct snd_ac97_bus_ops *soc_ac97_ops; |
2084 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | 2215 | EXPORT_SYMBOL_GPL(soc_ac97_ops); |
2085 | 2216 | ||
@@ -2098,6 +2229,35 @@ int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) | |||
2098 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); | 2229 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); |
2099 | 2230 | ||
2100 | /** | 2231 | /** |
2232 | * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions | ||
2233 | * | ||
2234 | * This function sets the reset and warm_reset properties of ops and parses | ||
2235 | * the device node of pdev to get pinctrl states and gpio numbers to use. | ||
2236 | */ | ||
2237 | int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, | ||
2238 | struct platform_device *pdev) | ||
2239 | { | ||
2240 | struct device *dev = &pdev->dev; | ||
2241 | struct snd_ac97_reset_cfg cfg; | ||
2242 | int ret; | ||
2243 | |||
2244 | ret = snd_soc_ac97_parse_pinctl(dev, &cfg); | ||
2245 | if (ret) | ||
2246 | return ret; | ||
2247 | |||
2248 | ret = snd_soc_set_ac97_ops(ops); | ||
2249 | if (ret) | ||
2250 | return ret; | ||
2251 | |||
2252 | ops->warm_reset = snd_soc_ac97_warm_reset; | ||
2253 | ops->reset = snd_soc_ac97_reset; | ||
2254 | |||
2255 | snd_ac97_rst_cfg = cfg; | ||
2256 | return 0; | ||
2257 | } | ||
2258 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); | ||
2259 | |||
2260 | /** | ||
2101 | * snd_soc_free_ac97_codec - free AC97 codec device | 2261 | * snd_soc_free_ac97_codec - free AC97 codec device |
2102 | * @codec: audio codec | 2262 | * @codec: audio codec |
2103 | * | 2263 | * |
@@ -2299,6 +2459,22 @@ static int snd_soc_add_controls(struct snd_card *card, struct device *dev, | |||
2299 | return 0; | 2459 | return 0; |
2300 | } | 2460 | } |
2301 | 2461 | ||
2462 | struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, | ||
2463 | const char *name) | ||
2464 | { | ||
2465 | struct snd_card *card = soc_card->snd_card; | ||
2466 | struct snd_kcontrol *kctl; | ||
2467 | |||
2468 | if (unlikely(!name)) | ||
2469 | return NULL; | ||
2470 | |||
2471 | list_for_each_entry(kctl, &card->controls, list) | ||
2472 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) | ||
2473 | return kctl; | ||
2474 | return NULL; | ||
2475 | } | ||
2476 | EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); | ||
2477 | |||
2302 | /** | 2478 | /** |
2303 | * snd_soc_add_codec_controls - add an array of controls to a codec. | 2479 | * 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 | 2480 | * Convenience function to add a list of controls. Many codecs were |
@@ -2541,59 +2717,6 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2541 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); | 2717 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); |
2542 | 2718 | ||
2543 | /** | 2719 | /** |
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 | 2720 | * snd_soc_info_volsw - single mixer info callback |
2598 | * @kcontrol: mixer control | 2721 | * @kcontrol: mixer control |
2599 | * @uinfo: control element information | 2722 | * @uinfo: control element information |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4375c9f2b791..c17c14c394df 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,35 +185,177 @@ 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->value = template.on_val; | ||
233 | |||
234 | data->widget = snd_soc_dapm_new_control(widget->dapm, | ||
235 | &template); | ||
236 | if (!data->widget) { | ||
237 | kfree(data); | ||
238 | return -ENOMEM; | ||
239 | } | ||
240 | } | ||
241 | break; | ||
242 | default: | ||
243 | break; | ||
244 | } | ||
245 | |||
246 | kcontrol->private_data = data; | ||
247 | |||
248 | return 0; | ||
190 | } | 249 | } |
191 | 250 | ||
192 | /* get soc_card from DAPM context */ | 251 | 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 | { | 252 | { |
196 | if (dapm->codec) | 253 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl); |
197 | return dapm->codec->card; | 254 | kfree(data->widget); |
198 | else if (dapm->platform) | 255 | kfree(data->wlist); |
199 | return dapm->platform->card; | 256 | kfree(data); |
257 | } | ||
258 | |||
259 | static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist( | ||
260 | const struct snd_kcontrol *kcontrol) | ||
261 | { | ||
262 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
263 | |||
264 | return data->wlist; | ||
265 | } | ||
266 | |||
267 | static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol, | ||
268 | struct snd_soc_dapm_widget *widget) | ||
269 | { | ||
270 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
271 | struct snd_soc_dapm_widget_list *new_wlist; | ||
272 | unsigned int n; | ||
273 | |||
274 | if (data->wlist) | ||
275 | n = data->wlist->num_widgets + 1; | ||
200 | else | 276 | else |
201 | BUG(); | 277 | n = 1; |
202 | 278 | ||
203 | /* unreachable */ | 279 | new_wlist = krealloc(data->wlist, |
204 | return NULL; | 280 | sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL); |
281 | if (!new_wlist) | ||
282 | return -ENOMEM; | ||
283 | |||
284 | new_wlist->widgets[n - 1] = widget; | ||
285 | new_wlist->num_widgets = n; | ||
286 | |||
287 | data->wlist = new_wlist; | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol, | ||
293 | struct snd_soc_dapm_path *path) | ||
294 | { | ||
295 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
296 | |||
297 | list_add_tail(&path->list_kcontrol, &data->paths); | ||
298 | |||
299 | if (data->widget) { | ||
300 | snd_soc_dapm_add_path(data->widget->dapm, data->widget, | ||
301 | path->source, NULL, NULL); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol) | ||
306 | { | ||
307 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
308 | |||
309 | if (!data->widget) | ||
310 | return true; | ||
311 | |||
312 | return data->widget->power; | ||
313 | } | ||
314 | |||
315 | static struct list_head *dapm_kcontrol_get_path_list( | ||
316 | const struct snd_kcontrol *kcontrol) | ||
317 | { | ||
318 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
319 | |||
320 | return &data->paths; | ||
321 | } | ||
322 | |||
323 | #define dapm_kcontrol_for_each_path(path, kcontrol) \ | ||
324 | list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \ | ||
325 | list_kcontrol) | ||
326 | |||
327 | static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) | ||
328 | { | ||
329 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
330 | |||
331 | return data->value; | ||
332 | } | ||
333 | |||
334 | static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, | ||
335 | unsigned int value) | ||
336 | { | ||
337 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
338 | |||
339 | if (data->value == value) | ||
340 | return false; | ||
341 | |||
342 | if (data->widget) | ||
343 | data->widget->on_val = value; | ||
344 | |||
345 | data->value = value; | ||
346 | |||
347 | return true; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol | ||
352 | * @kcontrol: The kcontrol | ||
353 | */ | ||
354 | struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol) | ||
355 | { | ||
356 | return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec; | ||
205 | } | 357 | } |
358 | EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec); | ||
206 | 359 | ||
207 | static void dapm_reset(struct snd_soc_card *card) | 360 | static void dapm_reset(struct snd_soc_card *card) |
208 | { | 361 | { |
@@ -211,6 +364,7 @@ static void dapm_reset(struct snd_soc_card *card) | |||
211 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); | 364 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); |
212 | 365 | ||
213 | list_for_each_entry(w, &card->widgets, list) { | 366 | list_for_each_entry(w, &card->widgets, list) { |
367 | w->new_power = w->power; | ||
214 | w->power_checked = false; | 368 | w->power_checked = false; |
215 | w->inputs = -1; | 369 | w->inputs = -1; |
216 | w->outputs = -1; | 370 | w->outputs = -1; |
@@ -428,6 +582,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
428 | case snd_soc_dapm_spk: | 582 | case snd_soc_dapm_spk: |
429 | case snd_soc_dapm_line: | 583 | case snd_soc_dapm_line: |
430 | case snd_soc_dapm_dai_link: | 584 | case snd_soc_dapm_dai_link: |
585 | case snd_soc_dapm_kcontrol: | ||
431 | p->connect = 1; | 586 | p->connect = 1; |
432 | break; | 587 | break; |
433 | /* does affect routing - dynamically connected */ | 588 | /* does affect routing - dynamically connected */ |
@@ -507,17 +662,12 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, | |||
507 | return 0; | 662 | return 0; |
508 | } | 663 | } |
509 | 664 | ||
510 | static void dapm_kcontrol_free(struct snd_kcontrol *kctl) | ||
511 | { | ||
512 | kfree(kctl->private_data); | ||
513 | } | ||
514 | |||
515 | /* | 665 | /* |
516 | * Determine if a kcontrol is shared. If it is, look it up. If it isn't, | 666 | * 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 | 667 | * create it. Either way, add the widget into the control's widget list |
518 | */ | 668 | */ |
519 | static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | 669 | static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, |
520 | int kci, struct snd_soc_dapm_path *path) | 670 | int kci) |
521 | { | 671 | { |
522 | struct snd_soc_dapm_context *dapm = w->dapm; | 672 | struct snd_soc_dapm_context *dapm = w->dapm; |
523 | struct snd_card *card = dapm->card->snd_card; | 673 | struct snd_card *card = dapm->card->snd_card; |
@@ -525,9 +675,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
525 | size_t prefix_len; | 675 | size_t prefix_len; |
526 | int shared; | 676 | int shared; |
527 | struct snd_kcontrol *kcontrol; | 677 | 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; | 678 | bool wname_in_long_name, kcname_in_long_name; |
532 | char *long_name; | 679 | char *long_name; |
533 | const char *name; | 680 | const char *name; |
@@ -546,25 +693,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], | 693 | shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci], |
547 | &kcontrol); | 694 | &kcontrol); |
548 | 695 | ||
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) { | 696 | if (!kcontrol) { |
569 | if (shared) { | 697 | if (shared) { |
570 | wname_in_long_name = false; | 698 | wname_in_long_name = false; |
@@ -587,7 +715,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
587 | kcname_in_long_name = false; | 715 | kcname_in_long_name = false; |
588 | break; | 716 | break; |
589 | default: | 717 | default: |
590 | kfree(wlist); | ||
591 | return -EINVAL; | 718 | return -EINVAL; |
592 | } | 719 | } |
593 | } | 720 | } |
@@ -602,10 +729,8 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
602 | long_name = kasprintf(GFP_KERNEL, "%s %s", | 729 | long_name = kasprintf(GFP_KERNEL, "%s %s", |
603 | w->name + prefix_len, | 730 | w->name + prefix_len, |
604 | w->kcontrol_news[kci].name); | 731 | w->kcontrol_news[kci].name); |
605 | if (long_name == NULL) { | 732 | if (long_name == NULL) |
606 | kfree(wlist); | ||
607 | return -ENOMEM; | 733 | return -ENOMEM; |
608 | } | ||
609 | 734 | ||
610 | name = long_name; | 735 | name = long_name; |
611 | } else if (wname_in_long_name) { | 736 | } else if (wname_in_long_name) { |
@@ -616,23 +741,33 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
616 | name = w->kcontrol_news[kci].name; | 741 | name = w->kcontrol_news[kci].name; |
617 | } | 742 | } |
618 | 743 | ||
619 | kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name, | 744 | kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name, |
620 | prefix); | 745 | prefix); |
621 | kcontrol->private_free = dapm_kcontrol_free; | ||
622 | kfree(long_name); | 746 | kfree(long_name); |
747 | if (!kcontrol) | ||
748 | return -ENOMEM; | ||
749 | kcontrol->private_free = dapm_kcontrol_free; | ||
750 | |||
751 | ret = dapm_kcontrol_data_alloc(w, kcontrol); | ||
752 | if (ret) { | ||
753 | snd_ctl_free_one(kcontrol); | ||
754 | return ret; | ||
755 | } | ||
756 | |||
623 | ret = snd_ctl_add(card, kcontrol); | 757 | ret = snd_ctl_add(card, kcontrol); |
624 | if (ret < 0) { | 758 | if (ret < 0) { |
625 | dev_err(dapm->dev, | 759 | dev_err(dapm->dev, |
626 | "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", | 760 | "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", |
627 | w->name, name, ret); | 761 | w->name, name, ret); |
628 | kfree(wlist); | ||
629 | return ret; | 762 | return ret; |
630 | } | 763 | } |
631 | } | 764 | } |
632 | 765 | ||
633 | kcontrol->private_data = wlist; | 766 | ret = dapm_kcontrol_add_widget(kcontrol, w); |
767 | if (ret) | ||
768 | return ret; | ||
769 | |||
634 | w->kcontrols[kci] = kcontrol; | 770 | w->kcontrols[kci] = kcontrol; |
635 | path->kcontrol = kcontrol; | ||
636 | 771 | ||
637 | return 0; | 772 | return 0; |
638 | } | 773 | } |
@@ -652,13 +787,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) | |||
652 | continue; | 787 | continue; |
653 | 788 | ||
654 | if (w->kcontrols[i]) { | 789 | if (w->kcontrols[i]) { |
655 | path->kcontrol = w->kcontrols[i]; | 790 | dapm_kcontrol_add_path(w->kcontrols[i], path); |
656 | continue; | 791 | continue; |
657 | } | 792 | } |
658 | 793 | ||
659 | ret = dapm_create_or_share_mixmux_kcontrol(w, i, path); | 794 | ret = dapm_create_or_share_mixmux_kcontrol(w, i); |
660 | if (ret < 0) | 795 | if (ret < 0) |
661 | return ret; | 796 | return ret; |
797 | |||
798 | dapm_kcontrol_add_path(w->kcontrols[i], path); | ||
662 | } | 799 | } |
663 | } | 800 | } |
664 | 801 | ||
@@ -684,15 +821,12 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
684 | return -EINVAL; | 821 | return -EINVAL; |
685 | } | 822 | } |
686 | 823 | ||
687 | path = list_first_entry(&w->sources, struct snd_soc_dapm_path, | 824 | 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) | 825 | if (ret < 0) |
692 | return ret; | 826 | return ret; |
693 | 827 | ||
694 | list_for_each_entry(path, &w->sources, list_sink) | 828 | list_for_each_entry(path, &w->sources, list_sink) |
695 | path->kcontrol = w->kcontrols[0]; | 829 | dapm_kcontrol_add_path(w->kcontrols[0], path); |
696 | 830 | ||
697 | return 0; | 831 | return 0; |
698 | } | 832 | } |
@@ -813,6 +947,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, | |||
813 | case snd_soc_dapm_supply: | 947 | case snd_soc_dapm_supply: |
814 | case snd_soc_dapm_regulator_supply: | 948 | case snd_soc_dapm_regulator_supply: |
815 | case snd_soc_dapm_clock_supply: | 949 | case snd_soc_dapm_clock_supply: |
950 | case snd_soc_dapm_kcontrol: | ||
816 | return 0; | 951 | return 0; |
817 | default: | 952 | default: |
818 | break; | 953 | break; |
@@ -908,6 +1043,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
908 | case snd_soc_dapm_supply: | 1043 | case snd_soc_dapm_supply: |
909 | case snd_soc_dapm_regulator_supply: | 1044 | case snd_soc_dapm_regulator_supply: |
910 | case snd_soc_dapm_clock_supply: | 1045 | case snd_soc_dapm_clock_supply: |
1046 | case snd_soc_dapm_kcontrol: | ||
911 | return 0; | 1047 | return 0; |
912 | default: | 1048 | default: |
913 | break; | 1049 | break; |
@@ -1062,7 +1198,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1062 | int ret; | 1198 | int ret; |
1063 | 1199 | ||
1064 | if (SND_SOC_DAPM_EVENT_ON(event)) { | 1200 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
1065 | if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { | 1201 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
1066 | ret = regulator_allow_bypass(w->regulator, false); | 1202 | ret = regulator_allow_bypass(w->regulator, false); |
1067 | if (ret != 0) | 1203 | if (ret != 0) |
1068 | dev_warn(w->dapm->dev, | 1204 | dev_warn(w->dapm->dev, |
@@ -1072,7 +1208,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1072 | 1208 | ||
1073 | return regulator_enable(w->regulator); | 1209 | return regulator_enable(w->regulator); |
1074 | } else { | 1210 | } else { |
1075 | if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { | 1211 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
1076 | ret = regulator_allow_bypass(w->regulator, true); | 1212 | ret = regulator_allow_bypass(w->regulator, true); |
1077 | if (ret != 0) | 1213 | if (ret != 0) |
1078 | dev_warn(w->dapm->dev, | 1214 | dev_warn(w->dapm->dev, |
@@ -1244,10 +1380,9 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, | |||
1244 | list_add_tail(&new_widget->power_list, list); | 1380 | list_add_tail(&new_widget->power_list, list); |
1245 | } | 1381 | } |
1246 | 1382 | ||
1247 | static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, | 1383 | static void dapm_seq_check_event(struct snd_soc_card *card, |
1248 | struct snd_soc_dapm_widget *w, int event) | 1384 | struct snd_soc_dapm_widget *w, int event) |
1249 | { | 1385 | { |
1250 | struct snd_soc_card *card = dapm->card; | ||
1251 | const char *ev_name; | 1386 | const char *ev_name; |
1252 | int power, ret; | 1387 | int power, ret; |
1253 | 1388 | ||
@@ -1281,55 +1416,50 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, | |||
1281 | return; | 1416 | return; |
1282 | } | 1417 | } |
1283 | 1418 | ||
1284 | if (w->power != power) | 1419 | if (w->new_power != power) |
1285 | return; | 1420 | return; |
1286 | 1421 | ||
1287 | if (w->event && (w->event_flags & event)) { | 1422 | if (w->event && (w->event_flags & event)) { |
1288 | pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n", | 1423 | pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n", |
1289 | w->name, ev_name); | 1424 | w->name, ev_name); |
1290 | trace_snd_soc_dapm_widget_event_start(w, event); | 1425 | trace_snd_soc_dapm_widget_event_start(w, event); |
1291 | ret = w->event(w, NULL, event); | 1426 | ret = w->event(w, NULL, event); |
1292 | trace_snd_soc_dapm_widget_event_done(w, event); | 1427 | trace_snd_soc_dapm_widget_event_done(w, event); |
1293 | if (ret < 0) | 1428 | if (ret < 0) |
1294 | dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n", | 1429 | dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n", |
1295 | ev_name, w->name, ret); | 1430 | ev_name, w->name, ret); |
1296 | } | 1431 | } |
1297 | } | 1432 | } |
1298 | 1433 | ||
1299 | /* Apply the coalesced changes from a DAPM sequence */ | 1434 | /* Apply the coalesced changes from a DAPM sequence */ |
1300 | static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | 1435 | static void dapm_seq_run_coalesced(struct snd_soc_card *card, |
1301 | struct list_head *pending) | 1436 | struct list_head *pending) |
1302 | { | 1437 | { |
1303 | struct snd_soc_card *card = dapm->card; | ||
1304 | struct snd_soc_dapm_widget *w; | 1438 | struct snd_soc_dapm_widget *w; |
1305 | int reg, power; | 1439 | int reg; |
1306 | unsigned int value = 0; | 1440 | unsigned int value = 0; |
1307 | unsigned int mask = 0; | 1441 | unsigned int mask = 0; |
1308 | unsigned int cur_mask; | ||
1309 | 1442 | ||
1310 | reg = list_first_entry(pending, struct snd_soc_dapm_widget, | 1443 | reg = list_first_entry(pending, struct snd_soc_dapm_widget, |
1311 | power_list)->reg; | 1444 | power_list)->reg; |
1312 | 1445 | ||
1313 | list_for_each_entry(w, pending, power_list) { | 1446 | list_for_each_entry(w, pending, power_list) { |
1314 | cur_mask = 1 << w->shift; | ||
1315 | BUG_ON(reg != w->reg); | 1447 | BUG_ON(reg != w->reg); |
1448 | w->power = w->new_power; | ||
1316 | 1449 | ||
1317 | if (w->invert) | 1450 | mask |= w->mask << w->shift; |
1318 | power = !w->power; | 1451 | if (w->power) |
1452 | value |= w->on_val << w->shift; | ||
1319 | else | 1453 | else |
1320 | power = w->power; | 1454 | value |= w->off_val << w->shift; |
1321 | 1455 | ||
1322 | mask |= cur_mask; | 1456 | 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", | 1457 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", |
1328 | w->name, reg, value, mask); | 1458 | w->name, reg, value, mask); |
1329 | 1459 | ||
1330 | /* Check for events */ | 1460 | /* Check for events */ |
1331 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU); | 1461 | dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU); |
1332 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD); | 1462 | dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD); |
1333 | } | 1463 | } |
1334 | 1464 | ||
1335 | if (reg >= 0) { | 1465 | if (reg >= 0) { |
@@ -1339,7 +1469,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
1339 | w = list_first_entry(pending, struct snd_soc_dapm_widget, | 1469 | w = list_first_entry(pending, struct snd_soc_dapm_widget, |
1340 | power_list); | 1470 | power_list); |
1341 | 1471 | ||
1342 | pop_dbg(dapm->dev, card->pop_time, | 1472 | pop_dbg(w->dapm->dev, card->pop_time, |
1343 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", | 1473 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", |
1344 | value, mask, reg, card->pop_time); | 1474 | value, mask, reg, card->pop_time); |
1345 | pop_wait(card->pop_time); | 1475 | pop_wait(card->pop_time); |
@@ -1347,8 +1477,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
1347 | } | 1477 | } |
1348 | 1478 | ||
1349 | list_for_each_entry(w, pending, power_list) { | 1479 | list_for_each_entry(w, pending, power_list) { |
1350 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU); | 1480 | dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU); |
1351 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD); | 1481 | dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD); |
1352 | } | 1482 | } |
1353 | } | 1483 | } |
1354 | 1484 | ||
@@ -1360,8 +1490,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 | 1490 | * Currently anything that requires more than a single write is not |
1361 | * handled. | 1491 | * handled. |
1362 | */ | 1492 | */ |
1363 | static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | 1493 | static void dapm_seq_run(struct snd_soc_card *card, |
1364 | struct list_head *list, int event, bool power_up) | 1494 | struct list_head *list, int event, bool power_up) |
1365 | { | 1495 | { |
1366 | struct snd_soc_dapm_widget *w, *n; | 1496 | struct snd_soc_dapm_widget *w, *n; |
1367 | LIST_HEAD(pending); | 1497 | LIST_HEAD(pending); |
@@ -1384,7 +1514,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
1384 | if (sort[w->id] != cur_sort || w->reg != cur_reg || | 1514 | if (sort[w->id] != cur_sort || w->reg != cur_reg || |
1385 | w->dapm != cur_dapm || w->subseq != cur_subseq) { | 1515 | w->dapm != cur_dapm || w->subseq != cur_subseq) { |
1386 | if (!list_empty(&pending)) | 1516 | if (!list_empty(&pending)) |
1387 | dapm_seq_run_coalesced(cur_dapm, &pending); | 1517 | dapm_seq_run_coalesced(card, &pending); |
1388 | 1518 | ||
1389 | if (cur_dapm && cur_dapm->seq_notifier) { | 1519 | if (cur_dapm && cur_dapm->seq_notifier) { |
1390 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | 1520 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) |
@@ -1444,7 +1574,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
1444 | } | 1574 | } |
1445 | 1575 | ||
1446 | if (!list_empty(&pending)) | 1576 | if (!list_empty(&pending)) |
1447 | dapm_seq_run_coalesced(cur_dapm, &pending); | 1577 | dapm_seq_run_coalesced(card, &pending); |
1448 | 1578 | ||
1449 | if (cur_dapm && cur_dapm->seq_notifier) { | 1579 | if (cur_dapm && cur_dapm->seq_notifier) { |
1450 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | 1580 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) |
@@ -1454,37 +1584,48 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
1454 | } | 1584 | } |
1455 | } | 1585 | } |
1456 | 1586 | ||
1457 | static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | 1587 | static void dapm_widget_update(struct snd_soc_card *card) |
1458 | { | 1588 | { |
1459 | struct snd_soc_dapm_update *update = dapm->update; | 1589 | struct snd_soc_dapm_update *update = card->update; |
1460 | struct snd_soc_dapm_widget *w; | 1590 | struct snd_soc_dapm_widget_list *wlist; |
1591 | struct snd_soc_dapm_widget *w = NULL; | ||
1592 | unsigned int wi; | ||
1461 | int ret; | 1593 | int ret; |
1462 | 1594 | ||
1463 | if (!update) | 1595 | if (!update || !dapm_kcontrol_is_powered(update->kcontrol)) |
1464 | return; | 1596 | return; |
1465 | 1597 | ||
1466 | w = update->widget; | 1598 | wlist = dapm_kcontrol_get_wlist(update->kcontrol); |
1467 | 1599 | ||
1468 | if (w->event && | 1600 | for (wi = 0; wi < wlist->num_widgets; wi++) { |
1469 | (w->event_flags & SND_SOC_DAPM_PRE_REG)) { | 1601 | w = wlist->widgets[wi]; |
1470 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); | 1602 | |
1471 | if (ret != 0) | 1603 | if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) { |
1472 | dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", | 1604 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); |
1473 | w->name, ret); | 1605 | if (ret != 0) |
1606 | dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", | ||
1607 | w->name, ret); | ||
1608 | } | ||
1474 | } | 1609 | } |
1475 | 1610 | ||
1611 | if (!w) | ||
1612 | return; | ||
1613 | |||
1476 | ret = soc_widget_update_bits_locked(w, update->reg, update->mask, | 1614 | ret = soc_widget_update_bits_locked(w, update->reg, update->mask, |
1477 | update->val); | 1615 | update->val); |
1478 | if (ret < 0) | 1616 | if (ret < 0) |
1479 | dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n", | 1617 | dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", |
1480 | w->name, ret); | 1618 | w->name, ret); |
1481 | 1619 | ||
1482 | if (w->event && | 1620 | for (wi = 0; wi < wlist->num_widgets; wi++) { |
1483 | (w->event_flags & SND_SOC_DAPM_POST_REG)) { | 1621 | w = wlist->widgets[wi]; |
1484 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); | 1622 | |
1485 | if (ret != 0) | 1623 | if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) { |
1486 | dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", | 1624 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); |
1487 | w->name, ret); | 1625 | if (ret != 0) |
1626 | dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", | ||
1627 | w->name, ret); | ||
1628 | } | ||
1488 | } | 1629 | } |
1489 | } | 1630 | } |
1490 | 1631 | ||
@@ -1596,6 +1737,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1596 | case snd_soc_dapm_supply: | 1737 | case snd_soc_dapm_supply: |
1597 | case snd_soc_dapm_regulator_supply: | 1738 | case snd_soc_dapm_regulator_supply: |
1598 | case snd_soc_dapm_clock_supply: | 1739 | case snd_soc_dapm_clock_supply: |
1740 | case snd_soc_dapm_kcontrol: | ||
1599 | /* Supplies can't affect their outputs, only their inputs */ | 1741 | /* Supplies can't affect their outputs, only their inputs */ |
1600 | break; | 1742 | break; |
1601 | default: | 1743 | default: |
@@ -1612,8 +1754,6 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1612 | dapm_seq_insert(w, up_list, true); | 1754 | dapm_seq_insert(w, up_list, true); |
1613 | else | 1755 | else |
1614 | dapm_seq_insert(w, down_list, false); | 1756 | dapm_seq_insert(w, down_list, false); |
1615 | |||
1616 | w->power = power; | ||
1617 | } | 1757 | } |
1618 | 1758 | ||
1619 | static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, | 1759 | static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, |
@@ -1647,9 +1787,8 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, | |||
1647 | * o Input pin to Output pin (bypass, sidetone) | 1787 | * o Input pin to Output pin (bypass, sidetone) |
1648 | * o DAC to ADC (loopback). | 1788 | * o DAC to ADC (loopback). |
1649 | */ | 1789 | */ |
1650 | static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | 1790 | static int dapm_power_widgets(struct snd_soc_card *card, int event) |
1651 | { | 1791 | { |
1652 | struct snd_soc_card *card = dapm->card; | ||
1653 | struct snd_soc_dapm_widget *w; | 1792 | struct snd_soc_dapm_widget *w; |
1654 | struct snd_soc_dapm_context *d; | 1793 | struct snd_soc_dapm_context *d; |
1655 | LIST_HEAD(up_list); | 1794 | LIST_HEAD(up_list); |
@@ -1689,7 +1828,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1689 | break; | 1828 | break; |
1690 | } | 1829 | } |
1691 | 1830 | ||
1692 | if (w->power) { | 1831 | if (w->new_power) { |
1693 | d = w->dapm; | 1832 | d = w->dapm; |
1694 | 1833 | ||
1695 | /* Supplies and micbiases only bring the | 1834 | /* Supplies and micbiases only bring the |
@@ -1731,29 +1870,29 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1731 | trace_snd_soc_dapm_walk_done(card); | 1870 | trace_snd_soc_dapm_walk_done(card); |
1732 | 1871 | ||
1733 | /* Run all the bias changes in parallel */ | 1872 | /* Run all the bias changes in parallel */ |
1734 | list_for_each_entry(d, &dapm->card->dapm_list, list) | 1873 | list_for_each_entry(d, &card->dapm_list, list) |
1735 | async_schedule_domain(dapm_pre_sequence_async, d, | 1874 | async_schedule_domain(dapm_pre_sequence_async, d, |
1736 | &async_domain); | 1875 | &async_domain); |
1737 | async_synchronize_full_domain(&async_domain); | 1876 | async_synchronize_full_domain(&async_domain); |
1738 | 1877 | ||
1739 | list_for_each_entry(w, &down_list, power_list) { | 1878 | list_for_each_entry(w, &down_list, power_list) { |
1740 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD); | 1879 | dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD); |
1741 | } | 1880 | } |
1742 | 1881 | ||
1743 | list_for_each_entry(w, &up_list, power_list) { | 1882 | list_for_each_entry(w, &up_list, power_list) { |
1744 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU); | 1883 | dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU); |
1745 | } | 1884 | } |
1746 | 1885 | ||
1747 | /* Power down widgets first; try to avoid amplifying pops. */ | 1886 | /* Power down widgets first; try to avoid amplifying pops. */ |
1748 | dapm_seq_run(dapm, &down_list, event, false); | 1887 | dapm_seq_run(card, &down_list, event, false); |
1749 | 1888 | ||
1750 | dapm_widget_update(dapm); | 1889 | dapm_widget_update(card); |
1751 | 1890 | ||
1752 | /* Now power up. */ | 1891 | /* Now power up. */ |
1753 | dapm_seq_run(dapm, &up_list, event, true); | 1892 | dapm_seq_run(card, &up_list, event, true); |
1754 | 1893 | ||
1755 | /* Run all the bias changes in parallel */ | 1894 | /* Run all the bias changes in parallel */ |
1756 | list_for_each_entry(d, &dapm->card->dapm_list, list) | 1895 | list_for_each_entry(d, &card->dapm_list, list) |
1757 | async_schedule_domain(dapm_post_sequence_async, d, | 1896 | async_schedule_domain(dapm_post_sequence_async, d, |
1758 | &async_domain); | 1897 | &async_domain); |
1759 | async_synchronize_full_domain(&async_domain); | 1898 | async_synchronize_full_domain(&async_domain); |
@@ -1764,7 +1903,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1764 | d->stream_event(d, event); | 1903 | d->stream_event(d, event); |
1765 | } | 1904 | } |
1766 | 1905 | ||
1767 | pop_dbg(dapm->dev, card->pop_time, | 1906 | pop_dbg(card->dev, card->pop_time, |
1768 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); | 1907 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); |
1769 | pop_wait(card->pop_time); | 1908 | pop_wait(card->pop_time); |
1770 | 1909 | ||
@@ -1799,8 +1938,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1799 | 1938 | ||
1800 | if (w->reg >= 0) | 1939 | if (w->reg >= 0) |
1801 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1940 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1802 | " - R%d(0x%x) bit %d", | 1941 | " - R%d(0x%x) mask 0x%x", |
1803 | w->reg, w->reg, w->shift); | 1942 | w->reg, w->reg, w->mask << w->shift); |
1804 | 1943 | ||
1805 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); | 1944 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); |
1806 | 1945 | ||
@@ -1937,22 +2076,14 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | |||
1937 | #endif | 2076 | #endif |
1938 | 2077 | ||
1939 | /* test and update the power status of a mux widget */ | 2078 | /* test and update the power status of a mux widget */ |
1940 | static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 2079 | static int soc_dapm_mux_update_power(struct snd_soc_card *card, |
1941 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 2080 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) |
1942 | { | 2081 | { |
1943 | struct snd_soc_dapm_path *path; | 2082 | struct snd_soc_dapm_path *path; |
1944 | int found = 0; | 2083 | int found = 0; |
1945 | 2084 | ||
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 */ | 2085 | /* find dapm widget path assoc with kcontrol */ |
1952 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | 2086 | dapm_kcontrol_for_each_path(path, kcontrol) { |
1953 | if (path->kcontrol != kcontrol) | ||
1954 | continue; | ||
1955 | |||
1956 | if (!path->name || !e->texts[mux]) | 2087 | if (!path->name || !e->texts[mux]) |
1957 | continue; | 2088 | continue; |
1958 | 2089 | ||
@@ -1967,73 +2098,68 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1967 | "mux disconnection"); | 2098 | "mux disconnection"); |
1968 | path->connect = 0; /* old connection must be powered down */ | 2099 | path->connect = 0; /* old connection must be powered down */ |
1969 | } | 2100 | } |
2101 | dapm_mark_dirty(path->sink, "mux change"); | ||
1970 | } | 2102 | } |
1971 | 2103 | ||
1972 | if (found) { | 2104 | if (found) |
1973 | dapm_mark_dirty(widget, "mux change"); | 2105 | dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); |
1974 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); | ||
1975 | } | ||
1976 | 2106 | ||
1977 | return found; | 2107 | return found; |
1978 | } | 2108 | } |
1979 | 2109 | ||
1980 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 2110 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm, |
1981 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 2111 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e, |
2112 | struct snd_soc_dapm_update *update) | ||
1982 | { | 2113 | { |
1983 | struct snd_soc_card *card = widget->dapm->card; | 2114 | struct snd_soc_card *card = dapm->card; |
1984 | int ret; | 2115 | int ret; |
1985 | 2116 | ||
1986 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2117 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
1987 | ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 2118 | card->update = update; |
2119 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); | ||
2120 | card->update = NULL; | ||
1988 | mutex_unlock(&card->dapm_mutex); | 2121 | mutex_unlock(&card->dapm_mutex); |
1989 | if (ret > 0) | 2122 | if (ret > 0) |
1990 | soc_dpcm_runtime_update(widget); | 2123 | soc_dpcm_runtime_update(card); |
1991 | return ret; | 2124 | return ret; |
1992 | } | 2125 | } |
1993 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); | 2126 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); |
1994 | 2127 | ||
1995 | /* test and update the power status of a mixer or switch widget */ | 2128 | /* 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, | 2129 | static int soc_dapm_mixer_update_power(struct snd_soc_card *card, |
1997 | struct snd_kcontrol *kcontrol, int connect) | 2130 | struct snd_kcontrol *kcontrol, int connect) |
1998 | { | 2131 | { |
1999 | struct snd_soc_dapm_path *path; | 2132 | struct snd_soc_dapm_path *path; |
2000 | int found = 0; | 2133 | int found = 0; |
2001 | 2134 | ||
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 */ | 2135 | /* find dapm widget path assoc with kcontrol */ |
2008 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | 2136 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2009 | if (path->kcontrol != kcontrol) | ||
2010 | continue; | ||
2011 | |||
2012 | /* found, now check type */ | ||
2013 | found = 1; | 2137 | found = 1; |
2014 | path->connect = connect; | 2138 | path->connect = connect; |
2015 | dapm_mark_dirty(path->source, "mixer connection"); | 2139 | dapm_mark_dirty(path->source, "mixer connection"); |
2140 | dapm_mark_dirty(path->sink, "mixer update"); | ||
2016 | } | 2141 | } |
2017 | 2142 | ||
2018 | if (found) { | 2143 | if (found) |
2019 | dapm_mark_dirty(widget, "mixer update"); | 2144 | dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); |
2020 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); | ||
2021 | } | ||
2022 | 2145 | ||
2023 | return found; | 2146 | return found; |
2024 | } | 2147 | } |
2025 | 2148 | ||
2026 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 2149 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, |
2027 | struct snd_kcontrol *kcontrol, int connect) | 2150 | struct snd_kcontrol *kcontrol, int connect, |
2151 | struct snd_soc_dapm_update *update) | ||
2028 | { | 2152 | { |
2029 | struct snd_soc_card *card = widget->dapm->card; | 2153 | struct snd_soc_card *card = dapm->card; |
2030 | int ret; | 2154 | int ret; |
2031 | 2155 | ||
2032 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2156 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2033 | ret = soc_dapm_mixer_update_power(widget, kcontrol, connect); | 2157 | card->update = update; |
2158 | ret = soc_dapm_mixer_update_power(card, kcontrol, connect); | ||
2159 | card->update = NULL; | ||
2034 | mutex_unlock(&card->dapm_mutex); | 2160 | mutex_unlock(&card->dapm_mutex); |
2035 | if (ret > 0) | 2161 | if (ret > 0) |
2036 | soc_dpcm_runtime_update(widget); | 2162 | soc_dpcm_runtime_update(card); |
2037 | return ret; | 2163 | return ret; |
2038 | } | 2164 | } |
2039 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); | 2165 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); |
@@ -2112,6 +2238,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) | |||
2112 | { | 2238 | { |
2113 | list_del(&path->list_sink); | 2239 | list_del(&path->list_sink); |
2114 | list_del(&path->list_source); | 2240 | list_del(&path->list_source); |
2241 | list_del(&path->list_kcontrol); | ||
2115 | list_del(&path->list); | 2242 | list_del(&path->list); |
2116 | kfree(path); | 2243 | kfree(path); |
2117 | } | 2244 | } |
@@ -2206,70 +2333,20 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
2206 | return 0; | 2333 | return 0; |
2207 | 2334 | ||
2208 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2335 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2209 | ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | 2336 | ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); |
2210 | mutex_unlock(&dapm->card->dapm_mutex); | 2337 | mutex_unlock(&dapm->card->dapm_mutex); |
2211 | return ret; | 2338 | return ret; |
2212 | } | 2339 | } |
2213 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 2340 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
2214 | 2341 | ||
2215 | static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | 2342 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, |
2216 | const struct snd_soc_dapm_route *route) | 2343 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, |
2344 | const char *control, | ||
2345 | int (*connected)(struct snd_soc_dapm_widget *source, | ||
2346 | struct snd_soc_dapm_widget *sink)) | ||
2217 | { | 2347 | { |
2218 | struct snd_soc_dapm_path *path; | 2348 | struct snd_soc_dapm_path *path; |
2219 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 2349 | 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 | 2350 | ||
2274 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); | 2351 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); |
2275 | if (!path) | 2352 | if (!path) |
@@ -2277,8 +2354,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2277 | 2354 | ||
2278 | path->source = wsource; | 2355 | path->source = wsource; |
2279 | path->sink = wsink; | 2356 | path->sink = wsink; |
2280 | path->connected = route->connected; | 2357 | path->connected = connected; |
2281 | INIT_LIST_HEAD(&path->list); | 2358 | INIT_LIST_HEAD(&path->list); |
2359 | INIT_LIST_HEAD(&path->list_kcontrol); | ||
2282 | INIT_LIST_HEAD(&path->list_source); | 2360 | INIT_LIST_HEAD(&path->list_source); |
2283 | INIT_LIST_HEAD(&path->list_sink); | 2361 | INIT_LIST_HEAD(&path->list_sink); |
2284 | 2362 | ||
@@ -2298,6 +2376,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2298 | wsource->ext = 1; | 2376 | wsource->ext = 1; |
2299 | } | 2377 | } |
2300 | 2378 | ||
2379 | dapm_mark_dirty(wsource, "Route added"); | ||
2380 | dapm_mark_dirty(wsink, "Route added"); | ||
2381 | |||
2301 | /* connect static paths */ | 2382 | /* connect static paths */ |
2302 | if (control == NULL) { | 2383 | if (control == NULL) { |
2303 | list_add(&path->list, &dapm->card->paths); | 2384 | list_add(&path->list, &dapm->card->paths); |
@@ -2328,6 +2409,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2328 | case snd_soc_dapm_dai_in: | 2409 | case snd_soc_dapm_dai_in: |
2329 | case snd_soc_dapm_dai_out: | 2410 | case snd_soc_dapm_dai_out: |
2330 | case snd_soc_dapm_dai_link: | 2411 | case snd_soc_dapm_dai_link: |
2412 | case snd_soc_dapm_kcontrol: | ||
2331 | list_add(&path->list, &dapm->card->paths); | 2413 | list_add(&path->list, &dapm->card->paths); |
2332 | list_add(&path->list_sink, &wsink->sources); | 2414 | list_add(&path->list_sink, &wsink->sources); |
2333 | list_add(&path->list_source, &wsource->sinks); | 2415 | list_add(&path->list_source, &wsource->sinks); |
@@ -2359,15 +2441,78 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2359 | return 0; | 2441 | return 0; |
2360 | } | 2442 | } |
2361 | 2443 | ||
2362 | dapm_mark_dirty(wsource, "Route added"); | ||
2363 | dapm_mark_dirty(wsink, "Route added"); | ||
2364 | |||
2365 | return 0; | 2444 | return 0; |
2445 | err: | ||
2446 | kfree(path); | ||
2447 | return ret; | ||
2448 | } | ||
2449 | |||
2450 | static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | ||
2451 | const struct snd_soc_dapm_route *route) | ||
2452 | { | ||
2453 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | ||
2454 | struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; | ||
2455 | const char *sink; | ||
2456 | const char *source; | ||
2457 | char prefixed_sink[80]; | ||
2458 | char prefixed_source[80]; | ||
2459 | int ret; | ||
2460 | |||
2461 | if (dapm->codec && dapm->codec->name_prefix) { | ||
2462 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | ||
2463 | dapm->codec->name_prefix, route->sink); | ||
2464 | sink = prefixed_sink; | ||
2465 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | ||
2466 | dapm->codec->name_prefix, route->source); | ||
2467 | source = prefixed_source; | ||
2468 | } else { | ||
2469 | sink = route->sink; | ||
2470 | source = route->source; | ||
2471 | } | ||
2472 | |||
2473 | /* | ||
2474 | * find src and dest widgets over all widgets but favor a widget from | ||
2475 | * current DAPM context | ||
2476 | */ | ||
2477 | list_for_each_entry(w, &dapm->card->widgets, list) { | ||
2478 | if (!wsink && !(strcmp(w->name, sink))) { | ||
2479 | wtsink = w; | ||
2480 | if (w->dapm == dapm) | ||
2481 | wsink = w; | ||
2482 | continue; | ||
2483 | } | ||
2484 | if (!wsource && !(strcmp(w->name, source))) { | ||
2485 | wtsource = w; | ||
2486 | if (w->dapm == dapm) | ||
2487 | wsource = w; | ||
2488 | } | ||
2489 | } | ||
2490 | /* use widget from another DAPM context if not found from this */ | ||
2491 | if (!wsink) | ||
2492 | wsink = wtsink; | ||
2493 | if (!wsource) | ||
2494 | wsource = wtsource; | ||
2366 | 2495 | ||
2496 | if (wsource == NULL) { | ||
2497 | dev_err(dapm->dev, "ASoC: no source widget found for %s\n", | ||
2498 | route->source); | ||
2499 | return -ENODEV; | ||
2500 | } | ||
2501 | if (wsink == NULL) { | ||
2502 | dev_err(dapm->dev, "ASoC: no sink widget found for %s\n", | ||
2503 | route->sink); | ||
2504 | return -ENODEV; | ||
2505 | } | ||
2506 | |||
2507 | ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control, | ||
2508 | route->connected); | ||
2509 | if (ret) | ||
2510 | goto err; | ||
2511 | |||
2512 | return 0; | ||
2367 | err: | 2513 | err: |
2368 | dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", | 2514 | dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", |
2369 | source, control, sink); | 2515 | source, route->control, sink); |
2370 | kfree(path); | ||
2371 | return ret; | 2516 | return ret; |
2372 | } | 2517 | } |
2373 | 2518 | ||
@@ -2569,14 +2714,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); | |||
2569 | * | 2714 | * |
2570 | * Returns 0 for success. | 2715 | * Returns 0 for success. |
2571 | */ | 2716 | */ |
2572 | int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | 2717 | int snd_soc_dapm_new_widgets(struct snd_soc_card *card) |
2573 | { | 2718 | { |
2574 | struct snd_soc_dapm_widget *w; | 2719 | struct snd_soc_dapm_widget *w; |
2575 | unsigned int val; | 2720 | unsigned int val; |
2576 | 2721 | ||
2577 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | 2722 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); |
2578 | 2723 | ||
2579 | list_for_each_entry(w, &dapm->card->widgets, list) | 2724 | list_for_each_entry(w, &card->widgets, list) |
2580 | { | 2725 | { |
2581 | if (w->new) | 2726 | if (w->new) |
2582 | continue; | 2727 | continue; |
@@ -2586,7 +2731,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2586 | sizeof(struct snd_kcontrol *), | 2731 | sizeof(struct snd_kcontrol *), |
2587 | GFP_KERNEL); | 2732 | GFP_KERNEL); |
2588 | if (!w->kcontrols) { | 2733 | if (!w->kcontrols) { |
2589 | mutex_unlock(&dapm->card->dapm_mutex); | 2734 | mutex_unlock(&card->dapm_mutex); |
2590 | return -ENOMEM; | 2735 | return -ENOMEM; |
2591 | } | 2736 | } |
2592 | } | 2737 | } |
@@ -2612,12 +2757,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2612 | 2757 | ||
2613 | /* Read the initial power state from the device */ | 2758 | /* Read the initial power state from the device */ |
2614 | if (w->reg >= 0) { | 2759 | if (w->reg >= 0) { |
2615 | val = soc_widget_read(w, w->reg); | 2760 | val = soc_widget_read(w, w->reg) >> w->shift; |
2616 | val &= 1 << w->shift; | 2761 | val &= w->mask; |
2617 | if (w->invert) | 2762 | if (val == w->on_val) |
2618 | val = !val; | ||
2619 | |||
2620 | if (val) | ||
2621 | w->power = 1; | 2763 | w->power = 1; |
2622 | } | 2764 | } |
2623 | 2765 | ||
@@ -2627,8 +2769,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2627 | dapm_debugfs_add_widget(w); | 2769 | dapm_debugfs_add_widget(w); |
2628 | } | 2770 | } |
2629 | 2771 | ||
2630 | dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | 2772 | dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); |
2631 | mutex_unlock(&dapm->card->dapm_mutex); | 2773 | mutex_unlock(&card->dapm_mutex); |
2632 | return 0; | 2774 | return 0; |
2633 | } | 2775 | } |
2634 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | 2776 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); |
@@ -2645,8 +2787,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | |||
2645 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | 2787 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, |
2646 | struct snd_ctl_elem_value *ucontrol) | 2788 | struct snd_ctl_elem_value *ucontrol) |
2647 | { | 2789 | { |
2648 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2790 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2649 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | 2791 | struct snd_soc_card *card = codec->card; |
2650 | struct soc_mixer_control *mc = | 2792 | struct soc_mixer_control *mc = |
2651 | (struct soc_mixer_control *)kcontrol->private_value; | 2793 | (struct soc_mixer_control *)kcontrol->private_value; |
2652 | unsigned int reg = mc->reg; | 2794 | unsigned int reg = mc->reg; |
@@ -2654,17 +2796,24 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
2654 | int max = mc->max; | 2796 | int max = mc->max; |
2655 | unsigned int mask = (1 << fls(max)) - 1; | 2797 | unsigned int mask = (1 << fls(max)) - 1; |
2656 | unsigned int invert = mc->invert; | 2798 | unsigned int invert = mc->invert; |
2799 | unsigned int val; | ||
2657 | 2800 | ||
2658 | if (snd_soc_volsw_is_stereo(mc)) | 2801 | if (snd_soc_volsw_is_stereo(mc)) |
2659 | dev_warn(widget->dapm->dev, | 2802 | dev_warn(codec->dapm.dev, |
2660 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2803 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2661 | kcontrol->id.name); | 2804 | kcontrol->id.name); |
2662 | 2805 | ||
2663 | ucontrol->value.integer.value[0] = | 2806 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2664 | (snd_soc_read(widget->codec, reg) >> shift) & mask; | 2807 | if (dapm_kcontrol_is_powered(kcontrol)) |
2808 | val = (snd_soc_read(codec, reg) >> shift) & mask; | ||
2809 | else | ||
2810 | val = dapm_kcontrol_get_value(kcontrol); | ||
2811 | mutex_unlock(&card->dapm_mutex); | ||
2812 | |||
2665 | if (invert) | 2813 | if (invert) |
2666 | ucontrol->value.integer.value[0] = | 2814 | ucontrol->value.integer.value[0] = max - val; |
2667 | max - ucontrol->value.integer.value[0]; | 2815 | else |
2816 | ucontrol->value.integer.value[0] = val; | ||
2668 | 2817 | ||
2669 | return 0; | 2818 | return 0; |
2670 | } | 2819 | } |
@@ -2682,9 +2831,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | |||
2682 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | 2831 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, |
2683 | struct snd_ctl_elem_value *ucontrol) | 2832 | struct snd_ctl_elem_value *ucontrol) |
2684 | { | 2833 | { |
2685 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2834 | 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; | 2835 | struct snd_soc_card *card = codec->card; |
2689 | struct soc_mixer_control *mc = | 2836 | struct soc_mixer_control *mc = |
2690 | (struct soc_mixer_control *)kcontrol->private_value; | 2837 | (struct soc_mixer_control *)kcontrol->private_value; |
@@ -2696,10 +2843,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2696 | unsigned int val; | 2843 | unsigned int val; |
2697 | int connect, change; | 2844 | int connect, change; |
2698 | struct snd_soc_dapm_update update; | 2845 | struct snd_soc_dapm_update update; |
2699 | int wi; | ||
2700 | 2846 | ||
2701 | if (snd_soc_volsw_is_stereo(mc)) | 2847 | if (snd_soc_volsw_is_stereo(mc)) |
2702 | dev_warn(widget->dapm->dev, | 2848 | dev_warn(codec->dapm.dev, |
2703 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2849 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2704 | kcontrol->id.name); | 2850 | kcontrol->id.name); |
2705 | 2851 | ||
@@ -2708,29 +2854,26 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2708 | 2854 | ||
2709 | if (invert) | 2855 | if (invert) |
2710 | val = max - val; | 2856 | val = max - val; |
2711 | mask = mask << shift; | ||
2712 | val = val << shift; | ||
2713 | 2857 | ||
2714 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2858 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2715 | 2859 | ||
2716 | change = snd_soc_test_bits(widget->codec, reg, mask, val); | 2860 | dapm_kcontrol_set_value(kcontrol, val); |
2717 | if (change) { | ||
2718 | for (wi = 0; wi < wlist->num_widgets; wi++) { | ||
2719 | widget = wlist->widgets[wi]; | ||
2720 | 2861 | ||
2721 | widget->value = val; | 2862 | mask = mask << shift; |
2863 | val = val << shift; | ||
2722 | 2864 | ||
2723 | update.kcontrol = kcontrol; | 2865 | change = snd_soc_test_bits(codec, reg, mask, val); |
2724 | update.widget = widget; | 2866 | if (change) { |
2725 | update.reg = reg; | 2867 | update.kcontrol = kcontrol; |
2726 | update.mask = mask; | 2868 | update.reg = reg; |
2727 | update.val = val; | 2869 | update.mask = mask; |
2728 | widget->dapm->update = &update; | 2870 | update.val = val; |
2729 | 2871 | ||
2730 | soc_dapm_mixer_update_power(widget, kcontrol, connect); | 2872 | card->update = &update; |
2731 | 2873 | ||
2732 | widget->dapm->update = NULL; | 2874 | soc_dapm_mixer_update_power(card, kcontrol, connect); |
2733 | } | 2875 | |
2876 | card->update = NULL; | ||
2734 | } | 2877 | } |
2735 | 2878 | ||
2736 | mutex_unlock(&card->dapm_mutex); | 2879 | mutex_unlock(&card->dapm_mutex); |
@@ -2750,12 +2893,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | |||
2750 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | 2893 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, |
2751 | struct snd_ctl_elem_value *ucontrol) | 2894 | struct snd_ctl_elem_value *ucontrol) |
2752 | { | 2895 | { |
2753 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2896 | 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; | 2897 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2756 | unsigned int val; | 2898 | unsigned int val; |
2757 | 2899 | ||
2758 | val = snd_soc_read(widget->codec, e->reg); | 2900 | val = snd_soc_read(codec, e->reg); |
2759 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; | 2901 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; |
2760 | if (e->shift_l != e->shift_r) | 2902 | if (e->shift_l != e->shift_r) |
2761 | ucontrol->value.enumerated.item[1] = | 2903 | ucontrol->value.enumerated.item[1] = |
@@ -2777,15 +2919,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | |||
2777 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | 2919 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
2778 | struct snd_ctl_elem_value *ucontrol) | 2920 | struct snd_ctl_elem_value *ucontrol) |
2779 | { | 2921 | { |
2780 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2922 | 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; | 2923 | struct snd_soc_card *card = codec->card; |
2784 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2924 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2785 | unsigned int val, mux, change; | 2925 | unsigned int val, mux, change; |
2786 | unsigned int mask; | 2926 | unsigned int mask; |
2787 | struct snd_soc_dapm_update update; | 2927 | struct snd_soc_dapm_update update; |
2788 | int wi; | ||
2789 | 2928 | ||
2790 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2929 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2791 | return -EINVAL; | 2930 | return -EINVAL; |
@@ -2801,24 +2940,17 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2801 | 2940 | ||
2802 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2941 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2803 | 2942 | ||
2804 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 2943 | change = snd_soc_test_bits(codec, e->reg, mask, val); |
2805 | if (change) { | 2944 | if (change) { |
2806 | for (wi = 0; wi < wlist->num_widgets; wi++) { | 2945 | update.kcontrol = kcontrol; |
2807 | widget = wlist->widgets[wi]; | 2946 | update.reg = e->reg; |
2808 | 2947 | update.mask = mask; | |
2809 | widget->value = val; | 2948 | update.val = val; |
2949 | card->update = &update; | ||
2810 | 2950 | ||
2811 | update.kcontrol = kcontrol; | 2951 | soc_dapm_mux_update_power(card, kcontrol, mux, e); |
2812 | update.widget = widget; | ||
2813 | update.reg = e->reg; | ||
2814 | update.mask = mask; | ||
2815 | update.val = val; | ||
2816 | widget->dapm->update = &update; | ||
2817 | 2952 | ||
2818 | soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 2953 | card->update = NULL; |
2819 | |||
2820 | widget->dapm->update = NULL; | ||
2821 | } | ||
2822 | } | 2954 | } |
2823 | 2955 | ||
2824 | mutex_unlock(&card->dapm_mutex); | 2956 | mutex_unlock(&card->dapm_mutex); |
@@ -2836,11 +2968,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | |||
2836 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | 2968 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, |
2837 | struct snd_ctl_elem_value *ucontrol) | 2969 | struct snd_ctl_elem_value *ucontrol) |
2838 | { | 2970 | { |
2839 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2971 | 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; | 2972 | return 0; |
2845 | } | 2973 | } |
2846 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | 2974 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); |
@@ -2855,30 +2983,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | |||
2855 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | 2983 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, |
2856 | struct snd_ctl_elem_value *ucontrol) | 2984 | struct snd_ctl_elem_value *ucontrol) |
2857 | { | 2985 | { |
2858 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2986 | 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; | 2987 | struct snd_soc_card *card = codec->card; |
2988 | unsigned int value; | ||
2862 | struct soc_enum *e = | 2989 | struct soc_enum *e = |
2863 | (struct soc_enum *)kcontrol->private_value; | 2990 | (struct soc_enum *)kcontrol->private_value; |
2864 | int change; | 2991 | int change; |
2865 | int wi; | ||
2866 | 2992 | ||
2867 | if (ucontrol->value.enumerated.item[0] >= e->max) | 2993 | if (ucontrol->value.enumerated.item[0] >= e->max) |
2868 | return -EINVAL; | 2994 | return -EINVAL; |
2869 | 2995 | ||
2870 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2996 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2871 | 2997 | ||
2872 | change = widget->value != ucontrol->value.enumerated.item[0]; | 2998 | value = ucontrol->value.enumerated.item[0]; |
2873 | if (change) { | 2999 | change = dapm_kcontrol_set_value(kcontrol, value); |
2874 | for (wi = 0; wi < wlist->num_widgets; wi++) { | 3000 | if (change) |
2875 | widget = wlist->widgets[wi]; | 3001 | 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 | 3002 | ||
2883 | mutex_unlock(&card->dapm_mutex); | 3003 | mutex_unlock(&card->dapm_mutex); |
2884 | return change; | 3004 | return change; |
@@ -2901,12 +3021,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | |||
2901 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | 3021 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, |
2902 | struct snd_ctl_elem_value *ucontrol) | 3022 | struct snd_ctl_elem_value *ucontrol) |
2903 | { | 3023 | { |
2904 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 3024 | 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; | 3025 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2907 | unsigned int reg_val, val, mux; | 3026 | unsigned int reg_val, val, mux; |
2908 | 3027 | ||
2909 | reg_val = snd_soc_read(widget->codec, e->reg); | 3028 | reg_val = snd_soc_read(codec, e->reg); |
2910 | val = (reg_val >> e->shift_l) & e->mask; | 3029 | val = (reg_val >> e->shift_l) & e->mask; |
2911 | for (mux = 0; mux < e->max; mux++) { | 3030 | for (mux = 0; mux < e->max; mux++) { |
2912 | if (val == e->values[mux]) | 3031 | if (val == e->values[mux]) |
@@ -2942,15 +3061,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | |||
2942 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | 3061 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, |
2943 | struct snd_ctl_elem_value *ucontrol) | 3062 | struct snd_ctl_elem_value *ucontrol) |
2944 | { | 3063 | { |
2945 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 3064 | 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; | 3065 | struct snd_soc_card *card = codec->card; |
2949 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 3066 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2950 | unsigned int val, mux, change; | 3067 | unsigned int val, mux, change; |
2951 | unsigned int mask; | 3068 | unsigned int mask; |
2952 | struct snd_soc_dapm_update update; | 3069 | struct snd_soc_dapm_update update; |
2953 | int wi; | ||
2954 | 3070 | ||
2955 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 3071 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2956 | return -EINVAL; | 3072 | return -EINVAL; |
@@ -2966,24 +3082,17 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2966 | 3082 | ||
2967 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 3083 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2968 | 3084 | ||
2969 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 3085 | change = snd_soc_test_bits(codec, e->reg, mask, val); |
2970 | if (change) { | 3086 | if (change) { |
2971 | for (wi = 0; wi < wlist->num_widgets; wi++) { | 3087 | update.kcontrol = kcontrol; |
2972 | widget = wlist->widgets[wi]; | 3088 | update.reg = e->reg; |
2973 | 3089 | update.mask = mask; | |
2974 | widget->value = val; | 3090 | update.val = val; |
3091 | card->update = &update; | ||
2975 | 3092 | ||
2976 | update.kcontrol = kcontrol; | 3093 | 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 | 3094 | ||
2983 | soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 3095 | card->update = NULL; |
2984 | |||
2985 | widget->dapm->update = NULL; | ||
2986 | } | ||
2987 | } | 3096 | } |
2988 | 3097 | ||
2989 | mutex_unlock(&card->dapm_mutex); | 3098 | mutex_unlock(&card->dapm_mutex); |
@@ -3080,7 +3189,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3080 | return NULL; | 3189 | return NULL; |
3081 | } | 3190 | } |
3082 | 3191 | ||
3083 | if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { | 3192 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
3084 | ret = regulator_allow_bypass(w->regulator, true); | 3193 | ret = regulator_allow_bypass(w->regulator, true); |
3085 | if (ret != 0) | 3194 | if (ret != 0) |
3086 | dev_warn(w->dapm->dev, | 3195 | dev_warn(w->dapm->dev, |
@@ -3127,16 +3236,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3127 | case snd_soc_dapm_value_mux: | 3236 | case snd_soc_dapm_value_mux: |
3128 | w->power_check = dapm_generic_check_power; | 3237 | w->power_check = dapm_generic_check_power; |
3129 | break; | 3238 | break; |
3130 | case snd_soc_dapm_adc: | ||
3131 | case snd_soc_dapm_aif_out: | ||
3132 | case snd_soc_dapm_dai_out: | 3239 | case snd_soc_dapm_dai_out: |
3133 | w->power_check = dapm_adc_check_power; | 3240 | w->power_check = dapm_adc_check_power; |
3134 | break; | 3241 | break; |
3135 | case snd_soc_dapm_dac: | ||
3136 | case snd_soc_dapm_aif_in: | ||
3137 | case snd_soc_dapm_dai_in: | 3242 | case snd_soc_dapm_dai_in: |
3138 | w->power_check = dapm_dac_check_power; | 3243 | w->power_check = dapm_dac_check_power; |
3139 | break; | 3244 | break; |
3245 | case snd_soc_dapm_adc: | ||
3246 | case snd_soc_dapm_aif_out: | ||
3247 | case snd_soc_dapm_dac: | ||
3248 | case snd_soc_dapm_aif_in: | ||
3140 | case snd_soc_dapm_pga: | 3249 | case snd_soc_dapm_pga: |
3141 | case snd_soc_dapm_out_drv: | 3250 | case snd_soc_dapm_out_drv: |
3142 | case snd_soc_dapm_input: | 3251 | case snd_soc_dapm_input: |
@@ -3152,6 +3261,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3152 | case snd_soc_dapm_supply: | 3261 | case snd_soc_dapm_supply: |
3153 | case snd_soc_dapm_regulator_supply: | 3262 | case snd_soc_dapm_regulator_supply: |
3154 | case snd_soc_dapm_clock_supply: | 3263 | case snd_soc_dapm_clock_supply: |
3264 | case snd_soc_dapm_kcontrol: | ||
3155 | w->power_check = dapm_supply_check_power; | 3265 | w->power_check = dapm_supply_check_power; |
3156 | break; | 3266 | break; |
3157 | default: | 3267 | default: |
@@ -3416,9 +3526,6 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
3416 | { | 3526 | { |
3417 | struct snd_soc_dapm_widget *dai_w, *w; | 3527 | struct snd_soc_dapm_widget *dai_w, *w; |
3418 | struct snd_soc_dai *dai; | 3528 | struct snd_soc_dai *dai; |
3419 | struct snd_soc_dapm_route r; | ||
3420 | |||
3421 | memset(&r, 0, sizeof(r)); | ||
3422 | 3529 | ||
3423 | /* For each DAI widget... */ | 3530 | /* For each DAI widget... */ |
3424 | list_for_each_entry(dai_w, &card->widgets, list) { | 3531 | list_for_each_entry(dai_w, &card->widgets, list) { |
@@ -3445,29 +3552,27 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
3445 | break; | 3552 | break; |
3446 | } | 3553 | } |
3447 | 3554 | ||
3448 | if (!w->sname) | 3555 | if (!w->sname || !strstr(w->sname, dai_w->name)) |
3449 | continue; | 3556 | continue; |
3450 | 3557 | ||
3451 | if (dai->driver->playback.stream_name && | 3558 | if (dai->driver->playback.stream_name && |
3452 | strstr(w->sname, | 3559 | strstr(w->sname, |
3453 | dai->driver->playback.stream_name)) { | 3560 | 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", | 3561 | dev_dbg(dai->dev, "%s -> %s\n", |
3457 | r.source, r.sink); | 3562 | dai->playback_widget->name, w->name); |
3458 | 3563 | ||
3459 | snd_soc_dapm_add_route(w->dapm, &r); | 3564 | snd_soc_dapm_add_path(w->dapm, |
3565 | dai->playback_widget, w, NULL, NULL); | ||
3460 | } | 3566 | } |
3461 | 3567 | ||
3462 | if (dai->driver->capture.stream_name && | 3568 | if (dai->driver->capture.stream_name && |
3463 | strstr(w->sname, | 3569 | strstr(w->sname, |
3464 | dai->driver->capture.stream_name)) { | 3570 | 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", | 3571 | dev_dbg(dai->dev, "%s -> %s\n", |
3468 | r.source, r.sink); | 3572 | w->name, dai->capture_widget->name); |
3469 | 3573 | ||
3470 | snd_soc_dapm_add_route(w->dapm, &r); | 3574 | snd_soc_dapm_add_path(w->dapm, w, |
3575 | dai->capture_widget, NULL, NULL); | ||
3471 | } | 3576 | } |
3472 | } | 3577 | } |
3473 | } | 3578 | } |
@@ -3529,7 +3634,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | |||
3529 | } | 3634 | } |
3530 | } | 3635 | } |
3531 | 3636 | ||
3532 | dapm_power_widgets(&rtd->card->dapm, event); | 3637 | dapm_power_widgets(rtd->card, event); |
3533 | } | 3638 | } |
3534 | 3639 | ||
3535 | /** | 3640 | /** |
@@ -3798,7 +3903,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
3798 | if (dapm->bias_level == SND_SOC_BIAS_ON) | 3903 | if (dapm->bias_level == SND_SOC_BIAS_ON) |
3799 | snd_soc_dapm_set_bias_level(dapm, | 3904 | snd_soc_dapm_set_bias_level(dapm, |
3800 | SND_SOC_BIAS_PREPARE); | 3905 | SND_SOC_BIAS_PREPARE); |
3801 | dapm_seq_run(dapm, &down_list, 0, false); | 3906 | dapm_seq_run(card, &down_list, 0, false); |
3802 | if (dapm->bias_level == SND_SOC_BIAS_PREPARE) | 3907 | if (dapm->bias_level == SND_SOC_BIAS_PREPARE) |
3803 | snd_soc_dapm_set_bias_level(dapm, | 3908 | snd_soc_dapm_set_bias_level(dapm, |
3804 | SND_SOC_BIAS_STANDBY); | 3909 | SND_SOC_BIAS_STANDBY); |
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 0bb5cccd7766..71358e3b54d9 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c | |||
@@ -183,8 +183,6 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, | |||
183 | list_add(&(pins[i].list), &jack->pins); | 183 | list_add(&(pins[i].list), &jack->pins); |
184 | } | 184 | } |
185 | 185 | ||
186 | snd_soc_dapm_new_widgets(&jack->codec->card->dapm); | ||
187 | |||
188 | /* Update to reflect the last reported status; canned jack | 186 | /* Update to reflect the last reported status; canned jack |
189 | * implementations are likely to set their state before the | 187 | * implementations are likely to set their state before the |
190 | * card has an opportunity to associate pins. | 188 | * card has an opportunity to associate pins. |
@@ -263,7 +261,7 @@ static irqreturn_t gpio_handler(int irq, void *data) | |||
263 | if (device_may_wakeup(dev)) | 261 | if (device_may_wakeup(dev)) |
264 | pm_wakeup_event(dev, gpio->debounce_time + 50); | 262 | pm_wakeup_event(dev, gpio->debounce_time + 50); |
265 | 263 | ||
266 | schedule_delayed_work(&gpio->work, | 264 | queue_delayed_work(system_power_efficient_wq, &gpio->work, |
267 | msecs_to_jiffies(gpio->debounce_time)); | 265 | msecs_to_jiffies(gpio->debounce_time)); |
268 | 266 | ||
269 | return IRQ_HANDLED; | 267 | return IRQ_HANDLED; |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index b6c640332a17..330c9a6b5cb5 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; |
@@ -2027,6 +2020,16 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2027 | capture = 1; | 2020 | capture = 1; |
2028 | } | 2021 | } |
2029 | 2022 | ||
2023 | if (rtd->dai_link->playback_only) { | ||
2024 | playback = 1; | ||
2025 | capture = 0; | ||
2026 | } | ||
2027 | |||
2028 | if (rtd->dai_link->capture_only) { | ||
2029 | playback = 0; | ||
2030 | capture = 1; | ||
2031 | } | ||
2032 | |||
2030 | /* create the PCM */ | 2033 | /* create the PCM */ |
2031 | if (rtd->dai_link->no_pcm) { | 2034 | if (rtd->dai_link->no_pcm) { |
2032 | snprintf(new_name, sizeof(new_name), "(%s)", | 2035 | snprintf(new_name, sizeof(new_name), "(%s)", |
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), |
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index b9defcdeb7ef..780bf3f62d28 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c | |||
@@ -346,10 +346,10 @@ static int usb6fire_fw_check(u8 *version) | |||
346 | if (!memcmp(version, known_fw_versions + i, 2)) | 346 | if (!memcmp(version, known_fw_versions + i, 2)) |
347 | return 0; | 347 | return 0; |
348 | 348 | ||
349 | snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. " | 349 | snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %4ph. " |
350 | "please reconnect to power. if this failure " | 350 | "please reconnect to power. if this failure " |
351 | "still happens, check your firmware installation.", | 351 | "still happens, check your firmware installation.", |
352 | 4, version); | 352 | version); |
353 | return -EINVAL; | 353 | return -EINVAL; |
354 | } | 354 | } |
355 | 355 | ||
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 659950e5b94f..93e970f2b3c0 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -418,6 +418,9 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, | |||
418 | struct snd_usb_endpoint *ep; | 418 | struct snd_usb_endpoint *ep; |
419 | int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK; | 419 | int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK; |
420 | 420 | ||
421 | if (WARN_ON(!alts)) | ||
422 | return NULL; | ||
423 | |||
421 | mutex_lock(&chip->mutex); | 424 | mutex_lock(&chip->mutex); |
422 | 425 | ||
423 | list_for_each_entry(ep, &chip->ep_list, list) { | 426 | list_for_each_entry(ep, &chip->ep_list, list) { |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 15b151ed4899..b375d58871e7 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -327,6 +327,137 @@ static int search_roland_implicit_fb(struct usb_device *dev, int ifnum, | |||
327 | return 0; | 327 | return 0; |
328 | } | 328 | } |
329 | 329 | ||
330 | static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, | ||
331 | struct usb_device *dev, | ||
332 | struct usb_interface_descriptor *altsd, | ||
333 | unsigned int attr) | ||
334 | { | ||
335 | struct usb_host_interface *alts; | ||
336 | struct usb_interface *iface; | ||
337 | unsigned int ep; | ||
338 | |||
339 | /* Implicit feedback sync EPs consumers are always playback EPs */ | ||
340 | if (subs->direction != SNDRV_PCM_STREAM_PLAYBACK) | ||
341 | return 0; | ||
342 | |||
343 | switch (subs->stream->chip->usb_id) { | ||
344 | case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ | ||
345 | case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ | ||
346 | ep = 0x81; | ||
347 | iface = usb_ifnum_to_if(dev, 3); | ||
348 | |||
349 | if (!iface || iface->num_altsetting == 0) | ||
350 | return -EINVAL; | ||
351 | |||
352 | alts = &iface->altsetting[1]; | ||
353 | goto add_sync_ep; | ||
354 | break; | ||
355 | case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ | ||
356 | case USB_ID(0x0763, 0x2081): | ||
357 | ep = 0x81; | ||
358 | iface = usb_ifnum_to_if(dev, 2); | ||
359 | |||
360 | if (!iface || iface->num_altsetting == 0) | ||
361 | return -EINVAL; | ||
362 | |||
363 | alts = &iface->altsetting[1]; | ||
364 | goto add_sync_ep; | ||
365 | } | ||
366 | if (attr == USB_ENDPOINT_SYNC_ASYNC && | ||
367 | altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && | ||
368 | altsd->bInterfaceProtocol == 2 && | ||
369 | altsd->bNumEndpoints == 1 && | ||
370 | USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ && | ||
371 | search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1, | ||
372 | altsd->bAlternateSetting, | ||
373 | &alts, &ep) >= 0) { | ||
374 | goto add_sync_ep; | ||
375 | } | ||
376 | |||
377 | /* No quirk */ | ||
378 | return 0; | ||
379 | |||
380 | add_sync_ep: | ||
381 | subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, | ||
382 | alts, ep, !subs->direction, | ||
383 | SND_USB_ENDPOINT_TYPE_DATA); | ||
384 | if (!subs->sync_endpoint) | ||
385 | return -EINVAL; | ||
386 | |||
387 | subs->data_endpoint->sync_master = subs->sync_endpoint; | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int set_sync_endpoint(struct snd_usb_substream *subs, | ||
393 | struct audioformat *fmt, | ||
394 | struct usb_device *dev, | ||
395 | struct usb_host_interface *alts, | ||
396 | struct usb_interface_descriptor *altsd) | ||
397 | { | ||
398 | int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; | ||
399 | unsigned int ep, attr; | ||
400 | bool implicit_fb; | ||
401 | int err; | ||
402 | |||
403 | /* we need a sync pipe in async OUT or adaptive IN mode */ | ||
404 | /* check the number of EP, since some devices have broken | ||
405 | * descriptors which fool us. if it has only one EP, | ||
406 | * assume it as adaptive-out or sync-in. | ||
407 | */ | ||
408 | attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; | ||
409 | |||
410 | err = set_sync_ep_implicit_fb_quirk(subs, dev, altsd, attr); | ||
411 | if (err < 0) | ||
412 | return err; | ||
413 | |||
414 | if (altsd->bNumEndpoints < 2) | ||
415 | return 0; | ||
416 | |||
417 | if ((is_playback && attr != USB_ENDPOINT_SYNC_ASYNC) || | ||
418 | (!is_playback && attr != USB_ENDPOINT_SYNC_ADAPTIVE)) | ||
419 | return 0; | ||
420 | |||
421 | /* check sync-pipe endpoint */ | ||
422 | /* ... and check descriptor size before accessing bSynchAddress | ||
423 | because there is a version of the SB Audigy 2 NX firmware lacking | ||
424 | the audio fields in the endpoint descriptors */ | ||
425 | if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC || | ||
426 | (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && | ||
427 | get_endpoint(alts, 1)->bSynchAddress != 0)) { | ||
428 | snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n", | ||
429 | dev->devnum, fmt->iface, fmt->altsetting, | ||
430 | get_endpoint(alts, 1)->bmAttributes, | ||
431 | get_endpoint(alts, 1)->bLength, | ||
432 | get_endpoint(alts, 1)->bSynchAddress); | ||
433 | return -EINVAL; | ||
434 | } | ||
435 | ep = get_endpoint(alts, 1)->bEndpointAddress; | ||
436 | if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && | ||
437 | ((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || | ||
438 | (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { | ||
439 | snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n", | ||
440 | dev->devnum, fmt->iface, fmt->altsetting, | ||
441 | is_playback, ep, get_endpoint(alts, 0)->bSynchAddress); | ||
442 | return -EINVAL; | ||
443 | } | ||
444 | |||
445 | implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK) | ||
446 | == USB_ENDPOINT_USAGE_IMPLICIT_FB; | ||
447 | |||
448 | subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, | ||
449 | alts, ep, !subs->direction, | ||
450 | implicit_fb ? | ||
451 | SND_USB_ENDPOINT_TYPE_DATA : | ||
452 | SND_USB_ENDPOINT_TYPE_SYNC); | ||
453 | if (!subs->sync_endpoint) | ||
454 | return -EINVAL; | ||
455 | |||
456 | subs->data_endpoint->sync_master = subs->sync_endpoint; | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
330 | /* | 461 | /* |
331 | * find a matching format and set up the interface | 462 | * find a matching format and set up the interface |
332 | */ | 463 | */ |
@@ -336,9 +467,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
336 | struct usb_host_interface *alts; | 467 | struct usb_host_interface *alts; |
337 | struct usb_interface_descriptor *altsd; | 468 | struct usb_interface_descriptor *altsd; |
338 | struct usb_interface *iface; | 469 | struct usb_interface *iface; |
339 | unsigned int ep, attr; | 470 | int err; |
340 | int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; | ||
341 | int err, implicit_fb = 0; | ||
342 | 471 | ||
343 | iface = usb_ifnum_to_if(dev, fmt->iface); | 472 | iface = usb_ifnum_to_if(dev, fmt->iface); |
344 | if (WARN_ON(!iface)) | 473 | if (WARN_ON(!iface)) |
@@ -383,118 +512,22 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
383 | subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, | 512 | subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, |
384 | alts, fmt->endpoint, subs->direction, | 513 | alts, fmt->endpoint, subs->direction, |
385 | SND_USB_ENDPOINT_TYPE_DATA); | 514 | SND_USB_ENDPOINT_TYPE_DATA); |
515 | |||
386 | if (!subs->data_endpoint) | 516 | if (!subs->data_endpoint) |
387 | return -EINVAL; | 517 | return -EINVAL; |
388 | 518 | ||
389 | /* we need a sync pipe in async OUT or adaptive IN mode */ | 519 | err = set_sync_endpoint(subs, fmt, dev, alts, altsd); |
390 | /* check the number of EP, since some devices have broken | 520 | if (err < 0) |
391 | * descriptors which fool us. if it has only one EP, | 521 | return err; |
392 | * assume it as adaptive-out or sync-in. | ||
393 | */ | ||
394 | attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; | ||
395 | |||
396 | switch (subs->stream->chip->usb_id) { | ||
397 | case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ | ||
398 | case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ | ||
399 | if (is_playback) { | ||
400 | implicit_fb = 1; | ||
401 | ep = 0x81; | ||
402 | iface = usb_ifnum_to_if(dev, 3); | ||
403 | |||
404 | if (!iface || iface->num_altsetting == 0) | ||
405 | return -EINVAL; | ||
406 | |||
407 | alts = &iface->altsetting[1]; | ||
408 | goto add_sync_ep; | ||
409 | } | ||
410 | break; | ||
411 | case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ | ||
412 | case USB_ID(0x0763, 0x2081): | ||
413 | if (is_playback) { | ||
414 | implicit_fb = 1; | ||
415 | ep = 0x81; | ||
416 | iface = usb_ifnum_to_if(dev, 2); | ||
417 | |||
418 | if (!iface || iface->num_altsetting == 0) | ||
419 | return -EINVAL; | ||
420 | |||
421 | alts = &iface->altsetting[1]; | ||
422 | goto add_sync_ep; | ||
423 | } | ||
424 | } | ||
425 | if (is_playback && | ||
426 | attr == USB_ENDPOINT_SYNC_ASYNC && | ||
427 | altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && | ||
428 | altsd->bInterfaceProtocol == 2 && | ||
429 | altsd->bNumEndpoints == 1 && | ||
430 | USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ && | ||
431 | search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1, | ||
432 | altsd->bAlternateSetting, | ||
433 | &alts, &ep) >= 0) { | ||
434 | implicit_fb = 1; | ||
435 | goto add_sync_ep; | ||
436 | } | ||
437 | |||
438 | if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) || | ||
439 | (!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && | ||
440 | altsd->bNumEndpoints >= 2) { | ||
441 | /* check sync-pipe endpoint */ | ||
442 | /* ... and check descriptor size before accessing bSynchAddress | ||
443 | because there is a version of the SB Audigy 2 NX firmware lacking | ||
444 | the audio fields in the endpoint descriptors */ | ||
445 | if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC || | ||
446 | (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && | ||
447 | get_endpoint(alts, 1)->bSynchAddress != 0 && | ||
448 | !implicit_fb)) { | ||
449 | snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n", | ||
450 | dev->devnum, fmt->iface, fmt->altsetting, | ||
451 | get_endpoint(alts, 1)->bmAttributes, | ||
452 | get_endpoint(alts, 1)->bLength, | ||
453 | get_endpoint(alts, 1)->bSynchAddress); | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | ep = get_endpoint(alts, 1)->bEndpointAddress; | ||
457 | if (!implicit_fb && | ||
458 | get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && | ||
459 | (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || | ||
460 | (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { | ||
461 | snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n", | ||
462 | dev->devnum, fmt->iface, fmt->altsetting, | ||
463 | is_playback, ep, get_endpoint(alts, 0)->bSynchAddress); | ||
464 | return -EINVAL; | ||
465 | } | ||
466 | |||
467 | implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK) | ||
468 | == USB_ENDPOINT_USAGE_IMPLICIT_FB; | ||
469 | |||
470 | add_sync_ep: | ||
471 | subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, | ||
472 | alts, ep, !subs->direction, | ||
473 | implicit_fb ? | ||
474 | SND_USB_ENDPOINT_TYPE_DATA : | ||
475 | SND_USB_ENDPOINT_TYPE_SYNC); | ||
476 | if (!subs->sync_endpoint) | ||
477 | return -EINVAL; | ||
478 | |||
479 | subs->data_endpoint->sync_master = subs->sync_endpoint; | ||
480 | } | ||
481 | 522 | ||
482 | if ((err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt)) < 0) | 523 | err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt); |
524 | if (err < 0) | ||
483 | return err; | 525 | return err; |
484 | 526 | ||
485 | subs->cur_audiofmt = fmt; | 527 | subs->cur_audiofmt = fmt; |
486 | 528 | ||
487 | snd_usb_set_format_quirk(subs, fmt); | 529 | snd_usb_set_format_quirk(subs, fmt); |
488 | 530 | ||
489 | #if 0 | ||
490 | printk(KERN_DEBUG | ||
491 | "setting done: format = %d, rate = %d..%d, channels = %d\n", | ||
492 | fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels); | ||
493 | printk(KERN_DEBUG | ||
494 | " datapipe = 0x%0x, syncpipe = 0x%0x\n", | ||
495 | subs->datapipe, subs->syncpipe); | ||
496 | #endif | ||
497 | |||
498 | return 0; | 531 | return 0; |
499 | } | 532 | } |
500 | 533 | ||
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 1f9bbd55553f..5a51b18c50fe 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c | |||
@@ -305,11 +305,9 @@ static void usX2Y_unlinkSeq(struct snd_usX2Y_AsyncSeq *S) | |||
305 | { | 305 | { |
306 | int i; | 306 | int i; |
307 | for (i = 0; i < URBS_AsyncSeq; ++i) { | 307 | for (i = 0; i < URBS_AsyncSeq; ++i) { |
308 | if (S[i].urb) { | 308 | usb_kill_urb(S->urb[i]); |
309 | usb_kill_urb(S->urb[i]); | 309 | usb_free_urb(S->urb[i]); |
310 | usb_free_urb(S->urb[i]); | 310 | S->urb[i] = NULL; |
311 | S->urb[i] = NULL; | ||
312 | } | ||
313 | } | 311 | } |
314 | kfree(S->buffer); | 312 | kfree(S->buffer); |
315 | } | 313 | } |