diff options
Diffstat (limited to 'sound/soc')
206 files changed, 16826 insertions, 5519 deletions
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index d88edfced8c4..865e090c8061 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,10 +1,14 @@ | |||
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 soc-devres.o | 2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o |
3 | 3 | ||
4 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) | 4 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) |
5 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o | 5 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o |
6 | endif | 6 | endif |
7 | 7 | ||
8 | ifneq ($(CONFIG_SND_SOC_AC97_BUS),) | ||
9 | snd-soc-core-objs += soc-ac97.o | ||
10 | endif | ||
11 | |||
8 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o | 12 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o |
9 | obj-$(CONFIG_SND_SOC) += codecs/ | 13 | obj-$(CONFIG_SND_SOC) += codecs/ |
10 | obj-$(CONFIG_SND_SOC) += generic/ | 14 | obj-$(CONFIG_SND_SOC) += generic/ |
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 27e3fc4a536b..fb3878312bf8 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig | |||
@@ -52,12 +52,3 @@ config SND_AT91_SOC_SAM9X5_WM8731 | |||
52 | help | 52 | help |
53 | Say Y if you want to add support for audio SoC on an | 53 | Say Y if you want to add support for audio SoC on an |
54 | at91sam9x5 based board that is using WM8731 codec. | 54 | at91sam9x5 based board that is using WM8731 codec. |
55 | |||
56 | config SND_AT91_SOC_AFEB9260 | ||
57 | tristate "SoC Audio support for AFEB9260 board" | ||
58 | depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC | ||
59 | select SND_ATMEL_SOC_PDC | ||
60 | select SND_ATMEL_SOC_SSC | ||
61 | select SND_SOC_TLV320AIC23_I2C | ||
62 | help | ||
63 | Say Y here to support sound on AFEB9260 board. | ||
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index 5baabc8bde3a..466a821da98c 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile | |||
@@ -17,4 +17,3 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o | |||
17 | 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 | 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 | 19 | obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o |
20 | obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o | ||
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index f403f399808a..b1cc2a4a7fc0 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -310,7 +310,10 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | |||
310 | * transmit and receive, so if a value has already | 310 | * transmit and receive, so if a value has already |
311 | * been set, it must match this value. | 311 | * been set, it must match this value. |
312 | */ | 312 | */ |
313 | if (ssc_p->cmr_div == 0) | 313 | if (ssc_p->dir_mask != |
314 | (SSC_DIR_MASK_PLAYBACK | SSC_DIR_MASK_CAPTURE)) | ||
315 | ssc_p->cmr_div = div; | ||
316 | else if (ssc_p->cmr_div == 0) | ||
314 | ssc_p->cmr_div = div; | 317 | ssc_p->cmr_div = div; |
315 | else | 318 | else |
316 | if (div != ssc_p->cmr_div) | 319 | if (div != ssc_p->cmr_div) |
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c deleted file mode 100644 index 9579799ace54..000000000000 --- a/sound/soc/atmel/snd-soc-afeb9260.c +++ /dev/null | |||
@@ -1,151 +0,0 @@ | |||
1 | /* | ||
2 | * afeb9260.c -- SoC audio for AFEB9260 | ||
3 | * | ||
4 | * Copyright (C) 2009 Sergey Lapin <slapin@ossfans.org> | ||
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 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | |||
28 | #include <linux/atmel-ssc.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/pcm.h> | ||
31 | #include <sound/pcm_params.h> | ||
32 | #include <sound/soc.h> | ||
33 | |||
34 | #include <asm/mach-types.h> | ||
35 | #include <mach/hardware.h> | ||
36 | #include <linux/gpio.h> | ||
37 | |||
38 | #include "../codecs/tlv320aic23.h" | ||
39 | #include "atmel-pcm.h" | ||
40 | #include "atmel_ssc_dai.h" | ||
41 | |||
42 | #define CODEC_CLOCK 12000000 | ||
43 | |||
44 | static int afeb9260_hw_params(struct snd_pcm_substream *substream, | ||
45 | struct snd_pcm_hw_params *params) | ||
46 | { | ||
47 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
48 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
49 | int err; | ||
50 | |||
51 | /* Set the codec system clock for DAC and ADC */ | ||
52 | err = | ||
53 | snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); | ||
54 | |||
55 | if (err < 0) { | ||
56 | printk(KERN_ERR "can't set codec system clock\n"); | ||
57 | return err; | ||
58 | } | ||
59 | |||
60 | return err; | ||
61 | } | ||
62 | |||
63 | static struct snd_soc_ops afeb9260_ops = { | ||
64 | .hw_params = afeb9260_hw_params, | ||
65 | }; | ||
66 | |||
67 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | ||
68 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
69 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
70 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
71 | }; | ||
72 | |||
73 | static const struct snd_soc_dapm_route afeb9260_audio_map[] = { | ||
74 | {"Headphone Jack", NULL, "LHPOUT"}, | ||
75 | {"Headphone Jack", NULL, "RHPOUT"}, | ||
76 | |||
77 | {"LLINEIN", NULL, "Line In"}, | ||
78 | {"RLINEIN", NULL, "Line In"}, | ||
79 | |||
80 | {"MICIN", NULL, "Mic Jack"}, | ||
81 | }; | ||
82 | |||
83 | |||
84 | /* Digital audio interface glue - connects codec <--> CPU */ | ||
85 | static struct snd_soc_dai_link afeb9260_dai = { | ||
86 | .name = "TLV320AIC23", | ||
87 | .stream_name = "AIC23", | ||
88 | .cpu_dai_name = "atmel-ssc-dai.0", | ||
89 | .codec_dai_name = "tlv320aic23-hifi", | ||
90 | .platform_name = "atmel_pcm-audio", | ||
91 | .codec_name = "tlv320aic23-codec.0-001a", | ||
92 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | | ||
93 | SND_SOC_DAIFMT_CBM_CFM, | ||
94 | .ops = &afeb9260_ops, | ||
95 | }; | ||
96 | |||
97 | /* Audio machine driver */ | ||
98 | static struct snd_soc_card snd_soc_machine_afeb9260 = { | ||
99 | .name = "AFEB9260", | ||
100 | .owner = THIS_MODULE, | ||
101 | .dai_link = &afeb9260_dai, | ||
102 | .num_links = 1, | ||
103 | |||
104 | .dapm_widgets = tlv320aic23_dapm_widgets, | ||
105 | .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), | ||
106 | .dapm_routes = afeb9260_audio_map, | ||
107 | .num_dapm_routes = ARRAY_SIZE(afeb9260_audio_map), | ||
108 | }; | ||
109 | |||
110 | static struct platform_device *afeb9260_snd_device; | ||
111 | |||
112 | static int __init afeb9260_soc_init(void) | ||
113 | { | ||
114 | int err; | ||
115 | struct device *dev; | ||
116 | |||
117 | if (!(machine_is_afeb9260())) | ||
118 | return -ENODEV; | ||
119 | |||
120 | |||
121 | afeb9260_snd_device = platform_device_alloc("soc-audio", -1); | ||
122 | if (!afeb9260_snd_device) { | ||
123 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | ||
124 | return -ENOMEM; | ||
125 | } | ||
126 | |||
127 | platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260); | ||
128 | err = platform_device_add(afeb9260_snd_device); | ||
129 | if (err) | ||
130 | goto err1; | ||
131 | |||
132 | dev = &afeb9260_snd_device->dev; | ||
133 | |||
134 | return 0; | ||
135 | err1: | ||
136 | platform_device_put(afeb9260_snd_device); | ||
137 | return err; | ||
138 | } | ||
139 | |||
140 | static void __exit afeb9260_soc_exit(void) | ||
141 | { | ||
142 | platform_device_unregister(afeb9260_snd_device); | ||
143 | } | ||
144 | |||
145 | module_init(afeb9260_soc_init); | ||
146 | module_exit(afeb9260_soc_exit); | ||
147 | |||
148 | MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>"); | ||
149 | MODULE_DESCRIPTION("ALSA SoC for AFEB9260"); | ||
150 | MODULE_LICENSE("GPL"); | ||
151 | |||
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index c8a2de103c5f..5159a50a45a6 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c | |||
@@ -205,7 +205,7 @@ static int au1xac97c_dai_probe(struct snd_soc_dai *dai) | |||
205 | 205 | ||
206 | static struct snd_soc_dai_driver au1xac97c_dai_driver = { | 206 | static struct snd_soc_dai_driver au1xac97c_dai_driver = { |
207 | .name = "alchemy-ac97c", | 207 | .name = "alchemy-ac97c", |
208 | .ac97_control = 1, | 208 | .bus_control = true, |
209 | .probe = au1xac97c_dai_probe, | 209 | .probe = au1xac97c_dai_probe, |
210 | .playback = { | 210 | .playback = { |
211 | .rates = AC97_RATES, | 211 | .rates = AC97_RATES, |
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 84f31e1f9d24..c6daec98ff89 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c | |||
@@ -343,7 +343,7 @@ static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { | |||
343 | }; | 343 | }; |
344 | 344 | ||
345 | static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { | 345 | static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { |
346 | .ac97_control = 1, | 346 | .bus_control = true, |
347 | .probe = au1xpsc_ac97_probe, | 347 | .probe = au1xpsc_ac97_probe, |
348 | .playback = { | 348 | .playback = { |
349 | .rates = AC97_RATES, | 349 | .rates = AC97_RATES, |
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index e82eb373a731..6bf21a6c02e4 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c | |||
@@ -260,7 +260,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai) | |||
260 | #endif | 260 | #endif |
261 | 261 | ||
262 | static struct snd_soc_dai_driver bfin_ac97_dai = { | 262 | static struct snd_soc_dai_driver bfin_ac97_dai = { |
263 | .ac97_control = 1, | 263 | .bus_control = true, |
264 | .suspend = bf5xx_ac97_suspend, | 264 | .suspend = bf5xx_ac97_suspend, |
265 | .resume = bf5xx_ac97_resume, | 265 | .resume = bf5xx_ac97_resume, |
266 | .playback = { | 266 | .playback = { |
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index 3450e8f9080d..0fa81a523b8a 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c | |||
@@ -46,8 +46,6 @@ | |||
46 | #include <linux/gpio.h> | 46 | #include <linux/gpio.h> |
47 | #include <asm/portmux.h> | 47 | #include <asm/portmux.h> |
48 | 48 | ||
49 | #include "../codecs/ad1980.h" | ||
50 | |||
51 | #include "bf5xx-ac97.h" | 49 | #include "bf5xx-ac97.h" |
52 | 50 | ||
53 | static struct snd_soc_card bf5xx_board; | 51 | static struct snd_soc_card bf5xx_board; |
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 5477c5475923..7b7fbcd49e5e 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig | |||
@@ -36,7 +36,8 @@ config SND_EP93XX_SOC_EDB93XX | |||
36 | tristate "SoC Audio support for Cirrus Logic EDB93xx boards" | 36 | tristate "SoC Audio support for Cirrus Logic EDB93xx boards" |
37 | depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A) | 37 | depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A) |
38 | select SND_EP93XX_SOC_I2S | 38 | select SND_EP93XX_SOC_I2S |
39 | select SND_SOC_CS4271 | 39 | select SND_SOC_CS4271_I2C if I2C |
40 | select SND_SOC_CS4271_SPI if SPI_MASTER | ||
40 | help | 41 | help |
41 | Say Y or M here if you want to add support for I2S audio on the | 42 | Say Y or M here if you want to add support for I2S audio on the |
42 | Cirrus Logic EDB93xx boards. | 43 | Cirrus Logic EDB93xx boards. |
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index f30dadf85b99..6b8a366b0211 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c | |||
@@ -338,7 +338,7 @@ static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = { | |||
338 | static struct snd_soc_dai_driver ep93xx_ac97_dai = { | 338 | static struct snd_soc_dai_driver ep93xx_ac97_dai = { |
339 | .name = "ep93xx-ac97", | 339 | .name = "ep93xx-ac97", |
340 | .id = 0, | 340 | .id = 0, |
341 | .ac97_control = 1, | 341 | .bus_control = true, |
342 | .probe = ep93xx_ac97_dai_probe, | 342 | .probe = ep93xx_ac97_dai_probe, |
343 | .playback = { | 343 | .playback = { |
344 | .stream_name = "AC97 Playback", | 344 | .stream_name = "AC97 Playback", |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..883c5778b309 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -50,7 +50,8 @@ config SND_SOC_ALL_CODECS | |||
50 | select SND_SOC_CS42L73 if I2C | 50 | select SND_SOC_CS42L73 if I2C |
51 | select SND_SOC_CS4265 if I2C | 51 | select SND_SOC_CS4265 if I2C |
52 | select SND_SOC_CS4270 if I2C | 52 | select SND_SOC_CS4270 if I2C |
53 | select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI | 53 | select SND_SOC_CS4271_I2C if I2C |
54 | select SND_SOC_CS4271_SPI if SPI_MASTER | ||
54 | select SND_SOC_CS42XX8_I2C if I2C | 55 | select SND_SOC_CS42XX8_I2C if I2C |
55 | select SND_SOC_CX20442 if TTY | 56 | select SND_SOC_CX20442 if TTY |
56 | select SND_SOC_DA7210 if I2C | 57 | select SND_SOC_DA7210 if I2C |
@@ -85,7 +86,7 @@ config SND_SOC_ALL_CODECS | |||
85 | select SND_SOC_RT5645 if I2C | 86 | select SND_SOC_RT5645 if I2C |
86 | select SND_SOC_RT5651 if I2C | 87 | select SND_SOC_RT5651 if I2C |
87 | select SND_SOC_RT5670 if I2C | 88 | select SND_SOC_RT5670 if I2C |
88 | select SND_SOC_RT5677 if I2C | 89 | select SND_SOC_RT5677 if I2C && SPI_MASTER |
89 | select SND_SOC_SGTL5000 if I2C | 90 | select SND_SOC_SGTL5000 if I2C |
90 | select SND_SOC_SI476X if MFD_SI476X_CORE | 91 | select SND_SOC_SI476X if MFD_SI476X_CORE |
91 | select SND_SOC_SIRF_AUDIO_CODEC | 92 | select SND_SOC_SIRF_AUDIO_CODEC |
@@ -101,6 +102,7 @@ config SND_SOC_ALL_CODECS | |||
101 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 102 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
102 | select SND_SOC_TAS2552 if I2C | 103 | select SND_SOC_TAS2552 if I2C |
103 | select SND_SOC_TAS5086 if I2C | 104 | select SND_SOC_TAS5086 if I2C |
105 | select SND_SOC_TFA9879 if I2C | ||
104 | select SND_SOC_TLV320AIC23_I2C if I2C | 106 | select SND_SOC_TLV320AIC23_I2C if I2C |
105 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER | 107 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER |
106 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 108 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
@@ -109,6 +111,7 @@ config SND_SOC_ALL_CODECS | |||
109 | select SND_SOC_TLV320AIC3X if I2C | 111 | select SND_SOC_TLV320AIC3X if I2C |
110 | select SND_SOC_TPA6130A2 if I2C | 112 | select SND_SOC_TPA6130A2 if I2C |
111 | select SND_SOC_TLV320DAC33 if I2C | 113 | select SND_SOC_TLV320DAC33 if I2C |
114 | select SND_SOC_TS3A227E if I2C | ||
112 | select SND_SOC_TWL4030 if TWL4030_CORE | 115 | select SND_SOC_TWL4030 if TWL4030_CORE |
113 | select SND_SOC_TWL6040 if TWL6040_CORE | 116 | select SND_SOC_TWL6040 if TWL6040_CORE |
114 | select SND_SOC_UDA134X | 117 | select SND_SOC_UDA134X |
@@ -223,6 +226,7 @@ config SND_SOC_AD193X_I2C | |||
223 | select SND_SOC_AD193X | 226 | select SND_SOC_AD193X |
224 | 227 | ||
225 | config SND_SOC_AD1980 | 228 | config SND_SOC_AD1980 |
229 | select REGMAP_AC97 | ||
226 | tristate | 230 | tristate |
227 | 231 | ||
228 | config SND_SOC_AD73311 | 232 | config SND_SOC_AD73311 |
@@ -336,7 +340,8 @@ config SND_SOC_CS42L51 | |||
336 | tristate | 340 | tristate |
337 | 341 | ||
338 | config SND_SOC_CS42L51_I2C | 342 | config SND_SOC_CS42L51_I2C |
339 | tristate | 343 | tristate "Cirrus Logic CS42L51 CODEC (I2C)" |
344 | depends on I2C | ||
340 | select SND_SOC_CS42L51 | 345 | select SND_SOC_CS42L51 |
341 | 346 | ||
342 | config SND_SOC_CS42L52 | 347 | config SND_SOC_CS42L52 |
@@ -370,8 +375,19 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
370 | depends on SND_SOC_CS4270 | 375 | depends on SND_SOC_CS4270 |
371 | 376 | ||
372 | config SND_SOC_CS4271 | 377 | config SND_SOC_CS4271 |
373 | tristate "Cirrus Logic CS4271 CODEC" | 378 | tristate |
374 | depends on SND_SOC_I2C_AND_SPI | 379 | |
380 | config SND_SOC_CS4271_I2C | ||
381 | tristate "Cirrus Logic CS4271 CODEC (I2C)" | ||
382 | depends on I2C | ||
383 | select SND_SOC_CS4271 | ||
384 | select REGMAP_I2C | ||
385 | |||
386 | config SND_SOC_CS4271_SPI | ||
387 | tristate "Cirrus Logic CS4271 CODEC (SPI)" | ||
388 | depends on SPI_MASTER | ||
389 | select SND_SOC_CS4271 | ||
390 | select REGMAP_SPI | ||
375 | 391 | ||
376 | config SND_SOC_CS42XX8 | 392 | config SND_SOC_CS42XX8 |
377 | tristate | 393 | tristate |
@@ -487,7 +503,8 @@ config SND_SOC_RT286 | |||
487 | depends on I2C | 503 | depends on I2C |
488 | 504 | ||
489 | config SND_SOC_RT5631 | 505 | config SND_SOC_RT5631 |
490 | tristate | 506 | tristate "Realtek ALC5631/RT5631 CODEC" |
507 | depends on I2C | ||
491 | 508 | ||
492 | config SND_SOC_RT5640 | 509 | config SND_SOC_RT5640 |
493 | tristate | 510 | tristate |
@@ -504,6 +521,10 @@ config SND_SOC_RT5670 | |||
504 | config SND_SOC_RT5677 | 521 | config SND_SOC_RT5677 |
505 | tristate | 522 | tristate |
506 | 523 | ||
524 | config SND_SOC_RT5677_SPI | ||
525 | tristate | ||
526 | default SND_SOC_RT5677 | ||
527 | |||
507 | #Freescale sgtl5000 codec | 528 | #Freescale sgtl5000 codec |
508 | config SND_SOC_SGTL5000 | 529 | config SND_SOC_SGTL5000 |
509 | tristate "Freescale SGTL5000 CODEC" | 530 | tristate "Freescale SGTL5000 CODEC" |
@@ -577,15 +598,21 @@ config SND_SOC_TAS5086 | |||
577 | tristate "Texas Instruments TAS5086 speaker amplifier" | 598 | tristate "Texas Instruments TAS5086 speaker amplifier" |
578 | depends on I2C | 599 | depends on I2C |
579 | 600 | ||
601 | config SND_SOC_TFA9879 | ||
602 | tristate "NXP Semiconductors TFA9879 amplifier" | ||
603 | depends on I2C | ||
604 | |||
580 | config SND_SOC_TLV320AIC23 | 605 | config SND_SOC_TLV320AIC23 |
581 | tristate | 606 | tristate |
582 | 607 | ||
583 | config SND_SOC_TLV320AIC23_I2C | 608 | config SND_SOC_TLV320AIC23_I2C |
584 | tristate | 609 | tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C" |
610 | depends on I2C | ||
585 | select SND_SOC_TLV320AIC23 | 611 | select SND_SOC_TLV320AIC23 |
586 | 612 | ||
587 | config SND_SOC_TLV320AIC23_SPI | 613 | config SND_SOC_TLV320AIC23_SPI |
588 | tristate | 614 | tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI" |
615 | depends on SPI_MASTER | ||
589 | select SND_SOC_TLV320AIC23 | 616 | select SND_SOC_TLV320AIC23 |
590 | 617 | ||
591 | config SND_SOC_TLV320AIC26 | 618 | config SND_SOC_TLV320AIC26 |
@@ -607,6 +634,10 @@ config SND_SOC_TLV320AIC3X | |||
607 | config SND_SOC_TLV320DAC33 | 634 | config SND_SOC_TLV320DAC33 |
608 | tristate | 635 | tristate |
609 | 636 | ||
637 | config SND_SOC_TS3A227E | ||
638 | tristate "TI Headset/Mic detect and keypress chip" | ||
639 | depends on I2C | ||
640 | |||
610 | config SND_SOC_TWL4030 | 641 | config SND_SOC_TWL4030 |
611 | select MFD_TWL4030_AUDIO | 642 | select MFD_TWL4030_AUDIO |
612 | tristate | 643 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5dce451661e4..bbdfd1e1c182 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -41,6 +41,8 @@ snd-soc-cs42l73-objs := cs42l73.o | |||
41 | snd-soc-cs4265-objs := cs4265.o | 41 | snd-soc-cs4265-objs := cs4265.o |
42 | snd-soc-cs4270-objs := cs4270.o | 42 | snd-soc-cs4270-objs := cs4270.o |
43 | snd-soc-cs4271-objs := cs4271.o | 43 | snd-soc-cs4271-objs := cs4271.o |
44 | snd-soc-cs4271-i2c-objs := cs4271-i2c.o | ||
45 | snd-soc-cs4271-spi-objs := cs4271-spi.o | ||
44 | snd-soc-cs42xx8-objs := cs42xx8.o | 46 | snd-soc-cs42xx8-objs := cs42xx8.o |
45 | snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o | 47 | snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o |
46 | snd-soc-cx20442-objs := cx20442.o | 48 | snd-soc-cx20442-objs := cx20442.o |
@@ -80,6 +82,7 @@ snd-soc-rt5645-objs := rt5645.o | |||
80 | snd-soc-rt5651-objs := rt5651.o | 82 | snd-soc-rt5651-objs := rt5651.o |
81 | snd-soc-rt5670-objs := rt5670.o | 83 | snd-soc-rt5670-objs := rt5670.o |
82 | snd-soc-rt5677-objs := rt5677.o | 84 | snd-soc-rt5677-objs := rt5677.o |
85 | snd-soc-rt5677-spi-objs := rt5677-spi.o | ||
83 | snd-soc-sgtl5000-objs := sgtl5000.o | 86 | snd-soc-sgtl5000-objs := sgtl5000.o |
84 | snd-soc-alc5623-objs := alc5623.o | 87 | snd-soc-alc5623-objs := alc5623.o |
85 | snd-soc-alc5632-objs := alc5632.o | 88 | snd-soc-alc5632-objs := alc5632.o |
@@ -101,6 +104,7 @@ snd-soc-sta350-objs := sta350.o | |||
101 | snd-soc-sta529-objs := sta529.o | 104 | snd-soc-sta529-objs := sta529.o |
102 | snd-soc-stac9766-objs := stac9766.o | 105 | snd-soc-stac9766-objs := stac9766.o |
103 | snd-soc-tas5086-objs := tas5086.o | 106 | snd-soc-tas5086-objs := tas5086.o |
107 | snd-soc-tfa9879-objs := tfa9879.o | ||
104 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 108 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
105 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o | 109 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o |
106 | snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o | 110 | snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o |
@@ -109,6 +113,7 @@ snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o | |||
109 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o | 113 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o |
110 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 114 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
111 | snd-soc-tlv320dac33-objs := tlv320dac33.o | 115 | snd-soc-tlv320dac33-objs := tlv320dac33.o |
116 | snd-soc-ts3a227e-objs := ts3a227e.o | ||
112 | snd-soc-twl4030-objs := twl4030.o | 117 | snd-soc-twl4030-objs := twl4030.o |
113 | snd-soc-twl6040-objs := twl6040.o | 118 | snd-soc-twl6040-objs := twl6040.o |
114 | snd-soc-uda134x-objs := uda134x.o | 119 | snd-soc-uda134x-objs := uda134x.o |
@@ -217,6 +222,8 @@ obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o | |||
217 | obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o | 222 | obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o |
218 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 223 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
219 | obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o | 224 | obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o |
225 | obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o | ||
226 | obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o | ||
220 | obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o | 227 | obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o |
221 | obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o | 228 | obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o |
222 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 229 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
@@ -256,6 +263,7 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o | |||
256 | obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o | 263 | obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o |
257 | obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o | 264 | obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o |
258 | obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o | 265 | obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o |
266 | obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o | ||
259 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | 267 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o |
260 | obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o | 268 | obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o |
261 | obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o | 269 | obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o |
@@ -274,6 +282,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o | |||
274 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 282 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
275 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o | 283 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o |
276 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o | 284 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o |
285 | obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o | ||
277 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 286 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
278 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o | 287 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o |
279 | obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o | 288 | obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o |
@@ -282,6 +291,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o | |||
282 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o | 291 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o |
283 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | 292 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o |
284 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o | 293 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o |
294 | obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o | ||
285 | obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o | 295 | obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o |
286 | obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o | 296 | obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o |
287 | obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o | 297 | obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o |
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index fd43827bb856..7dfbc9921e91 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c | |||
@@ -126,13 +126,13 @@ struct ab8500_codec_drvdata_dbg { | |||
126 | /* Private data for AB8500 device-driver */ | 126 | /* Private data for AB8500 device-driver */ |
127 | struct ab8500_codec_drvdata { | 127 | struct ab8500_codec_drvdata { |
128 | struct regmap *regmap; | 128 | struct regmap *regmap; |
129 | struct mutex ctrl_lock; | ||
129 | 130 | ||
130 | /* Sidetone */ | 131 | /* Sidetone */ |
131 | long *sid_fir_values; | 132 | long *sid_fir_values; |
132 | enum sid_state sid_status; | 133 | enum sid_state sid_status; |
133 | 134 | ||
134 | /* ANC */ | 135 | /* ANC */ |
135 | struct mutex anc_lock; | ||
136 | long *anc_fir_values; | 136 | long *anc_fir_values; |
137 | long *anc_iir_values; | 137 | long *anc_iir_values; |
138 | enum anc_state anc_status; | 138 | enum anc_state anc_status; |
@@ -1129,9 +1129,9 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol, | |||
1129 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 1129 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
1130 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | 1130 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); |
1131 | 1131 | ||
1132 | mutex_lock(&codec->mutex); | 1132 | mutex_lock(&drvdata->ctrl_lock); |
1133 | ucontrol->value.integer.value[0] = drvdata->sid_status; | 1133 | ucontrol->value.integer.value[0] = drvdata->sid_status; |
1134 | mutex_unlock(&codec->mutex); | 1134 | mutex_unlock(&drvdata->ctrl_lock); |
1135 | 1135 | ||
1136 | return 0; | 1136 | return 0; |
1137 | } | 1137 | } |
@@ -1154,7 +1154,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, | |||
1154 | return -EIO; | 1154 | return -EIO; |
1155 | } | 1155 | } |
1156 | 1156 | ||
1157 | mutex_lock(&codec->mutex); | 1157 | mutex_lock(&drvdata->ctrl_lock); |
1158 | 1158 | ||
1159 | sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF); | 1159 | sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF); |
1160 | if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { | 1160 | if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { |
@@ -1185,7 +1185,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, | |||
1185 | drvdata->sid_status = SID_FIR_CONFIGURED; | 1185 | drvdata->sid_status = SID_FIR_CONFIGURED; |
1186 | 1186 | ||
1187 | out: | 1187 | out: |
1188 | mutex_unlock(&codec->mutex); | 1188 | mutex_unlock(&drvdata->ctrl_lock); |
1189 | 1189 | ||
1190 | dev_dbg(codec->dev, "%s: Exit\n", __func__); | 1190 | dev_dbg(codec->dev, "%s: Exit\n", __func__); |
1191 | 1191 | ||
@@ -1198,9 +1198,9 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol, | |||
1198 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 1198 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
1199 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | 1199 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); |
1200 | 1200 | ||
1201 | mutex_lock(&codec->mutex); | 1201 | mutex_lock(&drvdata->ctrl_lock); |
1202 | ucontrol->value.integer.value[0] = drvdata->anc_status; | 1202 | ucontrol->value.integer.value[0] = drvdata->anc_status; |
1203 | mutex_unlock(&codec->mutex); | 1203 | mutex_unlock(&drvdata->ctrl_lock); |
1204 | 1204 | ||
1205 | return 0; | 1205 | return 0; |
1206 | } | 1206 | } |
@@ -1217,7 +1217,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, | |||
1217 | 1217 | ||
1218 | dev_dbg(dev, "%s: Enter.\n", __func__); | 1218 | dev_dbg(dev, "%s: Enter.\n", __func__); |
1219 | 1219 | ||
1220 | mutex_lock(&drvdata->anc_lock); | 1220 | mutex_lock(&drvdata->ctrl_lock); |
1221 | 1221 | ||
1222 | req = ucontrol->value.integer.value[0]; | 1222 | req = ucontrol->value.integer.value[0]; |
1223 | if (req >= ARRAY_SIZE(enum_anc_state)) { | 1223 | if (req >= ARRAY_SIZE(enum_anc_state)) { |
@@ -1244,9 +1244,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, | |||
1244 | } | 1244 | } |
1245 | snd_soc_dapm_sync(&codec->dapm); | 1245 | snd_soc_dapm_sync(&codec->dapm); |
1246 | 1246 | ||
1247 | mutex_lock(&codec->mutex); | ||
1248 | anc_configure(codec, apply_fir, apply_iir); | 1247 | anc_configure(codec, apply_fir, apply_iir); |
1249 | mutex_unlock(&codec->mutex); | ||
1250 | 1248 | ||
1251 | if (apply_fir) { | 1249 | if (apply_fir) { |
1252 | if (drvdata->anc_status == ANC_IIR_CONFIGURED) | 1250 | if (drvdata->anc_status == ANC_IIR_CONFIGURED) |
@@ -1265,7 +1263,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, | |||
1265 | snd_soc_dapm_sync(&codec->dapm); | 1263 | snd_soc_dapm_sync(&codec->dapm); |
1266 | 1264 | ||
1267 | cleanup: | 1265 | cleanup: |
1268 | mutex_unlock(&drvdata->anc_lock); | 1266 | mutex_unlock(&drvdata->ctrl_lock); |
1269 | 1267 | ||
1270 | if (status < 0) | 1268 | if (status < 0) |
1271 | dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n", | 1269 | dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n", |
@@ -1294,14 +1292,15 @@ static int filter_control_get(struct snd_kcontrol *kcontrol, | |||
1294 | struct snd_ctl_elem_value *ucontrol) | 1292 | struct snd_ctl_elem_value *ucontrol) |
1295 | { | 1293 | { |
1296 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 1294 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
1295 | struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec); | ||
1297 | struct filter_control *fc = | 1296 | struct filter_control *fc = |
1298 | (struct filter_control *)kcontrol->private_value; | 1297 | (struct filter_control *)kcontrol->private_value; |
1299 | unsigned int i; | 1298 | unsigned int i; |
1300 | 1299 | ||
1301 | mutex_lock(&codec->mutex); | 1300 | mutex_lock(&drvdata->ctrl_lock); |
1302 | for (i = 0; i < fc->count; i++) | 1301 | for (i = 0; i < fc->count; i++) |
1303 | ucontrol->value.integer.value[i] = fc->value[i]; | 1302 | ucontrol->value.integer.value[i] = fc->value[i]; |
1304 | mutex_unlock(&codec->mutex); | 1303 | mutex_unlock(&drvdata->ctrl_lock); |
1305 | 1304 | ||
1306 | return 0; | 1305 | return 0; |
1307 | } | 1306 | } |
@@ -1310,14 +1309,15 @@ static int filter_control_put(struct snd_kcontrol *kcontrol, | |||
1310 | struct snd_ctl_elem_value *ucontrol) | 1309 | struct snd_ctl_elem_value *ucontrol) |
1311 | { | 1310 | { |
1312 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 1311 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
1312 | struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec); | ||
1313 | struct filter_control *fc = | 1313 | struct filter_control *fc = |
1314 | (struct filter_control *)kcontrol->private_value; | 1314 | (struct filter_control *)kcontrol->private_value; |
1315 | unsigned int i; | 1315 | unsigned int i; |
1316 | 1316 | ||
1317 | mutex_lock(&codec->mutex); | 1317 | mutex_lock(&drvdata->ctrl_lock); |
1318 | for (i = 0; i < fc->count; i++) | 1318 | for (i = 0; i < fc->count; i++) |
1319 | fc->value[i] = ucontrol->value.integer.value[i]; | 1319 | fc->value[i] = ucontrol->value.integer.value[i]; |
1320 | mutex_unlock(&codec->mutex); | 1320 | mutex_unlock(&drvdata->ctrl_lock); |
1321 | 1321 | ||
1322 | return 0; | 1322 | return 0; |
1323 | } | 1323 | } |
@@ -2545,7 +2545,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) | |||
2545 | 2545 | ||
2546 | (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); | 2546 | (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); |
2547 | 2547 | ||
2548 | mutex_init(&drvdata->anc_lock); | 2548 | mutex_init(&drvdata->ctrl_lock); |
2549 | 2549 | ||
2550 | return status; | 2550 | return status; |
2551 | } | 2551 | } |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index bd9b1839c8b0..c6e5a313ebf4 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -37,10 +37,11 @@ static int ac97_prepare(struct snd_pcm_substream *substream, | |||
37 | struct snd_soc_dai *dai) | 37 | struct snd_soc_dai *dai) |
38 | { | 38 | { |
39 | struct snd_soc_codec *codec = dai->codec; | 39 | struct snd_soc_codec *codec = dai->codec; |
40 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
40 | 41 | ||
41 | int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | 42 | int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
42 | AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; | 43 | AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; |
43 | return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate); | 44 | return snd_ac97_set_rate(ac97, reg, substream->runtime->rate); |
44 | } | 45 | } |
45 | 46 | ||
46 | #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 47 | #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
@@ -53,7 +54,6 @@ static const struct snd_soc_dai_ops ac97_dai_ops = { | |||
53 | 54 | ||
54 | static struct snd_soc_dai_driver ac97_dai = { | 55 | static struct snd_soc_dai_driver ac97_dai = { |
55 | .name = "ac97-hifi", | 56 | .name = "ac97-hifi", |
56 | .ac97_control = 1, | ||
57 | .playback = { | 57 | .playback = { |
58 | .stream_name = "AC97 Playback", | 58 | .stream_name = "AC97 Playback", |
59 | .channels_min = 1, | 59 | .channels_min = 1, |
@@ -71,6 +71,7 @@ static struct snd_soc_dai_driver ac97_dai = { | |||
71 | 71 | ||
72 | static int ac97_soc_probe(struct snd_soc_codec *codec) | 72 | static int ac97_soc_probe(struct snd_soc_codec *codec) |
73 | { | 73 | { |
74 | struct snd_ac97 *ac97; | ||
74 | struct snd_ac97_bus *ac97_bus; | 75 | struct snd_ac97_bus *ac97_bus; |
75 | struct snd_ac97_template ac97_template; | 76 | struct snd_ac97_template ac97_template; |
76 | int ret; | 77 | int ret; |
@@ -82,24 +83,31 @@ static int ac97_soc_probe(struct snd_soc_codec *codec) | |||
82 | return ret; | 83 | return ret; |
83 | 84 | ||
84 | memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); | 85 | memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); |
85 | ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97); | 86 | ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); |
86 | if (ret < 0) | 87 | if (ret < 0) |
87 | return ret; | 88 | return ret; |
88 | 89 | ||
90 | snd_soc_codec_set_drvdata(codec, ac97); | ||
91 | |||
89 | return 0; | 92 | return 0; |
90 | } | 93 | } |
91 | 94 | ||
92 | #ifdef CONFIG_PM | 95 | #ifdef CONFIG_PM |
93 | static int ac97_soc_suspend(struct snd_soc_codec *codec) | 96 | static int ac97_soc_suspend(struct snd_soc_codec *codec) |
94 | { | 97 | { |
95 | snd_ac97_suspend(codec->ac97); | 98 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
99 | |||
100 | snd_ac97_suspend(ac97); | ||
96 | 101 | ||
97 | return 0; | 102 | return 0; |
98 | } | 103 | } |
99 | 104 | ||
100 | static int ac97_soc_resume(struct snd_soc_codec *codec) | 105 | static int ac97_soc_resume(struct snd_soc_codec *codec) |
101 | { | 106 | { |
102 | snd_ac97_resume(codec->ac97); | 107 | |
108 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
109 | |||
110 | snd_ac97_resume(ac97); | ||
103 | 111 | ||
104 | return 0; | 112 | return 0; |
105 | } | 113 | } |
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 6844d0b2af68..387530b0b0fd 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c | |||
@@ -72,11 +72,13 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = { | |||
72 | }; | 72 | }; |
73 | 73 | ||
74 | static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { | 74 | static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { |
75 | SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1), | 75 | SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), |
76 | SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0), | ||
76 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), | 77 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), |
77 | SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), | 78 | SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), |
78 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), | 79 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), |
79 | SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), | 80 | SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), |
81 | SND_SOC_DAPM_VMID("VMID"), | ||
80 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), | 82 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), |
81 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), | 83 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), |
82 | SND_SOC_DAPM_OUTPUT("DAC3OUT"), | 84 | SND_SOC_DAPM_OUTPUT("DAC3OUT"), |
@@ -87,13 +89,15 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { | |||
87 | 89 | ||
88 | static const struct snd_soc_dapm_route audio_paths[] = { | 90 | static const struct snd_soc_dapm_route audio_paths[] = { |
89 | { "DAC", NULL, "SYSCLK" }, | 91 | { "DAC", NULL, "SYSCLK" }, |
92 | { "DAC Output", NULL, "DAC" }, | ||
93 | { "DAC Output", NULL, "VMID" }, | ||
90 | { "ADC", NULL, "SYSCLK" }, | 94 | { "ADC", NULL, "SYSCLK" }, |
91 | { "DAC", NULL, "ADC_PWR" }, | 95 | { "DAC", NULL, "ADC_PWR" }, |
92 | { "ADC", NULL, "ADC_PWR" }, | 96 | { "ADC", NULL, "ADC_PWR" }, |
93 | { "DAC1OUT", NULL, "DAC" }, | 97 | { "DAC1OUT", NULL, "DAC Output" }, |
94 | { "DAC2OUT", NULL, "DAC" }, | 98 | { "DAC2OUT", NULL, "DAC Output" }, |
95 | { "DAC3OUT", NULL, "DAC" }, | 99 | { "DAC3OUT", NULL, "DAC Output" }, |
96 | { "DAC4OUT", NULL, "DAC" }, | 100 | { "DAC4OUT", NULL, "DAC Output" }, |
97 | { "ADC", NULL, "ADC1IN" }, | 101 | { "ADC", NULL, "ADC1IN" }, |
98 | { "ADC", NULL, "ADC2IN" }, | 102 | { "ADC", NULL, "ADC2IN" }, |
99 | { "SYSCLK", NULL, "PLL_PWR" }, | 103 | { "SYSCLK", NULL, "PLL_PWR" }, |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 304d3003339a..2860eef8610c 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -24,34 +24,86 @@ | |||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | #include <linux/regmap.h> | ||
27 | #include <sound/core.h> | 28 | #include <sound/core.h> |
28 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
29 | #include <sound/ac97_codec.h> | 30 | #include <sound/ac97_codec.h> |
30 | #include <sound/initval.h> | 31 | #include <sound/initval.h> |
31 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
32 | 33 | ||
33 | #include "ad1980.h" | 34 | static const struct reg_default ad1980_reg_defaults[] = { |
35 | { 0x02, 0x8000 }, | ||
36 | { 0x04, 0x8000 }, | ||
37 | { 0x06, 0x8000 }, | ||
38 | { 0x0c, 0x8008 }, | ||
39 | { 0x0e, 0x8008 }, | ||
40 | { 0x10, 0x8808 }, | ||
41 | { 0x12, 0x8808 }, | ||
42 | { 0x16, 0x8808 }, | ||
43 | { 0x18, 0x8808 }, | ||
44 | { 0x1a, 0x0000 }, | ||
45 | { 0x1c, 0x8000 }, | ||
46 | { 0x20, 0x0000 }, | ||
47 | { 0x28, 0x03c7 }, | ||
48 | { 0x2c, 0xbb80 }, | ||
49 | { 0x2e, 0xbb80 }, | ||
50 | { 0x30, 0xbb80 }, | ||
51 | { 0x32, 0xbb80 }, | ||
52 | { 0x36, 0x8080 }, | ||
53 | { 0x38, 0x8080 }, | ||
54 | { 0x3a, 0x2000 }, | ||
55 | { 0x60, 0x0000 }, | ||
56 | { 0x62, 0x0000 }, | ||
57 | { 0x72, 0x0000 }, | ||
58 | { 0x74, 0x1001 }, | ||
59 | { 0x76, 0x0000 }, | ||
60 | }; | ||
34 | 61 | ||
35 | /* | 62 | static bool ad1980_readable_reg(struct device *dev, unsigned int reg) |
36 | * AD1980 register cache | 63 | { |
37 | */ | 64 | switch (reg) { |
38 | static const u16 ad1980_reg[] = { | 65 | case AC97_RESET ... AC97_MASTER_MONO: |
39 | 0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */ | 66 | case AC97_PHONE ... AC97_CD: |
40 | 0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */ | 67 | case AC97_AUX ... AC97_GENERAL_PURPOSE: |
41 | 0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */ | 68 | case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE: |
42 | 0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */ | 69 | case AC97_SPDIF: |
43 | 0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */ | 70 | case AC97_CODEC_CLASS_REV: |
44 | 0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */ | 71 | case AC97_PCI_SVID: |
45 | 0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */ | 72 | case AC97_AD_CODEC_CFG: |
46 | 0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */ | 73 | case AC97_AD_JACK_SPDIF: |
47 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 74 | case AC97_AD_SERIAL_CFG: |
48 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 75 | case AC97_VENDOR_ID1: |
49 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 76 | case AC97_VENDOR_ID2: |
50 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 77 | return true; |
51 | 0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */ | 78 | default: |
52 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 79 | return false; |
53 | 0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */ | 80 | } |
54 | 0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */ | 81 | } |
82 | |||
83 | static bool ad1980_writeable_reg(struct device *dev, unsigned int reg) | ||
84 | { | ||
85 | switch (reg) { | ||
86 | case AC97_VENDOR_ID1: | ||
87 | case AC97_VENDOR_ID2: | ||
88 | return false; | ||
89 | default: | ||
90 | return ad1980_readable_reg(dev, reg); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | static const struct regmap_config ad1980_regmap_config = { | ||
95 | .reg_bits = 16, | ||
96 | .reg_stride = 2, | ||
97 | .val_bits = 16, | ||
98 | .max_register = 0x7e, | ||
99 | .cache_type = REGCACHE_RBTREE, | ||
100 | |||
101 | .volatile_reg = regmap_ac97_default_volatile, | ||
102 | .readable_reg = ad1980_readable_reg, | ||
103 | .writeable_reg = ad1980_writeable_reg, | ||
104 | |||
105 | .reg_defaults = ad1980_reg_defaults, | ||
106 | .num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults), | ||
55 | }; | 107 | }; |
56 | 108 | ||
57 | static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", | 109 | static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", |
@@ -134,45 +186,8 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = { | |||
134 | { "HP_OUT_R", NULL, "Playback" }, | 186 | { "HP_OUT_R", NULL, "Playback" }, |
135 | }; | 187 | }; |
136 | 188 | ||
137 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
138 | unsigned int reg) | ||
139 | { | ||
140 | u16 *cache = codec->reg_cache; | ||
141 | |||
142 | switch (reg) { | ||
143 | case AC97_RESET: | ||
144 | case AC97_INT_PAGING: | ||
145 | case AC97_POWERDOWN: | ||
146 | case AC97_EXTENDED_STATUS: | ||
147 | case AC97_VENDOR_ID1: | ||
148 | case AC97_VENDOR_ID2: | ||
149 | return soc_ac97_ops->read(codec->ac97, reg); | ||
150 | default: | ||
151 | reg = reg >> 1; | ||
152 | |||
153 | if (reg >= ARRAY_SIZE(ad1980_reg)) | ||
154 | return -EINVAL; | ||
155 | |||
156 | return cache[reg]; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
161 | unsigned int val) | ||
162 | { | ||
163 | u16 *cache = codec->reg_cache; | ||
164 | |||
165 | soc_ac97_ops->write(codec->ac97, reg, val); | ||
166 | reg = reg >> 1; | ||
167 | if (reg < ARRAY_SIZE(ad1980_reg)) | ||
168 | cache[reg] = val; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static struct snd_soc_dai_driver ad1980_dai = { | 189 | static struct snd_soc_dai_driver ad1980_dai = { |
174 | .name = "ad1980-hifi", | 190 | .name = "ad1980-hifi", |
175 | .ac97_control = 1, | ||
176 | .playback = { | 191 | .playback = { |
177 | .stream_name = "Playback", | 192 | .stream_name = "Playback", |
178 | .channels_min = 2, | 193 | .channels_min = 2, |
@@ -189,108 +204,115 @@ static struct snd_soc_dai_driver ad1980_dai = { | |||
189 | 204 | ||
190 | static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) | 205 | static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) |
191 | { | 206 | { |
207 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
192 | unsigned int retry_cnt = 0; | 208 | unsigned int retry_cnt = 0; |
193 | 209 | ||
194 | do { | 210 | do { |
195 | if (try_warm && soc_ac97_ops->warm_reset) { | 211 | if (try_warm && soc_ac97_ops->warm_reset) { |
196 | soc_ac97_ops->warm_reset(codec->ac97); | 212 | soc_ac97_ops->warm_reset(ac97); |
197 | if (ac97_read(codec, AC97_RESET) == 0x0090) | 213 | if (snd_soc_read(codec, AC97_RESET) == 0x0090) |
198 | return 1; | 214 | return 1; |
199 | } | 215 | } |
200 | 216 | ||
201 | soc_ac97_ops->reset(codec->ac97); | 217 | soc_ac97_ops->reset(ac97); |
202 | /* | 218 | /* |
203 | * Set bit 16slot in register 74h, then every slot will has only | 219 | * Set bit 16slot in register 74h, then every slot will has only |
204 | * 16 bits. This command is sent out in 20bit mode, in which | 220 | * 16 bits. This command is sent out in 20bit mode, in which |
205 | * case the first nibble of data is eaten by the addr. (Tag is | 221 | * case the first nibble of data is eaten by the addr. (Tag is |
206 | * always 16 bit) | 222 | * always 16 bit) |
207 | */ | 223 | */ |
208 | ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); | 224 | snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900); |
209 | 225 | ||
210 | if (ac97_read(codec, AC97_RESET) == 0x0090) | 226 | if (snd_soc_read(codec, AC97_RESET) == 0x0090) |
211 | return 0; | 227 | return 0; |
212 | } while (retry_cnt++ < 10); | 228 | } while (retry_cnt++ < 10); |
213 | 229 | ||
214 | printk(KERN_ERR "AD1980 AC97 reset failed\n"); | 230 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); |
231 | |||
215 | return -EIO; | 232 | return -EIO; |
216 | } | 233 | } |
217 | 234 | ||
218 | static int ad1980_soc_probe(struct snd_soc_codec *codec) | 235 | static int ad1980_soc_probe(struct snd_soc_codec *codec) |
219 | { | 236 | { |
237 | struct snd_ac97 *ac97; | ||
238 | struct regmap *regmap; | ||
220 | int ret; | 239 | int ret; |
221 | u16 vendor_id2; | 240 | u16 vendor_id2; |
222 | u16 ext_status; | 241 | u16 ext_status; |
223 | 242 | ||
224 | printk(KERN_INFO "AD1980 SoC Audio Codec\n"); | 243 | ac97 = snd_soc_new_ac97_codec(codec); |
225 | 244 | if (IS_ERR(ac97)) { | |
226 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | 245 | ret = PTR_ERR(ac97); |
227 | if (ret < 0) { | 246 | dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); |
228 | printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); | ||
229 | return ret; | 247 | return ret; |
230 | } | 248 | } |
231 | 249 | ||
250 | regmap = regmap_init_ac97(ac97, &ad1980_regmap_config); | ||
251 | if (IS_ERR(regmap)) { | ||
252 | ret = PTR_ERR(regmap); | ||
253 | goto err_free_ac97; | ||
254 | } | ||
255 | |||
256 | snd_soc_codec_init_regmap(codec, regmap); | ||
257 | snd_soc_codec_set_drvdata(codec, ac97); | ||
258 | |||
232 | ret = ad1980_reset(codec, 0); | 259 | ret = ad1980_reset(codec, 0); |
233 | if (ret < 0) { | 260 | if (ret < 0) |
234 | printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); | ||
235 | goto reset_err; | 261 | goto reset_err; |
236 | } | ||
237 | 262 | ||
238 | /* Read out vendor ID to make sure it is ad1980 */ | 263 | /* Read out vendor ID to make sure it is ad1980 */ |
239 | if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) { | 264 | if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) { |
240 | ret = -ENODEV; | 265 | ret = -ENODEV; |
241 | goto reset_err; | 266 | goto reset_err; |
242 | } | 267 | } |
243 | 268 | ||
244 | vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); | 269 | vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2); |
245 | 270 | ||
246 | if (vendor_id2 != 0x5370) { | 271 | if (vendor_id2 != 0x5370) { |
247 | if (vendor_id2 != 0x5374) { | 272 | if (vendor_id2 != 0x5374) { |
248 | ret = -ENODEV; | 273 | ret = -ENODEV; |
249 | goto reset_err; | 274 | goto reset_err; |
250 | } else { | 275 | } else { |
251 | printk(KERN_WARNING "ad1980: " | 276 | dev_warn(codec->dev, |
252 | "Found AD1981 - only 2/2 IN/OUT Channels " | 277 | "Found AD1981 - only 2/2 IN/OUT Channels supported\n"); |
253 | "supported\n"); | ||
254 | } | 278 | } |
255 | } | 279 | } |
256 | 280 | ||
257 | /* unmute captures and playbacks volume */ | 281 | /* unmute captures and playbacks volume */ |
258 | ac97_write(codec, AC97_MASTER, 0x0000); | 282 | snd_soc_write(codec, AC97_MASTER, 0x0000); |
259 | ac97_write(codec, AC97_PCM, 0x0000); | 283 | snd_soc_write(codec, AC97_PCM, 0x0000); |
260 | ac97_write(codec, AC97_REC_GAIN, 0x0000); | 284 | snd_soc_write(codec, AC97_REC_GAIN, 0x0000); |
261 | ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); | 285 | snd_soc_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); |
262 | ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); | 286 | snd_soc_write(codec, AC97_SURROUND_MASTER, 0x0000); |
263 | 287 | ||
264 | /*power on LFE/CENTER/Surround DACs*/ | 288 | /*power on LFE/CENTER/Surround DACs*/ |
265 | ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); | 289 | ext_status = snd_soc_read(codec, AC97_EXTENDED_STATUS); |
266 | ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); | 290 | snd_soc_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); |
267 | |||
268 | snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls, | ||
269 | ARRAY_SIZE(ad1980_snd_ac97_controls)); | ||
270 | 291 | ||
271 | return 0; | 292 | return 0; |
272 | 293 | ||
273 | reset_err: | 294 | reset_err: |
274 | snd_soc_free_ac97_codec(codec); | 295 | snd_soc_codec_exit_regmap(codec); |
296 | err_free_ac97: | ||
297 | snd_soc_free_ac97_codec(ac97); | ||
275 | return ret; | 298 | return ret; |
276 | } | 299 | } |
277 | 300 | ||
278 | static int ad1980_soc_remove(struct snd_soc_codec *codec) | 301 | static int ad1980_soc_remove(struct snd_soc_codec *codec) |
279 | { | 302 | { |
280 | snd_soc_free_ac97_codec(codec); | 303 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
304 | |||
305 | snd_soc_codec_exit_regmap(codec); | ||
306 | snd_soc_free_ac97_codec(ac97); | ||
281 | return 0; | 307 | return 0; |
282 | } | 308 | } |
283 | 309 | ||
284 | static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { | 310 | static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { |
285 | .probe = ad1980_soc_probe, | 311 | .probe = ad1980_soc_probe, |
286 | .remove = ad1980_soc_remove, | 312 | .remove = ad1980_soc_remove, |
287 | .reg_cache_size = ARRAY_SIZE(ad1980_reg), | ||
288 | .reg_word_size = sizeof(u16), | ||
289 | .reg_cache_default = ad1980_reg, | ||
290 | .reg_cache_step = 2, | ||
291 | .write = ac97_write, | ||
292 | .read = ac97_read, | ||
293 | 313 | ||
314 | .controls = ad1980_snd_ac97_controls, | ||
315 | .num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls), | ||
294 | .dapm_widgets = ad1980_dapm_widgets, | 316 | .dapm_widgets = ad1980_dapm_widgets, |
295 | .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets), | 317 | .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets), |
296 | .dapm_routes = ad1980_dapm_routes, | 318 | .dapm_routes = ad1980_dapm_routes, |
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h deleted file mode 100644 index eb0af44ad3df..000000000000 --- a/sound/soc/codecs/ad1980.h +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | /* | ||
2 | * ad1980.h -- ad1980 Soc Audio driver | ||
3 | * | ||
4 | * WARNING: | ||
5 | * | ||
6 | * Because Analog Devices Inc. discontinued the ad1980 sound chip since | ||
7 | * Sep. 2009, this ad1980 driver is not maintained, tested and supported | ||
8 | * by ADI now. | ||
9 | */ | ||
10 | |||
11 | #ifndef _AD1980_H | ||
12 | #define _AD1980_H | ||
13 | /* Bit definition of Power-Down Control/Status Register */ | ||
14 | #define ADC 0x0001 | ||
15 | #define DAC 0x0002 | ||
16 | #define ANL 0x0004 | ||
17 | #define REF 0x0008 | ||
18 | #define PR0 0x0100 | ||
19 | #define PR1 0x0200 | ||
20 | #define PR2 0x0400 | ||
21 | #define PR3 0x0800 | ||
22 | #define PR4 0x1000 | ||
23 | #define PR5 0x2000 | ||
24 | #define PR6 0x4000 | ||
25 | |||
26 | #endif | ||
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 7c784ad3e8b2..783dcb57043a 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c | |||
@@ -551,7 +551,7 @@ static const struct snd_kcontrol_new adau1373_drc_controls[] = { | |||
551 | static int adau1373_pll_event(struct snd_soc_dapm_widget *w, | 551 | static int adau1373_pll_event(struct snd_soc_dapm_widget *w, |
552 | struct snd_kcontrol *kcontrol, int event) | 552 | struct snd_kcontrol *kcontrol, int event) |
553 | { | 553 | { |
554 | struct snd_soc_codec *codec = w->codec; | 554 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
555 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 555 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
556 | unsigned int pll_id = w->name[3] - '1'; | 556 | unsigned int pll_id = w->name[3] - '1'; |
557 | unsigned int val; | 557 | unsigned int val; |
@@ -823,7 +823,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = { | |||
823 | static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, | 823 | static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, |
824 | struct snd_soc_dapm_widget *sink) | 824 | struct snd_soc_dapm_widget *sink) |
825 | { | 825 | { |
826 | struct snd_soc_codec *codec = source->codec; | 826 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
827 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 827 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
828 | unsigned int dai; | 828 | unsigned int dai; |
829 | const char *clk; | 829 | const char *clk; |
@@ -844,7 +844,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, | |||
844 | static int adau1373_check_src(struct snd_soc_dapm_widget *source, | 844 | static int adau1373_check_src(struct snd_soc_dapm_widget *source, |
845 | struct snd_soc_dapm_widget *sink) | 845 | struct snd_soc_dapm_widget *sink) |
846 | { | 846 | { |
847 | struct snd_soc_codec *codec = source->codec; | 847 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
848 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 848 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
849 | unsigned int dai; | 849 | unsigned int dai; |
850 | 850 | ||
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 370b742117ef..d4e219b6b98f 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c | |||
@@ -22,9 +22,14 @@ | |||
22 | #include <sound/pcm_params.h> | 22 | #include <sound/pcm_params.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | 24 | ||
25 | #include <asm/unaligned.h> | ||
26 | |||
25 | #include "sigmadsp.h" | 27 | #include "sigmadsp.h" |
26 | #include "adau1701.h" | 28 | #include "adau1701.h" |
27 | 29 | ||
30 | #define ADAU1701_SAFELOAD_DATA(i) (0x0810 + (i)) | ||
31 | #define ADAU1701_SAFELOAD_ADDR(i) (0x0815 + (i)) | ||
32 | |||
28 | #define ADAU1701_DSPCTRL 0x081c | 33 | #define ADAU1701_DSPCTRL 0x081c |
29 | #define ADAU1701_SEROCTL 0x081e | 34 | #define ADAU1701_SEROCTL 0x081e |
30 | #define ADAU1701_SERICTL 0x081f | 35 | #define ADAU1701_SERICTL 0x081f |
@@ -42,6 +47,7 @@ | |||
42 | #define ADAU1701_DSPCTRL_CR (1 << 2) | 47 | #define ADAU1701_DSPCTRL_CR (1 << 2) |
43 | #define ADAU1701_DSPCTRL_DAM (1 << 3) | 48 | #define ADAU1701_DSPCTRL_DAM (1 << 3) |
44 | #define ADAU1701_DSPCTRL_ADM (1 << 4) | 49 | #define ADAU1701_DSPCTRL_ADM (1 << 4) |
50 | #define ADAU1701_DSPCTRL_IST (1 << 5) | ||
45 | #define ADAU1701_DSPCTRL_SR_48 0x00 | 51 | #define ADAU1701_DSPCTRL_SR_48 0x00 |
46 | #define ADAU1701_DSPCTRL_SR_96 0x01 | 52 | #define ADAU1701_DSPCTRL_SR_96 0x01 |
47 | #define ADAU1701_DSPCTRL_SR_192 0x02 | 53 | #define ADAU1701_DSPCTRL_SR_192 0x02 |
@@ -102,7 +108,10 @@ struct adau1701 { | |||
102 | unsigned int pll_clkdiv; | 108 | unsigned int pll_clkdiv; |
103 | unsigned int sysclk; | 109 | unsigned int sysclk; |
104 | struct regmap *regmap; | 110 | struct regmap *regmap; |
111 | struct i2c_client *client; | ||
105 | u8 pin_config[12]; | 112 | u8 pin_config[12]; |
113 | |||
114 | struct sigmadsp *sigmadsp; | ||
106 | }; | 115 | }; |
107 | 116 | ||
108 | static const struct snd_kcontrol_new adau1701_controls[] = { | 117 | static const struct snd_kcontrol_new adau1701_controls[] = { |
@@ -159,6 +168,7 @@ static bool adau1701_volatile_reg(struct device *dev, unsigned int reg) | |||
159 | { | 168 | { |
160 | switch (reg) { | 169 | switch (reg) { |
161 | case ADAU1701_DACSET: | 170 | case ADAU1701_DACSET: |
171 | case ADAU1701_DSPCTRL: | ||
162 | return true; | 172 | return true; |
163 | default: | 173 | default: |
164 | return false; | 174 | return false; |
@@ -238,12 +248,58 @@ static int adau1701_reg_read(void *context, unsigned int reg, | |||
238 | return 0; | 248 | return 0; |
239 | } | 249 | } |
240 | 250 | ||
241 | static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) | 251 | static int adau1701_safeload(struct sigmadsp *sigmadsp, unsigned int addr, |
252 | const uint8_t bytes[], size_t len) | ||
253 | { | ||
254 | struct i2c_client *client = to_i2c_client(sigmadsp->dev); | ||
255 | struct adau1701 *adau1701 = i2c_get_clientdata(client); | ||
256 | unsigned int val; | ||
257 | unsigned int i; | ||
258 | uint8_t buf[10]; | ||
259 | int ret; | ||
260 | |||
261 | ret = regmap_read(adau1701->regmap, ADAU1701_DSPCTRL, &val); | ||
262 | if (ret) | ||
263 | return ret; | ||
264 | |||
265 | if (val & ADAU1701_DSPCTRL_IST) | ||
266 | msleep(50); | ||
267 | |||
268 | for (i = 0; i < len / 4; i++) { | ||
269 | put_unaligned_le16(ADAU1701_SAFELOAD_DATA(i), buf); | ||
270 | buf[2] = 0x00; | ||
271 | memcpy(buf + 3, bytes + i * 4, 4); | ||
272 | ret = i2c_master_send(client, buf, 7); | ||
273 | if (ret < 0) | ||
274 | return ret; | ||
275 | else if (ret != 7) | ||
276 | return -EIO; | ||
277 | |||
278 | put_unaligned_le16(ADAU1701_SAFELOAD_ADDR(i), buf); | ||
279 | put_unaligned_le16(addr + i, buf + 2); | ||
280 | ret = i2c_master_send(client, buf, 4); | ||
281 | if (ret < 0) | ||
282 | return ret; | ||
283 | else if (ret != 4) | ||
284 | return -EIO; | ||
285 | } | ||
286 | |||
287 | return regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL, | ||
288 | ADAU1701_DSPCTRL_IST, ADAU1701_DSPCTRL_IST); | ||
289 | } | ||
290 | |||
291 | static const struct sigmadsp_ops adau1701_sigmadsp_ops = { | ||
292 | .safeload = adau1701_safeload, | ||
293 | }; | ||
294 | |||
295 | static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv, | ||
296 | unsigned int rate) | ||
242 | { | 297 | { |
243 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | 298 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); |
244 | struct i2c_client *client = to_i2c_client(codec->dev); | ||
245 | int ret; | 299 | int ret; |
246 | 300 | ||
301 | sigmadsp_reset(adau1701->sigmadsp); | ||
302 | |||
247 | if (clkdiv != ADAU1707_CLKDIV_UNSET && | 303 | if (clkdiv != ADAU1707_CLKDIV_UNSET && |
248 | gpio_is_valid(adau1701->gpio_pll_mode[0]) && | 304 | gpio_is_valid(adau1701->gpio_pll_mode[0]) && |
249 | gpio_is_valid(adau1701->gpio_pll_mode[1])) { | 305 | gpio_is_valid(adau1701->gpio_pll_mode[1])) { |
@@ -284,7 +340,7 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) | |||
284 | * know the correct PLL setup | 340 | * know the correct PLL setup |
285 | */ | 341 | */ |
286 | if (clkdiv != ADAU1707_CLKDIV_UNSET) { | 342 | if (clkdiv != ADAU1707_CLKDIV_UNSET) { |
287 | ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); | 343 | ret = sigmadsp_setup(adau1701->sigmadsp, rate); |
288 | if (ret) { | 344 | if (ret) { |
289 | dev_warn(codec->dev, "Failed to load firmware\n"); | 345 | dev_warn(codec->dev, "Failed to load firmware\n"); |
290 | return ret; | 346 | return ret; |
@@ -385,7 +441,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream, | |||
385 | * firmware upload. | 441 | * firmware upload. |
386 | */ | 442 | */ |
387 | if (clkdiv != adau1701->pll_clkdiv) { | 443 | if (clkdiv != adau1701->pll_clkdiv) { |
388 | ret = adau1701_reset(codec, clkdiv); | 444 | ret = adau1701_reset(codec, clkdiv, params_rate(params)); |
389 | if (ret < 0) | 445 | if (ret < 0) |
390 | return ret; | 446 | return ret; |
391 | } | 447 | } |
@@ -554,6 +610,14 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, | |||
554 | return 0; | 610 | return 0; |
555 | } | 611 | } |
556 | 612 | ||
613 | static int adau1701_startup(struct snd_pcm_substream *substream, | ||
614 | struct snd_soc_dai *dai) | ||
615 | { | ||
616 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(dai->codec); | ||
617 | |||
618 | return sigmadsp_restrict_params(adau1701->sigmadsp, substream); | ||
619 | } | ||
620 | |||
557 | #define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ | 621 | #define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ |
558 | SNDRV_PCM_RATE_192000) | 622 | SNDRV_PCM_RATE_192000) |
559 | 623 | ||
@@ -564,6 +628,7 @@ static const struct snd_soc_dai_ops adau1701_dai_ops = { | |||
564 | .set_fmt = adau1701_set_dai_fmt, | 628 | .set_fmt = adau1701_set_dai_fmt, |
565 | .hw_params = adau1701_hw_params, | 629 | .hw_params = adau1701_hw_params, |
566 | .digital_mute = adau1701_digital_mute, | 630 | .digital_mute = adau1701_digital_mute, |
631 | .startup = adau1701_startup, | ||
567 | }; | 632 | }; |
568 | 633 | ||
569 | static struct snd_soc_dai_driver adau1701_dai = { | 634 | static struct snd_soc_dai_driver adau1701_dai = { |
@@ -600,6 +665,10 @@ static int adau1701_probe(struct snd_soc_codec *codec) | |||
600 | unsigned int val; | 665 | unsigned int val; |
601 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | 666 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); |
602 | 667 | ||
668 | ret = sigmadsp_attach(adau1701->sigmadsp, &codec->component); | ||
669 | if (ret) | ||
670 | return ret; | ||
671 | |||
603 | /* | 672 | /* |
604 | * Let the pll_clkdiv variable default to something that won't happen | 673 | * Let the pll_clkdiv variable default to something that won't happen |
605 | * at runtime. That way, we can postpone the firmware download from | 674 | * at runtime. That way, we can postpone the firmware download from |
@@ -609,7 +678,7 @@ static int adau1701_probe(struct snd_soc_codec *codec) | |||
609 | adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; | 678 | adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; |
610 | 679 | ||
611 | /* initalize with pre-configured pll mode settings */ | 680 | /* initalize with pre-configured pll mode settings */ |
612 | ret = adau1701_reset(codec, adau1701->pll_clkdiv); | 681 | ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0); |
613 | if (ret < 0) | 682 | if (ret < 0) |
614 | return ret; | 683 | return ret; |
615 | 684 | ||
@@ -667,6 +736,7 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
667 | if (!adau1701) | 736 | if (!adau1701) |
668 | return -ENOMEM; | 737 | return -ENOMEM; |
669 | 738 | ||
739 | adau1701->client = client; | ||
670 | adau1701->regmap = devm_regmap_init(dev, NULL, client, | 740 | adau1701->regmap = devm_regmap_init(dev, NULL, client, |
671 | &adau1701_regmap); | 741 | &adau1701_regmap); |
672 | if (IS_ERR(adau1701->regmap)) | 742 | if (IS_ERR(adau1701->regmap)) |
@@ -722,6 +792,12 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
722 | adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; | 792 | adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; |
723 | 793 | ||
724 | i2c_set_clientdata(client, adau1701); | 794 | i2c_set_clientdata(client, adau1701); |
795 | |||
796 | adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, | ||
797 | &adau1701_sigmadsp_ops, ADAU1701_FIRMWARE); | ||
798 | if (IS_ERR(adau1701->sigmadsp)) | ||
799 | return PTR_ERR(adau1701->sigmadsp); | ||
800 | |||
725 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, | 801 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, |
726 | &adau1701_dai, 1); | 802 | &adau1701_dai, 1); |
727 | return ret; | 803 | return ret; |
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 91f60282fd2f..a1baeee160f4 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c | |||
@@ -255,7 +255,8 @@ static const struct snd_kcontrol_new adau1761_input_mux_control = | |||
255 | static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w, | 255 | static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w, |
256 | struct snd_kcontrol *kcontrol, int event) | 256 | struct snd_kcontrol *kcontrol, int event) |
257 | { | 257 | { |
258 | struct adau *adau = snd_soc_codec_get_drvdata(w->codec); | 258 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
259 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
259 | 260 | ||
260 | /* After any power changes have been made the dejitter circuit | 261 | /* After any power changes have been made the dejitter circuit |
261 | * has to be reinitialized. */ | 262 | * has to be reinitialized. */ |
@@ -702,11 +703,6 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec) | |||
702 | ARRAY_SIZE(adau1761_dapm_routes)); | 703 | ARRAY_SIZE(adau1761_dapm_routes)); |
703 | if (ret) | 704 | if (ret) |
704 | return ret; | 705 | return ret; |
705 | |||
706 | ret = adau17x1_load_firmware(adau, codec->dev, | ||
707 | ADAU1761_FIRMWARE); | ||
708 | if (ret) | ||
709 | dev_warn(codec->dev, "Failed to firmware\n"); | ||
710 | } | 706 | } |
711 | 707 | ||
712 | ret = adau17x1_add_routes(codec); | 708 | ret = adau17x1_add_routes(codec); |
@@ -775,16 +771,20 @@ int adau1761_probe(struct device *dev, struct regmap *regmap, | |||
775 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) | 771 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) |
776 | { | 772 | { |
777 | struct snd_soc_dai_driver *dai_drv; | 773 | struct snd_soc_dai_driver *dai_drv; |
774 | const char *firmware_name; | ||
778 | int ret; | 775 | int ret; |
779 | 776 | ||
780 | ret = adau17x1_probe(dev, regmap, type, switch_mode); | 777 | if (type == ADAU1361) { |
781 | if (ret) | ||
782 | return ret; | ||
783 | |||
784 | if (type == ADAU1361) | ||
785 | dai_drv = &adau1361_dai_driver; | 778 | dai_drv = &adau1361_dai_driver; |
786 | else | 779 | firmware_name = NULL; |
780 | } else { | ||
787 | dai_drv = &adau1761_dai_driver; | 781 | dai_drv = &adau1761_dai_driver; |
782 | firmware_name = ADAU1761_FIRMWARE; | ||
783 | } | ||
784 | |||
785 | ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name); | ||
786 | if (ret) | ||
787 | return ret; | ||
788 | 788 | ||
789 | return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1); | 789 | return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1); |
790 | } | 790 | } |
@@ -798,6 +798,7 @@ const struct regmap_config adau1761_regmap_config = { | |||
798 | .num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults), | 798 | .num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults), |
799 | .readable_reg = adau1761_readable_register, | 799 | .readable_reg = adau1761_readable_register, |
800 | .volatile_reg = adau17x1_volatile_register, | 800 | .volatile_reg = adau17x1_volatile_register, |
801 | .precious_reg = adau17x1_precious_register, | ||
801 | .cache_type = REGCACHE_RBTREE, | 802 | .cache_type = REGCACHE_RBTREE, |
802 | }; | 803 | }; |
803 | EXPORT_SYMBOL_GPL(adau1761_regmap_config); | 804 | EXPORT_SYMBOL_GPL(adau1761_regmap_config); |
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index e9fc00fb13dd..35581f43fa6d 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c | |||
@@ -174,7 +174,7 @@ static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = { | |||
174 | static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w, | 174 | static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w, |
175 | struct snd_kcontrol *kcontrol, int event) | 175 | struct snd_kcontrol *kcontrol, int event) |
176 | { | 176 | { |
177 | struct snd_soc_codec *codec = w->codec; | 177 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
178 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 178 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
179 | 179 | ||
180 | /* After any power changes have been made the dejitter circuit | 180 | /* After any power changes have been made the dejitter circuit |
@@ -385,7 +385,6 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) | |||
385 | { | 385 | { |
386 | struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); | 386 | struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); |
387 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 387 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
388 | const char *firmware; | ||
389 | int ret; | 388 | int ret; |
390 | 389 | ||
391 | ret = adau17x1_add_widgets(codec); | 390 | ret = adau17x1_add_widgets(codec); |
@@ -422,25 +421,10 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) | |||
422 | return ret; | 421 | return ret; |
423 | } | 422 | } |
424 | 423 | ||
425 | switch (adau->type) { | ||
426 | case ADAU1381: | ||
427 | firmware = ADAU1381_FIRMWARE; | ||
428 | break; | ||
429 | case ADAU1781: | ||
430 | firmware = ADAU1781_FIRMWARE; | ||
431 | break; | ||
432 | default: | ||
433 | return -EINVAL; | ||
434 | } | ||
435 | |||
436 | ret = adau17x1_add_routes(codec); | 424 | ret = adau17x1_add_routes(codec); |
437 | if (ret < 0) | 425 | if (ret < 0) |
438 | return ret; | 426 | return ret; |
439 | 427 | ||
440 | ret = adau17x1_load_firmware(adau, codec->dev, firmware); | ||
441 | if (ret) | ||
442 | dev_warn(codec->dev, "Failed to load firmware\n"); | ||
443 | |||
444 | return 0; | 428 | return 0; |
445 | } | 429 | } |
446 | 430 | ||
@@ -488,6 +472,7 @@ const struct regmap_config adau1781_regmap_config = { | |||
488 | .num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults), | 472 | .num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults), |
489 | .readable_reg = adau1781_readable_register, | 473 | .readable_reg = adau1781_readable_register, |
490 | .volatile_reg = adau17x1_volatile_register, | 474 | .volatile_reg = adau17x1_volatile_register, |
475 | .precious_reg = adau17x1_precious_register, | ||
491 | .cache_type = REGCACHE_RBTREE, | 476 | .cache_type = REGCACHE_RBTREE, |
492 | }; | 477 | }; |
493 | EXPORT_SYMBOL_GPL(adau1781_regmap_config); | 478 | EXPORT_SYMBOL_GPL(adau1781_regmap_config); |
@@ -495,9 +480,21 @@ EXPORT_SYMBOL_GPL(adau1781_regmap_config); | |||
495 | int adau1781_probe(struct device *dev, struct regmap *regmap, | 480 | int adau1781_probe(struct device *dev, struct regmap *regmap, |
496 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) | 481 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) |
497 | { | 482 | { |
483 | const char *firmware_name; | ||
498 | int ret; | 484 | int ret; |
499 | 485 | ||
500 | ret = adau17x1_probe(dev, regmap, type, switch_mode); | 486 | switch (type) { |
487 | case ADAU1381: | ||
488 | firmware_name = ADAU1381_FIRMWARE; | ||
489 | break; | ||
490 | case ADAU1781: | ||
491 | firmware_name = ADAU1781_FIRMWARE; | ||
492 | break; | ||
493 | default: | ||
494 | return -EINVAL; | ||
495 | } | ||
496 | |||
497 | ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name); | ||
501 | if (ret) | 498 | if (ret) |
502 | return ret; | 499 | return ret; |
503 | 500 | ||
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 3e16c1c64115..fa2e690e51c8 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c | |||
@@ -61,7 +61,8 @@ static const struct snd_kcontrol_new adau17x1_controls[] = { | |||
61 | static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, | 61 | static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, |
62 | struct snd_kcontrol *kcontrol, int event) | 62 | struct snd_kcontrol *kcontrol, int event) |
63 | { | 63 | { |
64 | struct adau *adau = snd_soc_codec_get_drvdata(w->codec); | 64 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
65 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
65 | int ret; | 66 | int ret; |
66 | 67 | ||
67 | if (SND_SOC_DAPM_EVENT_ON(event)) { | 68 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
@@ -307,6 +308,7 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, | |||
307 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 308 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
308 | unsigned int val, div, dsp_div; | 309 | unsigned int val, div, dsp_div; |
309 | unsigned int freq; | 310 | unsigned int freq; |
311 | int ret; | ||
310 | 312 | ||
311 | if (adau->clk_src == ADAU17X1_CLK_SRC_PLL) | 313 | if (adau->clk_src == ADAU17X1_CLK_SRC_PLL) |
312 | freq = adau->pll_freq; | 314 | freq = adau->pll_freq; |
@@ -356,6 +358,12 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, | |||
356 | regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div); | 358 | regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div); |
357 | } | 359 | } |
358 | 360 | ||
361 | if (adau->sigmadsp) { | ||
362 | ret = adau17x1_setup_firmware(adau, params_rate(params)); | ||
363 | if (ret < 0) | ||
364 | return ret; | ||
365 | } | ||
366 | |||
359 | if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) | 367 | if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) |
360 | return 0; | 368 | return 0; |
361 | 369 | ||
@@ -661,12 +669,24 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai, | |||
661 | return 0; | 669 | return 0; |
662 | } | 670 | } |
663 | 671 | ||
672 | static int adau17x1_startup(struct snd_pcm_substream *substream, | ||
673 | struct snd_soc_dai *dai) | ||
674 | { | ||
675 | struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); | ||
676 | |||
677 | if (adau->sigmadsp) | ||
678 | return sigmadsp_restrict_params(adau->sigmadsp, substream); | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
664 | const struct snd_soc_dai_ops adau17x1_dai_ops = { | 683 | const struct snd_soc_dai_ops adau17x1_dai_ops = { |
665 | .hw_params = adau17x1_hw_params, | 684 | .hw_params = adau17x1_hw_params, |
666 | .set_sysclk = adau17x1_set_dai_sysclk, | 685 | .set_sysclk = adau17x1_set_dai_sysclk, |
667 | .set_fmt = adau17x1_set_dai_fmt, | 686 | .set_fmt = adau17x1_set_dai_fmt, |
668 | .set_pll = adau17x1_set_dai_pll, | 687 | .set_pll = adau17x1_set_dai_pll, |
669 | .set_tdm_slot = adau17x1_set_dai_tdm_slot, | 688 | .set_tdm_slot = adau17x1_set_dai_tdm_slot, |
689 | .startup = adau17x1_startup, | ||
670 | }; | 690 | }; |
671 | EXPORT_SYMBOL_GPL(adau17x1_dai_ops); | 691 | EXPORT_SYMBOL_GPL(adau17x1_dai_ops); |
672 | 692 | ||
@@ -687,8 +707,22 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, | |||
687 | } | 707 | } |
688 | EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage); | 708 | EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage); |
689 | 709 | ||
710 | bool adau17x1_precious_register(struct device *dev, unsigned int reg) | ||
711 | { | ||
712 | /* SigmaDSP parameter memory */ | ||
713 | if (reg < 0x400) | ||
714 | return true; | ||
715 | |||
716 | return false; | ||
717 | } | ||
718 | EXPORT_SYMBOL_GPL(adau17x1_precious_register); | ||
719 | |||
690 | bool adau17x1_readable_register(struct device *dev, unsigned int reg) | 720 | bool adau17x1_readable_register(struct device *dev, unsigned int reg) |
691 | { | 721 | { |
722 | /* SigmaDSP parameter memory */ | ||
723 | if (reg < 0x400) | ||
724 | return true; | ||
725 | |||
692 | switch (reg) { | 726 | switch (reg) { |
693 | case ADAU17X1_CLOCK_CONTROL: | 727 | case ADAU17X1_CLOCK_CONTROL: |
694 | case ADAU17X1_PLL_CONTROL: | 728 | case ADAU17X1_PLL_CONTROL: |
@@ -745,8 +779,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg) | |||
745 | } | 779 | } |
746 | EXPORT_SYMBOL_GPL(adau17x1_volatile_register); | 780 | EXPORT_SYMBOL_GPL(adau17x1_volatile_register); |
747 | 781 | ||
748 | int adau17x1_load_firmware(struct adau *adau, struct device *dev, | 782 | int adau17x1_setup_firmware(struct adau *adau, unsigned int rate) |
749 | const char *firmware) | ||
750 | { | 783 | { |
751 | int ret; | 784 | int ret; |
752 | int dspsr; | 785 | int dspsr; |
@@ -758,7 +791,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev, | |||
758 | regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1); | 791 | regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1); |
759 | regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf); | 792 | regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf); |
760 | 793 | ||
761 | ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware); | 794 | ret = sigmadsp_setup(adau->sigmadsp, rate); |
762 | if (ret) { | 795 | if (ret) { |
763 | regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0); | 796 | regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0); |
764 | return ret; | 797 | return ret; |
@@ -767,7 +800,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev, | |||
767 | 800 | ||
768 | return 0; | 801 | return 0; |
769 | } | 802 | } |
770 | EXPORT_SYMBOL_GPL(adau17x1_load_firmware); | 803 | EXPORT_SYMBOL_GPL(adau17x1_setup_firmware); |
771 | 804 | ||
772 | int adau17x1_add_widgets(struct snd_soc_codec *codec) | 805 | int adau17x1_add_widgets(struct snd_soc_codec *codec) |
773 | { | 806 | { |
@@ -787,8 +820,21 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec) | |||
787 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 820 | ret = snd_soc_dapm_new_controls(&codec->dapm, |
788 | adau17x1_dsp_dapm_widgets, | 821 | adau17x1_dsp_dapm_widgets, |
789 | ARRAY_SIZE(adau17x1_dsp_dapm_widgets)); | 822 | ARRAY_SIZE(adau17x1_dsp_dapm_widgets)); |
823 | if (ret) | ||
824 | return ret; | ||
825 | |||
826 | if (!adau->sigmadsp) | ||
827 | return 0; | ||
828 | |||
829 | ret = sigmadsp_attach(adau->sigmadsp, &codec->component); | ||
830 | if (ret) { | ||
831 | dev_err(codec->dev, "Failed to attach firmware: %d\n", | ||
832 | ret); | ||
833 | return ret; | ||
834 | } | ||
790 | } | 835 | } |
791 | return ret; | 836 | |
837 | return 0; | ||
792 | } | 838 | } |
793 | EXPORT_SYMBOL_GPL(adau17x1_add_widgets); | 839 | EXPORT_SYMBOL_GPL(adau17x1_add_widgets); |
794 | 840 | ||
@@ -829,7 +875,8 @@ int adau17x1_resume(struct snd_soc_codec *codec) | |||
829 | EXPORT_SYMBOL_GPL(adau17x1_resume); | 875 | EXPORT_SYMBOL_GPL(adau17x1_resume); |
830 | 876 | ||
831 | int adau17x1_probe(struct device *dev, struct regmap *regmap, | 877 | int adau17x1_probe(struct device *dev, struct regmap *regmap, |
832 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) | 878 | enum adau17x1_type type, void (*switch_mode)(struct device *dev), |
879 | const char *firmware_name) | ||
833 | { | 880 | { |
834 | struct adau *adau; | 881 | struct adau *adau; |
835 | 882 | ||
@@ -846,6 +893,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, | |||
846 | 893 | ||
847 | dev_set_drvdata(dev, adau); | 894 | dev_set_drvdata(dev, adau); |
848 | 895 | ||
896 | if (firmware_name) { | ||
897 | adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL, | ||
898 | firmware_name); | ||
899 | if (IS_ERR(adau->sigmadsp)) { | ||
900 | dev_warn(dev, "Could not find firmware file: %ld\n", | ||
901 | PTR_ERR(adau->sigmadsp)); | ||
902 | adau->sigmadsp = NULL; | ||
903 | } | ||
904 | } | ||
905 | |||
849 | if (switch_mode) | 906 | if (switch_mode) |
850 | switch_mode(dev); | 907 | switch_mode(dev); |
851 | 908 | ||
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index e4a557fd7155..e13583e6ff56 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h | |||
@@ -4,6 +4,8 @@ | |||
4 | #include <linux/regmap.h> | 4 | #include <linux/regmap.h> |
5 | #include <linux/platform_data/adau17x1.h> | 5 | #include <linux/platform_data/adau17x1.h> |
6 | 6 | ||
7 | #include "sigmadsp.h" | ||
8 | |||
7 | enum adau17x1_type { | 9 | enum adau17x1_type { |
8 | ADAU1361, | 10 | ADAU1361, |
9 | ADAU1761, | 11 | ADAU1761, |
@@ -42,22 +44,24 @@ struct adau { | |||
42 | bool dsp_bypass[2]; | 44 | bool dsp_bypass[2]; |
43 | 45 | ||
44 | struct regmap *regmap; | 46 | struct regmap *regmap; |
47 | struct sigmadsp *sigmadsp; | ||
45 | }; | 48 | }; |
46 | 49 | ||
47 | int adau17x1_add_widgets(struct snd_soc_codec *codec); | 50 | int adau17x1_add_widgets(struct snd_soc_codec *codec); |
48 | int adau17x1_add_routes(struct snd_soc_codec *codec); | 51 | int adau17x1_add_routes(struct snd_soc_codec *codec); |
49 | int adau17x1_probe(struct device *dev, struct regmap *regmap, | 52 | int adau17x1_probe(struct device *dev, struct regmap *regmap, |
50 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)); | 53 | enum adau17x1_type type, void (*switch_mode)(struct device *dev), |
54 | const char *firmware_name); | ||
51 | int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, | 55 | int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, |
52 | enum adau17x1_micbias_voltage micbias); | 56 | enum adau17x1_micbias_voltage micbias); |
53 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); | 57 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); |
54 | bool adau17x1_volatile_register(struct device *dev, unsigned int reg); | 58 | bool adau17x1_volatile_register(struct device *dev, unsigned int reg); |
59 | bool adau17x1_precious_register(struct device *dev, unsigned int reg); | ||
55 | int adau17x1_resume(struct snd_soc_codec *codec); | 60 | int adau17x1_resume(struct snd_soc_codec *codec); |
56 | 61 | ||
57 | extern const struct snd_soc_dai_ops adau17x1_dai_ops; | 62 | extern const struct snd_soc_dai_ops adau17x1_dai_ops; |
58 | 63 | ||
59 | int adau17x1_load_firmware(struct adau *adau, struct device *dev, | 64 | int adau17x1_setup_firmware(struct adau *adau, unsigned int rate); |
60 | const char *firmware); | ||
61 | bool adau17x1_has_dsp(struct adau *adau); | 65 | bool adau17x1_has_dsp(struct adau *adau); |
62 | 66 | ||
63 | #define ADAU17X1_CLOCK_CONTROL 0x4000 | 67 | #define ADAU17X1_CLOCK_CONTROL 0x4000 |
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index ce3cdca9fc62..b67480f1b1aa 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c | |||
@@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { | |||
212 | static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, | 212 | static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, |
213 | struct snd_soc_dapm_widget *sink) | 213 | struct snd_soc_dapm_widget *sink) |
214 | { | 214 | { |
215 | struct snd_soc_codec *codec = source->codec; | 215 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
216 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 216 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
217 | const char *clk; | 217 | const char *clk; |
218 | 218 | ||
@@ -236,7 +236,7 @@ static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, | |||
236 | static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, | 236 | static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, |
237 | struct snd_soc_dapm_widget *sink) | 237 | struct snd_soc_dapm_widget *sink) |
238 | { | 238 | { |
239 | struct snd_soc_codec *codec = source->codec; | 239 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
240 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 240 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
241 | 241 | ||
242 | return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; | 242 | return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; |
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 30e297890fec..9130d916f2f4 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -373,33 +373,9 @@ static struct snd_soc_dai_driver ak4535_dai = { | |||
373 | .ops = &ak4535_dai_ops, | 373 | .ops = &ak4535_dai_ops, |
374 | }; | 374 | }; |
375 | 375 | ||
376 | static int ak4535_suspend(struct snd_soc_codec *codec) | ||
377 | { | ||
378 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int ak4535_resume(struct snd_soc_codec *codec) | 376 | static int ak4535_resume(struct snd_soc_codec *codec) |
383 | { | 377 | { |
384 | snd_soc_cache_sync(codec); | 378 | snd_soc_cache_sync(codec); |
385 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int ak4535_probe(struct snd_soc_codec *codec) | ||
390 | { | ||
391 | /* power on device */ | ||
392 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
393 | |||
394 | snd_soc_add_codec_controls(codec, ak4535_snd_controls, | ||
395 | ARRAY_SIZE(ak4535_snd_controls)); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | /* power down chip */ | ||
400 | static int ak4535_remove(struct snd_soc_codec *codec) | ||
401 | { | ||
402 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
403 | return 0; | 379 | return 0; |
404 | } | 380 | } |
405 | 381 | ||
@@ -416,11 +392,12 @@ static const struct regmap_config ak4535_regmap = { | |||
416 | }; | 392 | }; |
417 | 393 | ||
418 | static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { | 394 | static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { |
419 | .probe = ak4535_probe, | ||
420 | .remove = ak4535_remove, | ||
421 | .suspend = ak4535_suspend, | ||
422 | .resume = ak4535_resume, | 395 | .resume = ak4535_resume, |
423 | .set_bias_level = ak4535_set_bias_level, | 396 | .set_bias_level = ak4535_set_bias_level, |
397 | .suspend_bias_off = true, | ||
398 | |||
399 | .controls = ak4535_snd_controls, | ||
400 | .num_controls = ARRAY_SIZE(ak4535_snd_controls), | ||
424 | .dapm_widgets = ak4535_dapm_widgets, | 401 | .dapm_widgets = ak4535_dapm_widgets, |
425 | .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), | 402 | .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), |
426 | .dapm_routes = ak4535_audio_map, | 403 | .dapm_routes = ak4535_audio_map, |
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 7afe8f482088..70861c7b1631 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c | |||
@@ -505,39 +505,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = { | |||
505 | }, | 505 | }, |
506 | }; | 506 | }; |
507 | 507 | ||
508 | static int ak4641_suspend(struct snd_soc_codec *codec) | ||
509 | { | ||
510 | ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static int ak4641_resume(struct snd_soc_codec *codec) | ||
515 | { | ||
516 | ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static int ak4641_probe(struct snd_soc_codec *codec) | ||
521 | { | ||
522 | /* power on device */ | ||
523 | ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | static int ak4641_remove(struct snd_soc_codec *codec) | ||
529 | { | ||
530 | ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | |||
536 | static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { | 508 | static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { |
537 | .probe = ak4641_probe, | ||
538 | .remove = ak4641_remove, | ||
539 | .suspend = ak4641_suspend, | ||
540 | .resume = ak4641_resume, | ||
541 | .controls = ak4641_snd_controls, | 509 | .controls = ak4641_snd_controls, |
542 | .num_controls = ARRAY_SIZE(ak4641_snd_controls), | 510 | .num_controls = ARRAY_SIZE(ak4641_snd_controls), |
543 | .dapm_widgets = ak4641_dapm_widgets, | 511 | .dapm_widgets = ak4641_dapm_widgets, |
@@ -545,6 +513,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { | |||
545 | .dapm_routes = ak4641_audio_map, | 513 | .dapm_routes = ak4641_audio_map, |
546 | .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), | 514 | .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), |
547 | .set_bias_level = ak4641_set_bias_level, | 515 | .set_bias_level = ak4641_set_bias_level, |
516 | .suspend_bias_off = true, | ||
548 | }; | 517 | }; |
549 | 518 | ||
550 | static const struct regmap_config ak4641_regmap = { | 519 | static const struct regmap_config ak4641_regmap = { |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 041712592e29..dde8b49c19ad 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -491,23 +491,7 @@ static int ak4642_resume(struct snd_soc_codec *codec) | |||
491 | return 0; | 491 | return 0; |
492 | } | 492 | } |
493 | 493 | ||
494 | |||
495 | static int ak4642_probe(struct snd_soc_codec *codec) | ||
496 | { | ||
497 | ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int ak4642_remove(struct snd_soc_codec *codec) | ||
503 | { | ||
504 | ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { | 494 | static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { |
509 | .probe = ak4642_probe, | ||
510 | .remove = ak4642_remove, | ||
511 | .resume = ak4642_resume, | 495 | .resume = ak4642_resume, |
512 | .set_bias_level = ak4642_set_bias_level, | 496 | .set_bias_level = ak4642_set_bias_level, |
513 | .controls = ak4642_snd_controls, | 497 | .controls = ak4642_snd_controls, |
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 998fa0c5a0b9..686cacb0e835 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c | |||
@@ -611,20 +611,7 @@ static struct snd_soc_dai_driver ak4671_dai = { | |||
611 | .ops = &ak4671_dai_ops, | 611 | .ops = &ak4671_dai_ops, |
612 | }; | 612 | }; |
613 | 613 | ||
614 | static int ak4671_probe(struct snd_soc_codec *codec) | ||
615 | { | ||
616 | return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
617 | } | ||
618 | |||
619 | static int ak4671_remove(struct snd_soc_codec *codec) | ||
620 | { | ||
621 | ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { | 614 | static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { |
626 | .probe = ak4671_probe, | ||
627 | .remove = ak4671_remove, | ||
628 | .set_bias_level = ak4671_set_bias_level, | 615 | .set_bias_level = ak4671_set_bias_level, |
629 | .controls = ak4671_snd_controls, | 616 | .controls = ak4671_snd_controls, |
630 | .num_controls = ARRAY_SIZE(ak4671_snd_controls), | 617 | .num_controls = ARRAY_SIZE(ak4671_snd_controls), |
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 9d0755aa1d16..bdf8c5ac8ca4 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c | |||
@@ -866,7 +866,6 @@ static int alc5623_suspend(struct snd_soc_codec *codec) | |||
866 | { | 866 | { |
867 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); | 867 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); |
868 | 868 | ||
869 | alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
870 | regcache_cache_only(alc5623->regmap, true); | 869 | regcache_cache_only(alc5623->regmap, true); |
871 | 870 | ||
872 | return 0; | 871 | return 0; |
@@ -887,15 +886,6 @@ static int alc5623_resume(struct snd_soc_codec *codec) | |||
887 | return ret; | 886 | return ret; |
888 | } | 887 | } |
889 | 888 | ||
890 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
891 | |||
892 | /* charge alc5623 caps */ | ||
893 | if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { | ||
894 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
895 | codec->dapm.bias_level = SND_SOC_BIAS_ON; | ||
896 | alc5623_set_bias_level(codec, codec->dapm.bias_level); | ||
897 | } | ||
898 | |||
899 | return 0; | 889 | return 0; |
900 | } | 890 | } |
901 | 891 | ||
@@ -906,9 +896,6 @@ static int alc5623_probe(struct snd_soc_codec *codec) | |||
906 | 896 | ||
907 | alc5623_reset(codec); | 897 | alc5623_reset(codec); |
908 | 898 | ||
909 | /* power on device */ | ||
910 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
911 | |||
912 | if (alc5623->add_ctrl) { | 899 | if (alc5623->add_ctrl) { |
913 | snd_soc_write(codec, ALC5623_ADD_CTRL_REG, | 900 | snd_soc_write(codec, ALC5623_ADD_CTRL_REG, |
914 | alc5623->add_ctrl); | 901 | alc5623->add_ctrl); |
@@ -964,19 +951,12 @@ static int alc5623_probe(struct snd_soc_codec *codec) | |||
964 | return 0; | 951 | return 0; |
965 | } | 952 | } |
966 | 953 | ||
967 | /* power down chip */ | ||
968 | static int alc5623_remove(struct snd_soc_codec *codec) | ||
969 | { | ||
970 | alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
971 | return 0; | ||
972 | } | ||
973 | |||
974 | static struct snd_soc_codec_driver soc_codec_device_alc5623 = { | 954 | static struct snd_soc_codec_driver soc_codec_device_alc5623 = { |
975 | .probe = alc5623_probe, | 955 | .probe = alc5623_probe, |
976 | .remove = alc5623_remove, | ||
977 | .suspend = alc5623_suspend, | 956 | .suspend = alc5623_suspend, |
978 | .resume = alc5623_resume, | 957 | .resume = alc5623_resume, |
979 | .set_bias_level = alc5623_set_bias_level, | 958 | .set_bias_level = alc5623_set_bias_level, |
959 | .suspend_bias_off = true, | ||
980 | }; | 960 | }; |
981 | 961 | ||
982 | static const struct regmap_config alc5623_regmap = { | 962 | static const struct regmap_config alc5623_regmap = { |
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 85942ca36cbf..d1fdbc266631 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c | |||
@@ -1038,23 +1038,15 @@ static struct snd_soc_dai_driver alc5632_dai = { | |||
1038 | }; | 1038 | }; |
1039 | 1039 | ||
1040 | #ifdef CONFIG_PM | 1040 | #ifdef CONFIG_PM |
1041 | static int alc5632_suspend(struct snd_soc_codec *codec) | ||
1042 | { | ||
1043 | alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | static int alc5632_resume(struct snd_soc_codec *codec) | 1041 | static int alc5632_resume(struct snd_soc_codec *codec) |
1048 | { | 1042 | { |
1049 | struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); | 1043 | struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); |
1050 | 1044 | ||
1051 | regcache_sync(alc5632->regmap); | 1045 | regcache_sync(alc5632->regmap); |
1052 | 1046 | ||
1053 | alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1054 | return 0; | 1047 | return 0; |
1055 | } | 1048 | } |
1056 | #else | 1049 | #else |
1057 | #define alc5632_suspend NULL | ||
1058 | #define alc5632_resume NULL | 1050 | #define alc5632_resume NULL |
1059 | #endif | 1051 | #endif |
1060 | 1052 | ||
@@ -1062,9 +1054,6 @@ static int alc5632_probe(struct snd_soc_codec *codec) | |||
1062 | { | 1054 | { |
1063 | struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); | 1055 | struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); |
1064 | 1056 | ||
1065 | /* power on device */ | ||
1066 | alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1067 | |||
1068 | switch (alc5632->id) { | 1057 | switch (alc5632->id) { |
1069 | case 0x5c: | 1058 | case 0x5c: |
1070 | snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls, | 1059 | snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls, |
@@ -1077,19 +1066,12 @@ static int alc5632_probe(struct snd_soc_codec *codec) | |||
1077 | return 0; | 1066 | return 0; |
1078 | } | 1067 | } |
1079 | 1068 | ||
1080 | /* power down chip */ | ||
1081 | static int alc5632_remove(struct snd_soc_codec *codec) | ||
1082 | { | ||
1083 | alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
1087 | static struct snd_soc_codec_driver soc_codec_device_alc5632 = { | 1069 | static struct snd_soc_codec_driver soc_codec_device_alc5632 = { |
1088 | .probe = alc5632_probe, | 1070 | .probe = alc5632_probe, |
1089 | .remove = alc5632_remove, | ||
1090 | .suspend = alc5632_suspend, | ||
1091 | .resume = alc5632_resume, | 1071 | .resume = alc5632_resume, |
1092 | .set_bias_level = alc5632_set_bias_level, | 1072 | .set_bias_level = alc5632_set_bias_level, |
1073 | .suspend_bias_off = true, | ||
1074 | |||
1093 | .controls = alc5632_snd_controls, | 1075 | .controls = alc5632_snd_controls, |
1094 | .num_controls = ARRAY_SIZE(alc5632_snd_controls), | 1076 | .num_controls = ARRAY_SIZE(alc5632_snd_controls), |
1095 | .dapm_widgets = alc5632_dapm_widgets, | 1077 | .dapm_widgets = alc5632_dapm_widgets, |
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0c05e7a7945f..9550d7433ad0 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -61,6 +61,11 @@ | |||
61 | #define ARIZONA_FLL_MIN_OUTDIV 2 | 61 | #define ARIZONA_FLL_MIN_OUTDIV 2 |
62 | #define ARIZONA_FLL_MAX_OUTDIV 7 | 62 | #define ARIZONA_FLL_MAX_OUTDIV 7 |
63 | 63 | ||
64 | #define ARIZONA_FMT_DSP_MODE_A 0 | ||
65 | #define ARIZONA_FMT_DSP_MODE_B 1 | ||
66 | #define ARIZONA_FMT_I2S_MODE 2 | ||
67 | #define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3 | ||
68 | |||
64 | #define arizona_fll_err(_fll, fmt, ...) \ | 69 | #define arizona_fll_err(_fll, fmt, ...) \ |
65 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) | 70 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) |
66 | #define arizona_fll_warn(_fll, fmt, ...) \ | 71 | #define arizona_fll_warn(_fll, fmt, ...) \ |
@@ -648,7 +653,7 @@ SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum, | |||
648 | EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); | 653 | EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); |
649 | 654 | ||
650 | static const char * const arizona_in_dmic_osr_text[] = { | 655 | static const char * const arizona_in_dmic_osr_text[] = { |
651 | "1.536MHz", "3.072MHz", "6.144MHz", | 656 | "1.536MHz", "3.072MHz", "6.144MHz", "768kHz", |
652 | }; | 657 | }; |
653 | 658 | ||
654 | const struct soc_enum arizona_in_dmic_osr[] = { | 659 | const struct soc_enum arizona_in_dmic_osr[] = { |
@@ -946,10 +951,26 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
946 | 951 | ||
947 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 952 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
948 | case SND_SOC_DAIFMT_DSP_A: | 953 | case SND_SOC_DAIFMT_DSP_A: |
949 | mode = 0; | 954 | mode = ARIZONA_FMT_DSP_MODE_A; |
955 | break; | ||
956 | case SND_SOC_DAIFMT_DSP_B: | ||
957 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) | ||
958 | != SND_SOC_DAIFMT_CBM_CFM) { | ||
959 | arizona_aif_err(dai, "DSP_B not valid in slave mode\n"); | ||
960 | return -EINVAL; | ||
961 | } | ||
962 | mode = ARIZONA_FMT_DSP_MODE_B; | ||
950 | break; | 963 | break; |
951 | case SND_SOC_DAIFMT_I2S: | 964 | case SND_SOC_DAIFMT_I2S: |
952 | mode = 2; | 965 | mode = ARIZONA_FMT_I2S_MODE; |
966 | break; | ||
967 | case SND_SOC_DAIFMT_LEFT_J: | ||
968 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) | ||
969 | != SND_SOC_DAIFMT_CBM_CFM) { | ||
970 | arizona_aif_err(dai, "LEFT_J not valid in slave mode\n"); | ||
971 | return -EINVAL; | ||
972 | } | ||
973 | mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE; | ||
953 | break; | 974 | break; |
954 | default: | 975 | default: |
955 | arizona_aif_err(dai, "Unsupported DAI format %d\n", | 976 | arizona_aif_err(dai, "Unsupported DAI format %d\n", |
@@ -1164,13 +1185,13 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, | |||
1164 | { 0x80, 0x0 }, | 1185 | { 0x80, 0x0 }, |
1165 | }; | 1186 | }; |
1166 | 1187 | ||
1167 | mutex_lock(&codec->mutex); | 1188 | mutex_lock(&arizona->dac_comp_lock); |
1168 | 1189 | ||
1169 | dac_comp[1].def = arizona->dac_comp_coeff; | 1190 | dac_comp[1].def = arizona->dac_comp_coeff; |
1170 | if (rate >= 176400) | 1191 | if (rate >= 176400) |
1171 | dac_comp[2].def = arizona->dac_comp_enabled; | 1192 | dac_comp[2].def = arizona->dac_comp_enabled; |
1172 | 1193 | ||
1173 | mutex_unlock(&codec->mutex); | 1194 | mutex_unlock(&arizona->dac_comp_lock); |
1174 | 1195 | ||
1175 | regmap_multi_reg_write(arizona->regmap, | 1196 | regmap_multi_reg_write(arizona->regmap, |
1176 | dac_comp, | 1197 | dac_comp, |
@@ -1298,7 +1319,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
1298 | 1319 | ||
1299 | /* Force multiple of 2 channels for I2S mode */ | 1320 | /* Force multiple of 2 channels for I2S mode */ |
1300 | val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); | 1321 | val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); |
1301 | if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) { | 1322 | val &= ARIZONA_AIF1_FMT_MASK; |
1323 | if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) { | ||
1302 | arizona_aif_dbg(dai, "Forcing stereo mode\n"); | 1324 | arizona_aif_dbg(dai, "Forcing stereo mode\n"); |
1303 | bclk_target /= channels; | 1325 | bclk_target /= channels; |
1304 | bclk_target *= channels + 1; | 1326 | bclk_target *= channels + 1; |
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 537327c7f7f1..8d638e8aa8eb 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c | |||
@@ -62,14 +62,10 @@ static int cq93vc_mute(struct snd_soc_dai *dai, int mute) | |||
62 | static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 62 | static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
63 | int clk_id, unsigned int freq, int dir) | 63 | int clk_id, unsigned int freq, int dir) |
64 | { | 64 | { |
65 | struct snd_soc_codec *codec = codec_dai->codec; | ||
66 | struct davinci_vc *davinci_vc = codec->dev->platform_data; | ||
67 | |||
68 | switch (freq) { | 65 | switch (freq) { |
69 | case 22579200: | 66 | case 22579200: |
70 | case 27000000: | 67 | case 27000000: |
71 | case 33868800: | 68 | case 33868800: |
72 | davinci_vc->cq93vc.sysclk = freq; | ||
73 | return 0; | 69 | return 0; |
74 | } | 70 | } |
75 | 71 | ||
@@ -126,32 +122,6 @@ static struct snd_soc_dai_driver cq93vc_dai = { | |||
126 | .ops = &cq93vc_dai_ops, | 122 | .ops = &cq93vc_dai_ops, |
127 | }; | 123 | }; |
128 | 124 | ||
129 | static int cq93vc_resume(struct snd_soc_codec *codec) | ||
130 | { | ||
131 | cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int cq93vc_probe(struct snd_soc_codec *codec) | ||
137 | { | ||
138 | struct davinci_vc *davinci_vc = codec->dev->platform_data; | ||
139 | |||
140 | davinci_vc->cq93vc.codec = codec; | ||
141 | |||
142 | /* Off, with power on */ | ||
143 | cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int cq93vc_remove(struct snd_soc_codec *codec) | ||
149 | { | ||
150 | cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static struct regmap *cq93vc_get_regmap(struct device *dev) | 125 | static struct regmap *cq93vc_get_regmap(struct device *dev) |
156 | { | 126 | { |
157 | struct davinci_vc *davinci_vc = dev->platform_data; | 127 | struct davinci_vc *davinci_vc = dev->platform_data; |
@@ -161,9 +131,6 @@ static struct regmap *cq93vc_get_regmap(struct device *dev) | |||
161 | 131 | ||
162 | static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { | 132 | static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { |
163 | .set_bias_level = cq93vc_set_bias_level, | 133 | .set_bias_level = cq93vc_set_bias_level, |
164 | .probe = cq93vc_probe, | ||
165 | .remove = cq93vc_remove, | ||
166 | .resume = cq93vc_resume, | ||
167 | .get_regmap = cq93vc_get_regmap, | 134 | .get_regmap = cq93vc_get_regmap, |
168 | .controls = cq93vc_snd_controls, | 135 | .controls = cq93vc_snd_controls, |
169 | .num_controls = ARRAY_SIZE(cq93vc_snd_controls), | 136 | .num_controls = ARRAY_SIZE(cq93vc_snd_controls), |
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 4fdd47d700e3..ce6086835ebd 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include "cs4265.h" | 32 | #include "cs4265.h" |
33 | 33 | ||
34 | struct cs4265_private { | 34 | struct cs4265_private { |
35 | struct device *dev; | ||
36 | struct regmap *regmap; | 35 | struct regmap *regmap; |
37 | struct gpio_desc *reset_gpio; | 36 | struct gpio_desc *reset_gpio; |
38 | u8 format; | 37 | u8 format; |
@@ -598,7 +597,6 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, | |||
598 | GFP_KERNEL); | 597 | GFP_KERNEL); |
599 | if (cs4265 == NULL) | 598 | if (cs4265 == NULL) |
600 | return -ENOMEM; | 599 | return -ENOMEM; |
601 | cs4265->dev = &i2c_client->dev; | ||
602 | 600 | ||
603 | cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap); | 601 | cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap); |
604 | if (IS_ERR(cs4265->regmap)) { | 602 | if (IS_ERR(cs4265->regmap)) { |
diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c new file mode 100644 index 000000000000..b264da030340 --- /dev/null +++ b/sound/soc/codecs/cs4271-i2c.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * CS4271 I2C audio driver | ||
3 | * | ||
4 | * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru> | ||
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 | #include <linux/module.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include "cs4271.h" | ||
22 | |||
23 | static int cs4271_i2c_probe(struct i2c_client *client, | ||
24 | const struct i2c_device_id *id) | ||
25 | { | ||
26 | struct regmap_config config; | ||
27 | |||
28 | config = cs4271_regmap_config; | ||
29 | config.reg_bits = 8; | ||
30 | config.val_bits = 8; | ||
31 | |||
32 | return cs4271_probe(&client->dev, | ||
33 | devm_regmap_init_i2c(client, &config)); | ||
34 | } | ||
35 | |||
36 | static int cs4271_i2c_remove(struct i2c_client *client) | ||
37 | { | ||
38 | snd_soc_unregister_codec(&client->dev); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static const struct i2c_device_id cs4271_i2c_id[] = { | ||
43 | { "cs4271", 0 }, | ||
44 | { } | ||
45 | }; | ||
46 | MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); | ||
47 | |||
48 | static struct i2c_driver cs4271_i2c_driver = { | ||
49 | .driver = { | ||
50 | .name = "cs4271", | ||
51 | .owner = THIS_MODULE, | ||
52 | .of_match_table = of_match_ptr(cs4271_dt_ids), | ||
53 | }, | ||
54 | .probe = cs4271_i2c_probe, | ||
55 | .remove = cs4271_i2c_remove, | ||
56 | .id_table = cs4271_i2c_id, | ||
57 | }; | ||
58 | module_i2c_driver(cs4271_i2c_driver); | ||
59 | |||
60 | MODULE_DESCRIPTION("ASoC CS4271 I2C Driver"); | ||
61 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); | ||
62 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs4271-spi.c b/sound/soc/codecs/cs4271-spi.c new file mode 100644 index 000000000000..acd49d86e706 --- /dev/null +++ b/sound/soc/codecs/cs4271-spi.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * CS4271 SPI audio driver | ||
3 | * | ||
4 | * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru> | ||
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 | #include <linux/module.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include "cs4271.h" | ||
22 | |||
23 | static int cs4271_spi_probe(struct spi_device *spi) | ||
24 | { | ||
25 | struct regmap_config config; | ||
26 | |||
27 | config = cs4271_regmap_config; | ||
28 | config.reg_bits = 16; | ||
29 | config.val_bits = 8; | ||
30 | config.read_flag_mask = 0x21; | ||
31 | config.write_flag_mask = 0x20; | ||
32 | |||
33 | return cs4271_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); | ||
34 | } | ||
35 | |||
36 | static int cs4271_spi_remove(struct spi_device *spi) | ||
37 | { | ||
38 | snd_soc_unregister_codec(&spi->dev); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static struct spi_driver cs4271_spi_driver = { | ||
43 | .driver = { | ||
44 | .name = "cs4271", | ||
45 | .owner = THIS_MODULE, | ||
46 | .of_match_table = of_match_ptr(cs4271_dt_ids), | ||
47 | }, | ||
48 | .probe = cs4271_spi_probe, | ||
49 | .remove = cs4271_spi_remove, | ||
50 | }; | ||
51 | module_spi_driver(cs4271_spi_driver); | ||
52 | |||
53 | MODULE_DESCRIPTION("ASoC CS4271 SPI Driver"); | ||
54 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); | ||
55 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 93cec52f4733..79a4efcb894c 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c | |||
@@ -23,8 +23,6 @@ | |||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/gpio.h> | 25 | #include <linux/gpio.h> |
26 | #include <linux/i2c.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | #include <linux/of.h> | 26 | #include <linux/of.h> |
29 | #include <linux/of_device.h> | 27 | #include <linux/of_device.h> |
30 | #include <linux/of_gpio.h> | 28 | #include <linux/of_gpio.h> |
@@ -32,6 +30,7 @@ | |||
32 | #include <sound/soc.h> | 30 | #include <sound/soc.h> |
33 | #include <sound/tlv.h> | 31 | #include <sound/tlv.h> |
34 | #include <sound/cs4271.h> | 32 | #include <sound/cs4271.h> |
33 | #include "cs4271.h" | ||
35 | 34 | ||
36 | #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | 35 | #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
37 | SNDRV_PCM_FMTBIT_S24_LE | \ | 36 | SNDRV_PCM_FMTBIT_S24_LE | \ |
@@ -527,14 +526,15 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec) | |||
527 | #endif /* CONFIG_PM */ | 526 | #endif /* CONFIG_PM */ |
528 | 527 | ||
529 | #ifdef CONFIG_OF | 528 | #ifdef CONFIG_OF |
530 | static const struct of_device_id cs4271_dt_ids[] = { | 529 | const struct of_device_id cs4271_dt_ids[] = { |
531 | { .compatible = "cirrus,cs4271", }, | 530 | { .compatible = "cirrus,cs4271", }, |
532 | { } | 531 | { } |
533 | }; | 532 | }; |
534 | MODULE_DEVICE_TABLE(of, cs4271_dt_ids); | 533 | MODULE_DEVICE_TABLE(of, cs4271_dt_ids); |
534 | EXPORT_SYMBOL_GPL(cs4271_dt_ids); | ||
535 | #endif | 535 | #endif |
536 | 536 | ||
537 | static int cs4271_probe(struct snd_soc_codec *codec) | 537 | static int cs4271_codec_probe(struct snd_soc_codec *codec) |
538 | { | 538 | { |
539 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | 539 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); |
540 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; | 540 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; |
@@ -587,7 +587,7 @@ static int cs4271_probe(struct snd_soc_codec *codec) | |||
587 | return 0; | 587 | return 0; |
588 | } | 588 | } |
589 | 589 | ||
590 | static int cs4271_remove(struct snd_soc_codec *codec) | 590 | static int cs4271_codec_remove(struct snd_soc_codec *codec) |
591 | { | 591 | { |
592 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | 592 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); |
593 | 593 | ||
@@ -599,8 +599,8 @@ static int cs4271_remove(struct snd_soc_codec *codec) | |||
599 | }; | 599 | }; |
600 | 600 | ||
601 | static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { | 601 | static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { |
602 | .probe = cs4271_probe, | 602 | .probe = cs4271_codec_probe, |
603 | .remove = cs4271_remove, | 603 | .remove = cs4271_codec_remove, |
604 | .suspend = cs4271_soc_suspend, | 604 | .suspend = cs4271_soc_suspend, |
605 | .resume = cs4271_soc_resume, | 605 | .resume = cs4271_soc_resume, |
606 | 606 | ||
@@ -642,14 +642,8 @@ static int cs4271_common_probe(struct device *dev, | |||
642 | return 0; | 642 | return 0; |
643 | } | 643 | } |
644 | 644 | ||
645 | #if defined(CONFIG_SPI_MASTER) | 645 | const struct regmap_config cs4271_regmap_config = { |
646 | |||
647 | static const struct regmap_config cs4271_spi_regmap = { | ||
648 | .reg_bits = 16, | ||
649 | .val_bits = 8, | ||
650 | .max_register = CS4271_LASTREG, | 646 | .max_register = CS4271_LASTREG, |
651 | .read_flag_mask = 0x21, | ||
652 | .write_flag_mask = 0x20, | ||
653 | 647 | ||
654 | .reg_defaults = cs4271_reg_defaults, | 648 | .reg_defaults = cs4271_reg_defaults, |
655 | .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), | 649 | .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), |
@@ -657,140 +651,27 @@ static const struct regmap_config cs4271_spi_regmap = { | |||
657 | 651 | ||
658 | .volatile_reg = cs4271_volatile_reg, | 652 | .volatile_reg = cs4271_volatile_reg, |
659 | }; | 653 | }; |
654 | EXPORT_SYMBOL_GPL(cs4271_regmap_config); | ||
660 | 655 | ||
661 | static int cs4271_spi_probe(struct spi_device *spi) | 656 | int cs4271_probe(struct device *dev, struct regmap *regmap) |
662 | { | 657 | { |
663 | struct cs4271_private *cs4271; | 658 | struct cs4271_private *cs4271; |
664 | int ret; | 659 | int ret; |
665 | 660 | ||
666 | ret = cs4271_common_probe(&spi->dev, &cs4271); | 661 | if (IS_ERR(regmap)) |
667 | if (ret < 0) | 662 | return PTR_ERR(regmap); |
668 | return ret; | ||
669 | |||
670 | spi_set_drvdata(spi, cs4271); | ||
671 | cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); | ||
672 | if (IS_ERR(cs4271->regmap)) | ||
673 | return PTR_ERR(cs4271->regmap); | ||
674 | |||
675 | return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271, | ||
676 | &cs4271_dai, 1); | ||
677 | } | ||
678 | |||
679 | static int cs4271_spi_remove(struct spi_device *spi) | ||
680 | { | ||
681 | snd_soc_unregister_codec(&spi->dev); | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static struct spi_driver cs4271_spi_driver = { | ||
686 | .driver = { | ||
687 | .name = "cs4271", | ||
688 | .owner = THIS_MODULE, | ||
689 | .of_match_table = of_match_ptr(cs4271_dt_ids), | ||
690 | }, | ||
691 | .probe = cs4271_spi_probe, | ||
692 | .remove = cs4271_spi_remove, | ||
693 | }; | ||
694 | #endif /* defined(CONFIG_SPI_MASTER) */ | ||
695 | |||
696 | #if IS_ENABLED(CONFIG_I2C) | ||
697 | static const struct i2c_device_id cs4271_i2c_id[] = { | ||
698 | {"cs4271", 0}, | ||
699 | {} | ||
700 | }; | ||
701 | MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); | ||
702 | 663 | ||
703 | static const struct regmap_config cs4271_i2c_regmap = { | 664 | ret = cs4271_common_probe(dev, &cs4271); |
704 | .reg_bits = 8, | ||
705 | .val_bits = 8, | ||
706 | .max_register = CS4271_LASTREG, | ||
707 | |||
708 | .reg_defaults = cs4271_reg_defaults, | ||
709 | .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), | ||
710 | .cache_type = REGCACHE_RBTREE, | ||
711 | |||
712 | .volatile_reg = cs4271_volatile_reg, | ||
713 | }; | ||
714 | |||
715 | static int cs4271_i2c_probe(struct i2c_client *client, | ||
716 | const struct i2c_device_id *id) | ||
717 | { | ||
718 | struct cs4271_private *cs4271; | ||
719 | int ret; | ||
720 | |||
721 | ret = cs4271_common_probe(&client->dev, &cs4271); | ||
722 | if (ret < 0) | 665 | if (ret < 0) |
723 | return ret; | 666 | return ret; |
724 | 667 | ||
725 | i2c_set_clientdata(client, cs4271); | 668 | dev_set_drvdata(dev, cs4271); |
726 | cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); | 669 | cs4271->regmap = regmap; |
727 | if (IS_ERR(cs4271->regmap)) | ||
728 | return PTR_ERR(cs4271->regmap); | ||
729 | 670 | ||
730 | return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271, | 671 | return snd_soc_register_codec(dev, &soc_codec_dev_cs4271, &cs4271_dai, |
731 | &cs4271_dai, 1); | 672 | 1); |
732 | } | ||
733 | |||
734 | static int cs4271_i2c_remove(struct i2c_client *client) | ||
735 | { | ||
736 | snd_soc_unregister_codec(&client->dev); | ||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static struct i2c_driver cs4271_i2c_driver = { | ||
741 | .driver = { | ||
742 | .name = "cs4271", | ||
743 | .owner = THIS_MODULE, | ||
744 | .of_match_table = of_match_ptr(cs4271_dt_ids), | ||
745 | }, | ||
746 | .id_table = cs4271_i2c_id, | ||
747 | .probe = cs4271_i2c_probe, | ||
748 | .remove = cs4271_i2c_remove, | ||
749 | }; | ||
750 | #endif /* IS_ENABLED(CONFIG_I2C) */ | ||
751 | |||
752 | /* | ||
753 | * We only register our serial bus driver here without | ||
754 | * assignment to particular chip. So if any of the below | ||
755 | * fails, there is some problem with I2C or SPI subsystem. | ||
756 | * In most cases this module will be compiled with support | ||
757 | * of only one serial bus. | ||
758 | */ | ||
759 | static int __init cs4271_modinit(void) | ||
760 | { | ||
761 | int ret; | ||
762 | |||
763 | #if IS_ENABLED(CONFIG_I2C) | ||
764 | ret = i2c_add_driver(&cs4271_i2c_driver); | ||
765 | if (ret) { | ||
766 | pr_err("Failed to register CS4271 I2C driver: %d\n", ret); | ||
767 | return ret; | ||
768 | } | ||
769 | #endif | ||
770 | |||
771 | #if defined(CONFIG_SPI_MASTER) | ||
772 | ret = spi_register_driver(&cs4271_spi_driver); | ||
773 | if (ret) { | ||
774 | pr_err("Failed to register CS4271 SPI driver: %d\n", ret); | ||
775 | return ret; | ||
776 | } | ||
777 | #endif | ||
778 | |||
779 | return 0; | ||
780 | } | ||
781 | module_init(cs4271_modinit); | ||
782 | |||
783 | static void __exit cs4271_modexit(void) | ||
784 | { | ||
785 | #if defined(CONFIG_SPI_MASTER) | ||
786 | spi_unregister_driver(&cs4271_spi_driver); | ||
787 | #endif | ||
788 | |||
789 | #if IS_ENABLED(CONFIG_I2C) | ||
790 | i2c_del_driver(&cs4271_i2c_driver); | ||
791 | #endif | ||
792 | } | 673 | } |
793 | module_exit(cs4271_modexit); | 674 | EXPORT_SYMBOL_GPL(cs4271_probe); |
794 | 675 | ||
795 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); | 676 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); |
796 | MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver"); | 677 | MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver"); |
diff --git a/sound/soc/codecs/cs4271.h b/sound/soc/codecs/cs4271.h new file mode 100644 index 000000000000..9adad8eefdc9 --- /dev/null +++ b/sound/soc/codecs/cs4271.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef _CS4271_PRIV_H | ||
2 | #define _CS4271_PRIV_H | ||
3 | |||
4 | #include <linux/regmap.h> | ||
5 | |||
6 | extern const struct of_device_id cs4271_dt_ids[]; | ||
7 | extern const struct regmap_config cs4271_regmap_config; | ||
8 | |||
9 | int cs4271_probe(struct device *dev, struct regmap *regmap); | ||
10 | |||
11 | #endif | ||
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 669c38fc3034..b3951524339f 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c | |||
@@ -153,15 +153,17 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = { | |||
153 | static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, | 153 | static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, |
154 | struct snd_kcontrol *kcontrol, int event) | 154 | struct snd_kcontrol *kcontrol, int event) |
155 | { | 155 | { |
156 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
157 | |||
156 | switch (event) { | 158 | switch (event) { |
157 | case SND_SOC_DAPM_PRE_PMD: | 159 | case SND_SOC_DAPM_PRE_PMD: |
158 | snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, | 160 | snd_soc_update_bits(codec, CS42L51_POWER_CTL1, |
159 | CS42L51_POWER_CTL1_PDN, | 161 | CS42L51_POWER_CTL1_PDN, |
160 | CS42L51_POWER_CTL1_PDN); | 162 | CS42L51_POWER_CTL1_PDN); |
161 | break; | 163 | break; |
162 | default: | 164 | default: |
163 | case SND_SOC_DAPM_POST_PMD: | 165 | case SND_SOC_DAPM_POST_PMD: |
164 | snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, | 166 | snd_soc_update_bits(codec, CS42L51_POWER_CTL1, |
165 | CS42L51_POWER_CTL1_PDN, 0); | 167 | CS42L51_POWER_CTL1_PDN, 0); |
166 | break; | 168 | break; |
167 | } | 169 | } |
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 2f8b94683e83..7c55537c69cf 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c | |||
@@ -584,7 +584,7 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { | |||
584 | static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, | 584 | static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, |
585 | struct snd_kcontrol *kcontrol, int event) | 585 | struct snd_kcontrol *kcontrol, int event) |
586 | { | 586 | { |
587 | struct snd_soc_codec *codec = w->codec; | 587 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
588 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); | 588 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); |
589 | switch (event) { | 589 | switch (event) { |
590 | case SND_SOC_DAPM_POST_PMD: | 590 | case SND_SOC_DAPM_POST_PMD: |
@@ -600,7 +600,7 @@ static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, | |||
600 | static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, | 600 | static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, |
601 | struct snd_kcontrol *kcontrol, int event) | 601 | struct snd_kcontrol *kcontrol, int event) |
602 | { | 602 | { |
603 | struct snd_soc_codec *codec = w->codec; | 603 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
604 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); | 604 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); |
605 | switch (event) { | 605 | switch (event) { |
606 | case SND_SOC_DAPM_POST_PMD: | 606 | case SND_SOC_DAPM_POST_PMD: |
@@ -618,7 +618,7 @@ static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, | |||
618 | static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w, | 618 | static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w, |
619 | struct snd_kcontrol *kcontrol, int event) | 619 | struct snd_kcontrol *kcontrol, int event) |
620 | { | 620 | { |
621 | struct snd_soc_codec *codec = w->codec; | 621 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
622 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); | 622 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); |
623 | switch (event) { | 623 | switch (event) { |
624 | case SND_SOC_DAPM_POST_PMD: | 624 | case SND_SOC_DAPM_POST_PMD: |
diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 1087fd5f9917..1391ad50f95d 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c | |||
@@ -47,6 +47,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = { | |||
47 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, | 47 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, |
48 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 48 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
49 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, | 49 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, |
50 | .sig_bits = 24, | ||
50 | }, | 51 | }, |
51 | .capture = { | 52 | .capture = { |
52 | .stream_name = "Capture", | 53 | .stream_name = "Capture", |
@@ -75,6 +76,7 @@ static struct snd_soc_codec_driver hdmi_codec = { | |||
75 | .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), | 76 | .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), |
76 | .dapm_routes = hdmi_routes, | 77 | .dapm_routes = hdmi_routes, |
77 | .num_dapm_routes = ARRAY_SIZE(hdmi_routes), | 78 | .num_dapm_routes = ARRAY_SIZE(hdmi_routes), |
79 | .ignore_pmdown_time = true, | ||
78 | }; | 80 | }; |
79 | 81 | ||
80 | static int hdmi_codec_probe(struct platform_device *pdev) | 82 | static int hdmi_codec_probe(struct platform_device *pdev) |
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index c1ae5764983f..c4dfde9bdf1c 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c | |||
@@ -1395,15 +1395,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = { | |||
1395 | }, | 1395 | }, |
1396 | }; | 1396 | }; |
1397 | 1397 | ||
1398 | /* power down chip */ | ||
1399 | static int lm49453_remove(struct snd_soc_codec *codec) | ||
1400 | { | ||
1401 | lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1402 | return 0; | ||
1403 | } | ||
1404 | |||
1405 | static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { | 1398 | static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { |
1406 | .remove = lm49453_remove, | ||
1407 | .set_bias_level = lm49453_set_bias_level, | 1399 | .set_bias_level = lm49453_set_bias_level, |
1408 | .controls = lm49453_snd_controls, | 1400 | .controls = lm49453_snd_controls, |
1409 | .num_controls = ARRAY_SIZE(lm49453_snd_controls), | 1401 | .num_controls = ARRAY_SIZE(lm49453_snd_controls), |
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 2cd3e5427441..805b3f8cd39d 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c | |||
@@ -875,7 +875,7 @@ static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = { | |||
875 | static int max98088_mic_event(struct snd_soc_dapm_widget *w, | 875 | static int max98088_mic_event(struct snd_soc_dapm_widget *w, |
876 | struct snd_kcontrol *kcontrol, int event) | 876 | struct snd_kcontrol *kcontrol, int event) |
877 | { | 877 | { |
878 | struct snd_soc_codec *codec = w->codec; | 878 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
879 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); | 879 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); |
880 | 880 | ||
881 | switch (event) { | 881 | switch (event) { |
@@ -905,7 +905,7 @@ static int max98088_mic_event(struct snd_soc_dapm_widget *w, | |||
905 | static int max98088_line_pga(struct snd_soc_dapm_widget *w, | 905 | static int max98088_line_pga(struct snd_soc_dapm_widget *w, |
906 | int event, int line, u8 channel) | 906 | int event, int line, u8 channel) |
907 | { | 907 | { |
908 | struct snd_soc_codec *codec = w->codec; | 908 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
909 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); | 909 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); |
910 | u8 *state; | 910 | u8 *state; |
911 | 911 | ||
@@ -1887,25 +1887,6 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec) | |||
1887 | max98088_handle_eq_pdata(codec); | 1887 | max98088_handle_eq_pdata(codec); |
1888 | } | 1888 | } |
1889 | 1889 | ||
1890 | #ifdef CONFIG_PM | ||
1891 | static int max98088_suspend(struct snd_soc_codec *codec) | ||
1892 | { | ||
1893 | max98088_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1894 | |||
1895 | return 0; | ||
1896 | } | ||
1897 | |||
1898 | static int max98088_resume(struct snd_soc_codec *codec) | ||
1899 | { | ||
1900 | max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1901 | |||
1902 | return 0; | ||
1903 | } | ||
1904 | #else | ||
1905 | #define max98088_suspend NULL | ||
1906 | #define max98088_resume NULL | ||
1907 | #endif | ||
1908 | |||
1909 | static int max98088_probe(struct snd_soc_codec *codec) | 1890 | static int max98088_probe(struct snd_soc_codec *codec) |
1910 | { | 1891 | { |
1911 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); | 1892 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); |
@@ -1946,9 +1927,6 @@ static int max98088_probe(struct snd_soc_codec *codec) | |||
1946 | 1927 | ||
1947 | snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV); | 1928 | snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV); |
1948 | 1929 | ||
1949 | /* initialize registers cache to hardware default */ | ||
1950 | max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1951 | |||
1952 | snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00); | 1930 | snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00); |
1953 | 1931 | ||
1954 | snd_soc_write(codec, M98088_REG_22_MIX_DAC, | 1932 | snd_soc_write(codec, M98088_REG_22_MIX_DAC, |
@@ -1974,7 +1952,6 @@ static int max98088_remove(struct snd_soc_codec *codec) | |||
1974 | { | 1952 | { |
1975 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); | 1953 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); |
1976 | 1954 | ||
1977 | max98088_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1978 | kfree(max98088->eq_texts); | 1955 | kfree(max98088->eq_texts); |
1979 | 1956 | ||
1980 | return 0; | 1957 | return 0; |
@@ -1983,9 +1960,9 @@ static int max98088_remove(struct snd_soc_codec *codec) | |||
1983 | static struct snd_soc_codec_driver soc_codec_dev_max98088 = { | 1960 | static struct snd_soc_codec_driver soc_codec_dev_max98088 = { |
1984 | .probe = max98088_probe, | 1961 | .probe = max98088_probe, |
1985 | .remove = max98088_remove, | 1962 | .remove = max98088_remove, |
1986 | .suspend = max98088_suspend, | ||
1987 | .resume = max98088_resume, | ||
1988 | .set_bias_level = max98088_set_bias_level, | 1963 | .set_bias_level = max98088_set_bias_level, |
1964 | .suspend_bias_off = true, | ||
1965 | |||
1989 | .controls = max98088_snd_controls, | 1966 | .controls = max98088_snd_controls, |
1990 | .num_controls = ARRAY_SIZE(max98088_snd_controls), | 1967 | .num_controls = ARRAY_SIZE(max98088_snd_controls), |
1991 | .dapm_widgets = max98088_dapm_widgets, | 1968 | .dapm_widgets = max98088_dapm_widgets, |
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 1229554f1464..151f718241ea 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
@@ -806,7 +806,7 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = { | |||
806 | static int max98090_micinput_event(struct snd_soc_dapm_widget *w, | 806 | static int max98090_micinput_event(struct snd_soc_dapm_widget *w, |
807 | struct snd_kcontrol *kcontrol, int event) | 807 | struct snd_kcontrol *kcontrol, int event) |
808 | { | 808 | { |
809 | struct snd_soc_codec *codec = w->codec; | 809 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
810 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | 810 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); |
811 | 811 | ||
812 | unsigned int val = snd_soc_read(codec, w->reg); | 812 | unsigned int val = snd_soc_read(codec, w->reg); |
@@ -1311,6 +1311,10 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1311 | {"MIC1 Input", NULL, "MIC1"}, | 1311 | {"MIC1 Input", NULL, "MIC1"}, |
1312 | {"MIC2 Input", NULL, "MIC2"}, | 1312 | {"MIC2 Input", NULL, "MIC2"}, |
1313 | 1313 | ||
1314 | {"DMICL", NULL, "DMICL_ENA"}, | ||
1315 | {"DMICL", NULL, "DMICR_ENA"}, | ||
1316 | {"DMICR", NULL, "DMICL_ENA"}, | ||
1317 | {"DMICR", NULL, "DMICR_ENA"}, | ||
1314 | {"DMICL", NULL, "AHPF"}, | 1318 | {"DMICL", NULL, "AHPF"}, |
1315 | {"DMICR", NULL, "AHPF"}, | 1319 | {"DMICR", NULL, "AHPF"}, |
1316 | 1320 | ||
@@ -1368,8 +1372,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1368 | {"DMIC Mux", "ADC", "ADCR"}, | 1372 | {"DMIC Mux", "ADC", "ADCR"}, |
1369 | {"DMIC Mux", "DMIC", "DMICL"}, | 1373 | {"DMIC Mux", "DMIC", "DMICL"}, |
1370 | {"DMIC Mux", "DMIC", "DMICR"}, | 1374 | {"DMIC Mux", "DMIC", "DMICR"}, |
1371 | {"DMIC Mux", "DMIC", "DMICL_ENA"}, | ||
1372 | {"DMIC Mux", "DMIC", "DMICR_ENA"}, | ||
1373 | 1375 | ||
1374 | {"LBENL Mux", "Normal", "DMIC Mux"}, | 1376 | {"LBENL Mux", "Normal", "DMIC Mux"}, |
1375 | {"LBENL Mux", "Loopback", "LTENL Mux"}, | 1377 | {"LBENL Mux", "Loopback", "LTENL Mux"}, |
@@ -1395,8 +1397,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1395 | {"STENL Mux", "Sidetone Left", "DMICL"}, | 1397 | {"STENL Mux", "Sidetone Left", "DMICL"}, |
1396 | {"STENR Mux", "Sidetone Right", "ADCR"}, | 1398 | {"STENR Mux", "Sidetone Right", "ADCR"}, |
1397 | {"STENR Mux", "Sidetone Right", "DMICR"}, | 1399 | {"STENR Mux", "Sidetone Right", "DMICR"}, |
1398 | {"DACL", "NULL", "STENL Mux"}, | 1400 | {"DACL", NULL, "STENL Mux"}, |
1399 | {"DACR", "NULL", "STENL Mux"}, | 1401 | {"DACR", NULL, "STENR Mux"}, |
1400 | 1402 | ||
1401 | {"AIFINL", NULL, "SHDN"}, | 1403 | {"AIFINL", NULL, "SHDN"}, |
1402 | {"AIFINR", NULL, "SHDN"}, | 1404 | {"AIFINR", NULL, "SHDN"}, |
@@ -1826,27 +1828,155 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, | |||
1826 | return 0; | 1828 | return 0; |
1827 | } | 1829 | } |
1828 | 1830 | ||
1829 | static const int comp_pclk_rates[] = { | 1831 | static const int dmic_divisors[] = { 2, 3, 4, 5, 6, 8 }; |
1830 | 11289600, 12288000, 12000000, 13000000, 19200000 | ||
1831 | }; | ||
1832 | |||
1833 | static const int dmic_micclk[] = { | ||
1834 | 2, 2, 2, 2, 4, 2 | ||
1835 | }; | ||
1836 | 1832 | ||
1837 | static const int comp_lrclk_rates[] = { | 1833 | static const int comp_lrclk_rates[] = { |
1838 | 8000, 16000, 32000, 44100, 48000, 96000 | 1834 | 8000, 16000, 32000, 44100, 48000, 96000 |
1839 | }; | 1835 | }; |
1840 | 1836 | ||
1841 | static const int dmic_comp[6][6] = { | 1837 | struct dmic_table { |
1842 | {7, 8, 3, 3, 3, 3}, | 1838 | int pclk; |
1843 | {7, 8, 3, 3, 3, 3}, | 1839 | struct { |
1844 | {7, 8, 3, 3, 3, 3}, | 1840 | int freq; |
1845 | {7, 8, 3, 1, 1, 1}, | 1841 | int comp[6]; /* One each for 8, 16, 32, 44.1, 48, and 96 kHz */ |
1846 | {7, 8, 3, 1, 2, 2}, | 1842 | } settings[6]; /* One for each dmic divisor. */ |
1847 | {7, 8, 3, 3, 3, 3} | ||
1848 | }; | 1843 | }; |
1849 | 1844 | ||
1845 | static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */ | ||
1846 | { | ||
1847 | .pclk = 11289600, | ||
1848 | .settings = { | ||
1849 | { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1850 | { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, | ||
1851 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1852 | { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } }, | ||
1853 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1854 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1855 | }, | ||
1856 | }, | ||
1857 | { | ||
1858 | .pclk = 12000000, | ||
1859 | .settings = { | ||
1860 | { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1861 | { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, | ||
1862 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1863 | { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, | ||
1864 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1865 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1866 | } | ||
1867 | }, | ||
1868 | { | ||
1869 | .pclk = 12288000, | ||
1870 | .settings = { | ||
1871 | { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1872 | { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, | ||
1873 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1874 | { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } }, | ||
1875 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1876 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1877 | } | ||
1878 | }, | ||
1879 | { | ||
1880 | .pclk = 13000000, | ||
1881 | .settings = { | ||
1882 | { .freq = 2, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1883 | { .freq = 1, .comp = { 7, 8, 0, 0, 0, 0 } }, | ||
1884 | { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1885 | { .freq = 0, .comp = { 7, 8, 4, 4, 5, 5 } }, | ||
1886 | { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1887 | { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1888 | } | ||
1889 | }, | ||
1890 | { | ||
1891 | .pclk = 19200000, | ||
1892 | .settings = { | ||
1893 | { .freq = 2, .comp = { 0, 0, 0, 0, 0, 0 } }, | ||
1894 | { .freq = 1, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1895 | { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, | ||
1896 | { .freq = 0, .comp = { 7, 8, 2, 2, 3, 3 } }, | ||
1897 | { .freq = 0, .comp = { 7, 8, 1, 1, 2, 2 } }, | ||
1898 | { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, | ||
1899 | } | ||
1900 | }, | ||
1901 | }; | ||
1902 | |||
1903 | static int max98090_find_divisor(int target_freq, int pclk) | ||
1904 | { | ||
1905 | int current_diff = INT_MAX; | ||
1906 | int test_diff = INT_MAX; | ||
1907 | int divisor_index = 0; | ||
1908 | int i; | ||
1909 | |||
1910 | for (i = 0; i < ARRAY_SIZE(dmic_divisors); i++) { | ||
1911 | test_diff = abs(target_freq - (pclk / dmic_divisors[i])); | ||
1912 | if (test_diff < current_diff) { | ||
1913 | current_diff = test_diff; | ||
1914 | divisor_index = i; | ||
1915 | } | ||
1916 | } | ||
1917 | |||
1918 | return divisor_index; | ||
1919 | } | ||
1920 | |||
1921 | static int max98090_find_closest_pclk(int pclk) | ||
1922 | { | ||
1923 | int m1; | ||
1924 | int m2; | ||
1925 | int i; | ||
1926 | |||
1927 | for (i = 0; i < ARRAY_SIZE(dmic_table); i++) { | ||
1928 | if (pclk == dmic_table[i].pclk) | ||
1929 | return i; | ||
1930 | if (pclk < dmic_table[i].pclk) { | ||
1931 | if (i == 0) | ||
1932 | return i; | ||
1933 | m1 = pclk - dmic_table[i-1].pclk; | ||
1934 | m2 = dmic_table[i].pclk - pclk; | ||
1935 | if (m1 < m2) | ||
1936 | return i - 1; | ||
1937 | else | ||
1938 | return i; | ||
1939 | } | ||
1940 | } | ||
1941 | |||
1942 | return -EINVAL; | ||
1943 | } | ||
1944 | |||
1945 | static int max98090_configure_dmic(struct max98090_priv *max98090, | ||
1946 | int target_dmic_clk, int pclk, int fs) | ||
1947 | { | ||
1948 | int micclk_index; | ||
1949 | int pclk_index; | ||
1950 | int dmic_freq; | ||
1951 | int dmic_comp; | ||
1952 | int i; | ||
1953 | |||
1954 | pclk_index = max98090_find_closest_pclk(pclk); | ||
1955 | if (pclk_index < 0) | ||
1956 | return pclk_index; | ||
1957 | |||
1958 | micclk_index = max98090_find_divisor(target_dmic_clk, pclk); | ||
1959 | |||
1960 | for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) { | ||
1961 | if (fs <= (comp_lrclk_rates[i] + comp_lrclk_rates[i+1]) / 2) | ||
1962 | break; | ||
1963 | } | ||
1964 | |||
1965 | dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq; | ||
1966 | dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i]; | ||
1967 | |||
1968 | regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE, | ||
1969 | M98090_MICCLK_MASK, | ||
1970 | micclk_index << M98090_MICCLK_SHIFT); | ||
1971 | |||
1972 | regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_CONFIG, | ||
1973 | M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK, | ||
1974 | dmic_comp << M98090_DMIC_COMP_SHIFT | | ||
1975 | dmic_freq << M98090_DMIC_FREQ_SHIFT); | ||
1976 | |||
1977 | return 0; | ||
1978 | } | ||
1979 | |||
1850 | static int max98090_dai_hw_params(struct snd_pcm_substream *substream, | 1980 | static int max98090_dai_hw_params(struct snd_pcm_substream *substream, |
1851 | struct snd_pcm_hw_params *params, | 1981 | struct snd_pcm_hw_params *params, |
1852 | struct snd_soc_dai *dai) | 1982 | struct snd_soc_dai *dai) |
@@ -1854,7 +1984,6 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, | |||
1854 | struct snd_soc_codec *codec = dai->codec; | 1984 | struct snd_soc_codec *codec = dai->codec; |
1855 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | 1985 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); |
1856 | struct max98090_cdata *cdata; | 1986 | struct max98090_cdata *cdata; |
1857 | int i, j; | ||
1858 | 1987 | ||
1859 | cdata = &max98090->dai[0]; | 1988 | cdata = &max98090->dai[0]; |
1860 | max98090->bclk = snd_soc_params_to_bclk(params); | 1989 | max98090->bclk = snd_soc_params_to_bclk(params); |
@@ -1893,27 +2022,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, | |||
1893 | snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, | 2022 | snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, |
1894 | M98090_DHF_MASK, M98090_DHF_MASK); | 2023 | M98090_DHF_MASK, M98090_DHF_MASK); |
1895 | 2024 | ||
1896 | /* Check for supported PCLK to LRCLK ratios */ | 2025 | max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk, |
1897 | for (j = 0; j < ARRAY_SIZE(comp_pclk_rates); j++) { | 2026 | max98090->lrclk); |
1898 | if (comp_pclk_rates[j] == max98090->sysclk) { | ||
1899 | break; | ||
1900 | } | ||
1901 | } | ||
1902 | |||
1903 | for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) { | ||
1904 | if (max98090->lrclk <= (comp_lrclk_rates[i] + | ||
1905 | comp_lrclk_rates[i + 1]) / 2) { | ||
1906 | break; | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1910 | snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_ENABLE, | ||
1911 | M98090_MICCLK_MASK, | ||
1912 | dmic_micclk[j] << M98090_MICCLK_SHIFT); | ||
1913 | |||
1914 | snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_CONFIG, | ||
1915 | M98090_DMIC_COMP_MASK, | ||
1916 | dmic_comp[j][i] << M98090_DMIC_COMP_SHIFT); | ||
1917 | 2027 | ||
1918 | return 0; | 2028 | return 0; |
1919 | } | 2029 | } |
@@ -1944,12 +2054,15 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, | |||
1944 | if ((freq >= 10000000) && (freq <= 20000000)) { | 2054 | if ((freq >= 10000000) && (freq <= 20000000)) { |
1945 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, | 2055 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, |
1946 | M98090_PSCLK_DIV1); | 2056 | M98090_PSCLK_DIV1); |
2057 | max98090->pclk = freq; | ||
1947 | } else if ((freq > 20000000) && (freq <= 40000000)) { | 2058 | } else if ((freq > 20000000) && (freq <= 40000000)) { |
1948 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, | 2059 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, |
1949 | M98090_PSCLK_DIV2); | 2060 | M98090_PSCLK_DIV2); |
2061 | max98090->pclk = freq >> 1; | ||
1950 | } else if ((freq > 40000000) && (freq <= 60000000)) { | 2062 | } else if ((freq > 40000000) && (freq <= 60000000)) { |
1951 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, | 2063 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, |
1952 | M98090_PSCLK_DIV4); | 2064 | M98090_PSCLK_DIV4); |
2065 | max98090->pclk = freq >> 2; | ||
1953 | } else { | 2066 | } else { |
1954 | dev_err(codec->dev, "Invalid master clock frequency\n"); | 2067 | dev_err(codec->dev, "Invalid master clock frequency\n"); |
1955 | return -EINVAL; | 2068 | return -EINVAL; |
@@ -2324,6 +2437,7 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
2324 | /* Initialize private data */ | 2437 | /* Initialize private data */ |
2325 | 2438 | ||
2326 | max98090->sysclk = (unsigned)-1; | 2439 | max98090->sysclk = (unsigned)-1; |
2440 | max98090->pclk = (unsigned)-1; | ||
2327 | max98090->master = false; | 2441 | max98090->master = false; |
2328 | 2442 | ||
2329 | cdata = &max98090->dai[0]; | 2443 | cdata = &max98090->dai[0]; |
@@ -2463,6 +2577,11 @@ static int max98090_i2c_probe(struct i2c_client *i2c, | |||
2463 | i2c_set_clientdata(i2c, max98090); | 2577 | i2c_set_clientdata(i2c, max98090); |
2464 | max98090->pdata = i2c->dev.platform_data; | 2578 | max98090->pdata = i2c->dev.platform_data; |
2465 | 2579 | ||
2580 | ret = of_property_read_u32(i2c->dev.of_node, "maxim,dmic-freq", | ||
2581 | &max98090->dmic_freq); | ||
2582 | if (ret < 0) | ||
2583 | max98090->dmic_freq = MAX98090_DEFAULT_DMIC_FREQ; | ||
2584 | |||
2466 | max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); | 2585 | max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); |
2467 | if (IS_ERR(max98090->regmap)) { | 2586 | if (IS_ERR(max98090->regmap)) { |
2468 | ret = PTR_ERR(max98090->regmap); | 2587 | ret = PTR_ERR(max98090->regmap); |
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index a5f6bada06da..21ff743f5af2 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h | |||
@@ -12,6 +12,12 @@ | |||
12 | #define _MAX98090_H | 12 | #define _MAX98090_H |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * The default operating frequency for a DMIC attached to the codec. | ||
16 | * This can be overridden by a device tree property. | ||
17 | */ | ||
18 | #define MAX98090_DEFAULT_DMIC_FREQ 2500000 | ||
19 | |||
20 | /* | ||
15 | * MAX98090 Register Definitions | 21 | * MAX98090 Register Definitions |
16 | */ | 22 | */ |
17 | 23 | ||
@@ -1518,8 +1524,10 @@ struct max98090_priv { | |||
1518 | struct max98090_pdata *pdata; | 1524 | struct max98090_pdata *pdata; |
1519 | struct clk *mclk; | 1525 | struct clk *mclk; |
1520 | unsigned int sysclk; | 1526 | unsigned int sysclk; |
1527 | unsigned int pclk; | ||
1521 | unsigned int bclk; | 1528 | unsigned int bclk; |
1522 | unsigned int lrclk; | 1529 | unsigned int lrclk; |
1530 | u32 dmic_freq; | ||
1523 | struct max98090_cdata dai[1]; | 1531 | struct max98090_cdata dai[1]; |
1524 | int jack_state; | 1532 | int jack_state; |
1525 | struct delayed_work jack_work; | 1533 | struct delayed_work jack_work; |
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 0ee6797d5083..8fba0c3db798 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/mutex.h> | ||
19 | #include <sound/core.h> | 20 | #include <sound/core.h> |
20 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
21 | #include <sound/pcm_params.h> | 22 | #include <sound/pcm_params.h> |
@@ -57,6 +58,7 @@ struct max98095_priv { | |||
57 | unsigned int mic2pre; | 58 | unsigned int mic2pre; |
58 | struct snd_soc_jack *headphone_jack; | 59 | struct snd_soc_jack *headphone_jack; |
59 | struct snd_soc_jack *mic_jack; | 60 | struct snd_soc_jack *mic_jack; |
61 | struct mutex lock; | ||
60 | }; | 62 | }; |
61 | 63 | ||
62 | static const struct reg_default max98095_reg_def[] = { | 64 | static const struct reg_default max98095_reg_def[] = { |
@@ -864,7 +866,7 @@ static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = { | |||
864 | static int max98095_mic_event(struct snd_soc_dapm_widget *w, | 866 | static int max98095_mic_event(struct snd_soc_dapm_widget *w, |
865 | struct snd_kcontrol *kcontrol, int event) | 867 | struct snd_kcontrol *kcontrol, int event) |
866 | { | 868 | { |
867 | struct snd_soc_codec *codec = w->codec; | 869 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
868 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | 870 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); |
869 | 871 | ||
870 | switch (event) { | 872 | switch (event) { |
@@ -894,7 +896,7 @@ static int max98095_mic_event(struct snd_soc_dapm_widget *w, | |||
894 | static int max98095_line_pga(struct snd_soc_dapm_widget *w, | 896 | static int max98095_line_pga(struct snd_soc_dapm_widget *w, |
895 | int event, u8 channel) | 897 | int event, u8 channel) |
896 | { | 898 | { |
897 | struct snd_soc_codec *codec = w->codec; | 899 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
898 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | 900 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); |
899 | u8 *state; | 901 | u8 *state; |
900 | 902 | ||
@@ -942,7 +944,7 @@ static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w, | |||
942 | static int max98095_lineout_event(struct snd_soc_dapm_widget *w, | 944 | static int max98095_lineout_event(struct snd_soc_dapm_widget *w, |
943 | struct snd_kcontrol *kcontrol, int event) | 945 | struct snd_kcontrol *kcontrol, int event) |
944 | { | 946 | { |
945 | struct snd_soc_codec *codec = w->codec; | 947 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
946 | 948 | ||
947 | switch (event) { | 949 | switch (event) { |
948 | case SND_SOC_DAPM_POST_PMU: | 950 | case SND_SOC_DAPM_POST_PMU: |
@@ -1803,7 +1805,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, | |||
1803 | regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); | 1805 | regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); |
1804 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); | 1806 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); |
1805 | 1807 | ||
1806 | mutex_lock(&codec->mutex); | 1808 | mutex_lock(&max98095->lock); |
1807 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); | 1809 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); |
1808 | m98095_eq_band(codec, channel, 0, coef_set->band1); | 1810 | m98095_eq_band(codec, channel, 0, coef_set->band1); |
1809 | m98095_eq_band(codec, channel, 1, coef_set->band2); | 1811 | m98095_eq_band(codec, channel, 1, coef_set->band2); |
@@ -1811,7 +1813,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, | |||
1811 | m98095_eq_band(codec, channel, 3, coef_set->band4); | 1813 | m98095_eq_band(codec, channel, 3, coef_set->band4); |
1812 | m98095_eq_band(codec, channel, 4, coef_set->band5); | 1814 | m98095_eq_band(codec, channel, 4, coef_set->band5); |
1813 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); | 1815 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); |
1814 | mutex_unlock(&codec->mutex); | 1816 | mutex_unlock(&max98095->lock); |
1815 | 1817 | ||
1816 | /* Restore the original on/off state */ | 1818 | /* Restore the original on/off state */ |
1817 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); | 1819 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); |
@@ -1957,12 +1959,12 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, | |||
1957 | regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); | 1959 | regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); |
1958 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); | 1960 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); |
1959 | 1961 | ||
1960 | mutex_lock(&codec->mutex); | 1962 | mutex_lock(&max98095->lock); |
1961 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); | 1963 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); |
1962 | m98095_biquad_band(codec, channel, 0, coef_set->band1); | 1964 | m98095_biquad_band(codec, channel, 0, coef_set->band1); |
1963 | m98095_biquad_band(codec, channel, 1, coef_set->band2); | 1965 | m98095_biquad_band(codec, channel, 1, coef_set->band2); |
1964 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); | 1966 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); |
1965 | mutex_unlock(&codec->mutex); | 1967 | mutex_unlock(&max98095->lock); |
1966 | 1968 | ||
1967 | /* Restore the original on/off state */ | 1969 | /* Restore the original on/off state */ |
1968 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); | 1970 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); |
@@ -2317,9 +2319,6 @@ static int max98095_probe(struct snd_soc_codec *codec) | |||
2317 | 2319 | ||
2318 | snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); | 2320 | snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); |
2319 | 2321 | ||
2320 | /* initialize registers cache to hardware default */ | ||
2321 | max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2322 | |||
2323 | snd_soc_write(codec, M98095_048_MIX_DAC_LR, | 2322 | snd_soc_write(codec, M98095_048_MIX_DAC_LR, |
2324 | M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR); | 2323 | M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR); |
2325 | 2324 | ||
@@ -2359,8 +2358,6 @@ static int max98095_remove(struct snd_soc_codec *codec) | |||
2359 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | 2358 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); |
2360 | struct i2c_client *client = to_i2c_client(codec->dev); | 2359 | struct i2c_client *client = to_i2c_client(codec->dev); |
2361 | 2360 | ||
2362 | max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
2363 | |||
2364 | if (max98095->headphone_jack || max98095->mic_jack) | 2361 | if (max98095->headphone_jack || max98095->mic_jack) |
2365 | max98095_jack_detect_disable(codec); | 2362 | max98095_jack_detect_disable(codec); |
2366 | 2363 | ||
@@ -2395,6 +2392,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c, | |||
2395 | if (max98095 == NULL) | 2392 | if (max98095 == NULL) |
2396 | return -ENOMEM; | 2393 | return -ENOMEM; |
2397 | 2394 | ||
2395 | mutex_init(&max98095->lock); | ||
2396 | |||
2398 | max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap); | 2397 | max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap); |
2399 | if (IS_ERR(max98095->regmap)) { | 2398 | if (IS_ERR(max98095->regmap)) { |
2400 | ret = PTR_ERR(max98095->regmap); | 2399 | ret = PTR_ERR(max98095->regmap); |
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 4fdf5aaa236f..10f8e47ce2c2 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c | |||
@@ -291,25 +291,6 @@ static struct snd_soc_dai_driver max9850_dai = { | |||
291 | .ops = &max9850_dai_ops, | 291 | .ops = &max9850_dai_ops, |
292 | }; | 292 | }; |
293 | 293 | ||
294 | #ifdef CONFIG_PM | ||
295 | static int max9850_suspend(struct snd_soc_codec *codec) | ||
296 | { | ||
297 | max9850_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int max9850_resume(struct snd_soc_codec *codec) | ||
303 | { | ||
304 | max9850_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | #else | ||
309 | #define max9850_suspend NULL | ||
310 | #define max9850_resume NULL | ||
311 | #endif | ||
312 | |||
313 | static int max9850_probe(struct snd_soc_codec *codec) | 294 | static int max9850_probe(struct snd_soc_codec *codec) |
314 | { | 295 | { |
315 | /* enable zero-detect */ | 296 | /* enable zero-detect */ |
@@ -324,9 +305,8 @@ static int max9850_probe(struct snd_soc_codec *codec) | |||
324 | 305 | ||
325 | static struct snd_soc_codec_driver soc_codec_dev_max9850 = { | 306 | static struct snd_soc_codec_driver soc_codec_dev_max9850 = { |
326 | .probe = max9850_probe, | 307 | .probe = max9850_probe, |
327 | .suspend = max9850_suspend, | ||
328 | .resume = max9850_resume, | ||
329 | .set_bias_level = max9850_set_bias_level, | 308 | .set_bias_level = max9850_set_bias_level, |
309 | .suspend_bias_off = true, | ||
330 | 310 | ||
331 | .controls = max9850_controls, | 311 | .controls = max9850_controls, |
332 | .num_controls = ARRAY_SIZE(max9850_controls), | 312 | .num_controls = ARRAY_SIZE(max9850_controls), |
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 4aa555cbcca8..2cd4fe463102 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/spi/spi.h> | 19 | #include <linux/spi/spi.h> |
20 | #include <linux/dmi.h> | ||
20 | #include <linux/acpi.h> | 21 | #include <linux/acpi.h> |
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
@@ -36,11 +37,13 @@ | |||
36 | 37 | ||
37 | struct rt286_priv { | 38 | struct rt286_priv { |
38 | struct regmap *regmap; | 39 | struct regmap *regmap; |
40 | struct snd_soc_codec *codec; | ||
39 | struct rt286_platform_data pdata; | 41 | struct rt286_platform_data pdata; |
40 | struct i2c_client *i2c; | 42 | struct i2c_client *i2c; |
41 | struct snd_soc_jack *jack; | 43 | struct snd_soc_jack *jack; |
42 | struct delayed_work jack_detect_work; | 44 | struct delayed_work jack_detect_work; |
43 | int sys_clk; | 45 | int sys_clk; |
46 | int clk_id; | ||
44 | struct reg_default *index_cache; | 47 | struct reg_default *index_cache; |
45 | }; | 48 | }; |
46 | 49 | ||
@@ -188,7 +191,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) | |||
188 | u8 data[4]; | 191 | u8 data[4]; |
189 | int ret, i; | 192 | int ret, i; |
190 | 193 | ||
191 | /*handle index registers*/ | 194 | /* handle index registers */ |
192 | if (reg <= 0xff) { | 195 | if (reg <= 0xff) { |
193 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | 196 | rt286_hw_write(client, RT286_COEF_INDEX, reg); |
194 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { | 197 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { |
@@ -231,7 +234,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value) | |||
231 | __be32 be_reg; | 234 | __be32 be_reg; |
232 | unsigned int index, vid, buf = 0x0; | 235 | unsigned int index, vid, buf = 0x0; |
233 | 236 | ||
234 | /*handle index registers*/ | 237 | /* handle index registers */ |
235 | if (reg <= 0xff) { | 238 | if (reg <= 0xff) { |
236 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | 239 | rt286_hw_write(client, RT286_COEF_INDEX, reg); |
237 | reg = RT286_PROC_COEF; | 240 | reg = RT286_PROC_COEF; |
@@ -298,7 +301,6 @@ static int rt286_support_power_controls[] = { | |||
298 | static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | 301 | static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) |
299 | { | 302 | { |
300 | unsigned int val, buf; | 303 | unsigned int val, buf; |
301 | int i; | ||
302 | 304 | ||
303 | *hp = false; | 305 | *hp = false; |
304 | *mic = false; | 306 | *mic = false; |
@@ -309,67 +311,44 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | |||
309 | if (*hp) { | 311 | if (*hp) { |
310 | /* power on HV,VERF */ | 312 | /* power on HV,VERF */ |
311 | regmap_update_bits(rt286->regmap, | 313 | regmap_update_bits(rt286->regmap, |
312 | RT286_POWER_CTRL1, 0x1001, 0x0); | 314 | RT286_DC_GAIN, 0x200, 0x200); |
315 | |||
316 | snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, | ||
317 | "HV"); | ||
318 | snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, | ||
319 | "VREF"); | ||
313 | /* power LDO1 */ | 320 | /* power LDO1 */ |
314 | regmap_update_bits(rt286->regmap, | 321 | snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, |
315 | RT286_POWER_CTRL2, 0x4, 0x4); | 322 | "LDO1"); |
316 | regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); | 323 | snd_soc_dapm_sync(&rt286->codec->dapm); |
317 | regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val); | ||
318 | 324 | ||
319 | msleep(200); | 325 | regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); |
320 | i = 40; | 326 | msleep(50); |
321 | while (((val & 0x0800) == 0) && (i > 0)) { | ||
322 | regmap_read(rt286->regmap, | ||
323 | RT286_CBJ_CTRL2, &val); | ||
324 | i--; | ||
325 | msleep(20); | ||
326 | } | ||
327 | 327 | ||
328 | if (0x0400 == (val & 0x0700)) { | 328 | regmap_update_bits(rt286->regmap, |
329 | *mic = false; | 329 | RT286_CBJ_CTRL1, 0xfcc0, 0xd400); |
330 | msleep(300); | ||
331 | regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val); | ||
330 | 332 | ||
331 | regmap_write(rt286->regmap, | 333 | if (0x0070 == (val & 0x0070)) { |
332 | RT286_SET_MIC1, 0x20); | ||
333 | /* power off HV,VERF */ | ||
334 | regmap_update_bits(rt286->regmap, | ||
335 | RT286_POWER_CTRL1, 0x1001, 0x1001); | ||
336 | regmap_update_bits(rt286->regmap, | ||
337 | RT286_A_BIAS_CTRL3, 0xc000, 0x0000); | ||
338 | regmap_update_bits(rt286->regmap, | ||
339 | RT286_CBJ_CTRL1, 0x0030, 0x0000); | ||
340 | regmap_update_bits(rt286->regmap, | ||
341 | RT286_A_BIAS_CTRL2, 0xc000, 0x0000); | ||
342 | } else if ((0x0200 == (val & 0x0700)) || | ||
343 | (0x0100 == (val & 0x0700))) { | ||
344 | *mic = true; | 334 | *mic = true; |
345 | regmap_update_bits(rt286->regmap, | ||
346 | RT286_A_BIAS_CTRL3, 0xc000, 0x8000); | ||
347 | regmap_update_bits(rt286->regmap, | ||
348 | RT286_CBJ_CTRL1, 0x0030, 0x0020); | ||
349 | regmap_update_bits(rt286->regmap, | ||
350 | RT286_A_BIAS_CTRL2, 0xc000, 0x8000); | ||
351 | } else { | 335 | } else { |
352 | *mic = false; | 336 | regmap_update_bits(rt286->regmap, |
337 | RT286_CBJ_CTRL1, 0xfcc0, 0xe400); | ||
338 | msleep(300); | ||
339 | regmap_read(rt286->regmap, | ||
340 | RT286_CBJ_CTRL2, &val); | ||
341 | if (0x0070 == (val & 0x0070)) | ||
342 | *mic = true; | ||
343 | else | ||
344 | *mic = false; | ||
353 | } | 345 | } |
354 | |||
355 | regmap_update_bits(rt286->regmap, | ||
356 | RT286_MISC_CTRL1, | ||
357 | 0x0060, 0x0000); | ||
358 | } else { | ||
359 | regmap_update_bits(rt286->regmap, | ||
360 | RT286_MISC_CTRL1, | ||
361 | 0x0060, 0x0020); | ||
362 | regmap_update_bits(rt286->regmap, | 346 | regmap_update_bits(rt286->regmap, |
363 | RT286_A_BIAS_CTRL3, | 347 | RT286_DC_GAIN, 0x200, 0x0); |
364 | 0xc000, 0x8000); | ||
365 | regmap_update_bits(rt286->regmap, | ||
366 | RT286_CBJ_CTRL1, | ||
367 | 0x0030, 0x0020); | ||
368 | regmap_update_bits(rt286->regmap, | ||
369 | RT286_A_BIAS_CTRL2, | ||
370 | 0xc000, 0x8000); | ||
371 | 348 | ||
349 | } else { | ||
372 | *mic = false; | 350 | *mic = false; |
351 | regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20); | ||
373 | } | 352 | } |
374 | } else { | 353 | } else { |
375 | regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); | 354 | regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); |
@@ -378,6 +357,12 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | |||
378 | *mic = buf & 0x80000000; | 357 | *mic = buf & 0x80000000; |
379 | } | 358 | } |
380 | 359 | ||
360 | snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV"); | ||
361 | snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF"); | ||
362 | if (!*hp) | ||
363 | snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1"); | ||
364 | snd_soc_dapm_sync(&rt286->codec->dapm); | ||
365 | |||
381 | return 0; | 366 | return 0; |
382 | } | 367 | } |
383 | 368 | ||
@@ -415,6 +400,17 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | |||
415 | } | 400 | } |
416 | EXPORT_SYMBOL_GPL(rt286_mic_detect); | 401 | EXPORT_SYMBOL_GPL(rt286_mic_detect); |
417 | 402 | ||
403 | static int is_mclk_mode(struct snd_soc_dapm_widget *source, | ||
404 | struct snd_soc_dapm_widget *sink) | ||
405 | { | ||
406 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec); | ||
407 | |||
408 | if (rt286->clk_id == RT286_SCLK_S_MCLK) | ||
409 | return 1; | ||
410 | else | ||
411 | return 0; | ||
412 | } | ||
413 | |||
418 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); | 414 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); |
419 | static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); | 415 | static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); |
420 | 416 | ||
@@ -568,7 +564,84 @@ static int rt286_adc_event(struct snd_soc_dapm_widget *w, | |||
568 | return 0; | 564 | return 0; |
569 | } | 565 | } |
570 | 566 | ||
567 | static int rt286_vref_event(struct snd_soc_dapm_widget *w, | ||
568 | struct snd_kcontrol *kcontrol, int event) | ||
569 | { | ||
570 | struct snd_soc_codec *codec = w->codec; | ||
571 | |||
572 | switch (event) { | ||
573 | case SND_SOC_DAPM_PRE_PMU: | ||
574 | snd_soc_update_bits(codec, | ||
575 | RT286_CBJ_CTRL1, 0x0400, 0x0000); | ||
576 | mdelay(50); | ||
577 | break; | ||
578 | default: | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int rt286_ldo2_event(struct snd_soc_dapm_widget *w, | ||
586 | struct snd_kcontrol *kcontrol, int event) | ||
587 | { | ||
588 | struct snd_soc_codec *codec = w->codec; | ||
589 | |||
590 | switch (event) { | ||
591 | case SND_SOC_DAPM_POST_PMU: | ||
592 | snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x08); | ||
593 | break; | ||
594 | case SND_SOC_DAPM_PRE_PMD: | ||
595 | snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x30); | ||
596 | break; | ||
597 | default: | ||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | static int rt286_mic1_event(struct snd_soc_dapm_widget *w, | ||
605 | struct snd_kcontrol *kcontrol, int event) | ||
606 | { | ||
607 | struct snd_soc_codec *codec = w->codec; | ||
608 | |||
609 | switch (event) { | ||
610 | case SND_SOC_DAPM_PRE_PMU: | ||
611 | snd_soc_update_bits(codec, | ||
612 | RT286_A_BIAS_CTRL3, 0xc000, 0x8000); | ||
613 | snd_soc_update_bits(codec, | ||
614 | RT286_A_BIAS_CTRL2, 0xc000, 0x8000); | ||
615 | break; | ||
616 | case SND_SOC_DAPM_POST_PMD: | ||
617 | snd_soc_update_bits(codec, | ||
618 | RT286_A_BIAS_CTRL3, 0xc000, 0x0000); | ||
619 | snd_soc_update_bits(codec, | ||
620 | RT286_A_BIAS_CTRL2, 0xc000, 0x0000); | ||
621 | break; | ||
622 | default: | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
571 | static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { | 629 | static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { |
630 | SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1, | ||
631 | 12, 1, NULL, 0), | ||
632 | SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1, | ||
633 | 0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU), | ||
634 | SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2, | ||
635 | 2, 0, NULL, 0), | ||
636 | SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1, | ||
637 | 13, 1, rt286_ldo2_event, SND_SOC_DAPM_PRE_PMD | | ||
638 | SND_SOC_DAPM_POST_PMU), | ||
639 | SND_SOC_DAPM_SUPPLY("MCLK MODE", RT286_PLL_CTRL1, | ||
640 | 5, 0, NULL, 0), | ||
641 | SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM, | ||
642 | 0, 0, rt286_mic1_event, SND_SOC_DAPM_PRE_PMU | | ||
643 | SND_SOC_DAPM_POST_PMD), | ||
644 | |||
572 | /* Input Lines */ | 645 | /* Input Lines */ |
573 | SND_SOC_DAPM_INPUT("DMIC1 Pin"), | 646 | SND_SOC_DAPM_INPUT("DMIC1 Pin"), |
574 | SND_SOC_DAPM_INPUT("DMIC2 Pin"), | 647 | SND_SOC_DAPM_INPUT("DMIC2 Pin"), |
@@ -642,6 +715,25 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { | |||
642 | }; | 715 | }; |
643 | 716 | ||
644 | static const struct snd_soc_dapm_route rt286_dapm_routes[] = { | 717 | static const struct snd_soc_dapm_route rt286_dapm_routes[] = { |
718 | {"ADC 0", NULL, "MCLK MODE", is_mclk_mode}, | ||
719 | {"ADC 1", NULL, "MCLK MODE", is_mclk_mode}, | ||
720 | {"Front", NULL, "MCLK MODE", is_mclk_mode}, | ||
721 | {"Surround", NULL, "MCLK MODE", is_mclk_mode}, | ||
722 | |||
723 | {"HP Power", NULL, "LDO1"}, | ||
724 | {"HP Power", NULL, "LDO2"}, | ||
725 | |||
726 | {"MIC1", NULL, "LDO1"}, | ||
727 | {"MIC1", NULL, "LDO2"}, | ||
728 | {"MIC1", NULL, "HV"}, | ||
729 | {"MIC1", NULL, "VREF"}, | ||
730 | {"MIC1", NULL, "MIC1 Input Buffer"}, | ||
731 | |||
732 | {"SPO", NULL, "LDO1"}, | ||
733 | {"SPO", NULL, "LDO2"}, | ||
734 | {"SPO", NULL, "HV"}, | ||
735 | {"SPO", NULL, "VREF"}, | ||
736 | |||
645 | {"DMIC1", NULL, "DMIC1 Pin"}, | 737 | {"DMIC1", NULL, "DMIC1 Pin"}, |
646 | {"DMIC2", NULL, "DMIC2 Pin"}, | 738 | {"DMIC2", NULL, "DMIC2 Pin"}, |
647 | {"DMIC1", NULL, "DMIC Receiver"}, | 739 | {"DMIC1", NULL, "DMIC Receiver"}, |
@@ -880,6 +972,7 @@ static int rt286_set_dai_sysclk(struct snd_soc_dai *dai, | |||
880 | } | 972 | } |
881 | 973 | ||
882 | rt286->sys_clk = freq; | 974 | rt286->sys_clk = freq; |
975 | rt286->clk_id = clk_id; | ||
883 | 976 | ||
884 | return 0; | 977 | return 0; |
885 | } | 978 | } |
@@ -915,13 +1008,18 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec, | |||
915 | 1008 | ||
916 | case SND_SOC_BIAS_ON: | 1009 | case SND_SOC_BIAS_ON: |
917 | mdelay(10); | 1010 | mdelay(10); |
1011 | snd_soc_update_bits(codec, | ||
1012 | RT286_CBJ_CTRL1, 0x0400, 0x0400); | ||
1013 | snd_soc_update_bits(codec, | ||
1014 | RT286_DC_GAIN, 0x200, 0x0); | ||
1015 | |||
918 | break; | 1016 | break; |
919 | 1017 | ||
920 | case SND_SOC_BIAS_STANDBY: | 1018 | case SND_SOC_BIAS_STANDBY: |
921 | snd_soc_write(codec, | 1019 | snd_soc_write(codec, |
922 | RT286_SET_AUDIO_POWER, AC_PWRST_D3); | 1020 | RT286_SET_AUDIO_POWER, AC_PWRST_D3); |
923 | snd_soc_update_bits(codec, | 1021 | snd_soc_update_bits(codec, |
924 | RT286_DC_GAIN, 0x200, 0x0); | 1022 | RT286_CBJ_CTRL1, 0x0400, 0x0000); |
925 | break; | 1023 | break; |
926 | 1024 | ||
927 | default: | 1025 | default: |
@@ -962,6 +1060,7 @@ static int rt286_probe(struct snd_soc_codec *codec) | |||
962 | { | 1060 | { |
963 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | 1061 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); |
964 | 1062 | ||
1063 | rt286->codec = codec; | ||
965 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | 1064 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; |
966 | 1065 | ||
967 | if (rt286->i2c->irq) { | 1066 | if (rt286->i2c->irq) { |
@@ -1107,6 +1206,16 @@ static const struct acpi_device_id rt286_acpi_match[] = { | |||
1107 | }; | 1206 | }; |
1108 | MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); | 1207 | MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); |
1109 | 1208 | ||
1209 | static struct dmi_system_id force_combo_jack_table[] = { | ||
1210 | { | ||
1211 | .ident = "Intel Wilson Beach", | ||
1212 | .matches = { | ||
1213 | DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS") | ||
1214 | } | ||
1215 | }, | ||
1216 | { } | ||
1217 | }; | ||
1218 | |||
1110 | static int rt286_i2c_probe(struct i2c_client *i2c, | 1219 | static int rt286_i2c_probe(struct i2c_client *i2c, |
1111 | const struct i2c_device_id *id) | 1220 | const struct i2c_device_id *id) |
1112 | { | 1221 | { |
@@ -1142,6 +1251,9 @@ static int rt286_i2c_probe(struct i2c_client *i2c, | |||
1142 | if (pdata) | 1251 | if (pdata) |
1143 | rt286->pdata = *pdata; | 1252 | rt286->pdata = *pdata; |
1144 | 1253 | ||
1254 | if (dmi_check_system(force_combo_jack_table)) | ||
1255 | rt286->pdata.cbj_en = true; | ||
1256 | |||
1145 | regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); | 1257 | regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); |
1146 | 1258 | ||
1147 | for (i = 0; i < RT286_POWER_REG_LEN; i++) | 1259 | for (i = 0; i < RT286_POWER_REG_LEN; i++) |
@@ -1152,7 +1264,6 @@ static int rt286_i2c_probe(struct i2c_client *i2c, | |||
1152 | if (!rt286->pdata.cbj_en) { | 1264 | if (!rt286->pdata.cbj_en) { |
1153 | regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000); | 1265 | regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000); |
1154 | regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816); | 1266 | regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816); |
1155 | regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); | ||
1156 | regmap_update_bits(rt286->regmap, | 1267 | regmap_update_bits(rt286->regmap, |
1157 | RT286_CBJ_CTRL1, 0xf000, 0xb000); | 1268 | RT286_CBJ_CTRL1, 0xf000, 0xb000); |
1158 | } else { | 1269 | } else { |
@@ -1169,10 +1280,12 @@ static int rt286_i2c_probe(struct i2c_client *i2c, | |||
1169 | 1280 | ||
1170 | mdelay(10); | 1281 | mdelay(10); |
1171 | 1282 | ||
1172 | /*Power down LDO2*/ | 1283 | regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); |
1173 | regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0); | 1284 | /* Power down LDO, VREF */ |
1285 | regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0xc, 0x0); | ||
1286 | regmap_update_bits(rt286->regmap, RT286_POWER_CTRL1, 0x1001, 0x1001); | ||
1174 | 1287 | ||
1175 | /*Set depop parameter*/ | 1288 | /* Set depop parameter */ |
1176 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a); | 1289 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a); |
1177 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); | 1290 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); |
1178 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); | 1291 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); |
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 1ba27db660a6..6d7b7ca7d530 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c | |||
@@ -1612,29 +1612,6 @@ static int rt5631_probe(struct snd_soc_codec *codec) | |||
1612 | return 0; | 1612 | return 0; |
1613 | } | 1613 | } |
1614 | 1614 | ||
1615 | static int rt5631_remove(struct snd_soc_codec *codec) | ||
1616 | { | ||
1617 | rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1618 | return 0; | ||
1619 | } | ||
1620 | |||
1621 | #ifdef CONFIG_PM | ||
1622 | static int rt5631_suspend(struct snd_soc_codec *codec) | ||
1623 | { | ||
1624 | rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1625 | return 0; | ||
1626 | } | ||
1627 | |||
1628 | static int rt5631_resume(struct snd_soc_codec *codec) | ||
1629 | { | ||
1630 | rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1631 | return 0; | ||
1632 | } | ||
1633 | #else | ||
1634 | #define rt5631_suspend NULL | ||
1635 | #define rt5631_resume NULL | ||
1636 | #endif | ||
1637 | |||
1638 | #define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000 | 1615 | #define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000 |
1639 | #define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \ | 1616 | #define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \ |
1640 | SNDRV_PCM_FMTBIT_S20_3LE | \ | 1617 | SNDRV_PCM_FMTBIT_S20_3LE | \ |
@@ -1672,10 +1649,8 @@ static struct snd_soc_dai_driver rt5631_dai[] = { | |||
1672 | 1649 | ||
1673 | static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { | 1650 | static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { |
1674 | .probe = rt5631_probe, | 1651 | .probe = rt5631_probe, |
1675 | .remove = rt5631_remove, | ||
1676 | .suspend = rt5631_suspend, | ||
1677 | .resume = rt5631_resume, | ||
1678 | .set_bias_level = rt5631_set_bias_level, | 1652 | .set_bias_level = rt5631_set_bias_level, |
1653 | .suspend_bias_off = true, | ||
1679 | .controls = rt5631_snd_controls, | 1654 | .controls = rt5631_snd_controls, |
1680 | .num_controls = ARRAY_SIZE(rt5631_snd_controls), | 1655 | .num_controls = ARRAY_SIZE(rt5631_snd_controls), |
1681 | .dapm_widgets = rt5631_dapm_widgets, | 1656 | .dapm_widgets = rt5631_dapm_widgets, |
@@ -1686,10 +1661,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { | |||
1686 | 1661 | ||
1687 | static const struct i2c_device_id rt5631_i2c_id[] = { | 1662 | static const struct i2c_device_id rt5631_i2c_id[] = { |
1688 | { "rt5631", 0 }, | 1663 | { "rt5631", 0 }, |
1664 | { "alc5631", 0 }, | ||
1689 | { } | 1665 | { } |
1690 | }; | 1666 | }; |
1691 | MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id); | 1667 | MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id); |
1692 | 1668 | ||
1669 | #ifdef CONFIG_OF | ||
1670 | static struct of_device_id rt5631_i2c_dt_ids[] = { | ||
1671 | { .compatible = "realtek,rt5631"}, | ||
1672 | { .compatible = "realtek,alc5631"}, | ||
1673 | { } | ||
1674 | }; | ||
1675 | MODULE_DEVICE_TABLE(of, rt5631_i2c_dt_ids); | ||
1676 | #endif | ||
1677 | |||
1693 | static const struct regmap_config rt5631_regmap_config = { | 1678 | static const struct regmap_config rt5631_regmap_config = { |
1694 | .reg_bits = 8, | 1679 | .reg_bits = 8, |
1695 | .val_bits = 16, | 1680 | .val_bits = 16, |
@@ -1734,6 +1719,7 @@ static struct i2c_driver rt5631_i2c_driver = { | |||
1734 | .driver = { | 1719 | .driver = { |
1735 | .name = "rt5631", | 1720 | .name = "rt5631", |
1736 | .owner = THIS_MODULE, | 1721 | .owner = THIS_MODULE, |
1722 | .of_match_table = of_match_ptr(rt5631_i2c_dt_ids), | ||
1737 | }, | 1723 | }, |
1738 | .probe = rt5631_i2c_probe, | 1724 | .probe = rt5631_i2c_probe, |
1739 | .remove = rt5631_i2c_remove, | 1725 | .remove = rt5631_i2c_remove, |
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index d16331e0b64d..a7789a8726e3 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c | |||
@@ -554,6 +554,53 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, | |||
554 | return 0; | 554 | return 0; |
555 | } | 555 | } |
556 | 556 | ||
557 | static int is_using_asrc(struct snd_soc_dapm_widget *source, | ||
558 | struct snd_soc_dapm_widget *sink) | ||
559 | { | ||
560 | unsigned int reg, shift, val; | ||
561 | |||
562 | switch (source->shift) { | ||
563 | case 0: | ||
564 | reg = RT5645_ASRC_3; | ||
565 | shift = 0; | ||
566 | break; | ||
567 | case 1: | ||
568 | reg = RT5645_ASRC_3; | ||
569 | shift = 4; | ||
570 | break; | ||
571 | case 3: | ||
572 | reg = RT5645_ASRC_2; | ||
573 | shift = 0; | ||
574 | break; | ||
575 | case 8: | ||
576 | reg = RT5645_ASRC_2; | ||
577 | shift = 4; | ||
578 | break; | ||
579 | case 9: | ||
580 | reg = RT5645_ASRC_2; | ||
581 | shift = 8; | ||
582 | break; | ||
583 | case 10: | ||
584 | reg = RT5645_ASRC_2; | ||
585 | shift = 12; | ||
586 | break; | ||
587 | default: | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | val = (snd_soc_read(source->codec, reg) >> shift) & 0xf; | ||
592 | switch (val) { | ||
593 | case 1: | ||
594 | case 2: | ||
595 | case 3: | ||
596 | case 4: | ||
597 | return 1; | ||
598 | default: | ||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | } | ||
603 | |||
557 | /* Digital Mixer */ | 604 | /* Digital Mixer */ |
558 | static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { | 605 | static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { |
559 | SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, | 606 | SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, |
@@ -1246,6 +1293,30 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { | |||
1246 | SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL, | 1293 | SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL, |
1247 | RT5645_PWR_MIC_DET_BIT, 0, NULL, 0), | 1294 | RT5645_PWR_MIC_DET_BIT, 0, NULL, 0), |
1248 | 1295 | ||
1296 | /* ASRC */ | ||
1297 | SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5645_ASRC_1, | ||
1298 | 11, 0, NULL, 0), | ||
1299 | SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5645_ASRC_1, | ||
1300 | 12, 0, NULL, 0), | ||
1301 | SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5645_ASRC_1, | ||
1302 | 10, 0, NULL, 0), | ||
1303 | SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5645_ASRC_1, | ||
1304 | 9, 0, NULL, 0), | ||
1305 | SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5645_ASRC_1, | ||
1306 | 8, 0, NULL, 0), | ||
1307 | SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5645_ASRC_1, | ||
1308 | 7, 0, NULL, 0), | ||
1309 | SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5645_ASRC_1, | ||
1310 | 5, 0, NULL, 0), | ||
1311 | SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5645_ASRC_1, | ||
1312 | 4, 0, NULL, 0), | ||
1313 | SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5645_ASRC_1, | ||
1314 | 3, 0, NULL, 0), | ||
1315 | SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5645_ASRC_1, | ||
1316 | 1, 0, NULL, 0), | ||
1317 | SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5645_ASRC_1, | ||
1318 | 0, 0, NULL, 0), | ||
1319 | |||
1249 | /* Input Side */ | 1320 | /* Input Side */ |
1250 | /* micbias */ | 1321 | /* micbias */ |
1251 | SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2, | 1322 | SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2, |
@@ -1504,6 +1575,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { | |||
1504 | }; | 1575 | }; |
1505 | 1576 | ||
1506 | static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { | 1577 | static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { |
1578 | { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc }, | ||
1579 | { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc }, | ||
1580 | { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc }, | ||
1581 | { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc }, | ||
1582 | { "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc }, | ||
1583 | { "dac mono right filter", NULL, "DAC MONO R ASRC", is_using_asrc }, | ||
1584 | { "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc }, | ||
1585 | |||
1586 | { "I2S1", NULL, "I2S1 ASRC" }, | ||
1587 | { "I2S2", NULL, "I2S2 ASRC" }, | ||
1588 | |||
1507 | { "IN1P", NULL, "LDO2" }, | 1589 | { "IN1P", NULL, "LDO2" }, |
1508 | { "IN2P", NULL, "LDO2" }, | 1590 | { "IN2P", NULL, "LDO2" }, |
1509 | 1591 | ||
@@ -1550,12 +1632,15 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { | |||
1550 | 1632 | ||
1551 | { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, | 1633 | { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, |
1552 | { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, | 1634 | { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, |
1635 | { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC" }, | ||
1553 | 1636 | ||
1554 | { "Mono DMIC L Mux", "DMIC1", "DMIC L1" }, | 1637 | { "Mono DMIC L Mux", "DMIC1", "DMIC L1" }, |
1555 | { "Mono DMIC L Mux", "DMIC2", "DMIC L2" }, | 1638 | { "Mono DMIC L Mux", "DMIC2", "DMIC L2" }, |
1639 | { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC" }, | ||
1556 | 1640 | ||
1557 | { "Mono DMIC R Mux", "DMIC1", "DMIC R1" }, | 1641 | { "Mono DMIC R Mux", "DMIC1", "DMIC R1" }, |
1558 | { "Mono DMIC R Mux", "DMIC2", "DMIC R2" }, | 1642 | { "Mono DMIC R Mux", "DMIC2", "DMIC R2" }, |
1643 | { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC" }, | ||
1559 | 1644 | ||
1560 | { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" }, | 1645 | { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" }, |
1561 | { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, | 1646 | { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, |
@@ -2029,8 +2114,11 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | |||
2029 | struct snd_soc_codec *codec = dai->codec; | 2114 | struct snd_soc_codec *codec = dai->codec; |
2030 | unsigned int val = 0; | 2115 | unsigned int val = 0; |
2031 | 2116 | ||
2032 | if (rx_mask || tx_mask) | 2117 | if (rx_mask || tx_mask) { |
2033 | val |= (1 << 14); | 2118 | val |= (1 << 14); |
2119 | snd_soc_update_bits(codec, RT5645_BASS_BACK, | ||
2120 | RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB); | ||
2121 | } | ||
2034 | 2122 | ||
2035 | switch (slots) { | 2123 | switch (slots) { |
2036 | case 4: | 2124 | case 4: |
@@ -2071,8 +2159,8 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2071 | enum snd_soc_bias_level level) | 2159 | enum snd_soc_bias_level level) |
2072 | { | 2160 | { |
2073 | switch (level) { | 2161 | switch (level) { |
2074 | case SND_SOC_BIAS_STANDBY: | 2162 | case SND_SOC_BIAS_PREPARE: |
2075 | if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { | 2163 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { |
2076 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | 2164 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, |
2077 | RT5645_PWR_VREF1 | RT5645_PWR_MB | | 2165 | RT5645_PWR_VREF1 | RT5645_PWR_MB | |
2078 | RT5645_PWR_BG | RT5645_PWR_VREF2, | 2166 | RT5645_PWR_BG | RT5645_PWR_VREF2, |
@@ -2087,15 +2175,24 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2087 | } | 2175 | } |
2088 | break; | 2176 | break; |
2089 | 2177 | ||
2178 | case SND_SOC_BIAS_STANDBY: | ||
2179 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | ||
2180 | RT5645_PWR_VREF1 | RT5645_PWR_MB | | ||
2181 | RT5645_PWR_BG | RT5645_PWR_VREF2, | ||
2182 | RT5645_PWR_VREF1 | RT5645_PWR_MB | | ||
2183 | RT5645_PWR_BG | RT5645_PWR_VREF2); | ||
2184 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | ||
2185 | RT5645_PWR_FV1 | RT5645_PWR_FV2, | ||
2186 | RT5645_PWR_FV1 | RT5645_PWR_FV2); | ||
2187 | break; | ||
2188 | |||
2090 | case SND_SOC_BIAS_OFF: | 2189 | case SND_SOC_BIAS_OFF: |
2091 | snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); | 2190 | snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); |
2092 | snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128); | 2191 | snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128); |
2093 | snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000); | 2192 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, |
2094 | snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000); | 2193 | RT5645_PWR_VREF1 | RT5645_PWR_MB | |
2095 | snd_soc_write(codec, RT5645_PWR_VOL, 0x0000); | 2194 | RT5645_PWR_BG | RT5645_PWR_VREF2 | |
2096 | snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000); | 2195 | RT5645_PWR_FV1 | RT5645_PWR_FV2, 0x0); |
2097 | snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000); | ||
2098 | snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000); | ||
2099 | break; | 2196 | break; |
2100 | 2197 | ||
2101 | default: | 2198 | default: |
@@ -2106,8 +2203,7 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2106 | return 0; | 2203 | return 0; |
2107 | } | 2204 | } |
2108 | 2205 | ||
2109 | static int rt5645_jack_detect(struct snd_soc_codec *codec, | 2206 | static int rt5645_jack_detect(struct snd_soc_codec *codec) |
2110 | struct snd_soc_jack *jack) | ||
2111 | { | 2207 | { |
2112 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | 2208 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); |
2113 | int gpio_state, jack_type = 0; | 2209 | int gpio_state, jack_type = 0; |
@@ -2145,34 +2241,44 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, | |||
2145 | 2241 | ||
2146 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); | 2242 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); |
2147 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); | 2243 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); |
2148 | snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); | 2244 | if (rt5645->pdata.jd_mode == 0) |
2245 | snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); | ||
2149 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); | 2246 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); |
2150 | snd_soc_dapm_sync(&codec->dapm); | 2247 | snd_soc_dapm_sync(&codec->dapm); |
2151 | } | 2248 | } |
2152 | 2249 | ||
2153 | snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET); | 2250 | snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE); |
2154 | 2251 | snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE); | |
2155 | return 0; | 2252 | return 0; |
2156 | } | 2253 | } |
2157 | 2254 | ||
2158 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, | 2255 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, |
2159 | struct snd_soc_jack *jack) | 2256 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack) |
2160 | { | 2257 | { |
2161 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | 2258 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); |
2162 | 2259 | ||
2163 | rt5645->jack = jack; | 2260 | rt5645->hp_jack = hp_jack; |
2164 | 2261 | rt5645->mic_jack = mic_jack; | |
2165 | rt5645_jack_detect(codec, rt5645->jack); | 2262 | rt5645_jack_detect(codec); |
2166 | 2263 | ||
2167 | return 0; | 2264 | return 0; |
2168 | } | 2265 | } |
2169 | EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); | 2266 | EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); |
2170 | 2267 | ||
2268 | static void rt5645_jack_detect_work(struct work_struct *work) | ||
2269 | { | ||
2270 | struct rt5645_priv *rt5645 = | ||
2271 | container_of(work, struct rt5645_priv, jack_detect_work.work); | ||
2272 | |||
2273 | rt5645_jack_detect(rt5645->codec); | ||
2274 | } | ||
2275 | |||
2171 | static irqreturn_t rt5645_irq(int irq, void *data) | 2276 | static irqreturn_t rt5645_irq(int irq, void *data) |
2172 | { | 2277 | { |
2173 | struct rt5645_priv *rt5645 = data; | 2278 | struct rt5645_priv *rt5645 = data; |
2174 | 2279 | ||
2175 | rt5645_jack_detect(rt5645->codec, rt5645->jack); | 2280 | queue_delayed_work(system_power_efficient_wq, |
2281 | &rt5645->jack_detect_work, msecs_to_jiffies(250)); | ||
2176 | 2282 | ||
2177 | return IRQ_HANDLED; | 2283 | return IRQ_HANDLED; |
2178 | } | 2284 | } |
@@ -2187,6 +2293,13 @@ static int rt5645_probe(struct snd_soc_codec *codec) | |||
2187 | 2293 | ||
2188 | snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); | 2294 | snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); |
2189 | 2295 | ||
2296 | /* for JD function */ | ||
2297 | if (rt5645->pdata.en_jd_func) { | ||
2298 | snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power"); | ||
2299 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); | ||
2300 | snd_soc_dapm_sync(&codec->dapm); | ||
2301 | } | ||
2302 | |||
2190 | return 0; | 2303 | return 0; |
2191 | } | 2304 | } |
2192 | 2305 | ||
@@ -2420,6 +2533,51 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2420 | 2533 | ||
2421 | } | 2534 | } |
2422 | 2535 | ||
2536 | if (rt5645->pdata.en_jd_func) { | ||
2537 | regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, | ||
2538 | RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU, | ||
2539 | RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU); | ||
2540 | regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, | ||
2541 | RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN); | ||
2542 | regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3, | ||
2543 | RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL, | ||
2544 | RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL); | ||
2545 | regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, | ||
2546 | RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT); | ||
2547 | } | ||
2548 | |||
2549 | if (rt5645->pdata.jd_mode) { | ||
2550 | regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, | ||
2551 | RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN); | ||
2552 | regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, | ||
2553 | RT5645_JD_PSV_MODE, RT5645_JD_PSV_MODE); | ||
2554 | regmap_update_bits(rt5645->regmap, RT5645_HPO_MIXER, | ||
2555 | RT5645_IRQ_PSV_MODE, RT5645_IRQ_PSV_MODE); | ||
2556 | regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, | ||
2557 | RT5645_MIC2_OVCD_EN, RT5645_MIC2_OVCD_EN); | ||
2558 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | ||
2559 | RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ); | ||
2560 | switch (rt5645->pdata.jd_mode) { | ||
2561 | case 1: | ||
2562 | regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, | ||
2563 | RT5645_JD1_MODE_MASK, | ||
2564 | RT5645_JD1_MODE_0); | ||
2565 | break; | ||
2566 | case 2: | ||
2567 | regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, | ||
2568 | RT5645_JD1_MODE_MASK, | ||
2569 | RT5645_JD1_MODE_1); | ||
2570 | break; | ||
2571 | case 3: | ||
2572 | regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, | ||
2573 | RT5645_JD1_MODE_MASK, | ||
2574 | RT5645_JD1_MODE_2); | ||
2575 | break; | ||
2576 | default: | ||
2577 | break; | ||
2578 | } | ||
2579 | } | ||
2580 | |||
2423 | if (rt5645->i2c->irq) { | 2581 | if (rt5645->i2c->irq) { |
2424 | ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, | 2582 | ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, |
2425 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 2583 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
@@ -2438,6 +2596,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2438 | dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n"); | 2596 | dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n"); |
2439 | } | 2597 | } |
2440 | 2598 | ||
2599 | INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); | ||
2600 | |||
2441 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, | 2601 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, |
2442 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); | 2602 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); |
2443 | } | 2603 | } |
@@ -2449,6 +2609,8 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) | |||
2449 | if (i2c->irq) | 2609 | if (i2c->irq) |
2450 | free_irq(i2c->irq, rt5645); | 2610 | free_irq(i2c->irq, rt5645); |
2451 | 2611 | ||
2612 | cancel_delayed_work_sync(&rt5645->jack_detect_work); | ||
2613 | |||
2452 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) | 2614 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) |
2453 | gpio_free(rt5645->pdata.hp_det_gpio); | 2615 | gpio_free(rt5645->pdata.hp_det_gpio); |
2454 | 2616 | ||
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 50c62c5668ea..a815e36a2bdb 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h | |||
@@ -594,6 +594,7 @@ | |||
594 | #define RT5645_M_DAC1_HM_SFT 14 | 594 | #define RT5645_M_DAC1_HM_SFT 14 |
595 | #define RT5645_M_HPVOL_HM (0x1 << 13) | 595 | #define RT5645_M_HPVOL_HM (0x1 << 13) |
596 | #define RT5645_M_HPVOL_HM_SFT 13 | 596 | #define RT5645_M_HPVOL_HM_SFT 13 |
597 | #define RT5645_IRQ_PSV_MODE (0x1 << 12) | ||
597 | 598 | ||
598 | /* SPK Left Mixer Control (0x46) */ | 599 | /* SPK Left Mixer Control (0x46) */ |
599 | #define RT5645_G_RM_L_SM_L_MASK (0x3 << 14) | 600 | #define RT5645_G_RM_L_SM_L_MASK (0x3 << 14) |
@@ -1348,6 +1349,12 @@ | |||
1348 | #define RT5645_PWR_CLK25M_SFT 4 | 1349 | #define RT5645_PWR_CLK25M_SFT 4 |
1349 | #define RT5645_PWR_CLK25M_PD (0x0 << 4) | 1350 | #define RT5645_PWR_CLK25M_PD (0x0 << 4) |
1350 | #define RT5645_PWR_CLK25M_PU (0x1 << 4) | 1351 | #define RT5645_PWR_CLK25M_PU (0x1 << 4) |
1352 | #define RT5645_IRQ_CLK_MCLK (0x0 << 3) | ||
1353 | #define RT5645_IRQ_CLK_INT (0x1 << 3) | ||
1354 | #define RT5645_JD1_MODE_MASK (0x3 << 0) | ||
1355 | #define RT5645_JD1_MODE_0 (0x0 << 0) | ||
1356 | #define RT5645_JD1_MODE_1 (0x1 << 0) | ||
1357 | #define RT5645_JD1_MODE_2 (0x2 << 0) | ||
1351 | 1358 | ||
1352 | /* VAD Control 4 (0x9d) */ | 1359 | /* VAD Control 4 (0x9d) */ |
1353 | #define RT5645_VAD_SEL_MASK (0x3 << 8) | 1360 | #define RT5645_VAD_SEL_MASK (0x3 << 8) |
@@ -1636,6 +1643,7 @@ | |||
1636 | #define RT5645_OT_P_SFT 10 | 1643 | #define RT5645_OT_P_SFT 10 |
1637 | #define RT5645_OT_P_NOR (0x0 << 10) | 1644 | #define RT5645_OT_P_NOR (0x0 << 10) |
1638 | #define RT5645_OT_P_INV (0x1 << 10) | 1645 | #define RT5645_OT_P_INV (0x1 << 10) |
1646 | #define RT5645_IRQ_JD_1_1_EN (0x1 << 9) | ||
1639 | 1647 | ||
1640 | /* IRQ Control 2 (0xbe) */ | 1648 | /* IRQ Control 2 (0xbe) */ |
1641 | #define RT5645_IRQ_MB1_OC_MASK (0x1 << 15) | 1649 | #define RT5645_IRQ_MB1_OC_MASK (0x1 << 15) |
@@ -1853,6 +1861,7 @@ | |||
1853 | #define RT5645_M_BB_HPF_R_SFT 6 | 1861 | #define RT5645_M_BB_HPF_R_SFT 6 |
1854 | #define RT5645_G_BB_BST_MASK (0x3f) | 1862 | #define RT5645_G_BB_BST_MASK (0x3f) |
1855 | #define RT5645_G_BB_BST_SFT 0 | 1863 | #define RT5645_G_BB_BST_SFT 0 |
1864 | #define RT5645_G_BB_BST_25DB 0x14 | ||
1856 | 1865 | ||
1857 | /* MP3 Plus Control 1 (0xd0) */ | 1866 | /* MP3 Plus Control 1 (0xd0) */ |
1858 | #define RT5645_M_MP3_L_MASK (0x1 << 15) | 1867 | #define RT5645_M_MP3_L_MASK (0x1 << 15) |
@@ -2116,6 +2125,10 @@ enum { | |||
2116 | #define RT5645_RXDP2_SEL_ADC (0x1 << 3) | 2125 | #define RT5645_RXDP2_SEL_ADC (0x1 << 3) |
2117 | #define RT5645_RXDP2_SEL_SFT (3) | 2126 | #define RT5645_RXDP2_SEL_SFT (3) |
2118 | 2127 | ||
2128 | /* General Control3 (0xfc) */ | ||
2129 | #define RT5645_JD_PSV_MODE (0x1 << 12) | ||
2130 | #define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11) | ||
2131 | #define RT5645_MICINDET_MANU (0x1 << 7) | ||
2119 | 2132 | ||
2120 | /* Vendor ID (0xfd) */ | 2133 | /* Vendor ID (0xfd) */ |
2121 | #define RT5645_VER_C 0x2 | 2134 | #define RT5645_VER_C 0x2 |
@@ -2167,7 +2180,9 @@ struct rt5645_priv { | |||
2167 | struct rt5645_platform_data pdata; | 2180 | struct rt5645_platform_data pdata; |
2168 | struct regmap *regmap; | 2181 | struct regmap *regmap; |
2169 | struct i2c_client *i2c; | 2182 | struct i2c_client *i2c; |
2170 | struct snd_soc_jack *jack; | 2183 | struct snd_soc_jack *hp_jack; |
2184 | struct snd_soc_jack *mic_jack; | ||
2185 | struct delayed_work jack_detect_work; | ||
2171 | 2186 | ||
2172 | int sysclk; | 2187 | int sysclk; |
2173 | int sysclk_src; | 2188 | int sysclk_src; |
@@ -2181,6 +2196,6 @@ struct rt5645_priv { | |||
2181 | }; | 2196 | }; |
2182 | 2197 | ||
2183 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, | 2198 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, |
2184 | struct snd_soc_jack *jack); | 2199 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack); |
2185 | 2200 | ||
2186 | #endif /* __RT5645_H__ */ | 2201 | #endif /* __RT5645_H__ */ |
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 9bd8b4f63303..8a0833de1665 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/acpi.h> | ||
19 | #include <linux/spi/spi.h> | 20 | #include <linux/spi/spi.h> |
20 | #include <sound/core.h> | 21 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
@@ -575,6 +576,18 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source, | |||
575 | 576 | ||
576 | } | 577 | } |
577 | 578 | ||
579 | static int can_use_asrc(struct snd_soc_dapm_widget *source, | ||
580 | struct snd_soc_dapm_widget *sink) | ||
581 | { | ||
582 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); | ||
583 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | ||
584 | |||
585 | if (rt5670->sysclk > rt5670->lrck[RT5670_AIF1] * 384) | ||
586 | return 1; | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
578 | /* Digital Mixer */ | 591 | /* Digital Mixer */ |
579 | static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { | 592 | static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { |
580 | SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, | 593 | SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, |
@@ -1281,6 +1294,14 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { | |||
1281 | 9, 0, NULL, 0), | 1294 | 9, 0, NULL, 0), |
1282 | SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1, | 1295 | SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1, |
1283 | 8, 0, NULL, 0), | 1296 | 8, 0, NULL, 0), |
1297 | SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5670_ASRC_1, | ||
1298 | 7, 0, NULL, 0), | ||
1299 | SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5670_ASRC_1, | ||
1300 | 6, 0, NULL, 0), | ||
1301 | SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5670_ASRC_1, | ||
1302 | 5, 0, NULL, 0), | ||
1303 | SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5670_ASRC_1, | ||
1304 | 4, 0, NULL, 0), | ||
1284 | SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1, | 1305 | SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1, |
1285 | 3, 0, NULL, 0), | 1306 | 3, 0, NULL, 0), |
1286 | SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1, | 1307 | SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1, |
@@ -1595,29 +1616,40 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { | |||
1595 | /* PDM */ | 1616 | /* PDM */ |
1596 | SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2, | 1617 | SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2, |
1597 | RT5670_PWR_PDM1_BIT, 0, NULL, 0), | 1618 | RT5670_PWR_PDM1_BIT, 0, NULL, 0), |
1598 | SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2, | ||
1599 | RT5670_PWR_PDM2_BIT, 0, NULL, 0), | ||
1600 | 1619 | ||
1601 | SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL, | 1620 | SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL, |
1602 | RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux), | 1621 | RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux), |
1603 | SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL, | 1622 | SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL, |
1604 | RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux), | 1623 | RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux), |
1605 | SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL, | ||
1606 | RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux), | ||
1607 | SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL, | ||
1608 | RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux), | ||
1609 | 1624 | ||
1610 | /* Output Lines */ | 1625 | /* Output Lines */ |
1611 | SND_SOC_DAPM_OUTPUT("HPOL"), | 1626 | SND_SOC_DAPM_OUTPUT("HPOL"), |
1612 | SND_SOC_DAPM_OUTPUT("HPOR"), | 1627 | SND_SOC_DAPM_OUTPUT("HPOR"), |
1613 | SND_SOC_DAPM_OUTPUT("LOUTL"), | 1628 | SND_SOC_DAPM_OUTPUT("LOUTL"), |
1614 | SND_SOC_DAPM_OUTPUT("LOUTR"), | 1629 | SND_SOC_DAPM_OUTPUT("LOUTR"), |
1630 | }; | ||
1631 | |||
1632 | static const struct snd_soc_dapm_widget rt5670_specific_dapm_widgets[] = { | ||
1633 | SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2, | ||
1634 | RT5670_PWR_PDM2_BIT, 0, NULL, 0), | ||
1635 | SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL, | ||
1636 | RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux), | ||
1637 | SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL, | ||
1638 | RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux), | ||
1615 | SND_SOC_DAPM_OUTPUT("PDM1L"), | 1639 | SND_SOC_DAPM_OUTPUT("PDM1L"), |
1616 | SND_SOC_DAPM_OUTPUT("PDM1R"), | 1640 | SND_SOC_DAPM_OUTPUT("PDM1R"), |
1617 | SND_SOC_DAPM_OUTPUT("PDM2L"), | 1641 | SND_SOC_DAPM_OUTPUT("PDM2L"), |
1618 | SND_SOC_DAPM_OUTPUT("PDM2R"), | 1642 | SND_SOC_DAPM_OUTPUT("PDM2R"), |
1619 | }; | 1643 | }; |
1620 | 1644 | ||
1645 | static const struct snd_soc_dapm_widget rt5672_specific_dapm_widgets[] = { | ||
1646 | SND_SOC_DAPM_PGA("SPO Amp", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1647 | SND_SOC_DAPM_OUTPUT("SPOLP"), | ||
1648 | SND_SOC_DAPM_OUTPUT("SPOLN"), | ||
1649 | SND_SOC_DAPM_OUTPUT("SPORP"), | ||
1650 | SND_SOC_DAPM_OUTPUT("SPORN"), | ||
1651 | }; | ||
1652 | |||
1621 | static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | 1653 | static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { |
1622 | { "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc }, | 1654 | { "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc }, |
1623 | { "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc }, | 1655 | { "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc }, |
@@ -1626,9 +1658,13 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | |||
1626 | { "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc }, | 1658 | { "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc }, |
1627 | { "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc }, | 1659 | { "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc }, |
1628 | { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc }, | 1660 | { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc }, |
1661 | { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc }, | ||
1662 | { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc }, | ||
1663 | { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc }, | ||
1664 | { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc }, | ||
1629 | 1665 | ||
1630 | { "I2S1", NULL, "I2S1 ASRC" }, | 1666 | { "I2S1", NULL, "I2S1 ASRC", can_use_asrc}, |
1631 | { "I2S2", NULL, "I2S2 ASRC" }, | 1667 | { "I2S2", NULL, "I2S2 ASRC", can_use_asrc}, |
1632 | 1668 | ||
1633 | { "DMIC1", NULL, "DMIC L1" }, | 1669 | { "DMIC1", NULL, "DMIC L1" }, |
1634 | { "DMIC1", NULL, "DMIC R1" }, | 1670 | { "DMIC1", NULL, "DMIC R1" }, |
@@ -1970,12 +2006,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | |||
1970 | { "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, | 2006 | { "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, |
1971 | { "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" }, | 2007 | { "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" }, |
1972 | { "PDM1 R Mux", NULL, "PDM1 Power" }, | 2008 | { "PDM1 R Mux", NULL, "PDM1 Power" }, |
1973 | { "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, | ||
1974 | { "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" }, | ||
1975 | { "PDM2 L Mux", NULL, "PDM2 Power" }, | ||
1976 | { "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, | ||
1977 | { "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" }, | ||
1978 | { "PDM2 R Mux", NULL, "PDM2 Power" }, | ||
1979 | 2009 | ||
1980 | { "HP Amp", NULL, "HPO MIX" }, | 2010 | { "HP Amp", NULL, "HPO MIX" }, |
1981 | { "HP Amp", NULL, "Mic Det Power" }, | 2011 | { "HP Amp", NULL, "Mic Det Power" }, |
@@ -1993,13 +2023,30 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | |||
1993 | { "LOUTR", NULL, "LOUT R Playback" }, | 2023 | { "LOUTR", NULL, "LOUT R Playback" }, |
1994 | { "LOUTL", NULL, "Improve HP Amp Drv" }, | 2024 | { "LOUTL", NULL, "Improve HP Amp Drv" }, |
1995 | { "LOUTR", NULL, "Improve HP Amp Drv" }, | 2025 | { "LOUTR", NULL, "Improve HP Amp Drv" }, |
2026 | }; | ||
1996 | 2027 | ||
2028 | static const struct snd_soc_dapm_route rt5670_specific_dapm_routes[] = { | ||
2029 | { "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, | ||
2030 | { "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" }, | ||
2031 | { "PDM2 L Mux", NULL, "PDM2 Power" }, | ||
2032 | { "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, | ||
2033 | { "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" }, | ||
2034 | { "PDM2 R Mux", NULL, "PDM2 Power" }, | ||
1997 | { "PDM1L", NULL, "PDM1 L Mux" }, | 2035 | { "PDM1L", NULL, "PDM1 L Mux" }, |
1998 | { "PDM1R", NULL, "PDM1 R Mux" }, | 2036 | { "PDM1R", NULL, "PDM1 R Mux" }, |
1999 | { "PDM2L", NULL, "PDM2 L Mux" }, | 2037 | { "PDM2L", NULL, "PDM2 L Mux" }, |
2000 | { "PDM2R", NULL, "PDM2 R Mux" }, | 2038 | { "PDM2R", NULL, "PDM2 R Mux" }, |
2001 | }; | 2039 | }; |
2002 | 2040 | ||
2041 | static const struct snd_soc_dapm_route rt5672_specific_dapm_routes[] = { | ||
2042 | { "SPO Amp", NULL, "PDM1 L Mux" }, | ||
2043 | { "SPO Amp", NULL, "PDM1 R Mux" }, | ||
2044 | { "SPOLP", NULL, "SPO Amp" }, | ||
2045 | { "SPOLN", NULL, "SPO Amp" }, | ||
2046 | { "SPORP", NULL, "SPO Amp" }, | ||
2047 | { "SPORN", NULL, "SPO Amp" }, | ||
2048 | }; | ||
2049 | |||
2003 | static int rt5670_hw_params(struct snd_pcm_substream *substream, | 2050 | static int rt5670_hw_params(struct snd_pcm_substream *substream, |
2004 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 2051 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
2005 | { | 2052 | { |
@@ -2287,6 +2334,8 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | |||
2287 | static int rt5670_set_bias_level(struct snd_soc_codec *codec, | 2334 | static int rt5670_set_bias_level(struct snd_soc_codec *codec, |
2288 | enum snd_soc_bias_level level) | 2335 | enum snd_soc_bias_level level) |
2289 | { | 2336 | { |
2337 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | ||
2338 | |||
2290 | switch (level) { | 2339 | switch (level) { |
2291 | case SND_SOC_BIAS_PREPARE: | 2340 | case SND_SOC_BIAS_PREPARE: |
2292 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { | 2341 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { |
@@ -2308,16 +2357,27 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, | |||
2308 | } | 2357 | } |
2309 | break; | 2358 | break; |
2310 | case SND_SOC_BIAS_STANDBY: | 2359 | case SND_SOC_BIAS_STANDBY: |
2311 | snd_soc_write(codec, RT5670_PWR_DIG1, 0x0000); | 2360 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, |
2312 | snd_soc_write(codec, RT5670_PWR_DIG2, 0x0001); | 2361 | RT5670_PWR_VREF1 | RT5670_PWR_VREF2 | |
2313 | snd_soc_write(codec, RT5670_PWR_VOL, 0x0000); | 2362 | RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); |
2314 | snd_soc_write(codec, RT5670_PWR_MIXER, 0x0001); | ||
2315 | snd_soc_write(codec, RT5670_PWR_ANLG1, 0x2800); | ||
2316 | snd_soc_write(codec, RT5670_PWR_ANLG2, 0x0004); | ||
2317 | snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0); | ||
2318 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, | 2363 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, |
2319 | RT5670_LDO_SEL_MASK, 0x1); | 2364 | RT5670_LDO_SEL_MASK, 0x1); |
2320 | break; | 2365 | break; |
2366 | case SND_SOC_BIAS_OFF: | ||
2367 | if (rt5670->pdata.jd_mode) | ||
2368 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, | ||
2369 | RT5670_PWR_VREF1 | RT5670_PWR_MB | | ||
2370 | RT5670_PWR_BG | RT5670_PWR_VREF2 | | ||
2371 | RT5670_PWR_FV1 | RT5670_PWR_FV2, | ||
2372 | RT5670_PWR_MB | RT5670_PWR_BG); | ||
2373 | else | ||
2374 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, | ||
2375 | RT5670_PWR_VREF1 | RT5670_PWR_MB | | ||
2376 | RT5670_PWR_BG | RT5670_PWR_VREF2 | | ||
2377 | RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); | ||
2378 | |||
2379 | snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0); | ||
2380 | break; | ||
2321 | 2381 | ||
2322 | default: | 2382 | default: |
2323 | break; | 2383 | break; |
@@ -2331,6 +2391,29 @@ static int rt5670_probe(struct snd_soc_codec *codec) | |||
2331 | { | 2391 | { |
2332 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | 2392 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
2333 | 2393 | ||
2394 | switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) { | ||
2395 | case RT5670_ID_5670: | ||
2396 | case RT5670_ID_5671: | ||
2397 | snd_soc_dapm_new_controls(&codec->dapm, | ||
2398 | rt5670_specific_dapm_widgets, | ||
2399 | ARRAY_SIZE(rt5670_specific_dapm_widgets)); | ||
2400 | snd_soc_dapm_add_routes(&codec->dapm, | ||
2401 | rt5670_specific_dapm_routes, | ||
2402 | ARRAY_SIZE(rt5670_specific_dapm_routes)); | ||
2403 | break; | ||
2404 | case RT5670_ID_5672: | ||
2405 | snd_soc_dapm_new_controls(&codec->dapm, | ||
2406 | rt5672_specific_dapm_widgets, | ||
2407 | ARRAY_SIZE(rt5672_specific_dapm_widgets)); | ||
2408 | snd_soc_dapm_add_routes(&codec->dapm, | ||
2409 | rt5672_specific_dapm_routes, | ||
2410 | ARRAY_SIZE(rt5672_specific_dapm_routes)); | ||
2411 | break; | ||
2412 | default: | ||
2413 | dev_err(codec->dev, | ||
2414 | "The driver is for RT5670 RT5671 or RT5672 only\n"); | ||
2415 | return -ENODEV; | ||
2416 | } | ||
2334 | rt5670->codec = codec; | 2417 | rt5670->codec = codec; |
2335 | 2418 | ||
2336 | return 0; | 2419 | return 0; |
@@ -2452,10 +2535,20 @@ static const struct regmap_config rt5670_regmap = { | |||
2452 | 2535 | ||
2453 | static const struct i2c_device_id rt5670_i2c_id[] = { | 2536 | static const struct i2c_device_id rt5670_i2c_id[] = { |
2454 | { "rt5670", 0 }, | 2537 | { "rt5670", 0 }, |
2538 | { "rt5671", 0 }, | ||
2539 | { "rt5672", 0 }, | ||
2455 | { } | 2540 | { } |
2456 | }; | 2541 | }; |
2457 | MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); | 2542 | MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); |
2458 | 2543 | ||
2544 | #ifdef CONFIG_ACPI | ||
2545 | static struct acpi_device_id rt5670_acpi_match[] = { | ||
2546 | { "10EC5670", 0}, | ||
2547 | { }, | ||
2548 | }; | ||
2549 | MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); | ||
2550 | #endif | ||
2551 | |||
2459 | static int rt5670_i2c_probe(struct i2c_client *i2c, | 2552 | static int rt5670_i2c_probe(struct i2c_client *i2c, |
2460 | const struct i2c_device_id *id) | 2553 | const struct i2c_device_id *id) |
2461 | { | 2554 | { |
@@ -2644,6 +2737,7 @@ static struct i2c_driver rt5670_i2c_driver = { | |||
2644 | .driver = { | 2737 | .driver = { |
2645 | .name = "rt5670", | 2738 | .name = "rt5670", |
2646 | .owner = THIS_MODULE, | 2739 | .owner = THIS_MODULE, |
2740 | .acpi_match_table = ACPI_PTR(rt5670_acpi_match), | ||
2647 | }, | 2741 | }, |
2648 | .probe = rt5670_i2c_probe, | 2742 | .probe = rt5670_i2c_probe, |
2649 | .remove = rt5670_i2c_remove, | 2743 | .remove = rt5670_i2c_remove, |
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index a0b5c855b492..d11b9c207e26 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h | |||
@@ -228,6 +228,12 @@ | |||
228 | #define RT5670_R_VOL_MASK (0x3f) | 228 | #define RT5670_R_VOL_MASK (0x3f) |
229 | #define RT5670_R_VOL_SFT 0 | 229 | #define RT5670_R_VOL_SFT 0 |
230 | 230 | ||
231 | /* SW Reset & Device ID (0x00) */ | ||
232 | #define RT5670_ID_MASK (0x3 << 1) | ||
233 | #define RT5670_ID_5670 (0x0 << 1) | ||
234 | #define RT5670_ID_5672 (0x1 << 1) | ||
235 | #define RT5670_ID_5671 (0x2 << 1) | ||
236 | |||
231 | /* Combo Jack Control 1 (0x0a) */ | 237 | /* Combo Jack Control 1 (0x0a) */ |
232 | #define RT5670_CBJ_BST1_MASK (0xf << 12) | 238 | #define RT5670_CBJ_BST1_MASK (0xf << 12) |
233 | #define RT5670_CBJ_BST1_SFT (12) | 239 | #define RT5670_CBJ_BST1_SFT (12) |
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c new file mode 100644 index 000000000000..ef6348cb9157 --- /dev/null +++ b/sound/soc/codecs/rt5677-spi.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * rt5677-spi.c -- RT5677 ALSA SoC audio codec driver | ||
3 | * | ||
4 | * Copyright 2013 Realtek Semiconductor Corp. | ||
5 | * Author: Oder Chiou <oder_chiou@realtek.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 <linux/input.h> | ||
14 | #include <linux/spi/spi.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/kthread.h> | ||
24 | #include <linux/uaccess.h> | ||
25 | #include <linux/miscdevice.h> | ||
26 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/pm_qos.h> | ||
28 | #include <linux/sysfs.h> | ||
29 | #include <linux/clk.h> | ||
30 | #include <linux/firmware.h> | ||
31 | |||
32 | #include "rt5677-spi.h" | ||
33 | |||
34 | static struct spi_device *g_spi; | ||
35 | |||
36 | /** | ||
37 | * rt5677_spi_write - Write data to SPI. | ||
38 | * @txbuf: Data Buffer for writing. | ||
39 | * @len: Data length. | ||
40 | * | ||
41 | * | ||
42 | * Returns true for success. | ||
43 | */ | ||
44 | int rt5677_spi_write(u8 *txbuf, size_t len) | ||
45 | { | ||
46 | int status; | ||
47 | |||
48 | status = spi_write(g_spi, txbuf, len); | ||
49 | |||
50 | if (status) | ||
51 | dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); | ||
52 | |||
53 | return status; | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(rt5677_spi_write); | ||
56 | |||
57 | /** | ||
58 | * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. | ||
59 | * @addr: Start address. | ||
60 | * @txbuf: Data Buffer for writng. | ||
61 | * @len: Data length, it must be a multiple of 8. | ||
62 | * | ||
63 | * | ||
64 | * Returns true for success. | ||
65 | */ | ||
66 | int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) | ||
67 | { | ||
68 | u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; | ||
69 | u8 *write_buf; | ||
70 | unsigned int i, end, offset = 0; | ||
71 | |||
72 | write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); | ||
73 | |||
74 | if (write_buf == NULL) | ||
75 | return -ENOMEM; | ||
76 | |||
77 | while (offset < fw->size) { | ||
78 | if (offset + RT5677_SPI_BUF_LEN <= fw->size) | ||
79 | end = RT5677_SPI_BUF_LEN; | ||
80 | else | ||
81 | end = fw->size % RT5677_SPI_BUF_LEN; | ||
82 | |||
83 | write_buf[0] = spi_cmd; | ||
84 | write_buf[1] = ((addr + offset) & 0xff000000) >> 24; | ||
85 | write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; | ||
86 | write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; | ||
87 | write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; | ||
88 | |||
89 | for (i = 0; i < end; i += 8) { | ||
90 | write_buf[i + 12] = fw->data[offset + i + 0]; | ||
91 | write_buf[i + 11] = fw->data[offset + i + 1]; | ||
92 | write_buf[i + 10] = fw->data[offset + i + 2]; | ||
93 | write_buf[i + 9] = fw->data[offset + i + 3]; | ||
94 | write_buf[i + 8] = fw->data[offset + i + 4]; | ||
95 | write_buf[i + 7] = fw->data[offset + i + 5]; | ||
96 | write_buf[i + 6] = fw->data[offset + i + 6]; | ||
97 | write_buf[i + 5] = fw->data[offset + i + 7]; | ||
98 | } | ||
99 | |||
100 | write_buf[end + 5] = spi_cmd; | ||
101 | |||
102 | rt5677_spi_write(write_buf, end + 6); | ||
103 | |||
104 | offset += RT5677_SPI_BUF_LEN; | ||
105 | } | ||
106 | |||
107 | kfree(write_buf); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | EXPORT_SYMBOL_GPL(rt5677_spi_burst_write); | ||
112 | |||
113 | static int rt5677_spi_probe(struct spi_device *spi) | ||
114 | { | ||
115 | g_spi = spi; | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static struct spi_driver rt5677_spi_driver = { | ||
120 | .driver = { | ||
121 | .name = "rt5677", | ||
122 | .owner = THIS_MODULE, | ||
123 | }, | ||
124 | .probe = rt5677_spi_probe, | ||
125 | }; | ||
126 | module_spi_driver(rt5677_spi_driver); | ||
127 | |||
128 | MODULE_DESCRIPTION("ASoC RT5677 SPI driver"); | ||
129 | MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); | ||
130 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h new file mode 100644 index 000000000000..ec41b2b3b2ca --- /dev/null +++ b/sound/soc/codecs/rt5677-spi.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * rt5677-spi.h -- RT5677 ALSA SoC audio codec driver | ||
3 | * | ||
4 | * Copyright 2013 Realtek Semiconductor Corp. | ||
5 | * Author: Oder Chiou <oder_chiou@realtek.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 | #ifndef __RT5677_SPI_H__ | ||
13 | #define __RT5677_SPI_H__ | ||
14 | |||
15 | #define RT5677_SPI_BUF_LEN 240 | ||
16 | #define RT5677_SPI_CMD_BURST_WRITE 0x05 | ||
17 | |||
18 | int rt5677_spi_write(u8 *txbuf, size_t len); | ||
19 | int rt5677_spi_burst_write(u32 addr, const struct firmware *fw); | ||
20 | |||
21 | #endif /* __RT5677_SPI_H__ */ | ||
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 16aa4d99a713..81fe1464d268 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/spi/spi.h> | 22 | #include <linux/spi/spi.h> |
23 | #include <linux/firmware.h> | ||
23 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
24 | #include <sound/core.h> | 25 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
@@ -31,6 +32,7 @@ | |||
31 | 32 | ||
32 | #include "rl6231.h" | 33 | #include "rl6231.h" |
33 | #include "rt5677.h" | 34 | #include "rt5677.h" |
35 | #include "rt5677-spi.h" | ||
34 | 36 | ||
35 | #define RT5677_DEVICE_ID 0x6327 | 37 | #define RT5677_DEVICE_ID 0x6327 |
36 | 38 | ||
@@ -53,12 +55,13 @@ static const struct regmap_range_cfg rt5677_ranges[] = { | |||
53 | }; | 55 | }; |
54 | 56 | ||
55 | static const struct reg_default init_list[] = { | 57 | static const struct reg_default init_list[] = { |
58 | {RT5677_ASRC_12, 0x0018}, | ||
56 | {RT5677_PR_BASE + 0x3d, 0x364d}, | 59 | {RT5677_PR_BASE + 0x3d, 0x364d}, |
57 | {RT5677_PR_BASE + 0x17, 0x4fc0}, | 60 | {RT5677_PR_BASE + 0x17, 0x4fc0}, |
58 | {RT5677_PR_BASE + 0x13, 0x0312}, | 61 | {RT5677_PR_BASE + 0x13, 0x0312}, |
59 | {RT5677_PR_BASE + 0x1e, 0x0000}, | 62 | {RT5677_PR_BASE + 0x1e, 0x0000}, |
60 | {RT5677_PR_BASE + 0x12, 0x0eaa}, | 63 | {RT5677_PR_BASE + 0x12, 0x0eaa}, |
61 | {RT5677_PR_BASE + 0x14, 0x018a}, | 64 | {RT5677_PR_BASE + 0x14, 0x018a}, |
62 | }; | 65 | }; |
63 | #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list) | 66 | #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list) |
64 | 67 | ||
@@ -171,7 +174,7 @@ static const struct reg_default rt5677_reg[] = { | |||
171 | {RT5677_ASRC_9 , 0x0000}, | 174 | {RT5677_ASRC_9 , 0x0000}, |
172 | {RT5677_ASRC_10 , 0x0000}, | 175 | {RT5677_ASRC_10 , 0x0000}, |
173 | {RT5677_ASRC_11 , 0x0000}, | 176 | {RT5677_ASRC_11 , 0x0000}, |
174 | {RT5677_ASRC_12 , 0x0008}, | 177 | {RT5677_ASRC_12 , 0x0018}, |
175 | {RT5677_ASRC_13 , 0x0000}, | 178 | {RT5677_ASRC_13 , 0x0000}, |
176 | {RT5677_ASRC_14 , 0x0000}, | 179 | {RT5677_ASRC_14 , 0x0000}, |
177 | {RT5677_ASRC_15 , 0x0000}, | 180 | {RT5677_ASRC_15 , 0x0000}, |
@@ -537,10 +540,232 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg) | |||
537 | } | 540 | } |
538 | } | 541 | } |
539 | 542 | ||
543 | /** | ||
544 | * rt5677_dsp_mode_i2c_write_addr - Write value to address on DSP mode. | ||
545 | * @rt5677: Private Data. | ||
546 | * @addr: Address index. | ||
547 | * @value: Address data. | ||
548 | * | ||
549 | * | ||
550 | * Returns 0 for success or negative error code. | ||
551 | */ | ||
552 | static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677, | ||
553 | unsigned int addr, unsigned int value, unsigned int opcode) | ||
554 | { | ||
555 | struct snd_soc_codec *codec = rt5677->codec; | ||
556 | int ret; | ||
557 | |||
558 | mutex_lock(&rt5677->dsp_cmd_lock); | ||
559 | |||
560 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, | ||
561 | addr >> 16); | ||
562 | if (ret < 0) { | ||
563 | dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); | ||
564 | goto err; | ||
565 | } | ||
566 | |||
567 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, | ||
568 | addr & 0xffff); | ||
569 | if (ret < 0) { | ||
570 | dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); | ||
571 | goto err; | ||
572 | } | ||
573 | |||
574 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, | ||
575 | value >> 16); | ||
576 | if (ret < 0) { | ||
577 | dev_err(codec->dev, "Failed to set data msb value: %d\n", ret); | ||
578 | goto err; | ||
579 | } | ||
580 | |||
581 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, | ||
582 | value & 0xffff); | ||
583 | if (ret < 0) { | ||
584 | dev_err(codec->dev, "Failed to set data lsb value: %d\n", ret); | ||
585 | goto err; | ||
586 | } | ||
587 | |||
588 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, | ||
589 | opcode); | ||
590 | if (ret < 0) { | ||
591 | dev_err(codec->dev, "Failed to set op code value: %d\n", ret); | ||
592 | goto err; | ||
593 | } | ||
594 | |||
595 | err: | ||
596 | mutex_unlock(&rt5677->dsp_cmd_lock); | ||
597 | |||
598 | return ret; | ||
599 | } | ||
600 | |||
601 | /** | ||
602 | * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode. | ||
603 | * rt5677: Private Data. | ||
604 | * @addr: Address index. | ||
605 | * @value: Address data. | ||
606 | * | ||
607 | * | ||
608 | * Returns 0 for success or negative error code. | ||
609 | */ | ||
610 | static int rt5677_dsp_mode_i2c_read_addr( | ||
611 | struct rt5677_priv *rt5677, unsigned int addr, unsigned int *value) | ||
612 | { | ||
613 | struct snd_soc_codec *codec = rt5677->codec; | ||
614 | int ret; | ||
615 | unsigned int msb, lsb; | ||
616 | |||
617 | mutex_lock(&rt5677->dsp_cmd_lock); | ||
618 | |||
619 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, | ||
620 | addr >> 16); | ||
621 | if (ret < 0) { | ||
622 | dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); | ||
623 | goto err; | ||
624 | } | ||
625 | |||
626 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, | ||
627 | addr & 0xffff); | ||
628 | if (ret < 0) { | ||
629 | dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); | ||
630 | goto err; | ||
631 | } | ||
632 | |||
633 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, | ||
634 | 0x0002); | ||
635 | if (ret < 0) { | ||
636 | dev_err(codec->dev, "Failed to set op code value: %d\n", ret); | ||
637 | goto err; | ||
638 | } | ||
639 | |||
640 | regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb); | ||
641 | regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb); | ||
642 | *value = (msb << 16) | lsb; | ||
643 | |||
644 | err: | ||
645 | mutex_unlock(&rt5677->dsp_cmd_lock); | ||
646 | |||
647 | return ret; | ||
648 | } | ||
649 | |||
650 | /** | ||
651 | * rt5677_dsp_mode_i2c_write - Write register on DSP mode. | ||
652 | * rt5677: Private Data. | ||
653 | * @reg: Register index. | ||
654 | * @value: Register data. | ||
655 | * | ||
656 | * | ||
657 | * Returns 0 for success or negative error code. | ||
658 | */ | ||
659 | static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677, | ||
660 | unsigned int reg, unsigned int value) | ||
661 | { | ||
662 | return rt5677_dsp_mode_i2c_write_addr(rt5677, 0x18020000 + reg * 2, | ||
663 | value, 0x0001); | ||
664 | } | ||
665 | |||
666 | /** | ||
667 | * rt5677_dsp_mode_i2c_read - Read register on DSP mode. | ||
668 | * @codec: SoC audio codec device. | ||
669 | * @reg: Register index. | ||
670 | * @value: Register data. | ||
671 | * | ||
672 | * | ||
673 | * Returns 0 for success or negative error code. | ||
674 | */ | ||
675 | static int rt5677_dsp_mode_i2c_read( | ||
676 | struct rt5677_priv *rt5677, unsigned int reg, unsigned int *value) | ||
677 | { | ||
678 | int ret = rt5677_dsp_mode_i2c_read_addr(rt5677, 0x18020000 + reg * 2, | ||
679 | value); | ||
680 | |||
681 | *value &= 0xffff; | ||
682 | |||
683 | return ret; | ||
684 | } | ||
685 | |||
686 | static void rt5677_set_dsp_mode(struct snd_soc_codec *codec, bool on) | ||
687 | { | ||
688 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
689 | |||
690 | if (on) { | ||
691 | regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2); | ||
692 | rt5677->is_dsp_mode = true; | ||
693 | } else { | ||
694 | regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0); | ||
695 | rt5677->is_dsp_mode = false; | ||
696 | } | ||
697 | } | ||
698 | |||
699 | static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) | ||
700 | { | ||
701 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
702 | static bool activity; | ||
703 | int ret; | ||
704 | |||
705 | if (on && !activity) { | ||
706 | activity = true; | ||
707 | |||
708 | regcache_cache_only(rt5677->regmap, false); | ||
709 | regcache_cache_bypass(rt5677->regmap, true); | ||
710 | |||
711 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1); | ||
712 | regmap_update_bits(rt5677->regmap, | ||
713 | RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00); | ||
714 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | ||
715 | RT5677_LDO1_SEL_MASK, 0x0); | ||
716 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, | ||
717 | RT5677_PWR_LDO1, RT5677_PWR_LDO1); | ||
718 | regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, | ||
719 | RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC); | ||
720 | regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, | ||
721 | RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK, | ||
722 | RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS); | ||
723 | regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff); | ||
724 | regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd); | ||
725 | rt5677_set_dsp_mode(codec, true); | ||
726 | |||
727 | ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, | ||
728 | codec->dev); | ||
729 | if (ret == 0) { | ||
730 | rt5677_spi_burst_write(0x50000000, rt5677->fw1); | ||
731 | release_firmware(rt5677->fw1); | ||
732 | } | ||
733 | |||
734 | ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, | ||
735 | codec->dev); | ||
736 | if (ret == 0) { | ||
737 | rt5677_spi_burst_write(0x60000000, rt5677->fw2); | ||
738 | release_firmware(rt5677->fw2); | ||
739 | } | ||
740 | |||
741 | regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x0); | ||
742 | |||
743 | regcache_cache_bypass(rt5677->regmap, false); | ||
744 | regcache_cache_only(rt5677->regmap, true); | ||
745 | } else if (!on && activity) { | ||
746 | activity = false; | ||
747 | |||
748 | regcache_cache_only(rt5677->regmap, false); | ||
749 | regcache_cache_bypass(rt5677->regmap, true); | ||
750 | |||
751 | regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1); | ||
752 | rt5677_set_dsp_mode(codec, false); | ||
753 | regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001); | ||
754 | |||
755 | regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); | ||
756 | |||
757 | regcache_cache_bypass(rt5677->regmap, false); | ||
758 | regcache_mark_dirty(rt5677->regmap); | ||
759 | regcache_sync(rt5677->regmap); | ||
760 | } | ||
761 | |||
762 | return 0; | ||
763 | } | ||
764 | |||
540 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); | 765 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); |
541 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); | 766 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); |
542 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); | 767 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); |
543 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); | 768 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); |
544 | static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); | 769 | static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); |
545 | static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0); | 770 | static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0); |
546 | 771 | ||
@@ -556,6 +781,31 @@ static unsigned int bst_tlv[] = { | |||
556 | 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), | 781 | 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), |
557 | }; | 782 | }; |
558 | 783 | ||
784 | static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol, | ||
785 | struct snd_ctl_elem_value *ucontrol) | ||
786 | { | ||
787 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
788 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
789 | |||
790 | ucontrol->value.integer.value[0] = rt5677->dsp_vad_en; | ||
791 | |||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol, | ||
796 | struct snd_ctl_elem_value *ucontrol) | ||
797 | { | ||
798 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
799 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
800 | |||
801 | rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0]; | ||
802 | |||
803 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | ||
804 | rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en); | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
559 | static const struct snd_kcontrol_new rt5677_snd_controls[] = { | 809 | static const struct snd_kcontrol_new rt5677_snd_controls[] = { |
560 | /* OUTPUT Control */ | 810 | /* OUTPUT Control */ |
561 | SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1, | 811 | SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1, |
@@ -567,13 +817,13 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { | |||
567 | 817 | ||
568 | /* DAC Digital Volume */ | 818 | /* DAC Digital Volume */ |
569 | SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL, | 819 | SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL, |
570 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), | 820 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), |
571 | SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL, | 821 | SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL, |
572 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), | 822 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), |
573 | SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL, | 823 | SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL, |
574 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), | 824 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), |
575 | SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL, | 825 | SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL, |
576 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), | 826 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), |
577 | 827 | ||
578 | /* IN1/IN2 Control */ | 828 | /* IN1/IN2 Control */ |
579 | SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv), | 829 | SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv), |
@@ -592,19 +842,19 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { | |||
592 | RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), | 842 | RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), |
593 | 843 | ||
594 | SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL, | 844 | SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL, |
595 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, | 845 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, |
596 | adc_vol_tlv), | 846 | adc_vol_tlv), |
597 | SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL, | 847 | SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL, |
598 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, | 848 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, |
599 | adc_vol_tlv), | 849 | adc_vol_tlv), |
600 | SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL, | 850 | SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL, |
601 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, | 851 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, |
602 | adc_vol_tlv), | 852 | adc_vol_tlv), |
603 | SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL, | 853 | SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL, |
604 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, | 854 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, |
605 | adc_vol_tlv), | 855 | adc_vol_tlv), |
606 | SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL, | 856 | SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL, |
607 | RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0, | 857 | RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 63, 0, |
608 | adc_vol_tlv), | 858 | adc_vol_tlv), |
609 | 859 | ||
610 | /* Sidetone Control */ | 860 | /* Sidetone Control */ |
@@ -627,6 +877,9 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { | |||
627 | SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2, | 877 | SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2, |
628 | RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0, | 878 | RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0, |
629 | adc_bst_tlv), | 879 | adc_bst_tlv), |
880 | |||
881 | SOC_SINGLE_EXT("DSP VAD Switch", SND_SOC_NOPM, 0, 1, 0, | ||
882 | rt5677_dsp_vad_get, rt5677_dsp_vad_put), | ||
630 | }; | 883 | }; |
631 | 884 | ||
632 | /** | 885 | /** |
@@ -1086,7 +1339,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1086 | static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux = | 1339 | static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux = |
1087 | SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum); | 1340 | SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum); |
1088 | 1341 | ||
1089 | /* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */ | 1342 | /* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */ |
1090 | static const char * const rt5677_stereo_adc2_src[] = { | 1343 | static const char * const rt5677_stereo_adc2_src[] = { |
1091 | "DD MIX1", "DMIC", "Stereo DAC MIX" | 1344 | "DD MIX1", "DMIC", "Stereo DAC MIX" |
1092 | }; | 1345 | }; |
@@ -1171,7 +1424,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1171 | static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux = | 1424 | static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux = |
1172 | SOC_DAPM_ENUM("Stereo2 ADC LR Source", rt5677_stereo2_adc_lr_enum); | 1425 | SOC_DAPM_ENUM("Stereo2 ADC LR Source", rt5677_stereo2_adc_lr_enum); |
1173 | 1426 | ||
1174 | /* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */ | 1427 | /* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */ |
1175 | static const char * const rt5677_stereo_adc1_src[] = { | 1428 | static const char * const rt5677_stereo_adc1_src[] = { |
1176 | "DD MIX1", "ADC1/2", "Stereo DAC MIX" | 1429 | "DD MIX1", "ADC1/2", "Stereo DAC MIX" |
1177 | }; | 1430 | }; |
@@ -1443,7 +1696,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1443 | static const struct snd_kcontrol_new rt5677_pdm2_r_mux = | 1696 | static const struct snd_kcontrol_new rt5677_pdm2_r_mux = |
1444 | SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum); | 1697 | SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum); |
1445 | 1698 | ||
1446 | /* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0]*/ | 1699 | /* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0] */ |
1447 | static const char * const rt5677_if12_adc1_src[] = { | 1700 | static const char * const rt5677_if12_adc1_src[] = { |
1448 | "STO1 ADC MIX", "OB01", "VAD ADC" | 1701 | "STO1 ADC MIX", "OB01", "VAD ADC" |
1449 | }; | 1702 | }; |
@@ -1521,7 +1774,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1521 | static const struct snd_kcontrol_new rt5677_slb_adc3_mux = | 1774 | static const struct snd_kcontrol_new rt5677_slb_adc3_mux = |
1522 | SOC_DAPM_ENUM("SLB ADC3 Source", rt5677_slb_adc3_enum); | 1775 | SOC_DAPM_ENUM("SLB ADC3 Source", rt5677_slb_adc3_enum); |
1523 | 1776 | ||
1524 | /* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */ | 1777 | /* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */ |
1525 | static const char * const rt5677_if12_adc4_src[] = { | 1778 | static const char * const rt5677_if12_adc4_src[] = { |
1526 | "STO4 ADC MIX", "OB67", "OB01" | 1779 | "STO4 ADC MIX", "OB67", "OB01" |
1527 | }; | 1780 | }; |
@@ -1547,7 +1800,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1547 | static const struct snd_kcontrol_new rt5677_slb_adc4_mux = | 1800 | static const struct snd_kcontrol_new rt5677_slb_adc4_mux = |
1548 | SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum); | 1801 | SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum); |
1549 | 1802 | ||
1550 | /* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4]*/ | 1803 | /* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4] */ |
1551 | static const char * const rt5677_if34_adc_src[] = { | 1804 | static const char * const rt5677_if34_adc_src[] = { |
1552 | "STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX", | 1805 | "STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX", |
1553 | "MONO ADC MIX", "OB01", "OB23", "VAD ADC" | 1806 | "MONO ADC MIX", "OB01", "OB23", "VAD ADC" |
@@ -1567,6 +1820,213 @@ static SOC_ENUM_SINGLE_DECL( | |||
1567 | static const struct snd_kcontrol_new rt5677_if4_adc_mux = | 1820 | static const struct snd_kcontrol_new rt5677_if4_adc_mux = |
1568 | SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum); | 1821 | SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum); |
1569 | 1822 | ||
1823 | /* TDM IF1/2 ADC Data Selection */ /* MX-3B MX-40 [7:6][5:4][3:2][1:0] */ | ||
1824 | static const char * const rt5677_if12_adc_swap_src[] = { | ||
1825 | "L/R", "R/L", "L/L", "R/R" | ||
1826 | }; | ||
1827 | |||
1828 | static SOC_ENUM_SINGLE_DECL( | ||
1829 | rt5677_if1_adc1_swap_enum, RT5677_TDM1_CTRL1, | ||
1830 | RT5677_IF1_ADC1_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1831 | |||
1832 | static const struct snd_kcontrol_new rt5677_if1_adc1_swap_mux = | ||
1833 | SOC_DAPM_ENUM("IF1 ADC1 Swap Source", rt5677_if1_adc1_swap_enum); | ||
1834 | |||
1835 | static SOC_ENUM_SINGLE_DECL( | ||
1836 | rt5677_if1_adc2_swap_enum, RT5677_TDM1_CTRL1, | ||
1837 | RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1838 | |||
1839 | static const struct snd_kcontrol_new rt5677_if1_adc2_swap_mux = | ||
1840 | SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if1_adc2_swap_enum); | ||
1841 | |||
1842 | static SOC_ENUM_SINGLE_DECL( | ||
1843 | rt5677_if1_adc3_swap_enum, RT5677_TDM1_CTRL1, | ||
1844 | RT5677_IF1_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1845 | |||
1846 | static const struct snd_kcontrol_new rt5677_if1_adc3_swap_mux = | ||
1847 | SOC_DAPM_ENUM("IF1 ADC3 Swap Source", rt5677_if1_adc3_swap_enum); | ||
1848 | |||
1849 | static SOC_ENUM_SINGLE_DECL( | ||
1850 | rt5677_if1_adc4_swap_enum, RT5677_TDM1_CTRL1, | ||
1851 | RT5677_IF1_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1852 | |||
1853 | static const struct snd_kcontrol_new rt5677_if1_adc4_swap_mux = | ||
1854 | SOC_DAPM_ENUM("IF1 ADC4 Swap Source", rt5677_if1_adc4_swap_enum); | ||
1855 | |||
1856 | static SOC_ENUM_SINGLE_DECL( | ||
1857 | rt5677_if2_adc1_swap_enum, RT5677_TDM2_CTRL1, | ||
1858 | RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1859 | |||
1860 | static const struct snd_kcontrol_new rt5677_if2_adc1_swap_mux = | ||
1861 | SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if2_adc1_swap_enum); | ||
1862 | |||
1863 | static SOC_ENUM_SINGLE_DECL( | ||
1864 | rt5677_if2_adc2_swap_enum, RT5677_TDM2_CTRL1, | ||
1865 | RT5677_IF2_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1866 | |||
1867 | static const struct snd_kcontrol_new rt5677_if2_adc2_swap_mux = | ||
1868 | SOC_DAPM_ENUM("IF2 ADC2 Swap Source", rt5677_if2_adc2_swap_enum); | ||
1869 | |||
1870 | static SOC_ENUM_SINGLE_DECL( | ||
1871 | rt5677_if2_adc3_swap_enum, RT5677_TDM2_CTRL1, | ||
1872 | RT5677_IF2_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1873 | |||
1874 | static const struct snd_kcontrol_new rt5677_if2_adc3_swap_mux = | ||
1875 | SOC_DAPM_ENUM("IF2 ADC3 Swap Source", rt5677_if2_adc3_swap_enum); | ||
1876 | |||
1877 | static SOC_ENUM_SINGLE_DECL( | ||
1878 | rt5677_if2_adc4_swap_enum, RT5677_TDM2_CTRL1, | ||
1879 | RT5677_IF2_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1880 | |||
1881 | static const struct snd_kcontrol_new rt5677_if2_adc4_swap_mux = | ||
1882 | SOC_DAPM_ENUM("IF2 ADC4 Swap Source", rt5677_if2_adc4_swap_enum); | ||
1883 | |||
1884 | /* TDM IF1 ADC Data Selection */ /* MX-3C [2:0] */ | ||
1885 | static const char * const rt5677_if1_adc_tdm_swap_src[] = { | ||
1886 | "1/2/3/4", "2/1/3/4", "2/3/1/4", "4/1/2/3", "1/3/2/4", "1/4/2/3", | ||
1887 | "3/1/2/4", "3/4/1/2" | ||
1888 | }; | ||
1889 | |||
1890 | static SOC_ENUM_SINGLE_DECL( | ||
1891 | rt5677_if1_adc_tdm_swap_enum, RT5677_TDM1_CTRL2, | ||
1892 | RT5677_IF1_ADC_CTRL_SFT, rt5677_if1_adc_tdm_swap_src); | ||
1893 | |||
1894 | static const struct snd_kcontrol_new rt5677_if1_adc_tdm_swap_mux = | ||
1895 | SOC_DAPM_ENUM("IF1 ADC TDM Swap Source", rt5677_if1_adc_tdm_swap_enum); | ||
1896 | |||
1897 | /* TDM IF2 ADC Data Selection */ /* MX-41[2:0] */ | ||
1898 | static const char * const rt5677_if2_adc_tdm_swap_src[] = { | ||
1899 | "1/2/3/4", "2/1/3/4", "3/1/2/4", "4/1/2/3", "1/3/2/4", "1/4/2/3", | ||
1900 | "2/3/1/4", "3/4/1/2" | ||
1901 | }; | ||
1902 | |||
1903 | static SOC_ENUM_SINGLE_DECL( | ||
1904 | rt5677_if2_adc_tdm_swap_enum, RT5677_TDM2_CTRL2, | ||
1905 | RT5677_IF2_ADC_CTRL_SFT, rt5677_if2_adc_tdm_swap_src); | ||
1906 | |||
1907 | static const struct snd_kcontrol_new rt5677_if2_adc_tdm_swap_mux = | ||
1908 | SOC_DAPM_ENUM("IF2 ADC TDM Swap Source", rt5677_if2_adc_tdm_swap_enum); | ||
1909 | |||
1910 | /* TDM IF1/2 DAC Data Selection */ /* MX-3E[14:12][10:8][6:4][2:0] | ||
1911 | MX-3F[14:12][10:8][6:4][2:0] | ||
1912 | MX-43[14:12][10:8][6:4][2:0] | ||
1913 | MX-44[14:12][10:8][6:4][2:0] */ | ||
1914 | static const char * const rt5677_if12_dac_tdm_sel_src[] = { | ||
1915 | "Slot0", "Slot1", "Slot2", "Slot3", "Slot4", "Slot5", "Slot6", "Slot7" | ||
1916 | }; | ||
1917 | |||
1918 | static SOC_ENUM_SINGLE_DECL( | ||
1919 | rt5677_if1_dac0_tdm_sel_enum, RT5677_TDM1_CTRL4, | ||
1920 | RT5677_IF1_DAC0_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1921 | |||
1922 | static const struct snd_kcontrol_new rt5677_if1_dac0_tdm_sel_mux = | ||
1923 | SOC_DAPM_ENUM("IF1 DAC0 TDM Source", rt5677_if1_dac0_tdm_sel_enum); | ||
1924 | |||
1925 | static SOC_ENUM_SINGLE_DECL( | ||
1926 | rt5677_if1_dac1_tdm_sel_enum, RT5677_TDM1_CTRL4, | ||
1927 | RT5677_IF1_DAC1_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1928 | |||
1929 | static const struct snd_kcontrol_new rt5677_if1_dac1_tdm_sel_mux = | ||
1930 | SOC_DAPM_ENUM("IF1 DAC1 TDM Source", rt5677_if1_dac1_tdm_sel_enum); | ||
1931 | |||
1932 | static SOC_ENUM_SINGLE_DECL( | ||
1933 | rt5677_if1_dac2_tdm_sel_enum, RT5677_TDM1_CTRL4, | ||
1934 | RT5677_IF1_DAC2_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1935 | |||
1936 | static const struct snd_kcontrol_new rt5677_if1_dac2_tdm_sel_mux = | ||
1937 | SOC_DAPM_ENUM("IF1 DAC2 TDM Source", rt5677_if1_dac2_tdm_sel_enum); | ||
1938 | |||
1939 | static SOC_ENUM_SINGLE_DECL( | ||
1940 | rt5677_if1_dac3_tdm_sel_enum, RT5677_TDM1_CTRL4, | ||
1941 | RT5677_IF1_DAC3_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1942 | |||
1943 | static const struct snd_kcontrol_new rt5677_if1_dac3_tdm_sel_mux = | ||
1944 | SOC_DAPM_ENUM("IF1 DAC3 TDM Source", rt5677_if1_dac3_tdm_sel_enum); | ||
1945 | |||
1946 | static SOC_ENUM_SINGLE_DECL( | ||
1947 | rt5677_if1_dac4_tdm_sel_enum, RT5677_TDM1_CTRL5, | ||
1948 | RT5677_IF1_DAC4_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1949 | |||
1950 | static const struct snd_kcontrol_new rt5677_if1_dac4_tdm_sel_mux = | ||
1951 | SOC_DAPM_ENUM("IF1 DAC4 TDM Source", rt5677_if1_dac4_tdm_sel_enum); | ||
1952 | |||
1953 | static SOC_ENUM_SINGLE_DECL( | ||
1954 | rt5677_if1_dac5_tdm_sel_enum, RT5677_TDM1_CTRL5, | ||
1955 | RT5677_IF1_DAC5_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1956 | |||
1957 | static const struct snd_kcontrol_new rt5677_if1_dac5_tdm_sel_mux = | ||
1958 | SOC_DAPM_ENUM("IF1 DAC5 TDM Source", rt5677_if1_dac5_tdm_sel_enum); | ||
1959 | |||
1960 | static SOC_ENUM_SINGLE_DECL( | ||
1961 | rt5677_if1_dac6_tdm_sel_enum, RT5677_TDM1_CTRL5, | ||
1962 | RT5677_IF1_DAC6_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1963 | |||
1964 | static const struct snd_kcontrol_new rt5677_if1_dac6_tdm_sel_mux = | ||
1965 | SOC_DAPM_ENUM("IF1 DAC6 TDM Source", rt5677_if1_dac6_tdm_sel_enum); | ||
1966 | |||
1967 | static SOC_ENUM_SINGLE_DECL( | ||
1968 | rt5677_if1_dac7_tdm_sel_enum, RT5677_TDM1_CTRL5, | ||
1969 | RT5677_IF1_DAC7_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1970 | |||
1971 | static const struct snd_kcontrol_new rt5677_if1_dac7_tdm_sel_mux = | ||
1972 | SOC_DAPM_ENUM("IF1 DAC7 TDM Source", rt5677_if1_dac7_tdm_sel_enum); | ||
1973 | |||
1974 | static SOC_ENUM_SINGLE_DECL( | ||
1975 | rt5677_if2_dac0_tdm_sel_enum, RT5677_TDM2_CTRL4, | ||
1976 | RT5677_IF2_DAC0_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1977 | |||
1978 | static const struct snd_kcontrol_new rt5677_if2_dac0_tdm_sel_mux = | ||
1979 | SOC_DAPM_ENUM("IF2 DAC0 TDM Source", rt5677_if2_dac0_tdm_sel_enum); | ||
1980 | |||
1981 | static SOC_ENUM_SINGLE_DECL( | ||
1982 | rt5677_if2_dac1_tdm_sel_enum, RT5677_TDM2_CTRL4, | ||
1983 | RT5677_IF2_DAC1_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1984 | |||
1985 | static const struct snd_kcontrol_new rt5677_if2_dac1_tdm_sel_mux = | ||
1986 | SOC_DAPM_ENUM("IF2 DAC1 TDM Source", rt5677_if2_dac1_tdm_sel_enum); | ||
1987 | |||
1988 | static SOC_ENUM_SINGLE_DECL( | ||
1989 | rt5677_if2_dac2_tdm_sel_enum, RT5677_TDM2_CTRL4, | ||
1990 | RT5677_IF2_DAC2_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1991 | |||
1992 | static const struct snd_kcontrol_new rt5677_if2_dac2_tdm_sel_mux = | ||
1993 | SOC_DAPM_ENUM("IF2 DAC2 TDM Source", rt5677_if2_dac2_tdm_sel_enum); | ||
1994 | |||
1995 | static SOC_ENUM_SINGLE_DECL( | ||
1996 | rt5677_if2_dac3_tdm_sel_enum, RT5677_TDM2_CTRL4, | ||
1997 | RT5677_IF2_DAC3_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1998 | |||
1999 | static const struct snd_kcontrol_new rt5677_if2_dac3_tdm_sel_mux = | ||
2000 | SOC_DAPM_ENUM("IF2 DAC3 TDM Source", rt5677_if2_dac3_tdm_sel_enum); | ||
2001 | |||
2002 | static SOC_ENUM_SINGLE_DECL( | ||
2003 | rt5677_if2_dac4_tdm_sel_enum, RT5677_TDM2_CTRL5, | ||
2004 | RT5677_IF2_DAC4_SFT, rt5677_if12_dac_tdm_sel_src); | ||
2005 | |||
2006 | static const struct snd_kcontrol_new rt5677_if2_dac4_tdm_sel_mux = | ||
2007 | SOC_DAPM_ENUM("IF2 DAC4 TDM Source", rt5677_if2_dac4_tdm_sel_enum); | ||
2008 | |||
2009 | static SOC_ENUM_SINGLE_DECL( | ||
2010 | rt5677_if2_dac5_tdm_sel_enum, RT5677_TDM2_CTRL5, | ||
2011 | RT5677_IF2_DAC5_SFT, rt5677_if12_dac_tdm_sel_src); | ||
2012 | |||
2013 | static const struct snd_kcontrol_new rt5677_if2_dac5_tdm_sel_mux = | ||
2014 | SOC_DAPM_ENUM("IF2 DAC5 TDM Source", rt5677_if2_dac5_tdm_sel_enum); | ||
2015 | |||
2016 | static SOC_ENUM_SINGLE_DECL( | ||
2017 | rt5677_if2_dac6_tdm_sel_enum, RT5677_TDM2_CTRL5, | ||
2018 | RT5677_IF2_DAC6_SFT, rt5677_if12_dac_tdm_sel_src); | ||
2019 | |||
2020 | static const struct snd_kcontrol_new rt5677_if2_dac6_tdm_sel_mux = | ||
2021 | SOC_DAPM_ENUM("IF2 DAC6 TDM Source", rt5677_if2_dac6_tdm_sel_enum); | ||
2022 | |||
2023 | static SOC_ENUM_SINGLE_DECL( | ||
2024 | rt5677_if2_dac7_tdm_sel_enum, RT5677_TDM2_CTRL5, | ||
2025 | RT5677_IF2_DAC7_SFT, rt5677_if12_dac_tdm_sel_src); | ||
2026 | |||
2027 | static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux = | ||
2028 | SOC_DAPM_ENUM("IF2 DAC7 TDM Source", rt5677_if2_dac7_tdm_sel_enum); | ||
2029 | |||
1570 | static int rt5677_bst1_event(struct snd_soc_dapm_widget *w, | 2030 | static int rt5677_bst1_event(struct snd_soc_dapm_widget *w, |
1571 | struct snd_kcontrol *kcontrol, int event) | 2031 | struct snd_kcontrol *kcontrol, int event) |
1572 | { | 2032 | { |
@@ -1678,6 +2138,77 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w, | |||
1678 | return 0; | 2138 | return 0; |
1679 | } | 2139 | } |
1680 | 2140 | ||
2141 | static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w, | ||
2142 | struct snd_kcontrol *kcontrol, int event) | ||
2143 | { | ||
2144 | struct snd_soc_codec *codec = w->codec; | ||
2145 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
2146 | unsigned int value; | ||
2147 | |||
2148 | switch (event) { | ||
2149 | case SND_SOC_DAPM_PRE_PMU: | ||
2150 | regmap_read(rt5677->regmap, RT5677_TDM1_CTRL2, &value); | ||
2151 | if (value & RT5677_IF1_ADC_CTRL_MASK) | ||
2152 | regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1, | ||
2153 | RT5677_IF1_ADC_MODE_MASK, | ||
2154 | RT5677_IF1_ADC_MODE_TDM); | ||
2155 | break; | ||
2156 | |||
2157 | default: | ||
2158 | return 0; | ||
2159 | } | ||
2160 | |||
2161 | return 0; | ||
2162 | } | ||
2163 | |||
2164 | static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w, | ||
2165 | struct snd_kcontrol *kcontrol, int event) | ||
2166 | { | ||
2167 | struct snd_soc_codec *codec = w->codec; | ||
2168 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
2169 | unsigned int value; | ||
2170 | |||
2171 | switch (event) { | ||
2172 | case SND_SOC_DAPM_PRE_PMU: | ||
2173 | regmap_read(rt5677->regmap, RT5677_TDM2_CTRL2, &value); | ||
2174 | if (value & RT5677_IF2_ADC_CTRL_MASK) | ||
2175 | regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1, | ||
2176 | RT5677_IF2_ADC_MODE_MASK, | ||
2177 | RT5677_IF2_ADC_MODE_TDM); | ||
2178 | break; | ||
2179 | |||
2180 | default: | ||
2181 | return 0; | ||
2182 | } | ||
2183 | |||
2184 | return 0; | ||
2185 | } | ||
2186 | |||
2187 | static int rt5677_vref_event(struct snd_soc_dapm_widget *w, | ||
2188 | struct snd_kcontrol *kcontrol, int event) | ||
2189 | { | ||
2190 | struct snd_soc_codec *codec = w->codec; | ||
2191 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
2192 | |||
2193 | switch (event) { | ||
2194 | case SND_SOC_DAPM_POST_PMU: | ||
2195 | if (codec->dapm.bias_level != SND_SOC_BIAS_ON && | ||
2196 | !rt5677->is_vref_slow) { | ||
2197 | mdelay(20); | ||
2198 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | ||
2199 | RT5677_PWR_FV1 | RT5677_PWR_FV2, | ||
2200 | RT5677_PWR_FV1 | RT5677_PWR_FV2); | ||
2201 | rt5677->is_vref_slow = true; | ||
2202 | } | ||
2203 | break; | ||
2204 | |||
2205 | default: | ||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2209 | return 0; | ||
2210 | } | ||
2211 | |||
1681 | static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | 2212 | static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { |
1682 | SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT, | 2213 | SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT, |
1683 | 0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU), | 2214 | 0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU), |
@@ -1837,10 +2368,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1837 | SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), | 2368 | SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), |
1838 | SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0), | 2369 | SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0), |
1839 | SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), | 2370 | SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), |
1840 | SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), | 2371 | SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), |
1841 | SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), | 2372 | SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), |
1842 | SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1843 | SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1844 | 2373 | ||
1845 | /* DSP */ | 2374 | /* DSP */ |
1846 | SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0, | 2375 | SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0, |
@@ -1963,6 +2492,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1963 | &rt5677_if1_adc3_mux), | 2492 | &rt5677_if1_adc3_mux), |
1964 | SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0, | 2493 | SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0, |
1965 | &rt5677_if1_adc4_mux), | 2494 | &rt5677_if1_adc4_mux), |
2495 | SND_SOC_DAPM_MUX("IF1 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2496 | &rt5677_if1_adc1_swap_mux), | ||
2497 | SND_SOC_DAPM_MUX("IF1 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2498 | &rt5677_if1_adc2_swap_mux), | ||
2499 | SND_SOC_DAPM_MUX("IF1 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2500 | &rt5677_if1_adc3_swap_mux), | ||
2501 | SND_SOC_DAPM_MUX("IF1 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2502 | &rt5677_if1_adc4_swap_mux), | ||
2503 | SND_SOC_DAPM_MUX_E("IF1 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2504 | &rt5677_if1_adc_tdm_swap_mux, rt5677_if1_adc_tdm_event, | ||
2505 | SND_SOC_DAPM_PRE_PMU), | ||
1966 | SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0, | 2506 | SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0, |
1967 | &rt5677_if2_adc1_mux), | 2507 | &rt5677_if2_adc1_mux), |
1968 | SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0, | 2508 | SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0, |
@@ -1971,6 +2511,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1971 | &rt5677_if2_adc3_mux), | 2511 | &rt5677_if2_adc3_mux), |
1972 | SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0, | 2512 | SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0, |
1973 | &rt5677_if2_adc4_mux), | 2513 | &rt5677_if2_adc4_mux), |
2514 | SND_SOC_DAPM_MUX("IF2 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2515 | &rt5677_if2_adc1_swap_mux), | ||
2516 | SND_SOC_DAPM_MUX("IF2 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2517 | &rt5677_if2_adc2_swap_mux), | ||
2518 | SND_SOC_DAPM_MUX("IF2 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2519 | &rt5677_if2_adc3_swap_mux), | ||
2520 | SND_SOC_DAPM_MUX("IF2 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2521 | &rt5677_if2_adc4_swap_mux), | ||
2522 | SND_SOC_DAPM_MUX_E("IF2 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2523 | &rt5677_if2_adc_tdm_swap_mux, rt5677_if2_adc_tdm_event, | ||
2524 | SND_SOC_DAPM_PRE_PMU), | ||
1974 | SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, | 2525 | SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, |
1975 | &rt5677_if3_adc_mux), | 2526 | &rt5677_if3_adc_mux), |
1976 | SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0, | 2527 | SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0, |
@@ -1984,6 +2535,40 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1984 | SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0, | 2535 | SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0, |
1985 | &rt5677_slb_adc4_mux), | 2536 | &rt5677_slb_adc4_mux), |
1986 | 2537 | ||
2538 | SND_SOC_DAPM_MUX("IF1 DAC0 Mux", SND_SOC_NOPM, 0, 0, | ||
2539 | &rt5677_if1_dac0_tdm_sel_mux), | ||
2540 | SND_SOC_DAPM_MUX("IF1 DAC1 Mux", SND_SOC_NOPM, 0, 0, | ||
2541 | &rt5677_if1_dac1_tdm_sel_mux), | ||
2542 | SND_SOC_DAPM_MUX("IF1 DAC2 Mux", SND_SOC_NOPM, 0, 0, | ||
2543 | &rt5677_if1_dac2_tdm_sel_mux), | ||
2544 | SND_SOC_DAPM_MUX("IF1 DAC3 Mux", SND_SOC_NOPM, 0, 0, | ||
2545 | &rt5677_if1_dac3_tdm_sel_mux), | ||
2546 | SND_SOC_DAPM_MUX("IF1 DAC4 Mux", SND_SOC_NOPM, 0, 0, | ||
2547 | &rt5677_if1_dac4_tdm_sel_mux), | ||
2548 | SND_SOC_DAPM_MUX("IF1 DAC5 Mux", SND_SOC_NOPM, 0, 0, | ||
2549 | &rt5677_if1_dac5_tdm_sel_mux), | ||
2550 | SND_SOC_DAPM_MUX("IF1 DAC6 Mux", SND_SOC_NOPM, 0, 0, | ||
2551 | &rt5677_if1_dac6_tdm_sel_mux), | ||
2552 | SND_SOC_DAPM_MUX("IF1 DAC7 Mux", SND_SOC_NOPM, 0, 0, | ||
2553 | &rt5677_if1_dac7_tdm_sel_mux), | ||
2554 | |||
2555 | SND_SOC_DAPM_MUX("IF2 DAC0 Mux", SND_SOC_NOPM, 0, 0, | ||
2556 | &rt5677_if2_dac0_tdm_sel_mux), | ||
2557 | SND_SOC_DAPM_MUX("IF2 DAC1 Mux", SND_SOC_NOPM, 0, 0, | ||
2558 | &rt5677_if2_dac1_tdm_sel_mux), | ||
2559 | SND_SOC_DAPM_MUX("IF2 DAC2 Mux", SND_SOC_NOPM, 0, 0, | ||
2560 | &rt5677_if2_dac2_tdm_sel_mux), | ||
2561 | SND_SOC_DAPM_MUX("IF2 DAC3 Mux", SND_SOC_NOPM, 0, 0, | ||
2562 | &rt5677_if2_dac3_tdm_sel_mux), | ||
2563 | SND_SOC_DAPM_MUX("IF2 DAC4 Mux", SND_SOC_NOPM, 0, 0, | ||
2564 | &rt5677_if2_dac4_tdm_sel_mux), | ||
2565 | SND_SOC_DAPM_MUX("IF2 DAC5 Mux", SND_SOC_NOPM, 0, 0, | ||
2566 | &rt5677_if2_dac5_tdm_sel_mux), | ||
2567 | SND_SOC_DAPM_MUX("IF2 DAC6 Mux", SND_SOC_NOPM, 0, 0, | ||
2568 | &rt5677_if2_dac6_tdm_sel_mux), | ||
2569 | SND_SOC_DAPM_MUX("IF2 DAC7 Mux", SND_SOC_NOPM, 0, 0, | ||
2570 | &rt5677_if2_dac7_tdm_sel_mux), | ||
2571 | |||
1987 | /* Audio Interface */ | 2572 | /* Audio Interface */ |
1988 | SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), | 2573 | SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), |
1989 | SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), | 2574 | SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), |
@@ -2022,7 +2607,7 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
2022 | rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)), | 2607 | rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)), |
2023 | 2608 | ||
2024 | /* Output Side */ | 2609 | /* Output Side */ |
2025 | /* DAC mixer before sound effect */ | 2610 | /* DAC mixer before sound effect */ |
2026 | SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, | 2611 | SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, |
2027 | rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)), | 2612 | rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)), |
2028 | SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, | 2613 | SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, |
@@ -2109,13 +2694,20 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
2109 | SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT, | 2694 | SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT, |
2110 | 1, &rt5677_pdm2_r_mux), | 2695 | 1, &rt5677_pdm2_r_mux), |
2111 | 2696 | ||
2112 | SND_SOC_DAPM_PGA_S("LOUT1 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT, | 2697 | SND_SOC_DAPM_PGA_S("LOUT1 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT, |
2113 | 0, NULL, 0), | 2698 | 0, NULL, 0), |
2114 | SND_SOC_DAPM_PGA_S("LOUT2 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT, | 2699 | SND_SOC_DAPM_PGA_S("LOUT2 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT, |
2115 | 0, NULL, 0), | 2700 | 0, NULL, 0), |
2116 | SND_SOC_DAPM_PGA_S("LOUT3 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT, | 2701 | SND_SOC_DAPM_PGA_S("LOUT3 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT, |
2117 | 0, NULL, 0), | 2702 | 0, NULL, 0), |
2118 | 2703 | ||
2704 | SND_SOC_DAPM_PGA_S("LOUT1 vref", 1, SND_SOC_NOPM, 0, 0, | ||
2705 | rt5677_vref_event, SND_SOC_DAPM_POST_PMU), | ||
2706 | SND_SOC_DAPM_PGA_S("LOUT2 vref", 1, SND_SOC_NOPM, 0, 0, | ||
2707 | rt5677_vref_event, SND_SOC_DAPM_POST_PMU), | ||
2708 | SND_SOC_DAPM_PGA_S("LOUT3 vref", 1, SND_SOC_NOPM, 0, 0, | ||
2709 | rt5677_vref_event, SND_SOC_DAPM_POST_PMU), | ||
2710 | |||
2119 | /* Output Lines */ | 2711 | /* Output Lines */ |
2120 | SND_SOC_DAPM_OUTPUT("LOUT1"), | 2712 | SND_SOC_DAPM_OUTPUT("LOUT1"), |
2121 | SND_SOC_DAPM_OUTPUT("LOUT2"), | 2713 | SND_SOC_DAPM_OUTPUT("LOUT2"), |
@@ -2124,6 +2716,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
2124 | SND_SOC_DAPM_OUTPUT("PDM1R"), | 2716 | SND_SOC_DAPM_OUTPUT("PDM1R"), |
2125 | SND_SOC_DAPM_OUTPUT("PDM2L"), | 2717 | SND_SOC_DAPM_OUTPUT("PDM2L"), |
2126 | SND_SOC_DAPM_OUTPUT("PDM2R"), | 2718 | SND_SOC_DAPM_OUTPUT("PDM2R"), |
2719 | |||
2720 | SND_SOC_DAPM_POST("vref", rt5677_vref_event), | ||
2127 | }; | 2721 | }; |
2128 | 2722 | ||
2129 | static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | 2723 | static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { |
@@ -2354,11 +2948,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2354 | { "IF1 ADC4 Mux", "OB67", "OB67" }, | 2948 | { "IF1 ADC4 Mux", "OB67", "OB67" }, |
2355 | { "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, | 2949 | { "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, |
2356 | 2950 | ||
2951 | { "IF1 ADC1 Swap Mux", "L/R", "IF1 ADC1 Mux" }, | ||
2952 | { "IF1 ADC1 Swap Mux", "R/L", "IF1 ADC1 Mux" }, | ||
2953 | { "IF1 ADC1 Swap Mux", "L/L", "IF1 ADC1 Mux" }, | ||
2954 | { "IF1 ADC1 Swap Mux", "R/R", "IF1 ADC1 Mux" }, | ||
2955 | |||
2956 | { "IF1 ADC2 Swap Mux", "L/R", "IF1 ADC2 Mux" }, | ||
2957 | { "IF1 ADC2 Swap Mux", "R/L", "IF1 ADC2 Mux" }, | ||
2958 | { "IF1 ADC2 Swap Mux", "L/L", "IF1 ADC2 Mux" }, | ||
2959 | { "IF1 ADC2 Swap Mux", "R/R", "IF1 ADC2 Mux" }, | ||
2960 | |||
2961 | { "IF1 ADC3 Swap Mux", "L/R", "IF1 ADC3 Mux" }, | ||
2962 | { "IF1 ADC3 Swap Mux", "R/L", "IF1 ADC3 Mux" }, | ||
2963 | { "IF1 ADC3 Swap Mux", "L/L", "IF1 ADC3 Mux" }, | ||
2964 | { "IF1 ADC3 Swap Mux", "R/R", "IF1 ADC3 Mux" }, | ||
2965 | |||
2966 | { "IF1 ADC4 Swap Mux", "L/R", "IF1 ADC4 Mux" }, | ||
2967 | { "IF1 ADC4 Swap Mux", "R/L", "IF1 ADC4 Mux" }, | ||
2968 | { "IF1 ADC4 Swap Mux", "L/L", "IF1 ADC4 Mux" }, | ||
2969 | { "IF1 ADC4 Swap Mux", "R/R", "IF1 ADC4 Mux" }, | ||
2970 | |||
2971 | { "IF1 ADC", NULL, "IF1 ADC1 Swap Mux" }, | ||
2972 | { "IF1 ADC", NULL, "IF1 ADC2 Swap Mux" }, | ||
2973 | { "IF1 ADC", NULL, "IF1 ADC3 Swap Mux" }, | ||
2974 | { "IF1 ADC", NULL, "IF1 ADC4 Swap Mux" }, | ||
2975 | |||
2976 | { "IF1 ADC TDM Swap Mux", "1/2/3/4", "IF1 ADC" }, | ||
2977 | { "IF1 ADC TDM Swap Mux", "2/1/3/4", "IF1 ADC" }, | ||
2978 | { "IF1 ADC TDM Swap Mux", "2/3/1/4", "IF1 ADC" }, | ||
2979 | { "IF1 ADC TDM Swap Mux", "4/1/2/3", "IF1 ADC" }, | ||
2980 | { "IF1 ADC TDM Swap Mux", "1/3/2/4", "IF1 ADC" }, | ||
2981 | { "IF1 ADC TDM Swap Mux", "1/4/2/3", "IF1 ADC" }, | ||
2982 | { "IF1 ADC TDM Swap Mux", "3/1/2/4", "IF1 ADC" }, | ||
2983 | { "IF1 ADC TDM Swap Mux", "3/4/1/2", "IF1 ADC" }, | ||
2984 | |||
2357 | { "AIF1TX", NULL, "I2S1" }, | 2985 | { "AIF1TX", NULL, "I2S1" }, |
2358 | { "AIF1TX", NULL, "IF1 ADC1 Mux" }, | 2986 | { "AIF1TX", NULL, "IF1 ADC TDM Swap Mux" }, |
2359 | { "AIF1TX", NULL, "IF1 ADC2 Mux" }, | ||
2360 | { "AIF1TX", NULL, "IF1 ADC3 Mux" }, | ||
2361 | { "AIF1TX", NULL, "IF1 ADC4 Mux" }, | ||
2362 | 2987 | ||
2363 | { "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, | 2988 | { "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, |
2364 | { "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" }, | 2989 | { "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" }, |
@@ -2375,11 +3000,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2375 | { "IF2 ADC4 Mux", "OB67", "OB67" }, | 3000 | { "IF2 ADC4 Mux", "OB67", "OB67" }, |
2376 | { "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, | 3001 | { "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, |
2377 | 3002 | ||
3003 | { "IF2 ADC1 Swap Mux", "L/R", "IF2 ADC1 Mux" }, | ||
3004 | { "IF2 ADC1 Swap Mux", "R/L", "IF2 ADC1 Mux" }, | ||
3005 | { "IF2 ADC1 Swap Mux", "L/L", "IF2 ADC1 Mux" }, | ||
3006 | { "IF2 ADC1 Swap Mux", "R/R", "IF2 ADC1 Mux" }, | ||
3007 | |||
3008 | { "IF2 ADC2 Swap Mux", "L/R", "IF2 ADC2 Mux" }, | ||
3009 | { "IF2 ADC2 Swap Mux", "R/L", "IF2 ADC2 Mux" }, | ||
3010 | { "IF2 ADC2 Swap Mux", "L/L", "IF2 ADC2 Mux" }, | ||
3011 | { "IF2 ADC2 Swap Mux", "R/R", "IF2 ADC2 Mux" }, | ||
3012 | |||
3013 | { "IF2 ADC3 Swap Mux", "L/R", "IF2 ADC3 Mux" }, | ||
3014 | { "IF2 ADC3 Swap Mux", "R/L", "IF2 ADC3 Mux" }, | ||
3015 | { "IF2 ADC3 Swap Mux", "L/L", "IF2 ADC3 Mux" }, | ||
3016 | { "IF2 ADC3 Swap Mux", "R/R", "IF2 ADC3 Mux" }, | ||
3017 | |||
3018 | { "IF2 ADC4 Swap Mux", "L/R", "IF2 ADC4 Mux" }, | ||
3019 | { "IF2 ADC4 Swap Mux", "R/L", "IF2 ADC4 Mux" }, | ||
3020 | { "IF2 ADC4 Swap Mux", "L/L", "IF2 ADC4 Mux" }, | ||
3021 | { "IF2 ADC4 Swap Mux", "R/R", "IF2 ADC4 Mux" }, | ||
3022 | |||
3023 | { "IF2 ADC", NULL, "IF2 ADC1 Swap Mux" }, | ||
3024 | { "IF2 ADC", NULL, "IF2 ADC2 Swap Mux" }, | ||
3025 | { "IF2 ADC", NULL, "IF2 ADC3 Swap Mux" }, | ||
3026 | { "IF2 ADC", NULL, "IF2 ADC4 Swap Mux" }, | ||
3027 | |||
3028 | { "IF2 ADC TDM Swap Mux", "1/2/3/4", "IF2 ADC" }, | ||
3029 | { "IF2 ADC TDM Swap Mux", "2/1/3/4", "IF2 ADC" }, | ||
3030 | { "IF2 ADC TDM Swap Mux", "3/1/2/4", "IF2 ADC" }, | ||
3031 | { "IF2 ADC TDM Swap Mux", "4/1/2/3", "IF2 ADC" }, | ||
3032 | { "IF2 ADC TDM Swap Mux", "1/3/2/4", "IF2 ADC" }, | ||
3033 | { "IF2 ADC TDM Swap Mux", "1/4/2/3", "IF2 ADC" }, | ||
3034 | { "IF2 ADC TDM Swap Mux", "2/3/1/4", "IF2 ADC" }, | ||
3035 | { "IF2 ADC TDM Swap Mux", "3/4/1/2", "IF2 ADC" }, | ||
3036 | |||
2378 | { "AIF2TX", NULL, "I2S2" }, | 3037 | { "AIF2TX", NULL, "I2S2" }, |
2379 | { "AIF2TX", NULL, "IF2 ADC1 Mux" }, | 3038 | { "AIF2TX", NULL, "IF2 ADC TDM Swap Mux" }, |
2380 | { "AIF2TX", NULL, "IF2 ADC2 Mux" }, | ||
2381 | { "AIF2TX", NULL, "IF2 ADC3 Mux" }, | ||
2382 | { "AIF2TX", NULL, "IF2 ADC4 Mux" }, | ||
2383 | 3039 | ||
2384 | { "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, | 3040 | { "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, |
2385 | { "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, | 3041 | { "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, |
@@ -2569,14 +3225,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2569 | { "IF1 DAC6", NULL, "I2S1" }, | 3225 | { "IF1 DAC6", NULL, "I2S1" }, |
2570 | { "IF1 DAC7", NULL, "I2S1" }, | 3226 | { "IF1 DAC7", NULL, "I2S1" }, |
2571 | 3227 | ||
2572 | { "IF1 DAC01", NULL, "IF1 DAC0" }, | 3228 | { "IF1 DAC0 Mux", "Slot0", "IF1 DAC0" }, |
2573 | { "IF1 DAC01", NULL, "IF1 DAC1" }, | 3229 | { "IF1 DAC0 Mux", "Slot1", "IF1 DAC1" }, |
2574 | { "IF1 DAC23", NULL, "IF1 DAC2" }, | 3230 | { "IF1 DAC0 Mux", "Slot2", "IF1 DAC2" }, |
2575 | { "IF1 DAC23", NULL, "IF1 DAC3" }, | 3231 | { "IF1 DAC0 Mux", "Slot3", "IF1 DAC3" }, |
2576 | { "IF1 DAC45", NULL, "IF1 DAC4" }, | 3232 | { "IF1 DAC0 Mux", "Slot4", "IF1 DAC4" }, |
2577 | { "IF1 DAC45", NULL, "IF1 DAC5" }, | 3233 | { "IF1 DAC0 Mux", "Slot5", "IF1 DAC5" }, |
2578 | { "IF1 DAC67", NULL, "IF1 DAC6" }, | 3234 | { "IF1 DAC0 Mux", "Slot6", "IF1 DAC6" }, |
2579 | { "IF1 DAC67", NULL, "IF1 DAC7" }, | 3235 | { "IF1 DAC0 Mux", "Slot7", "IF1 DAC7" }, |
3236 | |||
3237 | { "IF1 DAC1 Mux", "Slot0", "IF1 DAC0" }, | ||
3238 | { "IF1 DAC1 Mux", "Slot1", "IF1 DAC1" }, | ||
3239 | { "IF1 DAC1 Mux", "Slot2", "IF1 DAC2" }, | ||
3240 | { "IF1 DAC1 Mux", "Slot3", "IF1 DAC3" }, | ||
3241 | { "IF1 DAC1 Mux", "Slot4", "IF1 DAC4" }, | ||
3242 | { "IF1 DAC1 Mux", "Slot5", "IF1 DAC5" }, | ||
3243 | { "IF1 DAC1 Mux", "Slot6", "IF1 DAC6" }, | ||
3244 | { "IF1 DAC1 Mux", "Slot7", "IF1 DAC7" }, | ||
3245 | |||
3246 | { "IF1 DAC2 Mux", "Slot0", "IF1 DAC0" }, | ||
3247 | { "IF1 DAC2 Mux", "Slot1", "IF1 DAC1" }, | ||
3248 | { "IF1 DAC2 Mux", "Slot2", "IF1 DAC2" }, | ||
3249 | { "IF1 DAC2 Mux", "Slot3", "IF1 DAC3" }, | ||
3250 | { "IF1 DAC2 Mux", "Slot4", "IF1 DAC4" }, | ||
3251 | { "IF1 DAC2 Mux", "Slot5", "IF1 DAC5" }, | ||
3252 | { "IF1 DAC2 Mux", "Slot6", "IF1 DAC6" }, | ||
3253 | { "IF1 DAC2 Mux", "Slot7", "IF1 DAC7" }, | ||
3254 | |||
3255 | { "IF1 DAC3 Mux", "Slot0", "IF1 DAC0" }, | ||
3256 | { "IF1 DAC3 Mux", "Slot1", "IF1 DAC1" }, | ||
3257 | { "IF1 DAC3 Mux", "Slot2", "IF1 DAC2" }, | ||
3258 | { "IF1 DAC3 Mux", "Slot3", "IF1 DAC3" }, | ||
3259 | { "IF1 DAC3 Mux", "Slot4", "IF1 DAC4" }, | ||
3260 | { "IF1 DAC3 Mux", "Slot5", "IF1 DAC5" }, | ||
3261 | { "IF1 DAC3 Mux", "Slot6", "IF1 DAC6" }, | ||
3262 | { "IF1 DAC3 Mux", "Slot7", "IF1 DAC7" }, | ||
3263 | |||
3264 | { "IF1 DAC4 Mux", "Slot0", "IF1 DAC0" }, | ||
3265 | { "IF1 DAC4 Mux", "Slot1", "IF1 DAC1" }, | ||
3266 | { "IF1 DAC4 Mux", "Slot2", "IF1 DAC2" }, | ||
3267 | { "IF1 DAC4 Mux", "Slot3", "IF1 DAC3" }, | ||
3268 | { "IF1 DAC4 Mux", "Slot4", "IF1 DAC4" }, | ||
3269 | { "IF1 DAC4 Mux", "Slot5", "IF1 DAC5" }, | ||
3270 | { "IF1 DAC4 Mux", "Slot6", "IF1 DAC6" }, | ||
3271 | { "IF1 DAC4 Mux", "Slot7", "IF1 DAC7" }, | ||
3272 | |||
3273 | { "IF1 DAC5 Mux", "Slot0", "IF1 DAC0" }, | ||
3274 | { "IF1 DAC5 Mux", "Slot1", "IF1 DAC1" }, | ||
3275 | { "IF1 DAC5 Mux", "Slot2", "IF1 DAC2" }, | ||
3276 | { "IF1 DAC5 Mux", "Slot3", "IF1 DAC3" }, | ||
3277 | { "IF1 DAC5 Mux", "Slot4", "IF1 DAC4" }, | ||
3278 | { "IF1 DAC5 Mux", "Slot5", "IF1 DAC5" }, | ||
3279 | { "IF1 DAC5 Mux", "Slot6", "IF1 DAC6" }, | ||
3280 | { "IF1 DAC5 Mux", "Slot7", "IF1 DAC7" }, | ||
3281 | |||
3282 | { "IF1 DAC6 Mux", "Slot0", "IF1 DAC0" }, | ||
3283 | { "IF1 DAC6 Mux", "Slot1", "IF1 DAC1" }, | ||
3284 | { "IF1 DAC6 Mux", "Slot2", "IF1 DAC2" }, | ||
3285 | { "IF1 DAC6 Mux", "Slot3", "IF1 DAC3" }, | ||
3286 | { "IF1 DAC6 Mux", "Slot4", "IF1 DAC4" }, | ||
3287 | { "IF1 DAC6 Mux", "Slot5", "IF1 DAC5" }, | ||
3288 | { "IF1 DAC6 Mux", "Slot6", "IF1 DAC6" }, | ||
3289 | { "IF1 DAC6 Mux", "Slot7", "IF1 DAC7" }, | ||
3290 | |||
3291 | { "IF1 DAC7 Mux", "Slot0", "IF1 DAC0" }, | ||
3292 | { "IF1 DAC7 Mux", "Slot1", "IF1 DAC1" }, | ||
3293 | { "IF1 DAC7 Mux", "Slot2", "IF1 DAC2" }, | ||
3294 | { "IF1 DAC7 Mux", "Slot3", "IF1 DAC3" }, | ||
3295 | { "IF1 DAC7 Mux", "Slot4", "IF1 DAC4" }, | ||
3296 | { "IF1 DAC7 Mux", "Slot5", "IF1 DAC5" }, | ||
3297 | { "IF1 DAC7 Mux", "Slot6", "IF1 DAC6" }, | ||
3298 | { "IF1 DAC7 Mux", "Slot7", "IF1 DAC7" }, | ||
3299 | |||
3300 | { "IF1 DAC01", NULL, "IF1 DAC0 Mux" }, | ||
3301 | { "IF1 DAC01", NULL, "IF1 DAC1 Mux" }, | ||
3302 | { "IF1 DAC23", NULL, "IF1 DAC2 Mux" }, | ||
3303 | { "IF1 DAC23", NULL, "IF1 DAC3 Mux" }, | ||
3304 | { "IF1 DAC45", NULL, "IF1 DAC4 Mux" }, | ||
3305 | { "IF1 DAC45", NULL, "IF1 DAC5 Mux" }, | ||
3306 | { "IF1 DAC67", NULL, "IF1 DAC6 Mux" }, | ||
3307 | { "IF1 DAC67", NULL, "IF1 DAC7 Mux" }, | ||
2580 | 3308 | ||
2581 | { "IF2 DAC0", NULL, "AIF2RX" }, | 3309 | { "IF2 DAC0", NULL, "AIF2RX" }, |
2582 | { "IF2 DAC1", NULL, "AIF2RX" }, | 3310 | { "IF2 DAC1", NULL, "AIF2RX" }, |
@@ -2595,14 +3323,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2595 | { "IF2 DAC6", NULL, "I2S2" }, | 3323 | { "IF2 DAC6", NULL, "I2S2" }, |
2596 | { "IF2 DAC7", NULL, "I2S2" }, | 3324 | { "IF2 DAC7", NULL, "I2S2" }, |
2597 | 3325 | ||
2598 | { "IF2 DAC01", NULL, "IF2 DAC0" }, | 3326 | { "IF2 DAC0 Mux", "Slot0", "IF2 DAC0" }, |
2599 | { "IF2 DAC01", NULL, "IF2 DAC1" }, | 3327 | { "IF2 DAC0 Mux", "Slot1", "IF2 DAC1" }, |
2600 | { "IF2 DAC23", NULL, "IF2 DAC2" }, | 3328 | { "IF2 DAC0 Mux", "Slot2", "IF2 DAC2" }, |
2601 | { "IF2 DAC23", NULL, "IF2 DAC3" }, | 3329 | { "IF2 DAC0 Mux", "Slot3", "IF2 DAC3" }, |
2602 | { "IF2 DAC45", NULL, "IF2 DAC4" }, | 3330 | { "IF2 DAC0 Mux", "Slot4", "IF2 DAC4" }, |
2603 | { "IF2 DAC45", NULL, "IF2 DAC5" }, | 3331 | { "IF2 DAC0 Mux", "Slot5", "IF2 DAC5" }, |
2604 | { "IF2 DAC67", NULL, "IF2 DAC6" }, | 3332 | { "IF2 DAC0 Mux", "Slot6", "IF2 DAC6" }, |
2605 | { "IF2 DAC67", NULL, "IF2 DAC7" }, | 3333 | { "IF2 DAC0 Mux", "Slot7", "IF2 DAC7" }, |
3334 | |||
3335 | { "IF2 DAC1 Mux", "Slot0", "IF2 DAC0" }, | ||
3336 | { "IF2 DAC1 Mux", "Slot1", "IF2 DAC1" }, | ||
3337 | { "IF2 DAC1 Mux", "Slot2", "IF2 DAC2" }, | ||
3338 | { "IF2 DAC1 Mux", "Slot3", "IF2 DAC3" }, | ||
3339 | { "IF2 DAC1 Mux", "Slot4", "IF2 DAC4" }, | ||
3340 | { "IF2 DAC1 Mux", "Slot5", "IF2 DAC5" }, | ||
3341 | { "IF2 DAC1 Mux", "Slot6", "IF2 DAC6" }, | ||
3342 | { "IF2 DAC1 Mux", "Slot7", "IF2 DAC7" }, | ||
3343 | |||
3344 | { "IF2 DAC2 Mux", "Slot0", "IF2 DAC0" }, | ||
3345 | { "IF2 DAC2 Mux", "Slot1", "IF2 DAC1" }, | ||
3346 | { "IF2 DAC2 Mux", "Slot2", "IF2 DAC2" }, | ||
3347 | { "IF2 DAC2 Mux", "Slot3", "IF2 DAC3" }, | ||
3348 | { "IF2 DAC2 Mux", "Slot4", "IF2 DAC4" }, | ||
3349 | { "IF2 DAC2 Mux", "Slot5", "IF2 DAC5" }, | ||
3350 | { "IF2 DAC2 Mux", "Slot6", "IF2 DAC6" }, | ||
3351 | { "IF2 DAC2 Mux", "Slot7", "IF2 DAC7" }, | ||
3352 | |||
3353 | { "IF2 DAC3 Mux", "Slot0", "IF2 DAC0" }, | ||
3354 | { "IF2 DAC3 Mux", "Slot1", "IF2 DAC1" }, | ||
3355 | { "IF2 DAC3 Mux", "Slot2", "IF2 DAC2" }, | ||
3356 | { "IF2 DAC3 Mux", "Slot3", "IF2 DAC3" }, | ||
3357 | { "IF2 DAC3 Mux", "Slot4", "IF2 DAC4" }, | ||
3358 | { "IF2 DAC3 Mux", "Slot5", "IF2 DAC5" }, | ||
3359 | { "IF2 DAC3 Mux", "Slot6", "IF2 DAC6" }, | ||
3360 | { "IF2 DAC3 Mux", "Slot7", "IF2 DAC7" }, | ||
3361 | |||
3362 | { "IF2 DAC4 Mux", "Slot0", "IF2 DAC0" }, | ||
3363 | { "IF2 DAC4 Mux", "Slot1", "IF2 DAC1" }, | ||
3364 | { "IF2 DAC4 Mux", "Slot2", "IF2 DAC2" }, | ||
3365 | { "IF2 DAC4 Mux", "Slot3", "IF2 DAC3" }, | ||
3366 | { "IF2 DAC4 Mux", "Slot4", "IF2 DAC4" }, | ||
3367 | { "IF2 DAC4 Mux", "Slot5", "IF2 DAC5" }, | ||
3368 | { "IF2 DAC4 Mux", "Slot6", "IF2 DAC6" }, | ||
3369 | { "IF2 DAC4 Mux", "Slot7", "IF2 DAC7" }, | ||
3370 | |||
3371 | { "IF2 DAC5 Mux", "Slot0", "IF2 DAC0" }, | ||
3372 | { "IF2 DAC5 Mux", "Slot1", "IF2 DAC1" }, | ||
3373 | { "IF2 DAC5 Mux", "Slot2", "IF2 DAC2" }, | ||
3374 | { "IF2 DAC5 Mux", "Slot3", "IF2 DAC3" }, | ||
3375 | { "IF2 DAC5 Mux", "Slot4", "IF2 DAC4" }, | ||
3376 | { "IF2 DAC5 Mux", "Slot5", "IF2 DAC5" }, | ||
3377 | { "IF2 DAC5 Mux", "Slot6", "IF2 DAC6" }, | ||
3378 | { "IF2 DAC5 Mux", "Slot7", "IF2 DAC7" }, | ||
3379 | |||
3380 | { "IF2 DAC6 Mux", "Slot0", "IF2 DAC0" }, | ||
3381 | { "IF2 DAC6 Mux", "Slot1", "IF2 DAC1" }, | ||
3382 | { "IF2 DAC6 Mux", "Slot2", "IF2 DAC2" }, | ||
3383 | { "IF2 DAC6 Mux", "Slot3", "IF2 DAC3" }, | ||
3384 | { "IF2 DAC6 Mux", "Slot4", "IF2 DAC4" }, | ||
3385 | { "IF2 DAC6 Mux", "Slot5", "IF2 DAC5" }, | ||
3386 | { "IF2 DAC6 Mux", "Slot6", "IF2 DAC6" }, | ||
3387 | { "IF2 DAC6 Mux", "Slot7", "IF2 DAC7" }, | ||
3388 | |||
3389 | { "IF2 DAC7 Mux", "Slot0", "IF2 DAC0" }, | ||
3390 | { "IF2 DAC7 Mux", "Slot1", "IF2 DAC1" }, | ||
3391 | { "IF2 DAC7 Mux", "Slot2", "IF2 DAC2" }, | ||
3392 | { "IF2 DAC7 Mux", "Slot3", "IF2 DAC3" }, | ||
3393 | { "IF2 DAC7 Mux", "Slot4", "IF2 DAC4" }, | ||
3394 | { "IF2 DAC7 Mux", "Slot5", "IF2 DAC5" }, | ||
3395 | { "IF2 DAC7 Mux", "Slot6", "IF2 DAC6" }, | ||
3396 | { "IF2 DAC7 Mux", "Slot7", "IF2 DAC7" }, | ||
3397 | |||
3398 | { "IF2 DAC01", NULL, "IF2 DAC0 Mux" }, | ||
3399 | { "IF2 DAC01", NULL, "IF2 DAC1 Mux" }, | ||
3400 | { "IF2 DAC23", NULL, "IF2 DAC2 Mux" }, | ||
3401 | { "IF2 DAC23", NULL, "IF2 DAC3 Mux" }, | ||
3402 | { "IF2 DAC45", NULL, "IF2 DAC4 Mux" }, | ||
3403 | { "IF2 DAC45", NULL, "IF2 DAC5 Mux" }, | ||
3404 | { "IF2 DAC67", NULL, "IF2 DAC6 Mux" }, | ||
3405 | { "IF2 DAC67", NULL, "IF2 DAC7 Mux" }, | ||
2606 | 3406 | ||
2607 | { "IF3 DAC", NULL, "AIF3RX" }, | 3407 | { "IF3 DAC", NULL, "AIF3RX" }, |
2608 | { "IF3 DAC", NULL, "I2S3" }, | 3408 | { "IF3 DAC", NULL, "I2S3" }, |
@@ -2806,9 +3606,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2806 | { "LOUT2 amp", NULL, "DAC 2" }, | 3606 | { "LOUT2 amp", NULL, "DAC 2" }, |
2807 | { "LOUT3 amp", NULL, "DAC 3" }, | 3607 | { "LOUT3 amp", NULL, "DAC 3" }, |
2808 | 3608 | ||
2809 | { "LOUT1", NULL, "LOUT1 amp" }, | 3609 | { "LOUT1 vref", NULL, "LOUT1 amp" }, |
2810 | { "LOUT2", NULL, "LOUT2 amp" }, | 3610 | { "LOUT2 vref", NULL, "LOUT2 amp" }, |
2811 | { "LOUT3", NULL, "LOUT3 amp" }, | 3611 | { "LOUT3 vref", NULL, "LOUT3 amp" }, |
3612 | |||
3613 | { "LOUT1", NULL, "LOUT1 vref" }, | ||
3614 | { "LOUT2", NULL, "LOUT2 vref" }, | ||
3615 | { "LOUT3", NULL, "LOUT3 vref" }, | ||
2812 | 3616 | ||
2813 | { "PDM1L", NULL, "PDM1 L Mux" }, | 3617 | { "PDM1L", NULL, "PDM1 L Mux" }, |
2814 | { "PDM1R", NULL, "PDM1 R Mux" }, | 3618 | { "PDM1R", NULL, "PDM1 R Mux" }, |
@@ -2837,7 +3641,8 @@ static int rt5677_hw_params(struct snd_pcm_substream *substream, | |||
2837 | rt5677->lrck[dai->id] = params_rate(params); | 3641 | rt5677->lrck[dai->id] = params_rate(params); |
2838 | pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]); | 3642 | pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]); |
2839 | if (pre_div < 0) { | 3643 | if (pre_div < 0) { |
2840 | dev_err(codec->dev, "Unsupported clock setting\n"); | 3644 | dev_err(codec->dev, "Unsupported clock setting: sysclk=%dHz lrck=%dHz\n", |
3645 | rt5677->sysclk, rt5677->lrck[dai->id]); | ||
2841 | return -EINVAL; | 3646 | return -EINVAL; |
2842 | } | 3647 | } |
2843 | frame_size = snd_soc_params_to_frame_size(params); | 3648 | frame_size = snd_soc_params_to_frame_size(params); |
@@ -3181,6 +3986,8 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
3181 | 3986 | ||
3182 | case SND_SOC_BIAS_PREPARE: | 3987 | case SND_SOC_BIAS_PREPARE: |
3183 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | 3988 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { |
3989 | rt5677_set_dsp_vad(codec, false); | ||
3990 | |||
3184 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | 3991 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, |
3185 | RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, | 3992 | RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, |
3186 | 0x0055); | 3993 | 0x0055); |
@@ -3188,14 +3995,12 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
3188 | RT5677_PR_BASE + RT5677_BIAS_CUR4, | 3995 | RT5677_PR_BASE + RT5677_BIAS_CUR4, |
3189 | 0x0f00, 0x0f00); | 3996 | 0x0f00, 0x0f00); |
3190 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | 3997 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, |
3998 | RT5677_PWR_FV1 | RT5677_PWR_FV2 | | ||
3191 | RT5677_PWR_VREF1 | RT5677_PWR_MB | | 3999 | RT5677_PWR_VREF1 | RT5677_PWR_MB | |
3192 | RT5677_PWR_BG | RT5677_PWR_VREF2, | 4000 | RT5677_PWR_BG | RT5677_PWR_VREF2, |
3193 | RT5677_PWR_VREF1 | RT5677_PWR_MB | | 4001 | RT5677_PWR_VREF1 | RT5677_PWR_MB | |
3194 | RT5677_PWR_BG | RT5677_PWR_VREF2); | 4002 | RT5677_PWR_BG | RT5677_PWR_VREF2); |
3195 | mdelay(20); | 4003 | rt5677->is_vref_slow = false; |
3196 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | ||
3197 | RT5677_PWR_FV1 | RT5677_PWR_FV2, | ||
3198 | RT5677_PWR_FV1 | RT5677_PWR_FV2); | ||
3199 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, | 4004 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, |
3200 | RT5677_PWR_CORE, RT5677_PWR_CORE); | 4005 | RT5677_PWR_CORE, RT5677_PWR_CORE); |
3201 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, | 4006 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, |
@@ -3214,6 +4019,9 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
3214 | regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); | 4019 | regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); |
3215 | regmap_update_bits(rt5677->regmap, | 4020 | regmap_update_bits(rt5677->regmap, |
3216 | RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); | 4021 | RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); |
4022 | |||
4023 | if (rt5677->dsp_vad_en) | ||
4024 | rt5677_set_dsp_vad(codec, true); | ||
3217 | break; | 4025 | break; |
3218 | 4026 | ||
3219 | default: | 4027 | default: |
@@ -3309,6 +4117,78 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) | |||
3309 | return 0; | 4117 | return 0; |
3310 | } | 4118 | } |
3311 | 4119 | ||
4120 | /** Configures the gpio as | ||
4121 | * 0 - floating | ||
4122 | * 1 - pull down | ||
4123 | * 2 - pull up | ||
4124 | */ | ||
4125 | static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, | ||
4126 | int value) | ||
4127 | { | ||
4128 | int shift; | ||
4129 | |||
4130 | switch (offset) { | ||
4131 | case RT5677_GPIO1 ... RT5677_GPIO2: | ||
4132 | shift = 2 * (1 - offset); | ||
4133 | regmap_update_bits(rt5677->regmap, | ||
4134 | RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL2, | ||
4135 | 0x3 << shift, | ||
4136 | (value & 0x3) << shift); | ||
4137 | break; | ||
4138 | |||
4139 | case RT5677_GPIO3 ... RT5677_GPIO6: | ||
4140 | shift = 2 * (9 - offset); | ||
4141 | regmap_update_bits(rt5677->regmap, | ||
4142 | RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL3, | ||
4143 | 0x3 << shift, | ||
4144 | (value & 0x3) << shift); | ||
4145 | break; | ||
4146 | |||
4147 | default: | ||
4148 | break; | ||
4149 | } | ||
4150 | } | ||
4151 | |||
4152 | static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) | ||
4153 | { | ||
4154 | struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); | ||
4155 | struct regmap_irq_chip_data *data = rt5677->irq_data; | ||
4156 | int irq; | ||
4157 | |||
4158 | if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) { | ||
4159 | if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) || | ||
4160 | (rt5677->pdata.jd1_gpio == 2 && | ||
4161 | offset == RT5677_GPIO2) || | ||
4162 | (rt5677->pdata.jd1_gpio == 3 && | ||
4163 | offset == RT5677_GPIO3)) { | ||
4164 | irq = RT5677_IRQ_JD1; | ||
4165 | } else { | ||
4166 | return -ENXIO; | ||
4167 | } | ||
4168 | } | ||
4169 | |||
4170 | if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) { | ||
4171 | if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) || | ||
4172 | (rt5677->pdata.jd2_gpio == 2 && | ||
4173 | offset == RT5677_GPIO5) || | ||
4174 | (rt5677->pdata.jd2_gpio == 3 && | ||
4175 | offset == RT5677_GPIO6)) { | ||
4176 | irq = RT5677_IRQ_JD2; | ||
4177 | } else if ((rt5677->pdata.jd3_gpio == 1 && | ||
4178 | offset == RT5677_GPIO4) || | ||
4179 | (rt5677->pdata.jd3_gpio == 2 && | ||
4180 | offset == RT5677_GPIO5) || | ||
4181 | (rt5677->pdata.jd3_gpio == 3 && | ||
4182 | offset == RT5677_GPIO6)) { | ||
4183 | irq = RT5677_IRQ_JD3; | ||
4184 | } else { | ||
4185 | return -ENXIO; | ||
4186 | } | ||
4187 | } | ||
4188 | |||
4189 | return regmap_irq_get_virq(data, irq); | ||
4190 | } | ||
4191 | |||
3312 | static struct gpio_chip rt5677_template_chip = { | 4192 | static struct gpio_chip rt5677_template_chip = { |
3313 | .label = "rt5677", | 4193 | .label = "rt5677", |
3314 | .owner = THIS_MODULE, | 4194 | .owner = THIS_MODULE, |
@@ -3316,6 +4196,7 @@ static struct gpio_chip rt5677_template_chip = { | |||
3316 | .set = rt5677_gpio_set, | 4196 | .set = rt5677_gpio_set, |
3317 | .direction_input = rt5677_gpio_direction_in, | 4197 | .direction_input = rt5677_gpio_direction_in, |
3318 | .get = rt5677_gpio_get, | 4198 | .get = rt5677_gpio_get, |
4199 | .to_irq = rt5677_to_irq, | ||
3319 | .can_sleep = 1, | 4200 | .can_sleep = 1, |
3320 | }; | 4201 | }; |
3321 | 4202 | ||
@@ -3341,6 +4222,11 @@ static void rt5677_free_gpio(struct i2c_client *i2c) | |||
3341 | gpiochip_remove(&rt5677->gpio_chip); | 4222 | gpiochip_remove(&rt5677->gpio_chip); |
3342 | } | 4223 | } |
3343 | #else | 4224 | #else |
4225 | static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, | ||
4226 | int value) | ||
4227 | { | ||
4228 | } | ||
4229 | |||
3344 | static void rt5677_init_gpio(struct i2c_client *i2c) | 4230 | static void rt5677_init_gpio(struct i2c_client *i2c) |
3345 | { | 4231 | { |
3346 | } | 4232 | } |
@@ -3353,6 +4239,7 @@ static void rt5677_free_gpio(struct i2c_client *i2c) | |||
3353 | static int rt5677_probe(struct snd_soc_codec *codec) | 4239 | static int rt5677_probe(struct snd_soc_codec *codec) |
3354 | { | 4240 | { |
3355 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 4241 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
4242 | int i; | ||
3356 | 4243 | ||
3357 | rt5677->codec = codec; | 4244 | rt5677->codec = codec; |
3358 | 4245 | ||
@@ -3371,6 +4258,37 @@ static int rt5677_probe(struct snd_soc_codec *codec) | |||
3371 | regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); | 4258 | regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); |
3372 | regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); | 4259 | regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); |
3373 | 4260 | ||
4261 | for (i = 0; i < RT5677_GPIO_NUM; i++) | ||
4262 | rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); | ||
4263 | |||
4264 | if (rt5677->irq_data) { | ||
4265 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000, | ||
4266 | 0x8000); | ||
4267 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018, | ||
4268 | 0x0008); | ||
4269 | |||
4270 | if (rt5677->pdata.jd1_gpio) | ||
4271 | regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, | ||
4272 | RT5677_SEL_GPIO_JD1_MASK, | ||
4273 | rt5677->pdata.jd1_gpio << | ||
4274 | RT5677_SEL_GPIO_JD1_SFT); | ||
4275 | |||
4276 | if (rt5677->pdata.jd2_gpio) | ||
4277 | regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, | ||
4278 | RT5677_SEL_GPIO_JD2_MASK, | ||
4279 | rt5677->pdata.jd2_gpio << | ||
4280 | RT5677_SEL_GPIO_JD2_SFT); | ||
4281 | |||
4282 | if (rt5677->pdata.jd3_gpio) | ||
4283 | regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, | ||
4284 | RT5677_SEL_GPIO_JD3_MASK, | ||
4285 | rt5677->pdata.jd3_gpio << | ||
4286 | RT5677_SEL_GPIO_JD3_SFT); | ||
4287 | } | ||
4288 | |||
4289 | mutex_init(&rt5677->dsp_cmd_lock); | ||
4290 | mutex_init(&rt5677->dsp_pri_lock); | ||
4291 | |||
3374 | return 0; | 4292 | return 0; |
3375 | } | 4293 | } |
3376 | 4294 | ||
@@ -3390,8 +4308,11 @@ static int rt5677_suspend(struct snd_soc_codec *codec) | |||
3390 | { | 4308 | { |
3391 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 4309 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
3392 | 4310 | ||
3393 | regcache_cache_only(rt5677->regmap, true); | 4311 | if (!rt5677->dsp_vad_en) { |
3394 | regcache_mark_dirty(rt5677->regmap); | 4312 | regcache_cache_only(rt5677->regmap, true); |
4313 | regcache_mark_dirty(rt5677->regmap); | ||
4314 | } | ||
4315 | |||
3395 | if (gpio_is_valid(rt5677->pow_ldo2)) | 4316 | if (gpio_is_valid(rt5677->pow_ldo2)) |
3396 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); | 4317 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); |
3397 | 4318 | ||
@@ -3406,8 +4327,11 @@ static int rt5677_resume(struct snd_soc_codec *codec) | |||
3406 | gpio_set_value_cansleep(rt5677->pow_ldo2, 1); | 4327 | gpio_set_value_cansleep(rt5677->pow_ldo2, 1); |
3407 | msleep(10); | 4328 | msleep(10); |
3408 | } | 4329 | } |
3409 | regcache_cache_only(rt5677->regmap, false); | 4330 | |
3410 | regcache_sync(rt5677->regmap); | 4331 | if (!rt5677->dsp_vad_en) { |
4332 | regcache_cache_only(rt5677->regmap, false); | ||
4333 | regcache_sync(rt5677->regmap); | ||
4334 | } | ||
3411 | 4335 | ||
3412 | return 0; | 4336 | return 0; |
3413 | } | 4337 | } |
@@ -3416,6 +4340,51 @@ static int rt5677_resume(struct snd_soc_codec *codec) | |||
3416 | #define rt5677_resume NULL | 4340 | #define rt5677_resume NULL |
3417 | #endif | 4341 | #endif |
3418 | 4342 | ||
4343 | static int rt5677_read(void *context, unsigned int reg, unsigned int *val) | ||
4344 | { | ||
4345 | struct i2c_client *client = context; | ||
4346 | struct rt5677_priv *rt5677 = i2c_get_clientdata(client); | ||
4347 | |||
4348 | if (rt5677->is_dsp_mode) { | ||
4349 | if (reg > 0xff) { | ||
4350 | mutex_lock(&rt5677->dsp_pri_lock); | ||
4351 | rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, | ||
4352 | reg & 0xff); | ||
4353 | rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val); | ||
4354 | mutex_unlock(&rt5677->dsp_pri_lock); | ||
4355 | } else { | ||
4356 | rt5677_dsp_mode_i2c_read(rt5677, reg, val); | ||
4357 | } | ||
4358 | } else { | ||
4359 | regmap_read(rt5677->regmap_physical, reg, val); | ||
4360 | } | ||
4361 | |||
4362 | return 0; | ||
4363 | } | ||
4364 | |||
4365 | static int rt5677_write(void *context, unsigned int reg, unsigned int val) | ||
4366 | { | ||
4367 | struct i2c_client *client = context; | ||
4368 | struct rt5677_priv *rt5677 = i2c_get_clientdata(client); | ||
4369 | |||
4370 | if (rt5677->is_dsp_mode) { | ||
4371 | if (reg > 0xff) { | ||
4372 | mutex_lock(&rt5677->dsp_pri_lock); | ||
4373 | rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, | ||
4374 | reg & 0xff); | ||
4375 | rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA, | ||
4376 | val); | ||
4377 | mutex_unlock(&rt5677->dsp_pri_lock); | ||
4378 | } else { | ||
4379 | rt5677_dsp_mode_i2c_write(rt5677, reg, val); | ||
4380 | } | ||
4381 | } else { | ||
4382 | regmap_write(rt5677->regmap_physical, reg, val); | ||
4383 | } | ||
4384 | |||
4385 | return 0; | ||
4386 | } | ||
4387 | |||
3419 | #define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000 | 4388 | #define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000 |
3420 | #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | 4389 | #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
3421 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) | 4390 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) |
@@ -3541,6 +4510,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5677 = { | |||
3541 | .num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), | 4510 | .num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), |
3542 | }; | 4511 | }; |
3543 | 4512 | ||
4513 | static const struct regmap_config rt5677_regmap_physical = { | ||
4514 | .name = "physical", | ||
4515 | .reg_bits = 8, | ||
4516 | .val_bits = 16, | ||
4517 | |||
4518 | .max_register = RT5677_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5677_ranges) * | ||
4519 | RT5677_PR_SPACING), | ||
4520 | .readable_reg = rt5677_readable_register, | ||
4521 | |||
4522 | .cache_type = REGCACHE_NONE, | ||
4523 | .ranges = rt5677_ranges, | ||
4524 | .num_ranges = ARRAY_SIZE(rt5677_ranges), | ||
4525 | }; | ||
4526 | |||
3544 | static const struct regmap_config rt5677_regmap = { | 4527 | static const struct regmap_config rt5677_regmap = { |
3545 | .reg_bits = 8, | 4528 | .reg_bits = 8, |
3546 | .val_bits = 16, | 4529 | .val_bits = 16, |
@@ -3550,6 +4533,8 @@ static const struct regmap_config rt5677_regmap = { | |||
3550 | 4533 | ||
3551 | .volatile_reg = rt5677_volatile_register, | 4534 | .volatile_reg = rt5677_volatile_register, |
3552 | .readable_reg = rt5677_readable_register, | 4535 | .readable_reg = rt5677_readable_register, |
4536 | .reg_read = rt5677_read, | ||
4537 | .reg_write = rt5677_write, | ||
3553 | 4538 | ||
3554 | .cache_type = REGCACHE_RBTREE, | 4539 | .cache_type = REGCACHE_RBTREE, |
3555 | .reg_defaults = rt5677_reg, | 4540 | .reg_defaults = rt5677_reg, |
@@ -3590,9 +4575,77 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) | |||
3590 | (rt5677->pow_ldo2 != -ENOENT)) | 4575 | (rt5677->pow_ldo2 != -ENOENT)) |
3591 | return rt5677->pow_ldo2; | 4576 | return rt5677->pow_ldo2; |
3592 | 4577 | ||
4578 | of_property_read_u8_array(np, "realtek,gpio-config", | ||
4579 | rt5677->pdata.gpio_config, RT5677_GPIO_NUM); | ||
4580 | |||
4581 | of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); | ||
4582 | of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); | ||
4583 | of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); | ||
4584 | |||
4585 | return 0; | ||
4586 | } | ||
4587 | |||
4588 | static struct regmap_irq rt5677_irqs[] = { | ||
4589 | [RT5677_IRQ_JD1] = { | ||
4590 | .reg_offset = 0, | ||
4591 | .mask = RT5677_EN_IRQ_GPIO_JD1, | ||
4592 | }, | ||
4593 | [RT5677_IRQ_JD2] = { | ||
4594 | .reg_offset = 0, | ||
4595 | .mask = RT5677_EN_IRQ_GPIO_JD2, | ||
4596 | }, | ||
4597 | [RT5677_IRQ_JD3] = { | ||
4598 | .reg_offset = 0, | ||
4599 | .mask = RT5677_EN_IRQ_GPIO_JD3, | ||
4600 | }, | ||
4601 | }; | ||
4602 | |||
4603 | static struct regmap_irq_chip rt5677_irq_chip = { | ||
4604 | .name = "rt5677", | ||
4605 | .irqs = rt5677_irqs, | ||
4606 | .num_irqs = ARRAY_SIZE(rt5677_irqs), | ||
4607 | |||
4608 | .num_regs = 1, | ||
4609 | .status_base = RT5677_IRQ_CTRL1, | ||
4610 | .mask_base = RT5677_IRQ_CTRL1, | ||
4611 | .mask_invert = 1, | ||
4612 | }; | ||
4613 | |||
4614 | static int rt5677_init_irq(struct i2c_client *i2c) | ||
4615 | { | ||
4616 | int ret; | ||
4617 | struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); | ||
4618 | |||
4619 | if (!rt5677->pdata.jd1_gpio && | ||
4620 | !rt5677->pdata.jd2_gpio && | ||
4621 | !rt5677->pdata.jd3_gpio) | ||
4622 | return 0; | ||
4623 | |||
4624 | if (!i2c->irq) { | ||
4625 | dev_err(&i2c->dev, "No interrupt specified\n"); | ||
4626 | return -EINVAL; | ||
4627 | } | ||
4628 | |||
4629 | ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq, | ||
4630 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, | ||
4631 | &rt5677_irq_chip, &rt5677->irq_data); | ||
4632 | |||
4633 | if (ret != 0) { | ||
4634 | dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret); | ||
4635 | return ret; | ||
4636 | } | ||
4637 | |||
3593 | return 0; | 4638 | return 0; |
3594 | } | 4639 | } |
3595 | 4640 | ||
4641 | static void rt5677_free_irq(struct i2c_client *i2c) | ||
4642 | { | ||
4643 | struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); | ||
4644 | |||
4645 | if (rt5677->irq_data) | ||
4646 | regmap_del_irq_chip(i2c->irq, rt5677->irq_data); | ||
4647 | } | ||
4648 | |||
3596 | static int rt5677_i2c_probe(struct i2c_client *i2c, | 4649 | static int rt5677_i2c_probe(struct i2c_client *i2c, |
3597 | const struct i2c_device_id *id) | 4650 | const struct i2c_device_id *id) |
3598 | { | 4651 | { |
@@ -3638,7 +4691,16 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
3638 | msleep(10); | 4691 | msleep(10); |
3639 | } | 4692 | } |
3640 | 4693 | ||
3641 | rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap); | 4694 | rt5677->regmap_physical = devm_regmap_init_i2c(i2c, |
4695 | &rt5677_regmap_physical); | ||
4696 | if (IS_ERR(rt5677->regmap_physical)) { | ||
4697 | ret = PTR_ERR(rt5677->regmap_physical); | ||
4698 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | ||
4699 | ret); | ||
4700 | return ret; | ||
4701 | } | ||
4702 | |||
4703 | rt5677->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5677_regmap); | ||
3642 | if (IS_ERR(rt5677->regmap)) { | 4704 | if (IS_ERR(rt5677->regmap)) { |
3643 | ret = PTR_ERR(rt5677->regmap); | 4705 | ret = PTR_ERR(rt5677->regmap); |
3644 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | 4706 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", |
@@ -3690,6 +4752,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
3690 | } | 4752 | } |
3691 | 4753 | ||
3692 | rt5677_init_gpio(i2c); | 4754 | rt5677_init_gpio(i2c); |
4755 | rt5677_init_irq(i2c); | ||
3693 | 4756 | ||
3694 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, | 4757 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, |
3695 | rt5677_dai, ARRAY_SIZE(rt5677_dai)); | 4758 | rt5677_dai, ARRAY_SIZE(rt5677_dai)); |
@@ -3698,6 +4761,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
3698 | static int rt5677_i2c_remove(struct i2c_client *i2c) | 4761 | static int rt5677_i2c_remove(struct i2c_client *i2c) |
3699 | { | 4762 | { |
3700 | snd_soc_unregister_codec(&i2c->dev); | 4763 | snd_soc_unregister_codec(&i2c->dev); |
4764 | rt5677_free_irq(i2c); | ||
3701 | rt5677_free_gpio(i2c); | 4765 | rt5677_free_gpio(i2c); |
3702 | 4766 | ||
3703 | return 0; | 4767 | return 0; |
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index d4eb6d5e6746..c0a625f290cc 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #define __RT5677_H__ | 13 | #define __RT5677_H__ |
14 | 14 | ||
15 | #include <sound/rt5677.h> | 15 | #include <sound/rt5677.h> |
16 | #include <linux/gpio/driver.h> | ||
16 | 17 | ||
17 | /* Info */ | 18 | /* Info */ |
18 | #define RT5677_RESET 0x00 | 19 | #define RT5677_RESET 0x00 |
@@ -305,10 +306,10 @@ | |||
305 | #define RT5677_R_MUTE_SFT 7 | 306 | #define RT5677_R_MUTE_SFT 7 |
306 | #define RT5677_VOL_R_MUTE (0x1 << 6) | 307 | #define RT5677_VOL_R_MUTE (0x1 << 6) |
307 | #define RT5677_VOL_R_SFT 6 | 308 | #define RT5677_VOL_R_SFT 6 |
308 | #define RT5677_L_VOL_MASK (0x3f << 8) | 309 | #define RT5677_L_VOL_MASK (0x7f << 9) |
309 | #define RT5677_L_VOL_SFT 8 | 310 | #define RT5677_L_VOL_SFT 9 |
310 | #define RT5677_R_VOL_MASK (0x3f) | 311 | #define RT5677_R_VOL_MASK (0x7f << 1) |
311 | #define RT5677_R_VOL_SFT 0 | 312 | #define RT5677_R_VOL_SFT 1 |
312 | 313 | ||
313 | /* LOUT1 Control (0x01) */ | 314 | /* LOUT1 Control (0x01) */ |
314 | #define RT5677_LOUT1_L_MUTE (0x1 << 15) | 315 | #define RT5677_LOUT1_L_MUTE (0x1 << 15) |
@@ -446,16 +447,16 @@ | |||
446 | #define RT5677_SEL_DAC2_R_SRC_SFT 0 | 447 | #define RT5677_SEL_DAC2_R_SRC_SFT 0 |
447 | 448 | ||
448 | /* Stereo1 ADC Digital Volume Control (0x1c) */ | 449 | /* Stereo1 ADC Digital Volume Control (0x1c) */ |
449 | #define RT5677_STO1_ADC_L_VOL_MASK (0x7f << 8) | 450 | #define RT5677_STO1_ADC_L_VOL_MASK (0x3f << 9) |
450 | #define RT5677_STO1_ADC_L_VOL_SFT 8 | 451 | #define RT5677_STO1_ADC_L_VOL_SFT 9 |
451 | #define RT5677_STO1_ADC_R_VOL_MASK (0x7f) | 452 | #define RT5677_STO1_ADC_R_VOL_MASK (0x3f << 1) |
452 | #define RT5677_STO1_ADC_R_VOL_SFT 0 | 453 | #define RT5677_STO1_ADC_R_VOL_SFT 1 |
453 | 454 | ||
454 | /* Mono ADC Digital Volume Control (0x1d) */ | 455 | /* Mono ADC Digital Volume Control (0x1d) */ |
455 | #define RT5677_MONO_ADC_L_VOL_MASK (0x7f << 8) | 456 | #define RT5677_MONO_ADC_L_VOL_MASK (0x3f << 9) |
456 | #define RT5677_MONO_ADC_L_VOL_SFT 8 | 457 | #define RT5677_MONO_ADC_L_VOL_SFT 9 |
457 | #define RT5677_MONO_ADC_R_VOL_MASK (0x7f) | 458 | #define RT5677_MONO_ADC_R_VOL_MASK (0x3f << 1) |
458 | #define RT5677_MONO_ADC_R_VOL_SFT 0 | 459 | #define RT5677_MONO_ADC_R_VOL_SFT 1 |
459 | 460 | ||
460 | /* Stereo 1/2 ADC Boost Gain Control (0x1e) */ | 461 | /* Stereo 1/2 ADC Boost Gain Control (0x1e) */ |
461 | #define RT5677_STO1_ADC_L_BST_MASK (0x3 << 14) | 462 | #define RT5677_STO1_ADC_L_BST_MASK (0x3 << 14) |
@@ -798,7 +799,21 @@ | |||
798 | #define RT5677_PDM2_I2C_EXE (0x1 << 1) | 799 | #define RT5677_PDM2_I2C_EXE (0x1 << 1) |
799 | #define RT5677_PDM2_I2C_BUSY (0x1 << 0) | 800 | #define RT5677_PDM2_I2C_BUSY (0x1 << 0) |
800 | 801 | ||
801 | /* MX3C TDM1 control 1 (0x3c) */ | 802 | /* TDM1 control 1 (0x3b) */ |
803 | #define RT5677_IF1_ADC_MODE_MASK (0x1 << 12) | ||
804 | #define RT5677_IF1_ADC_MODE_SFT 12 | ||
805 | #define RT5677_IF1_ADC_MODE_I2S (0x0 << 12) | ||
806 | #define RT5677_IF1_ADC_MODE_TDM (0x1 << 12) | ||
807 | #define RT5677_IF1_ADC1_SWAP_MASK (0x3 << 6) | ||
808 | #define RT5677_IF1_ADC1_SWAP_SFT 6 | ||
809 | #define RT5677_IF1_ADC2_SWAP_MASK (0x3 << 4) | ||
810 | #define RT5677_IF1_ADC2_SWAP_SFT 4 | ||
811 | #define RT5677_IF1_ADC3_SWAP_MASK (0x3 << 2) | ||
812 | #define RT5677_IF1_ADC3_SWAP_SFT 2 | ||
813 | #define RT5677_IF1_ADC4_SWAP_MASK (0x3 << 0) | ||
814 | #define RT5677_IF1_ADC4_SWAP_SFT 0 | ||
815 | |||
816 | /* TDM1 control 2 (0x3c) */ | ||
802 | #define RT5677_IF1_ADC4_MASK (0x3 << 10) | 817 | #define RT5677_IF1_ADC4_MASK (0x3 << 10) |
803 | #define RT5677_IF1_ADC4_SFT 10 | 818 | #define RT5677_IF1_ADC4_SFT 10 |
804 | #define RT5677_IF1_ADC3_MASK (0x3 << 8) | 819 | #define RT5677_IF1_ADC3_MASK (0x3 << 8) |
@@ -807,8 +822,44 @@ | |||
807 | #define RT5677_IF1_ADC2_SFT 6 | 822 | #define RT5677_IF1_ADC2_SFT 6 |
808 | #define RT5677_IF1_ADC1_MASK (0x3 << 4) | 823 | #define RT5677_IF1_ADC1_MASK (0x3 << 4) |
809 | #define RT5677_IF1_ADC1_SFT 4 | 824 | #define RT5677_IF1_ADC1_SFT 4 |
810 | 825 | #define RT5677_IF1_ADC_CTRL_MASK (0x7 << 0) | |
811 | /* MX41 TDM2 control 1 (0x41) */ | 826 | #define RT5677_IF1_ADC_CTRL_SFT 0 |
827 | |||
828 | /* TDM1 control 4 (0x3e) */ | ||
829 | #define RT5677_IF1_DAC0_MASK (0x7 << 12) | ||
830 | #define RT5677_IF1_DAC0_SFT 12 | ||
831 | #define RT5677_IF1_DAC1_MASK (0x7 << 8) | ||
832 | #define RT5677_IF1_DAC1_SFT 8 | ||
833 | #define RT5677_IF1_DAC2_MASK (0x7 << 4) | ||
834 | #define RT5677_IF1_DAC2_SFT 4 | ||
835 | #define RT5677_IF1_DAC3_MASK (0x7 << 0) | ||
836 | #define RT5677_IF1_DAC3_SFT 0 | ||
837 | |||
838 | /* TDM1 control 5 (0x3f) */ | ||
839 | #define RT5677_IF1_DAC4_MASK (0x7 << 12) | ||
840 | #define RT5677_IF1_DAC4_SFT 12 | ||
841 | #define RT5677_IF1_DAC5_MASK (0x7 << 8) | ||
842 | #define RT5677_IF1_DAC5_SFT 8 | ||
843 | #define RT5677_IF1_DAC6_MASK (0x7 << 4) | ||
844 | #define RT5677_IF1_DAC6_SFT 4 | ||
845 | #define RT5677_IF1_DAC7_MASK (0x7 << 0) | ||
846 | #define RT5677_IF1_DAC7_SFT 0 | ||
847 | |||
848 | /* TDM2 control 1 (0x40) */ | ||
849 | #define RT5677_IF2_ADC_MODE_MASK (0x1 << 12) | ||
850 | #define RT5677_IF2_ADC_MODE_SFT 12 | ||
851 | #define RT5677_IF2_ADC_MODE_I2S (0x0 << 12) | ||
852 | #define RT5677_IF2_ADC_MODE_TDM (0x1 << 12) | ||
853 | #define RT5677_IF2_ADC1_SWAP_MASK (0x3 << 6) | ||
854 | #define RT5677_IF2_ADC1_SWAP_SFT 6 | ||
855 | #define RT5677_IF2_ADC2_SWAP_MASK (0x3 << 4) | ||
856 | #define RT5677_IF2_ADC2_SWAP_SFT 4 | ||
857 | #define RT5677_IF2_ADC3_SWAP_MASK (0x3 << 2) | ||
858 | #define RT5677_IF2_ADC3_SWAP_SFT 2 | ||
859 | #define RT5677_IF2_ADC4_SWAP_MASK (0x3 << 0) | ||
860 | #define RT5677_IF2_ADC4_SWAP_SFT 0 | ||
861 | |||
862 | /* TDM2 control 2 (0x41) */ | ||
812 | #define RT5677_IF2_ADC4_MASK (0x3 << 10) | 863 | #define RT5677_IF2_ADC4_MASK (0x3 << 10) |
813 | #define RT5677_IF2_ADC4_SFT 10 | 864 | #define RT5677_IF2_ADC4_SFT 10 |
814 | #define RT5677_IF2_ADC3_MASK (0x3 << 8) | 865 | #define RT5677_IF2_ADC3_MASK (0x3 << 8) |
@@ -817,6 +868,28 @@ | |||
817 | #define RT5677_IF2_ADC2_SFT 6 | 868 | #define RT5677_IF2_ADC2_SFT 6 |
818 | #define RT5677_IF2_ADC1_MASK (0x3 << 4) | 869 | #define RT5677_IF2_ADC1_MASK (0x3 << 4) |
819 | #define RT5677_IF2_ADC1_SFT 4 | 870 | #define RT5677_IF2_ADC1_SFT 4 |
871 | #define RT5677_IF2_ADC_CTRL_MASK (0x7 << 0) | ||
872 | #define RT5677_IF2_ADC_CTRL_SFT 0 | ||
873 | |||
874 | /* TDM2 control 4 (0x43) */ | ||
875 | #define RT5677_IF2_DAC0_MASK (0x7 << 12) | ||
876 | #define RT5677_IF2_DAC0_SFT 12 | ||
877 | #define RT5677_IF2_DAC1_MASK (0x7 << 8) | ||
878 | #define RT5677_IF2_DAC1_SFT 8 | ||
879 | #define RT5677_IF2_DAC2_MASK (0x7 << 4) | ||
880 | #define RT5677_IF2_DAC2_SFT 4 | ||
881 | #define RT5677_IF2_DAC3_MASK (0x7 << 0) | ||
882 | #define RT5677_IF2_DAC3_SFT 0 | ||
883 | |||
884 | /* TDM2 control 5 (0x44) */ | ||
885 | #define RT5677_IF2_DAC4_MASK (0x7 << 12) | ||
886 | #define RT5677_IF2_DAC4_SFT 12 | ||
887 | #define RT5677_IF2_DAC5_MASK (0x7 << 8) | ||
888 | #define RT5677_IF2_DAC5_SFT 8 | ||
889 | #define RT5677_IF2_DAC6_MASK (0x7 << 4) | ||
890 | #define RT5677_IF2_DAC6_SFT 4 | ||
891 | #define RT5677_IF2_DAC7_MASK (0x7 << 0) | ||
892 | #define RT5677_IF2_DAC7_SFT 0 | ||
820 | 893 | ||
821 | /* Digital Microphone Control 1 (0x50) */ | 894 | /* Digital Microphone Control 1 (0x50) */ |
822 | #define RT5677_DMIC_1_EN_MASK (0x1 << 15) | 895 | #define RT5677_DMIC_1_EN_MASK (0x1 << 15) |
@@ -1367,6 +1440,48 @@ | |||
1367 | #define RT5677_SEL_SRC_IB01 (0x1 << 0) | 1440 | #define RT5677_SEL_SRC_IB01 (0x1 << 0) |
1368 | #define RT5677_SEL_SRC_IB01_SFT 0 | 1441 | #define RT5677_SEL_SRC_IB01_SFT 0 |
1369 | 1442 | ||
1443 | /* Jack Detect Control 1 (0xb5) */ | ||
1444 | #define RT5677_SEL_GPIO_JD1_MASK (0x3 << 14) | ||
1445 | #define RT5677_SEL_GPIO_JD1_SFT 14 | ||
1446 | #define RT5677_SEL_GPIO_JD2_MASK (0x3 << 12) | ||
1447 | #define RT5677_SEL_GPIO_JD2_SFT 12 | ||
1448 | #define RT5677_SEL_GPIO_JD3_MASK (0x3 << 10) | ||
1449 | #define RT5677_SEL_GPIO_JD3_SFT 10 | ||
1450 | |||
1451 | /* IRQ Control 1 (0xbd) */ | ||
1452 | #define RT5677_STA_GPIO_JD1 (0x1 << 15) | ||
1453 | #define RT5677_STA_GPIO_JD1_SFT 15 | ||
1454 | #define RT5677_EN_IRQ_GPIO_JD1 (0x1 << 14) | ||
1455 | #define RT5677_EN_IRQ_GPIO_JD1_SFT 14 | ||
1456 | #define RT5677_EN_GPIO_JD1_STICKY (0x1 << 13) | ||
1457 | #define RT5677_EN_GPIO_JD1_STICKY_SFT 13 | ||
1458 | #define RT5677_INV_GPIO_JD1 (0x1 << 12) | ||
1459 | #define RT5677_INV_GPIO_JD1_SFT 12 | ||
1460 | #define RT5677_STA_GPIO_JD2 (0x1 << 11) | ||
1461 | #define RT5677_STA_GPIO_JD2_SFT 11 | ||
1462 | #define RT5677_EN_IRQ_GPIO_JD2 (0x1 << 10) | ||
1463 | #define RT5677_EN_IRQ_GPIO_JD2_SFT 10 | ||
1464 | #define RT5677_EN_GPIO_JD2_STICKY (0x1 << 9) | ||
1465 | #define RT5677_EN_GPIO_JD2_STICKY_SFT 9 | ||
1466 | #define RT5677_INV_GPIO_JD2 (0x1 << 8) | ||
1467 | #define RT5677_INV_GPIO_JD2_SFT 8 | ||
1468 | #define RT5677_STA_MICBIAS1_OVCD (0x1 << 7) | ||
1469 | #define RT5677_STA_MICBIAS1_OVCD_SFT 7 | ||
1470 | #define RT5677_EN_IRQ_MICBIAS1_OVCD (0x1 << 6) | ||
1471 | #define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT 6 | ||
1472 | #define RT5677_EN_MICBIAS1_OVCD_STICKY (0x1 << 5) | ||
1473 | #define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT 5 | ||
1474 | #define RT5677_INV_MICBIAS1_OVCD (0x1 << 4) | ||
1475 | #define RT5677_INV_MICBIAS1_OVCD_SFT 4 | ||
1476 | #define RT5677_STA_GPIO_JD3 (0x1 << 3) | ||
1477 | #define RT5677_STA_GPIO_JD3_SFT 3 | ||
1478 | #define RT5677_EN_IRQ_GPIO_JD3 (0x1 << 2) | ||
1479 | #define RT5677_EN_IRQ_GPIO_JD3_SFT 2 | ||
1480 | #define RT5677_EN_GPIO_JD3_STICKY (0x1 << 1) | ||
1481 | #define RT5677_EN_GPIO_JD3_STICKY_SFT 1 | ||
1482 | #define RT5677_INV_GPIO_JD3 (0x1 << 0) | ||
1483 | #define RT5677_INV_GPIO_JD3_SFT 0 | ||
1484 | |||
1370 | /* GPIO status (0xbf) */ | 1485 | /* GPIO status (0xbf) */ |
1371 | #define RT5677_GPIO6_STATUS_MASK (0x1 << 5) | 1486 | #define RT5677_GPIO6_STATUS_MASK (0x1 << 5) |
1372 | #define RT5677_GPIO6_STATUS_SFT 5 | 1487 | #define RT5677_GPIO6_STATUS_SFT 5 |
@@ -1506,6 +1621,9 @@ | |||
1506 | #define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) | 1621 | #define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) |
1507 | #define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) | 1622 | #define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) |
1508 | 1623 | ||
1624 | #define RT5677_FIRMWARE1 "rt5677_dsp_fw1.bin" | ||
1625 | #define RT5677_FIRMWARE2 "rt5677_dsp_fw2.bin" | ||
1626 | |||
1509 | /* System Clock Source */ | 1627 | /* System Clock Source */ |
1510 | enum { | 1628 | enum { |
1511 | RT5677_SCLK_S_MCLK, | 1629 | RT5677_SCLK_S_MCLK, |
@@ -1541,10 +1659,18 @@ enum { | |||
1541 | RT5677_GPIO_NUM, | 1659 | RT5677_GPIO_NUM, |
1542 | }; | 1660 | }; |
1543 | 1661 | ||
1662 | enum { | ||
1663 | RT5677_IRQ_JD1, | ||
1664 | RT5677_IRQ_JD2, | ||
1665 | RT5677_IRQ_JD3, | ||
1666 | }; | ||
1667 | |||
1544 | struct rt5677_priv { | 1668 | struct rt5677_priv { |
1545 | struct snd_soc_codec *codec; | 1669 | struct snd_soc_codec *codec; |
1546 | struct rt5677_platform_data pdata; | 1670 | struct rt5677_platform_data pdata; |
1547 | struct regmap *regmap; | 1671 | struct regmap *regmap, *regmap_physical; |
1672 | const struct firmware *fw1, *fw2; | ||
1673 | struct mutex dsp_cmd_lock, dsp_pri_lock; | ||
1548 | 1674 | ||
1549 | int sysclk; | 1675 | int sysclk; |
1550 | int sysclk_src; | 1676 | int sysclk_src; |
@@ -1558,6 +1684,10 @@ struct rt5677_priv { | |||
1558 | #ifdef CONFIG_GPIOLIB | 1684 | #ifdef CONFIG_GPIOLIB |
1559 | struct gpio_chip gpio_chip; | 1685 | struct gpio_chip gpio_chip; |
1560 | #endif | 1686 | #endif |
1687 | bool dsp_vad_en; | ||
1688 | struct regmap_irq_chip_data *irq_data; | ||
1689 | bool is_dsp_mode; | ||
1690 | bool is_vref_slow; | ||
1561 | }; | 1691 | }; |
1562 | 1692 | ||
1563 | #endif /* __RT5677_H__ */ | 1693 | #endif /* __RT5677_H__ */ |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index dab9b15304af..29cf7ce610f4 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/log2.h> | ||
19 | #include <linux/regmap.h> | 20 | #include <linux/regmap.h> |
20 | #include <linux/regulator/driver.h> | 21 | #include <linux/regulator/driver.h> |
21 | #include <linux/regulator/machine.h> | 22 | #include <linux/regulator/machine.h> |
@@ -121,6 +122,13 @@ struct ldo_regulator { | |||
121 | bool enabled; | 122 | bool enabled; |
122 | }; | 123 | }; |
123 | 124 | ||
125 | enum sgtl5000_micbias_resistor { | ||
126 | SGTL5000_MICBIAS_OFF = 0, | ||
127 | SGTL5000_MICBIAS_2K = 2, | ||
128 | SGTL5000_MICBIAS_4K = 4, | ||
129 | SGTL5000_MICBIAS_8K = 8, | ||
130 | }; | ||
131 | |||
124 | /* sgtl5000 private structure in codec */ | 132 | /* sgtl5000 private structure in codec */ |
125 | struct sgtl5000_priv { | 133 | struct sgtl5000_priv { |
126 | int sysclk; /* sysclk rate */ | 134 | int sysclk; /* sysclk rate */ |
@@ -131,6 +139,8 @@ struct sgtl5000_priv { | |||
131 | struct regmap *regmap; | 139 | struct regmap *regmap; |
132 | struct clk *mclk; | 140 | struct clk *mclk; |
133 | int revision; | 141 | int revision; |
142 | u8 micbias_resistor; | ||
143 | u8 micbias_voltage; | ||
134 | }; | 144 | }; |
135 | 145 | ||
136 | /* | 146 | /* |
@@ -145,12 +155,14 @@ struct sgtl5000_priv { | |||
145 | static int mic_bias_event(struct snd_soc_dapm_widget *w, | 155 | static int mic_bias_event(struct snd_soc_dapm_widget *w, |
146 | struct snd_kcontrol *kcontrol, int event) | 156 | struct snd_kcontrol *kcontrol, int event) |
147 | { | 157 | { |
158 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec); | ||
159 | |||
148 | switch (event) { | 160 | switch (event) { |
149 | case SND_SOC_DAPM_POST_PMU: | 161 | case SND_SOC_DAPM_POST_PMU: |
150 | /* change mic bias resistor to 4Kohm */ | 162 | /* change mic bias resistor */ |
151 | snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, | 163 | snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, |
152 | SGTL5000_BIAS_R_MASK, | 164 | SGTL5000_BIAS_R_MASK, |
153 | SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT); | 165 | sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); |
154 | break; | 166 | break; |
155 | 167 | ||
156 | case SND_SOC_DAPM_PRE_PMD: | 168 | case SND_SOC_DAPM_PRE_PMD: |
@@ -530,16 +542,16 @@ static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
530 | 542 | ||
531 | /* | 543 | /* |
532 | * set clock according to i2s frame clock, | 544 | * set clock according to i2s frame clock, |
533 | * sgtl5000 provide 2 clock sources. | 545 | * sgtl5000 provides 2 clock sources: |
534 | * 1. sys_mclk. sample freq can only configure to | 546 | * 1. sys_mclk: sample freq can only be configured to |
535 | * 1/256, 1/384, 1/512 of sys_mclk. | 547 | * 1/256, 1/384, 1/512 of sys_mclk. |
536 | * 2. pll. can derive any audio clocks. | 548 | * 2. pll: can derive any audio clocks. |
537 | * | 549 | * |
538 | * clock setting rules: | 550 | * clock setting rules: |
539 | * 1. in slave mode, only sys_mclk can use. | 551 | * 1. in slave mode, only sys_mclk can be used |
540 | * 2. as constraint by sys_mclk, sample freq should | 552 | * 2. as constraint by sys_mclk, sample freq should be set to 32 kHz, 44.1 kHz |
541 | * set to 32k, 44.1k and above. | 553 | * and above. |
542 | * 3. using sys_mclk prefer to pll to save power. | 554 | * 3. usage of sys_mclk is preferred over pll to save power. |
543 | */ | 555 | */ |
544 | static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | 556 | static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) |
545 | { | 557 | { |
@@ -549,8 +561,8 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
549 | 561 | ||
550 | /* | 562 | /* |
551 | * sample freq should be divided by frame clock, | 563 | * sample freq should be divided by frame clock, |
552 | * if frame clock lower than 44.1khz, sample feq should set to | 564 | * if frame clock is lower than 44.1 kHz, sample freq should be set to |
553 | * 32khz or 44.1khz. | 565 | * 32 kHz or 44.1 kHz. |
554 | */ | 566 | */ |
555 | switch (frame_rate) { | 567 | switch (frame_rate) { |
556 | case 8000: | 568 | case 8000: |
@@ -603,9 +615,10 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
603 | 615 | ||
604 | /* | 616 | /* |
605 | * calculate the divider of mclk/sample_freq, | 617 | * calculate the divider of mclk/sample_freq, |
606 | * factor of freq =96k can only be 256, since mclk in range (12m,27m) | 618 | * factor of freq = 96 kHz can only be 256, since mclk is in the range |
619 | * of 8 MHz - 27 MHz | ||
607 | */ | 620 | */ |
608 | switch (sgtl5000->sysclk / sys_fs) { | 621 | switch (sgtl5000->sysclk / frame_rate) { |
609 | case 256: | 622 | case 256: |
610 | clk_ctl |= SGTL5000_MCLK_FREQ_256FS << | 623 | clk_ctl |= SGTL5000_MCLK_FREQ_256FS << |
611 | SGTL5000_MCLK_FREQ_SHIFT; | 624 | SGTL5000_MCLK_FREQ_SHIFT; |
@@ -619,7 +632,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
619 | SGTL5000_MCLK_FREQ_SHIFT; | 632 | SGTL5000_MCLK_FREQ_SHIFT; |
620 | break; | 633 | break; |
621 | default: | 634 | default: |
622 | /* if mclk not satisify the divider, use pll */ | 635 | /* if mclk does not satisfy the divider, use pll */ |
623 | if (sgtl5000->master) { | 636 | if (sgtl5000->master) { |
624 | clk_ctl |= SGTL5000_MCLK_FREQ_PLL << | 637 | clk_ctl |= SGTL5000_MCLK_FREQ_PLL << |
625 | SGTL5000_MCLK_FREQ_SHIFT; | 638 | SGTL5000_MCLK_FREQ_SHIFT; |
@@ -628,7 +641,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
628 | "PLL not supported in slave mode\n"); | 641 | "PLL not supported in slave mode\n"); |
629 | dev_err(codec->dev, "%d ratio is not supported. " | 642 | dev_err(codec->dev, "%d ratio is not supported. " |
630 | "SYS_MCLK needs to be 256, 384 or 512 * fs\n", | 643 | "SYS_MCLK needs to be 256, 384 or 512 * fs\n", |
631 | sgtl5000->sysclk / sys_fs); | 644 | sgtl5000->sysclk / frame_rate); |
632 | return -EINVAL; | 645 | return -EINVAL; |
633 | } | 646 | } |
634 | } | 647 | } |
@@ -795,7 +808,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev) | |||
795 | SGTL5000_LINEREG_D_POWERUP, | 808 | SGTL5000_LINEREG_D_POWERUP, |
796 | SGTL5000_LINEREG_D_POWERUP); | 809 | SGTL5000_LINEREG_D_POWERUP); |
797 | 810 | ||
798 | /* when internal ldo enabled, simple digital power can be disabled */ | 811 | /* when internal ldo is enabled, simple digital power can be disabled */ |
799 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | 812 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, |
800 | SGTL5000_LINREG_SIMPLE_POWERUP, | 813 | SGTL5000_LINREG_SIMPLE_POWERUP, |
801 | 0); | 814 | 0); |
@@ -1079,7 +1092,7 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg) | |||
1079 | /* | 1092 | /* |
1080 | * sgtl5000 has 3 internal power supplies: | 1093 | * sgtl5000 has 3 internal power supplies: |
1081 | * 1. VAG, normally set to vdda/2 | 1094 | * 1. VAG, normally set to vdda/2 |
1082 | * 2. chargepump, set to different value | 1095 | * 2. charge pump, set to different value |
1083 | * according to voltage of vdda and vddio | 1096 | * according to voltage of vdda and vddio |
1084 | * 3. line out VAG, normally set to vddio/2 | 1097 | * 3. line out VAG, normally set to vddio/2 |
1085 | * | 1098 | * |
@@ -1325,8 +1338,13 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) | |||
1325 | SGTL5000_HP_ZCD_EN | | 1338 | SGTL5000_HP_ZCD_EN | |
1326 | SGTL5000_ADC_ZCD_EN); | 1339 | SGTL5000_ADC_ZCD_EN); |
1327 | 1340 | ||
1328 | snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2); | 1341 | snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, |
1342 | SGTL5000_BIAS_R_MASK, | ||
1343 | sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); | ||
1329 | 1344 | ||
1345 | snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, | ||
1346 | SGTL5000_BIAS_R_MASK, | ||
1347 | sgtl5000->micbias_voltage << SGTL5000_BIAS_R_SHIFT); | ||
1330 | /* | 1348 | /* |
1331 | * disable DAP | 1349 | * disable DAP |
1332 | * TODO: | 1350 | * TODO: |
@@ -1416,10 +1434,10 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1416 | { | 1434 | { |
1417 | struct sgtl5000_priv *sgtl5000; | 1435 | struct sgtl5000_priv *sgtl5000; |
1418 | int ret, reg, rev; | 1436 | int ret, reg, rev; |
1419 | unsigned int mclk; | 1437 | struct device_node *np = client->dev.of_node; |
1438 | u32 value; | ||
1420 | 1439 | ||
1421 | sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv), | 1440 | sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL); |
1422 | GFP_KERNEL); | ||
1423 | if (!sgtl5000) | 1441 | if (!sgtl5000) |
1424 | return -ENOMEM; | 1442 | return -ENOMEM; |
1425 | 1443 | ||
@@ -1440,14 +1458,6 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1440 | return ret; | 1458 | return ret; |
1441 | } | 1459 | } |
1442 | 1460 | ||
1443 | /* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */ | ||
1444 | mclk = clk_get_rate(sgtl5000->mclk); | ||
1445 | if (mclk < 8000000 || mclk > 27000000) { | ||
1446 | dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n", | ||
1447 | mclk / 1000000, mclk / 1000 % 1000); | ||
1448 | return -EINVAL; | ||
1449 | } | ||
1450 | |||
1451 | ret = clk_prepare_enable(sgtl5000->mclk); | 1461 | ret = clk_prepare_enable(sgtl5000->mclk); |
1452 | if (ret) | 1462 | if (ret) |
1453 | return ret; | 1463 | return ret; |
@@ -1469,6 +1479,47 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1469 | dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); | 1479 | dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); |
1470 | sgtl5000->revision = rev; | 1480 | sgtl5000->revision = rev; |
1471 | 1481 | ||
1482 | if (np) { | ||
1483 | if (!of_property_read_u32(np, | ||
1484 | "micbias-resistor-k-ohms", &value)) { | ||
1485 | switch (value) { | ||
1486 | case SGTL5000_MICBIAS_OFF: | ||
1487 | sgtl5000->micbias_resistor = 0; | ||
1488 | break; | ||
1489 | case SGTL5000_MICBIAS_2K: | ||
1490 | sgtl5000->micbias_resistor = 1; | ||
1491 | break; | ||
1492 | case SGTL5000_MICBIAS_4K: | ||
1493 | sgtl5000->micbias_resistor = 2; | ||
1494 | break; | ||
1495 | case SGTL5000_MICBIAS_8K: | ||
1496 | sgtl5000->micbias_resistor = 3; | ||
1497 | break; | ||
1498 | default: | ||
1499 | sgtl5000->micbias_resistor = 2; | ||
1500 | dev_err(&client->dev, | ||
1501 | "Unsuitable MicBias resistor\n"); | ||
1502 | } | ||
1503 | } else { | ||
1504 | /* default is 4Kohms */ | ||
1505 | sgtl5000->micbias_resistor = 2; | ||
1506 | } | ||
1507 | if (!of_property_read_u32(np, | ||
1508 | "micbias-voltage-m-volts", &value)) { | ||
1509 | /* 1250mV => 0 */ | ||
1510 | /* steps of 250mV */ | ||
1511 | if ((value >= 1250) && (value <= 3000)) | ||
1512 | sgtl5000->micbias_voltage = (value / 250) - 5; | ||
1513 | else { | ||
1514 | sgtl5000->micbias_voltage = 0; | ||
1515 | dev_err(&client->dev, | ||
1516 | "Unsuitable MicBias resistor\n"); | ||
1517 | } | ||
1518 | } else { | ||
1519 | sgtl5000->micbias_voltage = 0; | ||
1520 | } | ||
1521 | } | ||
1522 | |||
1472 | i2c_set_clientdata(client, sgtl5000); | 1523 | i2c_set_clientdata(client, sgtl5000); |
1473 | 1524 | ||
1474 | /* Ensure sgtl5000 will start with sane register values */ | 1525 | /* Ensure sgtl5000 will start with sane register values */ |
diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c index 246081aae8ca..21ca3a5e9f66 100644 --- a/sound/soc/codecs/sigmadsp-i2c.c +++ b/sound/soc/codecs/sigmadsp-i2c.c | |||
@@ -6,29 +6,88 @@ | |||
6 | * Licensed under the GPL-2 or later. | 6 | * Licensed under the GPL-2 or later. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/i2c.h> | ||
10 | #include <linux/export.h> | 9 | #include <linux/export.h> |
10 | #include <linux/i2c.h> | ||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/slab.h> | ||
13 | #include <asm/unaligned.h> | ||
12 | 14 | ||
13 | #include "sigmadsp.h" | 15 | #include "sigmadsp.h" |
14 | 16 | ||
15 | static int sigma_action_write_i2c(void *control_data, | 17 | static int sigmadsp_write_i2c(void *control_data, |
16 | const struct sigma_action *sa, size_t len) | 18 | unsigned int addr, const uint8_t data[], size_t len) |
19 | { | ||
20 | uint8_t *buf; | ||
21 | int ret; | ||
22 | |||
23 | buf = kzalloc(2 + len, GFP_KERNEL | GFP_DMA); | ||
24 | if (!buf) | ||
25 | return -ENOMEM; | ||
26 | |||
27 | put_unaligned_be16(addr, buf); | ||
28 | memcpy(buf + 2, data, len); | ||
29 | |||
30 | ret = i2c_master_send(control_data, buf, len + 2); | ||
31 | |||
32 | kfree(buf); | ||
33 | |||
34 | return ret; | ||
35 | } | ||
36 | |||
37 | static int sigmadsp_read_i2c(void *control_data, | ||
38 | unsigned int addr, uint8_t data[], size_t len) | ||
17 | { | 39 | { |
18 | return i2c_master_send(control_data, (const unsigned char *)&sa->addr, | 40 | struct i2c_client *client = control_data; |
19 | len); | 41 | struct i2c_msg msgs[2]; |
42 | uint8_t buf[2]; | ||
43 | int ret; | ||
44 | |||
45 | put_unaligned_be16(addr, buf); | ||
46 | |||
47 | msgs[0].addr = client->addr; | ||
48 | msgs[0].len = sizeof(buf); | ||
49 | msgs[0].buf = buf; | ||
50 | msgs[0].flags = 0; | ||
51 | |||
52 | msgs[1].addr = client->addr; | ||
53 | msgs[1].len = len; | ||
54 | msgs[1].buf = data; | ||
55 | msgs[1].flags = I2C_M_RD; | ||
56 | |||
57 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
58 | if (ret < 0) | ||
59 | return ret; | ||
60 | else if (ret != ARRAY_SIZE(msgs)) | ||
61 | return -EIO; | ||
62 | return 0; | ||
20 | } | 63 | } |
21 | 64 | ||
22 | int process_sigma_firmware(struct i2c_client *client, const char *name) | 65 | /** |
66 | * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance | ||
67 | * @client: The parent I2C device | ||
68 | * @ops: The sigmadsp_ops to use for this instance | ||
69 | * @firmware_name: Name of the firmware file to load | ||
70 | * | ||
71 | * Allocates a SigmaDSP instance and loads the specified firmware file. | ||
72 | * | ||
73 | * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. | ||
74 | */ | ||
75 | struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client, | ||
76 | const struct sigmadsp_ops *ops, const char *firmware_name) | ||
23 | { | 77 | { |
24 | struct sigma_firmware ssfw; | 78 | struct sigmadsp *sigmadsp; |
79 | |||
80 | sigmadsp = devm_sigmadsp_init(&client->dev, ops, firmware_name); | ||
81 | if (IS_ERR(sigmadsp)) | ||
82 | return sigmadsp; | ||
25 | 83 | ||
26 | ssfw.control_data = client; | 84 | sigmadsp->control_data = client; |
27 | ssfw.write = sigma_action_write_i2c; | 85 | sigmadsp->write = sigmadsp_write_i2c; |
86 | sigmadsp->read = sigmadsp_read_i2c; | ||
28 | 87 | ||
29 | return _process_sigma_firmware(&client->dev, &ssfw, name); | 88 | return sigmadsp; |
30 | } | 89 | } |
31 | EXPORT_SYMBOL(process_sigma_firmware); | 90 | EXPORT_SYMBOL_GPL(devm_sigmadsp_init_i2c); |
32 | 91 | ||
33 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 92 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
34 | MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); | 93 | MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); |
diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c index f78ed8d2cfb2..912861be5b87 100644 --- a/sound/soc/codecs/sigmadsp-regmap.c +++ b/sound/soc/codecs/sigmadsp-regmap.c | |||
@@ -12,24 +12,48 @@ | |||
12 | 12 | ||
13 | #include "sigmadsp.h" | 13 | #include "sigmadsp.h" |
14 | 14 | ||
15 | static int sigma_action_write_regmap(void *control_data, | 15 | static int sigmadsp_write_regmap(void *control_data, |
16 | const struct sigma_action *sa, size_t len) | 16 | unsigned int addr, const uint8_t data[], size_t len) |
17 | { | 17 | { |
18 | return regmap_raw_write(control_data, be16_to_cpu(sa->addr), | 18 | return regmap_raw_write(control_data, addr, |
19 | sa->payload, len - 2); | 19 | data, len); |
20 | } | 20 | } |
21 | 21 | ||
22 | int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, | 22 | static int sigmadsp_read_regmap(void *control_data, |
23 | const char *name) | 23 | unsigned int addr, uint8_t data[], size_t len) |
24 | { | 24 | { |
25 | struct sigma_firmware ssfw; | 25 | return regmap_raw_read(control_data, addr, |
26 | data, len); | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance | ||
31 | * @dev: The parent device | ||
32 | * @regmap: Regmap instance to use | ||
33 | * @ops: The sigmadsp_ops to use for this instance | ||
34 | * @firmware_name: Name of the firmware file to load | ||
35 | * | ||
36 | * Allocates a SigmaDSP instance and loads the specified firmware file. | ||
37 | * | ||
38 | * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. | ||
39 | */ | ||
40 | struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev, | ||
41 | struct regmap *regmap, const struct sigmadsp_ops *ops, | ||
42 | const char *firmware_name) | ||
43 | { | ||
44 | struct sigmadsp *sigmadsp; | ||
45 | |||
46 | sigmadsp = devm_sigmadsp_init(dev, ops, firmware_name); | ||
47 | if (IS_ERR(sigmadsp)) | ||
48 | return sigmadsp; | ||
26 | 49 | ||
27 | ssfw.control_data = regmap; | 50 | sigmadsp->control_data = regmap; |
28 | ssfw.write = sigma_action_write_regmap; | 51 | sigmadsp->write = sigmadsp_write_regmap; |
52 | sigmadsp->read = sigmadsp_read_regmap; | ||
29 | 53 | ||
30 | return _process_sigma_firmware(dev, &ssfw, name); | 54 | return sigmadsp; |
31 | } | 55 | } |
32 | EXPORT_SYMBOL(process_sigma_firmware_regmap); | 56 | EXPORT_SYMBOL_GPL(devm_sigmadsp_init_regmap); |
33 | 57 | ||
34 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 58 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
35 | MODULE_DESCRIPTION("SigmaDSP regmap firmware loader"); | 59 | MODULE_DESCRIPTION("SigmaDSP regmap firmware loader"); |
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index f2de7e049bc6..d53680ac78e4 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c | |||
@@ -1,23 +1,74 @@ | |||
1 | /* | 1 | /* |
2 | * Load Analog Devices SigmaStudio firmware files | 2 | * Load Analog Devices SigmaStudio firmware files |
3 | * | 3 | * |
4 | * Copyright 2009-2011 Analog Devices Inc. | 4 | * Copyright 2009-2014 Analog Devices Inc. |
5 | * | 5 | * |
6 | * Licensed under the GPL-2 or later. | 6 | * Licensed under the GPL-2 or later. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/crc32.h> | 9 | #include <linux/crc32.h> |
10 | #include <linux/delay.h> | ||
11 | #include <linux/firmware.h> | 10 | #include <linux/firmware.h> |
12 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
13 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
14 | #include <linux/regmap.h> | 13 | #include <linux/regmap.h> |
15 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include <sound/control.h> | ||
18 | #include <sound/soc.h> | ||
16 | 19 | ||
17 | #include "sigmadsp.h" | 20 | #include "sigmadsp.h" |
18 | 21 | ||
19 | #define SIGMA_MAGIC "ADISIGM" | 22 | #define SIGMA_MAGIC "ADISIGM" |
20 | 23 | ||
24 | #define SIGMA_FW_CHUNK_TYPE_DATA 0 | ||
25 | #define SIGMA_FW_CHUNK_TYPE_CONTROL 1 | ||
26 | #define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2 | ||
27 | |||
28 | struct sigmadsp_control { | ||
29 | struct list_head head; | ||
30 | uint32_t samplerates; | ||
31 | unsigned int addr; | ||
32 | unsigned int num_bytes; | ||
33 | const char *name; | ||
34 | struct snd_kcontrol *kcontrol; | ||
35 | bool cached; | ||
36 | uint8_t cache[]; | ||
37 | }; | ||
38 | |||
39 | struct sigmadsp_data { | ||
40 | struct list_head head; | ||
41 | uint32_t samplerates; | ||
42 | unsigned int addr; | ||
43 | unsigned int length; | ||
44 | uint8_t data[]; | ||
45 | }; | ||
46 | |||
47 | struct sigma_fw_chunk { | ||
48 | __le32 length; | ||
49 | __le32 tag; | ||
50 | __le32 samplerates; | ||
51 | } __packed; | ||
52 | |||
53 | struct sigma_fw_chunk_data { | ||
54 | struct sigma_fw_chunk chunk; | ||
55 | __le16 addr; | ||
56 | uint8_t data[]; | ||
57 | } __packed; | ||
58 | |||
59 | struct sigma_fw_chunk_control { | ||
60 | struct sigma_fw_chunk chunk; | ||
61 | __le16 type; | ||
62 | __le16 addr; | ||
63 | __le16 num_bytes; | ||
64 | const char name[]; | ||
65 | } __packed; | ||
66 | |||
67 | struct sigma_fw_chunk_samplerate { | ||
68 | struct sigma_fw_chunk chunk; | ||
69 | __le32 samplerates[]; | ||
70 | } __packed; | ||
71 | |||
21 | struct sigma_firmware_header { | 72 | struct sigma_firmware_header { |
22 | unsigned char magic[7]; | 73 | unsigned char magic[7]; |
23 | u8 version; | 74 | u8 version; |
@@ -28,12 +79,286 @@ enum { | |||
28 | SIGMA_ACTION_WRITEXBYTES = 0, | 79 | SIGMA_ACTION_WRITEXBYTES = 0, |
29 | SIGMA_ACTION_WRITESINGLE, | 80 | SIGMA_ACTION_WRITESINGLE, |
30 | SIGMA_ACTION_WRITESAFELOAD, | 81 | SIGMA_ACTION_WRITESAFELOAD, |
31 | SIGMA_ACTION_DELAY, | ||
32 | SIGMA_ACTION_PLLWAIT, | ||
33 | SIGMA_ACTION_NOOP, | ||
34 | SIGMA_ACTION_END, | 82 | SIGMA_ACTION_END, |
35 | }; | 83 | }; |
36 | 84 | ||
85 | struct sigma_action { | ||
86 | u8 instr; | ||
87 | u8 len_hi; | ||
88 | __le16 len; | ||
89 | __be16 addr; | ||
90 | unsigned char payload[]; | ||
91 | } __packed; | ||
92 | |||
93 | static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr, | ||
94 | const uint8_t data[], size_t len) | ||
95 | { | ||
96 | return sigmadsp->write(sigmadsp->control_data, addr, data, len); | ||
97 | } | ||
98 | |||
99 | static int sigmadsp_read(struct sigmadsp *sigmadsp, unsigned int addr, | ||
100 | uint8_t data[], size_t len) | ||
101 | { | ||
102 | return sigmadsp->read(sigmadsp->control_data, addr, data, len); | ||
103 | } | ||
104 | |||
105 | static int sigmadsp_ctrl_info(struct snd_kcontrol *kcontrol, | ||
106 | struct snd_ctl_elem_info *info) | ||
107 | { | ||
108 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | ||
109 | |||
110 | info->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
111 | info->count = ctrl->num_bytes; | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int sigmadsp_ctrl_write(struct sigmadsp *sigmadsp, | ||
117 | struct sigmadsp_control *ctrl, void *data) | ||
118 | { | ||
119 | /* safeload loads up to 20 bytes in a atomic operation */ | ||
120 | if (ctrl->num_bytes > 4 && ctrl->num_bytes <= 20 && sigmadsp->ops && | ||
121 | sigmadsp->ops->safeload) | ||
122 | return sigmadsp->ops->safeload(sigmadsp, ctrl->addr, data, | ||
123 | ctrl->num_bytes); | ||
124 | else | ||
125 | return sigmadsp_write(sigmadsp, ctrl->addr, data, | ||
126 | ctrl->num_bytes); | ||
127 | } | ||
128 | |||
129 | static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, | ||
130 | struct snd_ctl_elem_value *ucontrol) | ||
131 | { | ||
132 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | ||
133 | struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); | ||
134 | uint8_t *data; | ||
135 | int ret = 0; | ||
136 | |||
137 | mutex_lock(&sigmadsp->lock); | ||
138 | |||
139 | data = ucontrol->value.bytes.data; | ||
140 | |||
141 | if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) | ||
142 | ret = sigmadsp_ctrl_write(sigmadsp, ctrl, data); | ||
143 | |||
144 | if (ret == 0) { | ||
145 | memcpy(ctrl->cache, data, ctrl->num_bytes); | ||
146 | ctrl->cached = true; | ||
147 | } | ||
148 | |||
149 | mutex_unlock(&sigmadsp->lock); | ||
150 | |||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, | ||
155 | struct snd_ctl_elem_value *ucontrol) | ||
156 | { | ||
157 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | ||
158 | struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); | ||
159 | int ret = 0; | ||
160 | |||
161 | mutex_lock(&sigmadsp->lock); | ||
162 | |||
163 | if (!ctrl->cached) { | ||
164 | ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache, | ||
165 | ctrl->num_bytes); | ||
166 | } | ||
167 | |||
168 | if (ret == 0) { | ||
169 | ctrl->cached = true; | ||
170 | memcpy(ucontrol->value.bytes.data, ctrl->cache, | ||
171 | ctrl->num_bytes); | ||
172 | } | ||
173 | |||
174 | mutex_unlock(&sigmadsp->lock); | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static void sigmadsp_control_free(struct snd_kcontrol *kcontrol) | ||
180 | { | ||
181 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | ||
182 | |||
183 | ctrl->kcontrol = NULL; | ||
184 | } | ||
185 | |||
186 | static bool sigma_fw_validate_control_name(const char *name, unsigned int len) | ||
187 | { | ||
188 | unsigned int i; | ||
189 | |||
190 | for (i = 0; i < len; i++) { | ||
191 | /* Normal ASCII characters are valid */ | ||
192 | if (name[i] < ' ' || name[i] > '~') | ||
193 | return false; | ||
194 | } | ||
195 | |||
196 | return true; | ||
197 | } | ||
198 | |||
199 | static int sigma_fw_load_control(struct sigmadsp *sigmadsp, | ||
200 | const struct sigma_fw_chunk *chunk, unsigned int length) | ||
201 | { | ||
202 | const struct sigma_fw_chunk_control *ctrl_chunk; | ||
203 | struct sigmadsp_control *ctrl; | ||
204 | unsigned int num_bytes; | ||
205 | size_t name_len; | ||
206 | char *name; | ||
207 | int ret; | ||
208 | |||
209 | if (length <= sizeof(*ctrl_chunk)) | ||
210 | return -EINVAL; | ||
211 | |||
212 | ctrl_chunk = (const struct sigma_fw_chunk_control *)chunk; | ||
213 | |||
214 | name_len = length - sizeof(*ctrl_chunk); | ||
215 | if (name_len >= SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
216 | name_len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1; | ||
217 | |||
218 | /* Make sure there are no non-displayable characaters in the string */ | ||
219 | if (!sigma_fw_validate_control_name(ctrl_chunk->name, name_len)) | ||
220 | return -EINVAL; | ||
221 | |||
222 | num_bytes = le16_to_cpu(ctrl_chunk->num_bytes); | ||
223 | ctrl = kzalloc(sizeof(*ctrl) + num_bytes, GFP_KERNEL); | ||
224 | if (!ctrl) | ||
225 | return -ENOMEM; | ||
226 | |||
227 | name = kzalloc(name_len + 1, GFP_KERNEL); | ||
228 | if (!name) { | ||
229 | ret = -ENOMEM; | ||
230 | goto err_free_ctrl; | ||
231 | } | ||
232 | memcpy(name, ctrl_chunk->name, name_len); | ||
233 | name[name_len] = '\0'; | ||
234 | ctrl->name = name; | ||
235 | |||
236 | ctrl->addr = le16_to_cpu(ctrl_chunk->addr); | ||
237 | ctrl->num_bytes = num_bytes; | ||
238 | ctrl->samplerates = le32_to_cpu(chunk->samplerates); | ||
239 | |||
240 | list_add_tail(&ctrl->head, &sigmadsp->ctrl_list); | ||
241 | |||
242 | return 0; | ||
243 | |||
244 | err_free_ctrl: | ||
245 | kfree(ctrl); | ||
246 | |||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | static int sigma_fw_load_data(struct sigmadsp *sigmadsp, | ||
251 | const struct sigma_fw_chunk *chunk, unsigned int length) | ||
252 | { | ||
253 | const struct sigma_fw_chunk_data *data_chunk; | ||
254 | struct sigmadsp_data *data; | ||
255 | |||
256 | if (length <= sizeof(*data_chunk)) | ||
257 | return -EINVAL; | ||
258 | |||
259 | data_chunk = (struct sigma_fw_chunk_data *)chunk; | ||
260 | |||
261 | length -= sizeof(*data_chunk); | ||
262 | |||
263 | data = kzalloc(sizeof(*data) + length, GFP_KERNEL); | ||
264 | if (!data) | ||
265 | return -ENOMEM; | ||
266 | |||
267 | data->addr = le16_to_cpu(data_chunk->addr); | ||
268 | data->length = length; | ||
269 | data->samplerates = le32_to_cpu(chunk->samplerates); | ||
270 | memcpy(data->data, data_chunk->data, length); | ||
271 | list_add_tail(&data->head, &sigmadsp->data_list); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int sigma_fw_load_samplerates(struct sigmadsp *sigmadsp, | ||
277 | const struct sigma_fw_chunk *chunk, unsigned int length) | ||
278 | { | ||
279 | const struct sigma_fw_chunk_samplerate *rate_chunk; | ||
280 | unsigned int num_rates; | ||
281 | unsigned int *rates; | ||
282 | unsigned int i; | ||
283 | |||
284 | rate_chunk = (const struct sigma_fw_chunk_samplerate *)chunk; | ||
285 | |||
286 | num_rates = (length - sizeof(*rate_chunk)) / sizeof(__le32); | ||
287 | |||
288 | if (num_rates > 32 || num_rates == 0) | ||
289 | return -EINVAL; | ||
290 | |||
291 | /* We only allow one samplerates block per file */ | ||
292 | if (sigmadsp->rate_constraints.count) | ||
293 | return -EINVAL; | ||
294 | |||
295 | rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL); | ||
296 | if (!rates) | ||
297 | return -ENOMEM; | ||
298 | |||
299 | for (i = 0; i < num_rates; i++) | ||
300 | rates[i] = le32_to_cpu(rate_chunk->samplerates[i]); | ||
301 | |||
302 | sigmadsp->rate_constraints.count = num_rates; | ||
303 | sigmadsp->rate_constraints.list = rates; | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int sigmadsp_fw_load_v2(struct sigmadsp *sigmadsp, | ||
309 | const struct firmware *fw) | ||
310 | { | ||
311 | struct sigma_fw_chunk *chunk; | ||
312 | unsigned int length, pos; | ||
313 | int ret; | ||
314 | |||
315 | /* | ||
316 | * Make sure that there is at least one chunk to avoid integer | ||
317 | * underflows later on. Empty firmware is still valid though. | ||
318 | */ | ||
319 | if (fw->size < sizeof(*chunk) + sizeof(struct sigma_firmware_header)) | ||
320 | return 0; | ||
321 | |||
322 | pos = sizeof(struct sigma_firmware_header); | ||
323 | |||
324 | while (pos < fw->size - sizeof(*chunk)) { | ||
325 | chunk = (struct sigma_fw_chunk *)(fw->data + pos); | ||
326 | |||
327 | length = le32_to_cpu(chunk->length); | ||
328 | |||
329 | if (length > fw->size - pos || length < sizeof(*chunk)) | ||
330 | return -EINVAL; | ||
331 | |||
332 | switch (le32_to_cpu(chunk->tag)) { | ||
333 | case SIGMA_FW_CHUNK_TYPE_DATA: | ||
334 | ret = sigma_fw_load_data(sigmadsp, chunk, length); | ||
335 | break; | ||
336 | case SIGMA_FW_CHUNK_TYPE_CONTROL: | ||
337 | ret = sigma_fw_load_control(sigmadsp, chunk, length); | ||
338 | break; | ||
339 | case SIGMA_FW_CHUNK_TYPE_SAMPLERATES: | ||
340 | ret = sigma_fw_load_samplerates(sigmadsp, chunk, length); | ||
341 | break; | ||
342 | default: | ||
343 | dev_warn(sigmadsp->dev, "Unknown chunk type: %d\n", | ||
344 | chunk->tag); | ||
345 | ret = 0; | ||
346 | break; | ||
347 | } | ||
348 | |||
349 | if (ret) | ||
350 | return ret; | ||
351 | |||
352 | /* | ||
353 | * This can not overflow since if length is larger than the | ||
354 | * maximum firmware size (0x4000000) we'll error out earilier. | ||
355 | */ | ||
356 | pos += ALIGN(length, sizeof(__le32)); | ||
357 | } | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
37 | static inline u32 sigma_action_len(struct sigma_action *sa) | 362 | static inline u32 sigma_action_len(struct sigma_action *sa) |
38 | { | 363 | { |
39 | return (sa->len_hi << 16) | le16_to_cpu(sa->len); | 364 | return (sa->len_hi << 16) | le16_to_cpu(sa->len); |
@@ -62,11 +387,11 @@ static size_t sigma_action_size(struct sigma_action *sa) | |||
62 | * Returns a negative error value in case of an error, 0 if processing of | 387 | * Returns a negative error value in case of an error, 0 if processing of |
63 | * the firmware should be stopped after this action, 1 otherwise. | 388 | * the firmware should be stopped after this action, 1 otherwise. |
64 | */ | 389 | */ |
65 | static int | 390 | static int process_sigma_action(struct sigmadsp *sigmadsp, |
66 | process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) | 391 | struct sigma_action *sa) |
67 | { | 392 | { |
68 | size_t len = sigma_action_len(sa); | 393 | size_t len = sigma_action_len(sa); |
69 | int ret; | 394 | struct sigmadsp_data *data; |
70 | 395 | ||
71 | pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, | 396 | pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, |
72 | sa->instr, sa->addr, len); | 397 | sa->instr, sa->addr, len); |
@@ -75,13 +400,17 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) | |||
75 | case SIGMA_ACTION_WRITEXBYTES: | 400 | case SIGMA_ACTION_WRITEXBYTES: |
76 | case SIGMA_ACTION_WRITESINGLE: | 401 | case SIGMA_ACTION_WRITESINGLE: |
77 | case SIGMA_ACTION_WRITESAFELOAD: | 402 | case SIGMA_ACTION_WRITESAFELOAD: |
78 | ret = ssfw->write(ssfw->control_data, sa, len); | 403 | if (len < 3) |
79 | if (ret < 0) | ||
80 | return -EINVAL; | 404 | return -EINVAL; |
81 | break; | 405 | |
82 | case SIGMA_ACTION_DELAY: | 406 | data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL); |
83 | udelay(len); | 407 | if (!data) |
84 | len = 0; | 408 | return -ENOMEM; |
409 | |||
410 | data->addr = be16_to_cpu(sa->addr); | ||
411 | data->length = len - 2; | ||
412 | memcpy(data->data, sa->payload, data->length); | ||
413 | list_add_tail(&data->head, &sigmadsp->data_list); | ||
85 | break; | 414 | break; |
86 | case SIGMA_ACTION_END: | 415 | case SIGMA_ACTION_END: |
87 | return 0; | 416 | return 0; |
@@ -92,22 +421,24 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) | |||
92 | return 1; | 421 | return 1; |
93 | } | 422 | } |
94 | 423 | ||
95 | static int | 424 | static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp, |
96 | process_sigma_actions(struct sigma_firmware *ssfw) | 425 | const struct firmware *fw) |
97 | { | 426 | { |
98 | struct sigma_action *sa; | 427 | struct sigma_action *sa; |
99 | size_t size; | 428 | size_t size, pos; |
100 | int ret; | 429 | int ret; |
101 | 430 | ||
102 | while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) { | 431 | pos = sizeof(struct sigma_firmware_header); |
103 | sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos); | 432 | |
433 | while (pos + sizeof(*sa) <= fw->size) { | ||
434 | sa = (struct sigma_action *)(fw->data + pos); | ||
104 | 435 | ||
105 | size = sigma_action_size(sa); | 436 | size = sigma_action_size(sa); |
106 | ssfw->pos += size; | 437 | pos += size; |
107 | if (ssfw->pos > ssfw->fw->size || size == 0) | 438 | if (pos > fw->size || size == 0) |
108 | break; | 439 | break; |
109 | 440 | ||
110 | ret = process_sigma_action(ssfw, sa); | 441 | ret = process_sigma_action(sigmadsp, sa); |
111 | 442 | ||
112 | pr_debug("%s: action returned %i\n", __func__, ret); | 443 | pr_debug("%s: action returned %i\n", __func__, ret); |
113 | 444 | ||
@@ -115,29 +446,47 @@ process_sigma_actions(struct sigma_firmware *ssfw) | |||
115 | return ret; | 446 | return ret; |
116 | } | 447 | } |
117 | 448 | ||
118 | if (ssfw->pos != ssfw->fw->size) | 449 | if (pos != fw->size) |
119 | return -EINVAL; | 450 | return -EINVAL; |
120 | 451 | ||
121 | return 0; | 452 | return 0; |
122 | } | 453 | } |
123 | 454 | ||
124 | int _process_sigma_firmware(struct device *dev, | 455 | static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp) |
125 | struct sigma_firmware *ssfw, const char *name) | ||
126 | { | 456 | { |
127 | int ret; | 457 | struct sigmadsp_control *ctrl, *_ctrl; |
128 | struct sigma_firmware_header *ssfw_head; | 458 | struct sigmadsp_data *data, *_data; |
459 | |||
460 | list_for_each_entry_safe(ctrl, _ctrl, &sigmadsp->ctrl_list, head) { | ||
461 | kfree(ctrl->name); | ||
462 | kfree(ctrl); | ||
463 | } | ||
464 | |||
465 | list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head) | ||
466 | kfree(data); | ||
467 | |||
468 | INIT_LIST_HEAD(&sigmadsp->ctrl_list); | ||
469 | INIT_LIST_HEAD(&sigmadsp->data_list); | ||
470 | } | ||
471 | |||
472 | static void devm_sigmadsp_release(struct device *dev, void *res) | ||
473 | { | ||
474 | sigmadsp_firmware_release((struct sigmadsp *)res); | ||
475 | } | ||
476 | |||
477 | static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) | ||
478 | { | ||
479 | const struct sigma_firmware_header *ssfw_head; | ||
129 | const struct firmware *fw; | 480 | const struct firmware *fw; |
481 | int ret; | ||
130 | u32 crc; | 482 | u32 crc; |
131 | 483 | ||
132 | pr_debug("%s: loading firmware %s\n", __func__, name); | ||
133 | |||
134 | /* first load the blob */ | 484 | /* first load the blob */ |
135 | ret = request_firmware(&fw, name, dev); | 485 | ret = request_firmware(&fw, name, sigmadsp->dev); |
136 | if (ret) { | 486 | if (ret) { |
137 | pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); | 487 | pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); |
138 | return ret; | 488 | goto done; |
139 | } | 489 | } |
140 | ssfw->fw = fw; | ||
141 | 490 | ||
142 | /* then verify the header */ | 491 | /* then verify the header */ |
143 | ret = -EINVAL; | 492 | ret = -EINVAL; |
@@ -149,13 +498,13 @@ int _process_sigma_firmware(struct device *dev, | |||
149 | * overflows later in the loading process. | 498 | * overflows later in the loading process. |
150 | */ | 499 | */ |
151 | if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { | 500 | if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { |
152 | dev_err(dev, "Failed to load firmware: Invalid size\n"); | 501 | dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n"); |
153 | goto done; | 502 | goto done; |
154 | } | 503 | } |
155 | 504 | ||
156 | ssfw_head = (void *)fw->data; | 505 | ssfw_head = (void *)fw->data; |
157 | if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { | 506 | if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { |
158 | dev_err(dev, "Failed to load firmware: Invalid magic\n"); | 507 | dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n"); |
159 | goto done; | 508 | goto done; |
160 | } | 509 | } |
161 | 510 | ||
@@ -163,23 +512,303 @@ int _process_sigma_firmware(struct device *dev, | |||
163 | fw->size - sizeof(*ssfw_head)); | 512 | fw->size - sizeof(*ssfw_head)); |
164 | pr_debug("%s: crc=%x\n", __func__, crc); | 513 | pr_debug("%s: crc=%x\n", __func__, crc); |
165 | if (crc != le32_to_cpu(ssfw_head->crc)) { | 514 | if (crc != le32_to_cpu(ssfw_head->crc)) { |
166 | dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", | 515 | dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", |
167 | le32_to_cpu(ssfw_head->crc), crc); | 516 | le32_to_cpu(ssfw_head->crc), crc); |
168 | goto done; | 517 | goto done; |
169 | } | 518 | } |
170 | 519 | ||
171 | ssfw->pos = sizeof(*ssfw_head); | 520 | switch (ssfw_head->version) { |
521 | case 1: | ||
522 | ret = sigmadsp_fw_load_v1(sigmadsp, fw); | ||
523 | break; | ||
524 | case 2: | ||
525 | ret = sigmadsp_fw_load_v2(sigmadsp, fw); | ||
526 | break; | ||
527 | default: | ||
528 | dev_err(sigmadsp->dev, | ||
529 | "Failed to load firmware: Invalid version %d. Supported firmware versions: 1, 2\n", | ||
530 | ssfw_head->version); | ||
531 | ret = -EINVAL; | ||
532 | break; | ||
533 | } | ||
172 | 534 | ||
173 | /* finally process all of the actions */ | 535 | if (ret) |
174 | ret = process_sigma_actions(ssfw); | 536 | sigmadsp_firmware_release(sigmadsp); |
175 | 537 | ||
176 | done: | 538 | done: |
177 | release_firmware(fw); | 539 | release_firmware(fw); |
178 | 540 | ||
179 | pr_debug("%s: loaded %s\n", __func__, name); | 541 | return ret; |
542 | } | ||
543 | |||
544 | static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev, | ||
545 | const struct sigmadsp_ops *ops, const char *firmware_name) | ||
546 | { | ||
547 | sigmadsp->ops = ops; | ||
548 | sigmadsp->dev = dev; | ||
549 | |||
550 | INIT_LIST_HEAD(&sigmadsp->ctrl_list); | ||
551 | INIT_LIST_HEAD(&sigmadsp->data_list); | ||
552 | mutex_init(&sigmadsp->lock); | ||
553 | |||
554 | return sigmadsp_firmware_load(sigmadsp, firmware_name); | ||
555 | } | ||
556 | |||
557 | /** | ||
558 | * devm_sigmadsp_init() - Initialize SigmaDSP instance | ||
559 | * @dev: The parent device | ||
560 | * @ops: The sigmadsp_ops to use for this instance | ||
561 | * @firmware_name: Name of the firmware file to load | ||
562 | * | ||
563 | * Allocates a SigmaDSP instance and loads the specified firmware file. | ||
564 | * | ||
565 | * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. | ||
566 | */ | ||
567 | struct sigmadsp *devm_sigmadsp_init(struct device *dev, | ||
568 | const struct sigmadsp_ops *ops, const char *firmware_name) | ||
569 | { | ||
570 | struct sigmadsp *sigmadsp; | ||
571 | int ret; | ||
572 | |||
573 | sigmadsp = devres_alloc(devm_sigmadsp_release, sizeof(*sigmadsp), | ||
574 | GFP_KERNEL); | ||
575 | if (!sigmadsp) | ||
576 | return ERR_PTR(-ENOMEM); | ||
577 | |||
578 | ret = sigmadsp_init(sigmadsp, dev, ops, firmware_name); | ||
579 | if (ret) { | ||
580 | devres_free(sigmadsp); | ||
581 | return ERR_PTR(ret); | ||
582 | } | ||
583 | |||
584 | devres_add(dev, sigmadsp); | ||
585 | |||
586 | return sigmadsp; | ||
587 | } | ||
588 | EXPORT_SYMBOL_GPL(devm_sigmadsp_init); | ||
589 | |||
590 | static int sigmadsp_rate_to_index(struct sigmadsp *sigmadsp, unsigned int rate) | ||
591 | { | ||
592 | unsigned int i; | ||
593 | |||
594 | for (i = 0; i < sigmadsp->rate_constraints.count; i++) { | ||
595 | if (sigmadsp->rate_constraints.list[i] == rate) | ||
596 | return i; | ||
597 | } | ||
598 | |||
599 | return -EINVAL; | ||
600 | } | ||
601 | |||
602 | static unsigned int sigmadsp_get_samplerate_mask(struct sigmadsp *sigmadsp, | ||
603 | unsigned int samplerate) | ||
604 | { | ||
605 | int samplerate_index; | ||
606 | |||
607 | if (samplerate == 0) | ||
608 | return 0; | ||
609 | |||
610 | if (sigmadsp->rate_constraints.count) { | ||
611 | samplerate_index = sigmadsp_rate_to_index(sigmadsp, samplerate); | ||
612 | if (samplerate_index < 0) | ||
613 | return 0; | ||
614 | |||
615 | return BIT(samplerate_index); | ||
616 | } else { | ||
617 | return ~0; | ||
618 | } | ||
619 | } | ||
620 | |||
621 | static bool sigmadsp_samplerate_valid(unsigned int supported, | ||
622 | unsigned int requested) | ||
623 | { | ||
624 | /* All samplerates are supported */ | ||
625 | if (!supported) | ||
626 | return true; | ||
627 | |||
628 | return supported & requested; | ||
629 | } | ||
630 | |||
631 | static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp, | ||
632 | struct sigmadsp_control *ctrl, unsigned int samplerate_mask) | ||
633 | { | ||
634 | struct snd_kcontrol_new template; | ||
635 | struct snd_kcontrol *kcontrol; | ||
636 | |||
637 | memset(&template, 0, sizeof(template)); | ||
638 | template.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
639 | template.name = ctrl->name; | ||
640 | template.info = sigmadsp_ctrl_info; | ||
641 | template.get = sigmadsp_ctrl_get; | ||
642 | template.put = sigmadsp_ctrl_put; | ||
643 | template.private_value = (unsigned long)ctrl; | ||
644 | template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
645 | if (!sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask)) | ||
646 | template.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
647 | |||
648 | kcontrol = snd_ctl_new1(&template, sigmadsp); | ||
649 | if (!kcontrol) | ||
650 | return -ENOMEM; | ||
651 | |||
652 | kcontrol->private_free = sigmadsp_control_free; | ||
653 | ctrl->kcontrol = kcontrol; | ||
654 | |||
655 | return snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol); | ||
656 | } | ||
657 | |||
658 | static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, | ||
659 | struct sigmadsp_control *ctrl, unsigned int samplerate_mask) | ||
660 | { | ||
661 | struct snd_card *card = sigmadsp->component->card->snd_card; | ||
662 | struct snd_kcontrol_volatile *vd; | ||
663 | struct snd_ctl_elem_id id; | ||
664 | bool active; | ||
665 | bool changed = false; | ||
666 | |||
667 | active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask); | ||
668 | |||
669 | down_write(&card->controls_rwsem); | ||
670 | if (!ctrl->kcontrol) { | ||
671 | up_write(&card->controls_rwsem); | ||
672 | return; | ||
673 | } | ||
674 | |||
675 | id = ctrl->kcontrol->id; | ||
676 | vd = &ctrl->kcontrol->vd[0]; | ||
677 | if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) { | ||
678 | vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
679 | changed = true; | ||
680 | } | ||
681 | up_write(&card->controls_rwsem); | ||
682 | |||
683 | if (active && changed) { | ||
684 | mutex_lock(&sigmadsp->lock); | ||
685 | if (ctrl->cached) | ||
686 | sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); | ||
687 | mutex_unlock(&sigmadsp->lock); | ||
688 | } | ||
689 | |||
690 | if (changed) | ||
691 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id); | ||
692 | } | ||
693 | |||
694 | /** | ||
695 | * sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component | ||
696 | * @sigmadsp: The sigmadsp instance to attach | ||
697 | * @component: The component to attach to | ||
698 | * | ||
699 | * Typically called in the components probe callback. | ||
700 | * | ||
701 | * Note, once this function has been called the firmware must not be released | ||
702 | * until after the ALSA snd_card that the component belongs to has been | ||
703 | * disconnected, even if sigmadsp_attach() returns an error. | ||
704 | */ | ||
705 | int sigmadsp_attach(struct sigmadsp *sigmadsp, | ||
706 | struct snd_soc_component *component) | ||
707 | { | ||
708 | struct sigmadsp_control *ctrl; | ||
709 | unsigned int samplerate_mask; | ||
710 | int ret; | ||
711 | |||
712 | sigmadsp->component = component; | ||
713 | |||
714 | samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, | ||
715 | sigmadsp->current_samplerate); | ||
716 | |||
717 | list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) { | ||
718 | ret = sigmadsp_alloc_control(sigmadsp, ctrl, samplerate_mask); | ||
719 | if (ret) | ||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | EXPORT_SYMBOL_GPL(sigmadsp_attach); | ||
726 | |||
727 | /** | ||
728 | * sigmadsp_setup() - Setup the DSP for the specified samplerate | ||
729 | * @sigmadsp: The sigmadsp instance to configure | ||
730 | * @samplerate: The samplerate the DSP should be configured for | ||
731 | * | ||
732 | * Loads the appropriate firmware program and parameter memory (if not already | ||
733 | * loaded) and enables the controls for the specified samplerate. Any control | ||
734 | * parameter changes that have been made previously will be restored. | ||
735 | * | ||
736 | * Returns 0 on success, a negative error code otherwise. | ||
737 | */ | ||
738 | int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate) | ||
739 | { | ||
740 | struct sigmadsp_control *ctrl; | ||
741 | unsigned int samplerate_mask; | ||
742 | struct sigmadsp_data *data; | ||
743 | int ret; | ||
744 | |||
745 | if (sigmadsp->current_samplerate == samplerate) | ||
746 | return 0; | ||
747 | |||
748 | samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, samplerate); | ||
749 | if (samplerate_mask == 0) | ||
750 | return -EINVAL; | ||
751 | |||
752 | list_for_each_entry(data, &sigmadsp->data_list, head) { | ||
753 | if (!sigmadsp_samplerate_valid(data->samplerates, | ||
754 | samplerate_mask)) | ||
755 | continue; | ||
756 | ret = sigmadsp_write(sigmadsp, data->addr, data->data, | ||
757 | data->length); | ||
758 | if (ret) | ||
759 | goto err; | ||
760 | } | ||
761 | |||
762 | list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) | ||
763 | sigmadsp_activate_ctrl(sigmadsp, ctrl, samplerate_mask); | ||
764 | |||
765 | sigmadsp->current_samplerate = samplerate; | ||
766 | |||
767 | return 0; | ||
768 | err: | ||
769 | sigmadsp_reset(sigmadsp); | ||
180 | 770 | ||
181 | return ret; | 771 | return ret; |
182 | } | 772 | } |
183 | EXPORT_SYMBOL_GPL(_process_sigma_firmware); | 773 | EXPORT_SYMBOL_GPL(sigmadsp_setup); |
774 | |||
775 | /** | ||
776 | * sigmadsp_reset() - Notify the sigmadsp instance that the DSP has been reset | ||
777 | * @sigmadsp: The sigmadsp instance to reset | ||
778 | * | ||
779 | * Should be called whenever the DSP has been reset and parameter and program | ||
780 | * memory need to be re-loaded. | ||
781 | */ | ||
782 | void sigmadsp_reset(struct sigmadsp *sigmadsp) | ||
783 | { | ||
784 | struct sigmadsp_control *ctrl; | ||
785 | |||
786 | list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) | ||
787 | sigmadsp_activate_ctrl(sigmadsp, ctrl, false); | ||
788 | |||
789 | sigmadsp->current_samplerate = 0; | ||
790 | } | ||
791 | EXPORT_SYMBOL_GPL(sigmadsp_reset); | ||
792 | |||
793 | /** | ||
794 | * sigmadsp_restrict_params() - Applies DSP firmware specific constraints | ||
795 | * @sigmadsp: The sigmadsp instance | ||
796 | * @substream: The substream to restrict | ||
797 | * | ||
798 | * Applies samplerate constraints that may be required by the firmware Should | ||
799 | * typically be called from the CODEC/component drivers startup callback. | ||
800 | * | ||
801 | * Returns 0 on success, a negative error code otherwise. | ||
802 | */ | ||
803 | int sigmadsp_restrict_params(struct sigmadsp *sigmadsp, | ||
804 | struct snd_pcm_substream *substream) | ||
805 | { | ||
806 | if (sigmadsp->rate_constraints.count == 0) | ||
807 | return 0; | ||
808 | |||
809 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
810 | SNDRV_PCM_HW_PARAM_RATE, &sigmadsp->rate_constraints); | ||
811 | } | ||
812 | EXPORT_SYMBOL_GPL(sigmadsp_restrict_params); | ||
184 | 813 | ||
185 | MODULE_LICENSE("GPL"); | 814 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h index c47cd23e9827..614475cbb823 100644 --- a/sound/soc/codecs/sigmadsp.h +++ b/sound/soc/codecs/sigmadsp.h | |||
@@ -11,31 +11,56 @@ | |||
11 | 11 | ||
12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
13 | #include <linux/regmap.h> | 13 | #include <linux/regmap.h> |
14 | #include <linux/list.h> | ||
14 | 15 | ||
15 | struct sigma_action { | 16 | #include <sound/pcm.h> |
16 | u8 instr; | ||
17 | u8 len_hi; | ||
18 | __le16 len; | ||
19 | __be16 addr; | ||
20 | unsigned char payload[]; | ||
21 | } __packed; | ||
22 | 17 | ||
23 | struct sigma_firmware { | 18 | struct sigmadsp; |
24 | const struct firmware *fw; | 19 | struct snd_soc_component; |
25 | size_t pos; | 20 | struct snd_pcm_substream; |
21 | |||
22 | struct sigmadsp_ops { | ||
23 | int (*safeload)(struct sigmadsp *sigmadsp, unsigned int addr, | ||
24 | const uint8_t *data, size_t len); | ||
25 | }; | ||
26 | |||
27 | struct sigmadsp { | ||
28 | const struct sigmadsp_ops *ops; | ||
29 | |||
30 | struct list_head ctrl_list; | ||
31 | struct list_head data_list; | ||
32 | |||
33 | struct snd_pcm_hw_constraint_list rate_constraints; | ||
34 | |||
35 | unsigned int current_samplerate; | ||
36 | struct snd_soc_component *component; | ||
37 | struct device *dev; | ||
38 | |||
39 | struct mutex lock; | ||
26 | 40 | ||
27 | void *control_data; | 41 | void *control_data; |
28 | int (*write)(void *control_data, const struct sigma_action *sa, | 42 | int (*write)(void *, unsigned int, const uint8_t *, size_t); |
29 | size_t len); | 43 | int (*read)(void *, unsigned int, uint8_t *, size_t); |
30 | }; | 44 | }; |
31 | 45 | ||
32 | int _process_sigma_firmware(struct device *dev, | 46 | struct sigmadsp *devm_sigmadsp_init(struct device *dev, |
33 | struct sigma_firmware *ssfw, const char *name); | 47 | const struct sigmadsp_ops *ops, const char *firmware_name); |
48 | void sigmadsp_reset(struct sigmadsp *sigmadsp); | ||
49 | |||
50 | int sigmadsp_restrict_params(struct sigmadsp *sigmadsp, | ||
51 | struct snd_pcm_substream *substream); | ||
34 | 52 | ||
35 | struct i2c_client; | 53 | struct i2c_client; |
36 | 54 | ||
37 | extern int process_sigma_firmware(struct i2c_client *client, const char *name); | 55 | struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev, |
38 | extern int process_sigma_firmware_regmap(struct device *dev, | 56 | struct regmap *regmap, const struct sigmadsp_ops *ops, |
39 | struct regmap *regmap, const char *name); | 57 | const char *firmware_name); |
58 | struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client, | ||
59 | const struct sigmadsp_ops *ops, const char *firmware_name); | ||
60 | |||
61 | int sigmadsp_attach(struct sigmadsp *sigmadsp, | ||
62 | struct snd_soc_component *component); | ||
63 | int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate); | ||
64 | void sigmadsp_reset(struct sigmadsp *sigmadsp); | ||
40 | 65 | ||
41 | #endif | 66 | #endif |
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 06ba4923fd5a..07eea20e6645 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c | |||
@@ -120,7 +120,8 @@ static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, | |||
120 | { | 120 | { |
121 | #define ATLAS6_CODEC_ENABLE_BITS (1 << 29) | 121 | #define ATLAS6_CODEC_ENABLE_BITS (1 << 29) |
122 | #define ATLAS6_CODEC_RESET_BITS (1 << 28) | 122 | #define ATLAS6_CODEC_RESET_BITS (1 << 28) |
123 | struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); | 123 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
124 | struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); | ||
124 | switch (event) { | 125 | switch (event) { |
125 | case SND_SOC_DAPM_PRE_PMU: | 126 | case SND_SOC_DAPM_PRE_PMU: |
126 | enable_and_reset_codec(sirf_audio_codec->regmap, | 127 | enable_and_reset_codec(sirf_audio_codec->regmap, |
@@ -142,7 +143,8 @@ static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, | |||
142 | { | 143 | { |
143 | #define PRIMA2_CODEC_ENABLE_BITS (1 << 27) | 144 | #define PRIMA2_CODEC_ENABLE_BITS (1 << 27) |
144 | #define PRIMA2_CODEC_RESET_BITS (1 << 26) | 145 | #define PRIMA2_CODEC_RESET_BITS (1 << 26) |
145 | struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); | 146 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
147 | struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); | ||
146 | switch (event) { | 148 | switch (event) { |
147 | case SND_SOC_DAPM_POST_PMU: | 149 | case SND_SOC_DAPM_POST_PMU: |
148 | enable_and_reset_codec(sirf_audio_codec->regmap, | 150 | enable_and_reset_codec(sirf_audio_codec->regmap, |
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index cf8fa40662f0..31d97cd5e59b 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c | |||
@@ -867,25 +867,16 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) | |||
867 | snd_soc_write(codec, SN95031_SSR2, 0x10); | 867 | snd_soc_write(codec, SN95031_SSR2, 0x10); |
868 | snd_soc_write(codec, SN95031_SSR3, 0x40); | 868 | snd_soc_write(codec, SN95031_SSR3, 0x40); |
869 | 869 | ||
870 | snd_soc_add_codec_controls(codec, sn95031_snd_controls, | ||
871 | ARRAY_SIZE(sn95031_snd_controls)); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int sn95031_codec_remove(struct snd_soc_codec *codec) | ||
877 | { | ||
878 | pr_debug("codec_remove called\n"); | ||
879 | sn95031_set_vaud_bias(codec, SND_SOC_BIAS_OFF); | ||
880 | |||
881 | return 0; | 870 | return 0; |
882 | } | 871 | } |
883 | 872 | ||
884 | static struct snd_soc_codec_driver sn95031_codec = { | 873 | static struct snd_soc_codec_driver sn95031_codec = { |
885 | .probe = sn95031_codec_probe, | 874 | .probe = sn95031_codec_probe, |
886 | .remove = sn95031_codec_remove, | ||
887 | .set_bias_level = sn95031_set_vaud_bias, | 875 | .set_bias_level = sn95031_set_vaud_bias, |
888 | .idle_bias_off = true, | 876 | .idle_bias_off = true, |
877 | |||
878 | .controls = sn95031_snd_controls, | ||
879 | .num_controls = ARRAY_SIZE(sn95031_snd_controls), | ||
889 | .dapm_widgets = sn95031_dapm_widgets, | 880 | .dapm_widgets = sn95031_dapm_widgets, |
890 | .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), | 881 | .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), |
891 | .dapm_routes = sn95031_audio_map, | 882 | .dapm_routes = sn95031_audio_map, |
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 4b5c17f8507e..a984485108cd 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c | |||
@@ -69,6 +69,22 @@ | |||
69 | #define SSM4567_DAC_FS_64000_96000 0x3 | 69 | #define SSM4567_DAC_FS_64000_96000 0x3 |
70 | #define SSM4567_DAC_FS_128000_192000 0x4 | 70 | #define SSM4567_DAC_FS_128000_192000 0x4 |
71 | 71 | ||
72 | /* SAI_CTRL_1 */ | ||
73 | #define SSM4567_SAI_CTRL_1_BCLK BIT(6) | ||
74 | #define SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK (0x3 << 4) | ||
75 | #define SSM4567_SAI_CTRL_1_TDM_BLCKS_32 (0x0 << 4) | ||
76 | #define SSM4567_SAI_CTRL_1_TDM_BLCKS_48 (0x1 << 4) | ||
77 | #define SSM4567_SAI_CTRL_1_TDM_BLCKS_64 (0x2 << 4) | ||
78 | #define SSM4567_SAI_CTRL_1_FSYNC BIT(3) | ||
79 | #define SSM4567_SAI_CTRL_1_LJ BIT(2) | ||
80 | #define SSM4567_SAI_CTRL_1_TDM BIT(1) | ||
81 | #define SSM4567_SAI_CTRL_1_PDM BIT(0) | ||
82 | |||
83 | /* SAI_CTRL_2 */ | ||
84 | #define SSM4567_SAI_CTRL_2_AUTO_SLOT BIT(3) | ||
85 | #define SSM4567_SAI_CTRL_2_TDM_SLOT_MASK 0x7 | ||
86 | #define SSM4567_SAI_CTRL_2_TDM_SLOT(x) (x) | ||
87 | |||
72 | struct ssm4567 { | 88 | struct ssm4567 { |
73 | struct regmap *regmap; | 89 | struct regmap *regmap; |
74 | }; | 90 | }; |
@@ -145,15 +161,24 @@ static const struct snd_kcontrol_new ssm4567_snd_controls[] = { | |||
145 | SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0, | 161 | SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0, |
146 | 0xff, 1, ssm4567_vol_tlv), | 162 | 0xff, 1, ssm4567_vol_tlv), |
147 | SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0), | 163 | SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0), |
164 | SOC_SINGLE("DAC High Pass Filter Switch", SSM4567_REG_DAC_CTRL, | ||
165 | 5, 1, 0), | ||
148 | }; | 166 | }; |
149 | 167 | ||
168 | static const struct snd_kcontrol_new ssm4567_amplifier_boost_control = | ||
169 | SOC_DAPM_SINGLE("Switch", SSM4567_REG_POWER_CTRL, 1, 1, 1); | ||
170 | |||
150 | static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { | 171 | static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { |
151 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1), | 172 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1), |
173 | SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1, | ||
174 | &ssm4567_amplifier_boost_control), | ||
152 | 175 | ||
153 | SND_SOC_DAPM_OUTPUT("OUT"), | 176 | SND_SOC_DAPM_OUTPUT("OUT"), |
154 | }; | 177 | }; |
155 | 178 | ||
156 | static const struct snd_soc_dapm_route ssm4567_routes[] = { | 179 | static const struct snd_soc_dapm_route ssm4567_routes[] = { |
180 | { "OUT", NULL, "Amplifier Boost" }, | ||
181 | { "Amplifier Boost", "Switch", "DAC" }, | ||
157 | { "OUT", NULL, "DAC" }, | 182 | { "OUT", NULL, "DAC" }, |
158 | }; | 183 | }; |
159 | 184 | ||
@@ -192,6 +217,107 @@ static int ssm4567_mute(struct snd_soc_dai *dai, int mute) | |||
192 | SSM4567_DAC_MUTE, val); | 217 | SSM4567_DAC_MUTE, val); |
193 | } | 218 | } |
194 | 219 | ||
220 | static int ssm4567_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
221 | unsigned int rx_mask, int slots, int width) | ||
222 | { | ||
223 | struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai); | ||
224 | unsigned int blcks; | ||
225 | int slot; | ||
226 | int ret; | ||
227 | |||
228 | if (tx_mask == 0) | ||
229 | return -EINVAL; | ||
230 | |||
231 | if (rx_mask && rx_mask != tx_mask) | ||
232 | return -EINVAL; | ||
233 | |||
234 | slot = __ffs(tx_mask); | ||
235 | if (tx_mask != BIT(slot)) | ||
236 | return -EINVAL; | ||
237 | |||
238 | switch (width) { | ||
239 | case 32: | ||
240 | blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_32; | ||
241 | break; | ||
242 | case 48: | ||
243 | blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_48; | ||
244 | break; | ||
245 | case 64: | ||
246 | blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_64; | ||
247 | break; | ||
248 | default: | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | |||
252 | ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_2, | ||
253 | SSM4567_SAI_CTRL_2_AUTO_SLOT | SSM4567_SAI_CTRL_2_TDM_SLOT_MASK, | ||
254 | SSM4567_SAI_CTRL_2_TDM_SLOT(slot)); | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
258 | return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, | ||
259 | SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK, blcks); | ||
260 | } | ||
261 | |||
262 | static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
263 | { | ||
264 | struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai); | ||
265 | unsigned int ctrl1 = 0; | ||
266 | bool invert_fclk; | ||
267 | |||
268 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
269 | case SND_SOC_DAIFMT_CBS_CFS: | ||
270 | break; | ||
271 | default: | ||
272 | return -EINVAL; | ||
273 | } | ||
274 | |||
275 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
276 | case SND_SOC_DAIFMT_NB_NF: | ||
277 | invert_fclk = false; | ||
278 | break; | ||
279 | case SND_SOC_DAIFMT_IB_NF: | ||
280 | ctrl1 |= SSM4567_SAI_CTRL_1_BCLK; | ||
281 | invert_fclk = false; | ||
282 | break; | ||
283 | case SND_SOC_DAIFMT_NB_IF: | ||
284 | ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC; | ||
285 | invert_fclk = true; | ||
286 | break; | ||
287 | case SND_SOC_DAIFMT_IB_IF: | ||
288 | ctrl1 |= SSM4567_SAI_CTRL_1_BCLK; | ||
289 | invert_fclk = true; | ||
290 | break; | ||
291 | default: | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | |||
295 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
296 | case SND_SOC_DAIFMT_I2S: | ||
297 | break; | ||
298 | case SND_SOC_DAIFMT_LEFT_J: | ||
299 | ctrl1 |= SSM4567_SAI_CTRL_1_LJ; | ||
300 | invert_fclk = !invert_fclk; | ||
301 | break; | ||
302 | case SND_SOC_DAIFMT_DSP_A: | ||
303 | ctrl1 |= SSM4567_SAI_CTRL_1_TDM; | ||
304 | break; | ||
305 | case SND_SOC_DAIFMT_DSP_B: | ||
306 | ctrl1 |= SSM4567_SAI_CTRL_1_TDM | SSM4567_SAI_CTRL_1_LJ; | ||
307 | break; | ||
308 | case SND_SOC_DAIFMT_PDM: | ||
309 | ctrl1 |= SSM4567_SAI_CTRL_1_PDM; | ||
310 | break; | ||
311 | default: | ||
312 | return -EINVAL; | ||
313 | } | ||
314 | |||
315 | if (invert_fclk) | ||
316 | ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC; | ||
317 | |||
318 | return regmap_write(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, ctrl1); | ||
319 | } | ||
320 | |||
195 | static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) | 321 | static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) |
196 | { | 322 | { |
197 | int ret = 0; | 323 | int ret = 0; |
@@ -246,6 +372,8 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec, | |||
246 | static const struct snd_soc_dai_ops ssm4567_dai_ops = { | 372 | static const struct snd_soc_dai_ops ssm4567_dai_ops = { |
247 | .hw_params = ssm4567_hw_params, | 373 | .hw_params = ssm4567_hw_params, |
248 | .digital_mute = ssm4567_mute, | 374 | .digital_mute = ssm4567_mute, |
375 | .set_fmt = ssm4567_set_dai_fmt, | ||
376 | .set_tdm_slot = ssm4567_set_tdm_slot, | ||
249 | }; | 377 | }; |
250 | 378 | ||
251 | static struct snd_soc_dai_driver ssm4567_dai = { | 379 | static struct snd_soc_dai_driver ssm4567_dai = { |
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 48740855566d..7e18200dd6a9 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c | |||
@@ -833,23 +833,6 @@ static struct snd_soc_dai_driver sta32x_dai = { | |||
833 | .ops = &sta32x_dai_ops, | 833 | .ops = &sta32x_dai_ops, |
834 | }; | 834 | }; |
835 | 835 | ||
836 | #ifdef CONFIG_PM | ||
837 | static int sta32x_suspend(struct snd_soc_codec *codec) | ||
838 | { | ||
839 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | static int sta32x_resume(struct snd_soc_codec *codec) | ||
844 | { | ||
845 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
846 | return 0; | ||
847 | } | ||
848 | #else | ||
849 | #define sta32x_suspend NULL | ||
850 | #define sta32x_resume NULL | ||
851 | #endif | ||
852 | |||
853 | static int sta32x_probe(struct snd_soc_codec *codec) | 836 | static int sta32x_probe(struct snd_soc_codec *codec) |
854 | { | 837 | { |
855 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | 838 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); |
@@ -936,7 +919,6 @@ static int sta32x_remove(struct snd_soc_codec *codec) | |||
936 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | 919 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); |
937 | 920 | ||
938 | sta32x_watchdog_stop(sta32x); | 921 | sta32x_watchdog_stop(sta32x); |
939 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
940 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | 922 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); |
941 | 923 | ||
942 | return 0; | 924 | return 0; |
@@ -955,9 +937,8 @@ static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg) | |||
955 | static const struct snd_soc_codec_driver sta32x_codec = { | 937 | static const struct snd_soc_codec_driver sta32x_codec = { |
956 | .probe = sta32x_probe, | 938 | .probe = sta32x_probe, |
957 | .remove = sta32x_remove, | 939 | .remove = sta32x_remove, |
958 | .suspend = sta32x_suspend, | ||
959 | .resume = sta32x_resume, | ||
960 | .set_bias_level = sta32x_set_bias_level, | 940 | .set_bias_level = sta32x_set_bias_level, |
941 | .suspend_bias_off = true, | ||
961 | .controls = sta32x_snd_controls, | 942 | .controls = sta32x_snd_controls, |
962 | .num_controls = ARRAY_SIZE(sta32x_snd_controls), | 943 | .num_controls = ARRAY_SIZE(sta32x_snd_controls), |
963 | .dapm_widgets = sta32x_dapm_widgets, | 944 | .dapm_widgets = sta32x_dapm_widgets, |
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index cc97dd52aa9c..bda2ee18769e 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c | |||
@@ -912,23 +912,6 @@ static struct snd_soc_dai_driver sta350_dai = { | |||
912 | .ops = &sta350_dai_ops, | 912 | .ops = &sta350_dai_ops, |
913 | }; | 913 | }; |
914 | 914 | ||
915 | #ifdef CONFIG_PM | ||
916 | static int sta350_suspend(struct snd_soc_codec *codec) | ||
917 | { | ||
918 | sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static int sta350_resume(struct snd_soc_codec *codec) | ||
923 | { | ||
924 | sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
925 | return 0; | ||
926 | } | ||
927 | #else | ||
928 | #define sta350_suspend NULL | ||
929 | #define sta350_resume NULL | ||
930 | #endif | ||
931 | |||
932 | static int sta350_probe(struct snd_soc_codec *codec) | 915 | static int sta350_probe(struct snd_soc_codec *codec) |
933 | { | 916 | { |
934 | struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); | 917 | struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); |
@@ -1065,7 +1048,6 @@ static int sta350_remove(struct snd_soc_codec *codec) | |||
1065 | { | 1048 | { |
1066 | struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); | 1049 | struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); |
1067 | 1050 | ||
1068 | sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1069 | regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); | 1051 | regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); |
1070 | 1052 | ||
1071 | return 0; | 1053 | return 0; |
@@ -1074,9 +1056,8 @@ static int sta350_remove(struct snd_soc_codec *codec) | |||
1074 | static const struct snd_soc_codec_driver sta350_codec = { | 1056 | static const struct snd_soc_codec_driver sta350_codec = { |
1075 | .probe = sta350_probe, | 1057 | .probe = sta350_probe, |
1076 | .remove = sta350_remove, | 1058 | .remove = sta350_remove, |
1077 | .suspend = sta350_suspend, | ||
1078 | .resume = sta350_resume, | ||
1079 | .set_bias_level = sta350_set_bias_level, | 1059 | .set_bias_level = sta350_set_bias_level, |
1060 | .suspend_bias_off = true, | ||
1080 | .controls = sta350_snd_controls, | 1061 | .controls = sta350_snd_controls, |
1081 | .num_controls = ARRAY_SIZE(sta350_snd_controls), | 1062 | .num_controls = ARRAY_SIZE(sta350_snd_controls), |
1082 | .dapm_widgets = sta350_dapm_widgets, | 1063 | .dapm_widgets = sta350_dapm_widgets, |
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 89c748dd3d6e..b0f436d10125 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c | |||
@@ -319,41 +319,10 @@ static struct snd_soc_dai_driver sta529_dai = { | |||
319 | .ops = &sta529_dai_ops, | 319 | .ops = &sta529_dai_ops, |
320 | }; | 320 | }; |
321 | 321 | ||
322 | static int sta529_probe(struct snd_soc_codec *codec) | ||
323 | { | ||
324 | sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /* power down chip */ | ||
330 | static int sta529_remove(struct snd_soc_codec *codec) | ||
331 | { | ||
332 | sta529_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int sta529_suspend(struct snd_soc_codec *codec) | ||
338 | { | ||
339 | sta529_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int sta529_resume(struct snd_soc_codec *codec) | ||
345 | { | ||
346 | sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static const struct snd_soc_codec_driver sta529_codec_driver = { | 322 | static const struct snd_soc_codec_driver sta529_codec_driver = { |
352 | .probe = sta529_probe, | ||
353 | .remove = sta529_remove, | ||
354 | .set_bias_level = sta529_set_bias_level, | 323 | .set_bias_level = sta529_set_bias_level, |
355 | .suspend = sta529_suspend, | 324 | .suspend_bias_off = true, |
356 | .resume = sta529_resume, | 325 | |
357 | .controls = sta529_snd_controls, | 326 | .controls = sta529_snd_controls, |
358 | .num_controls = ARRAY_SIZE(sta529_snd_controls), | 327 | .num_controls = ARRAY_SIZE(sta529_snd_controls), |
359 | }; | 328 | }; |
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 53b810d23fea..dbff0c89be48 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c | |||
@@ -139,18 +139,19 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { | |||
139 | static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 139 | static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
140 | unsigned int val) | 140 | unsigned int val) |
141 | { | 141 | { |
142 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
142 | u16 *cache = codec->reg_cache; | 143 | u16 *cache = codec->reg_cache; |
143 | 144 | ||
144 | if (reg > AC97_STAC_PAGE0) { | 145 | if (reg > AC97_STAC_PAGE0) { |
145 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); | 146 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); |
146 | soc_ac97_ops->write(codec->ac97, reg, val); | 147 | soc_ac97_ops->write(ac97, reg, val); |
147 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); | 148 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); |
148 | return 0; | 149 | return 0; |
149 | } | 150 | } |
150 | if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) | 151 | if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) |
151 | return -EIO; | 152 | return -EIO; |
152 | 153 | ||
153 | soc_ac97_ops->write(codec->ac97, reg, val); | 154 | soc_ac97_ops->write(ac97, reg, val); |
154 | cache[reg / 2] = val; | 155 | cache[reg / 2] = val; |
155 | return 0; | 156 | return 0; |
156 | } | 157 | } |
@@ -158,11 +159,12 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
158 | static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, | 159 | static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, |
159 | unsigned int reg) | 160 | unsigned int reg) |
160 | { | 161 | { |
162 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
161 | u16 val = 0, *cache = codec->reg_cache; | 163 | u16 val = 0, *cache = codec->reg_cache; |
162 | 164 | ||
163 | if (reg > AC97_STAC_PAGE0) { | 165 | if (reg > AC97_STAC_PAGE0) { |
164 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); | 166 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); |
165 | val = soc_ac97_ops->read(codec->ac97, reg - AC97_STAC_PAGE0); | 167 | val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0); |
166 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); | 168 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); |
167 | return val; | 169 | return val; |
168 | } | 170 | } |
@@ -173,7 +175,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, | |||
173 | reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || | 175 | reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || |
174 | reg == AC97_VENDOR_ID2) { | 176 | reg == AC97_VENDOR_ID2) { |
175 | 177 | ||
176 | val = soc_ac97_ops->read(codec->ac97, reg); | 178 | val = soc_ac97_ops->read(ac97, reg); |
177 | return val; | 179 | return val; |
178 | } | 180 | } |
179 | return cache[reg / 2]; | 181 | return cache[reg / 2]; |
@@ -240,45 +242,41 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, | |||
240 | 242 | ||
241 | static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) | 243 | static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) |
242 | { | 244 | { |
245 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
246 | |||
243 | if (try_warm && soc_ac97_ops->warm_reset) { | 247 | if (try_warm && soc_ac97_ops->warm_reset) { |
244 | soc_ac97_ops->warm_reset(codec->ac97); | 248 | soc_ac97_ops->warm_reset(ac97); |
245 | if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) | 249 | if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) |
246 | return 1; | 250 | return 1; |
247 | } | 251 | } |
248 | 252 | ||
249 | soc_ac97_ops->reset(codec->ac97); | 253 | soc_ac97_ops->reset(ac97); |
250 | if (soc_ac97_ops->warm_reset) | 254 | if (soc_ac97_ops->warm_reset) |
251 | soc_ac97_ops->warm_reset(codec->ac97); | 255 | soc_ac97_ops->warm_reset(ac97); |
252 | if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) | 256 | if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) |
253 | return -EIO; | 257 | return -EIO; |
254 | return 0; | 258 | return 0; |
255 | } | 259 | } |
256 | 260 | ||
257 | static int stac9766_codec_suspend(struct snd_soc_codec *codec) | ||
258 | { | ||
259 | stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int stac9766_codec_resume(struct snd_soc_codec *codec) | 261 | static int stac9766_codec_resume(struct snd_soc_codec *codec) |
264 | { | 262 | { |
263 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
265 | u16 id, reset; | 264 | u16 id, reset; |
266 | 265 | ||
267 | reset = 0; | 266 | reset = 0; |
268 | /* give the codec an AC97 warm reset to start the link */ | 267 | /* give the codec an AC97 warm reset to start the link */ |
269 | reset: | 268 | reset: |
270 | if (reset > 5) { | 269 | if (reset > 5) { |
271 | printk(KERN_ERR "stac9766 failed to resume"); | 270 | dev_err(codec->dev, "Failed to resume\n"); |
272 | return -EIO; | 271 | return -EIO; |
273 | } | 272 | } |
274 | codec->ac97->bus->ops->warm_reset(codec->ac97); | 273 | ac97->bus->ops->warm_reset(ac97); |
275 | id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2); | 274 | id = soc_ac97_ops->read(ac97, AC97_VENDOR_ID2); |
276 | if (id != 0x4c13) { | 275 | if (id != 0x4c13) { |
277 | stac9766_reset(codec, 0); | 276 | stac9766_reset(codec, 0); |
278 | reset++; | 277 | reset++; |
279 | goto reset; | 278 | goto reset; |
280 | } | 279 | } |
281 | stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
282 | 280 | ||
283 | return 0; | 281 | return 0; |
284 | } | 282 | } |
@@ -294,7 +292,6 @@ static const struct snd_soc_dai_ops stac9766_dai_ops_digital = { | |||
294 | static struct snd_soc_dai_driver stac9766_dai[] = { | 292 | static struct snd_soc_dai_driver stac9766_dai[] = { |
295 | { | 293 | { |
296 | .name = "stac9766-hifi-analog", | 294 | .name = "stac9766-hifi-analog", |
297 | .ac97_control = 1, | ||
298 | 295 | ||
299 | /* stream cababilities */ | 296 | /* stream cababilities */ |
300 | .playback = { | 297 | .playback = { |
@@ -316,7 +313,6 @@ static struct snd_soc_dai_driver stac9766_dai[] = { | |||
316 | }, | 313 | }, |
317 | { | 314 | { |
318 | .name = "stac9766-hifi-IEC958", | 315 | .name = "stac9766-hifi-IEC958", |
319 | .ac97_control = 1, | ||
320 | 316 | ||
321 | /* stream cababilities */ | 317 | /* stream cababilities */ |
322 | .playback = { | 318 | .playback = { |
@@ -334,46 +330,48 @@ static struct snd_soc_dai_driver stac9766_dai[] = { | |||
334 | 330 | ||
335 | static int stac9766_codec_probe(struct snd_soc_codec *codec) | 331 | static int stac9766_codec_probe(struct snd_soc_codec *codec) |
336 | { | 332 | { |
333 | struct snd_ac97 *ac97; | ||
337 | int ret = 0; | 334 | int ret = 0; |
338 | 335 | ||
339 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | 336 | ac97 = snd_soc_new_ac97_codec(codec); |
340 | if (ret < 0) | 337 | if (IS_ERR(ac97)) |
341 | goto codec_err; | 338 | return PTR_ERR(ac97); |
339 | |||
340 | snd_soc_codec_set_drvdata(codec, ac97); | ||
342 | 341 | ||
343 | /* do a cold reset for the controller and then try | 342 | /* do a cold reset for the controller and then try |
344 | * a warm reset followed by an optional cold reset for codec */ | 343 | * a warm reset followed by an optional cold reset for codec */ |
345 | stac9766_reset(codec, 0); | 344 | stac9766_reset(codec, 0); |
346 | ret = stac9766_reset(codec, 1); | 345 | ret = stac9766_reset(codec, 1); |
347 | if (ret < 0) { | 346 | if (ret < 0) { |
348 | printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n"); | 347 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); |
349 | goto codec_err; | 348 | goto codec_err; |
350 | } | 349 | } |
351 | 350 | ||
352 | stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
353 | |||
354 | snd_soc_add_codec_controls(codec, stac9766_snd_ac97_controls, | ||
355 | ARRAY_SIZE(stac9766_snd_ac97_controls)); | ||
356 | |||
357 | return 0; | 351 | return 0; |
358 | 352 | ||
359 | codec_err: | 353 | codec_err: |
360 | snd_soc_free_ac97_codec(codec); | 354 | snd_soc_free_ac97_codec(ac97); |
361 | return ret; | 355 | return ret; |
362 | } | 356 | } |
363 | 357 | ||
364 | static int stac9766_codec_remove(struct snd_soc_codec *codec) | 358 | static int stac9766_codec_remove(struct snd_soc_codec *codec) |
365 | { | 359 | { |
366 | snd_soc_free_ac97_codec(codec); | 360 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
361 | |||
362 | snd_soc_free_ac97_codec(ac97); | ||
367 | return 0; | 363 | return 0; |
368 | } | 364 | } |
369 | 365 | ||
370 | static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { | 366 | static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { |
367 | .controls = stac9766_snd_ac97_controls, | ||
368 | .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), | ||
371 | .write = stac9766_ac97_write, | 369 | .write = stac9766_ac97_write, |
372 | .read = stac9766_ac97_read, | 370 | .read = stac9766_ac97_read, |
373 | .set_bias_level = stac9766_set_bias_level, | 371 | .set_bias_level = stac9766_set_bias_level, |
372 | .suspend_bias_off = true, | ||
374 | .probe = stac9766_codec_probe, | 373 | .probe = stac9766_codec_probe, |
375 | .remove = stac9766_codec_remove, | 374 | .remove = stac9766_codec_remove, |
376 | .suspend = stac9766_codec_suspend, | ||
377 | .resume = stac9766_codec_resume, | 375 | .resume = stac9766_codec_resume, |
378 | .reg_cache_size = ARRAY_SIZE(stac9766_reg), | 376 | .reg_cache_size = ARRAY_SIZE(stac9766_reg), |
379 | .reg_word_size = sizeof(u16), | 377 | .reg_word_size = sizeof(u16), |
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index f039dc825971..b505212019e2 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c | |||
@@ -345,7 +345,6 @@ static const struct reg_default tas2552_init_regs[] = { | |||
345 | static int tas2552_codec_probe(struct snd_soc_codec *codec) | 345 | static int tas2552_codec_probe(struct snd_soc_codec *codec) |
346 | { | 346 | { |
347 | struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); | 347 | struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); |
348 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
349 | int ret; | 348 | int ret; |
350 | 349 | ||
351 | tas2552->codec = codec; | 350 | tas2552->codec = codec; |
@@ -390,11 +389,6 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec) | |||
390 | snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | | 389 | snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | |
391 | TAS2552_APT_EN | TAS2552_LIM_EN); | 390 | TAS2552_APT_EN | TAS2552_LIM_EN); |
392 | 391 | ||
393 | snd_soc_dapm_new_controls(dapm, tas2552_dapm_widgets, | ||
394 | ARRAY_SIZE(tas2552_dapm_widgets)); | ||
395 | snd_soc_dapm_add_routes(dapm, tas2552_audio_map, | ||
396 | ARRAY_SIZE(tas2552_audio_map)); | ||
397 | |||
398 | return 0; | 392 | return 0; |
399 | 393 | ||
400 | patch_fail: | 394 | patch_fail: |
@@ -462,6 +456,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = { | |||
462 | .resume = tas2552_resume, | 456 | .resume = tas2552_resume, |
463 | .controls = tas2552_snd_controls, | 457 | .controls = tas2552_snd_controls, |
464 | .num_controls = ARRAY_SIZE(tas2552_snd_controls), | 458 | .num_controls = ARRAY_SIZE(tas2552_snd_controls), |
459 | .dapm_widgets = tas2552_dapm_widgets, | ||
460 | .num_dapm_widgets = ARRAY_SIZE(tas2552_dapm_widgets), | ||
461 | .dapm_routes = tas2552_audio_map, | ||
462 | .num_dapm_routes = ARRAY_SIZE(tas2552_audio_map), | ||
465 | }; | 463 | }; |
466 | 464 | ||
467 | static const struct regmap_config tas2552_regmap_config = { | 465 | static const struct regmap_config tas2552_regmap_config = { |
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c new file mode 100644 index 000000000000..16f1b71edb55 --- /dev/null +++ b/sound/soc/codecs/tfa9879.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * tfa9879.c -- driver for NXP Semiconductors TFA9879 | ||
3 | * | ||
4 | * Copyright (C) 2014 Axentia Technologies AB | ||
5 | * Author: Peter Rosin <peda@axentia.se> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/regmap.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/tlv.h> | ||
20 | #include <sound/pcm_params.h> | ||
21 | |||
22 | #include "tfa9879.h" | ||
23 | |||
24 | struct tfa9879_priv { | ||
25 | struct regmap *regmap; | ||
26 | int lsb_justified; | ||
27 | }; | ||
28 | |||
29 | static int tfa9879_hw_params(struct snd_pcm_substream *substream, | ||
30 | struct snd_pcm_hw_params *params, | ||
31 | struct snd_soc_dai *dai) | ||
32 | { | ||
33 | struct snd_soc_codec *codec = dai->codec; | ||
34 | struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec); | ||
35 | int fs; | ||
36 | int i2s_set = 0; | ||
37 | |||
38 | switch (params_rate(params)) { | ||
39 | case 8000: | ||
40 | fs = TFA9879_I2S_FS_8000; | ||
41 | break; | ||
42 | case 11025: | ||
43 | fs = TFA9879_I2S_FS_11025; | ||
44 | break; | ||
45 | case 12000: | ||
46 | fs = TFA9879_I2S_FS_12000; | ||
47 | break; | ||
48 | case 16000: | ||
49 | fs = TFA9879_I2S_FS_16000; | ||
50 | break; | ||
51 | case 22050: | ||
52 | fs = TFA9879_I2S_FS_22050; | ||
53 | break; | ||
54 | case 24000: | ||
55 | fs = TFA9879_I2S_FS_24000; | ||
56 | break; | ||
57 | case 32000: | ||
58 | fs = TFA9879_I2S_FS_32000; | ||
59 | break; | ||
60 | case 44100: | ||
61 | fs = TFA9879_I2S_FS_44100; | ||
62 | break; | ||
63 | case 48000: | ||
64 | fs = TFA9879_I2S_FS_48000; | ||
65 | break; | ||
66 | case 64000: | ||
67 | fs = TFA9879_I2S_FS_64000; | ||
68 | break; | ||
69 | case 88200: | ||
70 | fs = TFA9879_I2S_FS_88200; | ||
71 | break; | ||
72 | case 96000: | ||
73 | fs = TFA9879_I2S_FS_96000; | ||
74 | break; | ||
75 | default: | ||
76 | return -EINVAL; | ||
77 | } | ||
78 | |||
79 | switch (params_width(params)) { | ||
80 | case 16: | ||
81 | i2s_set = TFA9879_I2S_SET_LSB_J_16; | ||
82 | break; | ||
83 | case 24: | ||
84 | i2s_set = TFA9879_I2S_SET_LSB_J_24; | ||
85 | break; | ||
86 | default: | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | if (tfa9879->lsb_justified) | ||
91 | snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, | ||
92 | TFA9879_I2S_SET_MASK, | ||
93 | i2s_set << TFA9879_I2S_SET_SHIFT); | ||
94 | |||
95 | snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, | ||
96 | TFA9879_I2S_FS_MASK, | ||
97 | fs << TFA9879_I2S_FS_SHIFT); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int tfa9879_digital_mute(struct snd_soc_dai *dai, int mute) | ||
102 | { | ||
103 | struct snd_soc_codec *codec = dai->codec; | ||
104 | |||
105 | snd_soc_update_bits(codec, TFA9879_MISC_CONTROL, | ||
106 | TFA9879_S_MUTE_MASK, | ||
107 | !!mute << TFA9879_S_MUTE_SHIFT); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
113 | { | ||
114 | struct snd_soc_codec *codec = dai->codec; | ||
115 | struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec); | ||
116 | int i2s_set; | ||
117 | int sck_pol; | ||
118 | |||
119 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
120 | case SND_SOC_DAIFMT_CBS_CFS: | ||
121 | break; | ||
122 | default: | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | |||
126 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
127 | case SND_SOC_DAIFMT_NB_NF: | ||
128 | sck_pol = TFA9879_SCK_POL_NORMAL; | ||
129 | break; | ||
130 | case SND_SOC_DAIFMT_IB_NF: | ||
131 | sck_pol = TFA9879_SCK_POL_INVERSE; | ||
132 | break; | ||
133 | default: | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
137 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
138 | case SND_SOC_DAIFMT_I2S: | ||
139 | tfa9879->lsb_justified = 0; | ||
140 | i2s_set = TFA9879_I2S_SET_I2S_24; | ||
141 | break; | ||
142 | case SND_SOC_DAIFMT_LEFT_J: | ||
143 | tfa9879->lsb_justified = 0; | ||
144 | i2s_set = TFA9879_I2S_SET_MSB_J_24; | ||
145 | break; | ||
146 | case SND_SOC_DAIFMT_RIGHT_J: | ||
147 | tfa9879->lsb_justified = 1; | ||
148 | i2s_set = TFA9879_I2S_SET_LSB_J_24; | ||
149 | break; | ||
150 | default: | ||
151 | return -EINVAL; | ||
152 | } | ||
153 | |||
154 | snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, | ||
155 | TFA9879_SCK_POL_MASK, | ||
156 | sck_pol << TFA9879_SCK_POL_SHIFT); | ||
157 | snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, | ||
158 | TFA9879_I2S_SET_MASK, | ||
159 | i2s_set << TFA9879_I2S_SET_SHIFT); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static struct reg_default tfa9879_regs[] = { | ||
164 | { TFA9879_DEVICE_CONTROL, 0x0000 }, /* 0x00 */ | ||
165 | { TFA9879_SERIAL_INTERFACE_1, 0x0a18 }, /* 0x01 */ | ||
166 | { TFA9879_PCM_IOM2_FORMAT_1, 0x0007 }, /* 0x02 */ | ||
167 | { TFA9879_SERIAL_INTERFACE_2, 0x0a18 }, /* 0x03 */ | ||
168 | { TFA9879_PCM_IOM2_FORMAT_2, 0x0007 }, /* 0x04 */ | ||
169 | { TFA9879_EQUALIZER_A1, 0x59dd }, /* 0x05 */ | ||
170 | { TFA9879_EQUALIZER_A2, 0xc63e }, /* 0x06 */ | ||
171 | { TFA9879_EQUALIZER_B1, 0x651a }, /* 0x07 */ | ||
172 | { TFA9879_EQUALIZER_B2, 0xe53e }, /* 0x08 */ | ||
173 | { TFA9879_EQUALIZER_C1, 0x4616 }, /* 0x09 */ | ||
174 | { TFA9879_EQUALIZER_C2, 0xd33e }, /* 0x0a */ | ||
175 | { TFA9879_EQUALIZER_D1, 0x4df3 }, /* 0x0b */ | ||
176 | { TFA9879_EQUALIZER_D2, 0xea3e }, /* 0x0c */ | ||
177 | { TFA9879_EQUALIZER_E1, 0x5ee0 }, /* 0x0d */ | ||
178 | { TFA9879_EQUALIZER_E2, 0xf93e }, /* 0x0e */ | ||
179 | { TFA9879_BYPASS_CONTROL, 0x0093 }, /* 0x0f */ | ||
180 | { TFA9879_DYNAMIC_RANGE_COMPR, 0x92ba }, /* 0x10 */ | ||
181 | { TFA9879_BASS_TREBLE, 0x12a5 }, /* 0x11 */ | ||
182 | { TFA9879_HIGH_PASS_FILTER, 0x0004 }, /* 0x12 */ | ||
183 | { TFA9879_VOLUME_CONTROL, 0x10bd }, /* 0x13 */ | ||
184 | { TFA9879_MISC_CONTROL, 0x0000 }, /* 0x14 */ | ||
185 | }; | ||
186 | |||
187 | static bool tfa9879_volatile_reg(struct device *dev, unsigned int reg) | ||
188 | { | ||
189 | return reg == TFA9879_MISC_STATUS; | ||
190 | } | ||
191 | |||
192 | static const DECLARE_TLV_DB_SCALE(volume_tlv, -7050, 50, 1); | ||
193 | static const DECLARE_TLV_DB_SCALE(tb_gain_tlv, -1800, 200, 0); | ||
194 | static const char * const tb_freq_text[] = { | ||
195 | "Low", "Mid", "High" | ||
196 | }; | ||
197 | static const struct soc_enum treble_freq_enum = | ||
198 | SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_TRBLE_SHIFT, | ||
199 | ARRAY_SIZE(tb_freq_text), tb_freq_text); | ||
200 | static const struct soc_enum bass_freq_enum = | ||
201 | SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_BASS_SHIFT, | ||
202 | ARRAY_SIZE(tb_freq_text), tb_freq_text); | ||
203 | |||
204 | static const struct snd_kcontrol_new tfa9879_controls[] = { | ||
205 | SOC_SINGLE_TLV("PCM Playback Volume", TFA9879_VOLUME_CONTROL, | ||
206 | TFA9879_VOL_SHIFT, 0xbd, 1, volume_tlv), | ||
207 | SOC_SINGLE_TLV("Treble Volume", TFA9879_BASS_TREBLE, | ||
208 | TFA9879_G_TRBLE_SHIFT, 18, 0, tb_gain_tlv), | ||
209 | SOC_SINGLE_TLV("Bass Volume", TFA9879_BASS_TREBLE, | ||
210 | TFA9879_G_BASS_SHIFT, 18, 0, tb_gain_tlv), | ||
211 | SOC_ENUM("Treble Corner Freq", treble_freq_enum), | ||
212 | SOC_ENUM("Bass Corner Freq", bass_freq_enum), | ||
213 | }; | ||
214 | |||
215 | static const struct snd_soc_dapm_widget tfa9879_dapm_widgets[] = { | ||
216 | SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), | ||
217 | SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), | ||
218 | SND_SOC_DAPM_DAC("DAC", NULL, TFA9879_DEVICE_CONTROL, TFA9879_OPMODE_SHIFT, 0), | ||
219 | SND_SOC_DAPM_OUTPUT("LINEOUT"), | ||
220 | SND_SOC_DAPM_SUPPLY("POWER", TFA9879_DEVICE_CONTROL, TFA9879_POWERUP_SHIFT, 0, | ||
221 | NULL, 0), | ||
222 | }; | ||
223 | |||
224 | static const struct snd_soc_dapm_route tfa9879_dapm_routes[] = { | ||
225 | { "DAC", NULL, "AIFINL" }, | ||
226 | { "DAC", NULL, "AIFINR" }, | ||
227 | |||
228 | { "LINEOUT", NULL, "DAC" }, | ||
229 | |||
230 | { "DAC", NULL, "POWER" }, | ||
231 | }; | ||
232 | |||
233 | static const struct snd_soc_codec_driver tfa9879_codec = { | ||
234 | .controls = tfa9879_controls, | ||
235 | .num_controls = ARRAY_SIZE(tfa9879_controls), | ||
236 | |||
237 | .dapm_widgets = tfa9879_dapm_widgets, | ||
238 | .num_dapm_widgets = ARRAY_SIZE(tfa9879_dapm_widgets), | ||
239 | .dapm_routes = tfa9879_dapm_routes, | ||
240 | .num_dapm_routes = ARRAY_SIZE(tfa9879_dapm_routes), | ||
241 | }; | ||
242 | |||
243 | static const struct regmap_config tfa9879_regmap = { | ||
244 | .reg_bits = 8, | ||
245 | .val_bits = 16, | ||
246 | |||
247 | .volatile_reg = tfa9879_volatile_reg, | ||
248 | .max_register = TFA9879_MISC_STATUS, | ||
249 | .reg_defaults = tfa9879_regs, | ||
250 | .num_reg_defaults = ARRAY_SIZE(tfa9879_regs), | ||
251 | .cache_type = REGCACHE_RBTREE, | ||
252 | }; | ||
253 | |||
254 | static const struct snd_soc_dai_ops tfa9879_dai_ops = { | ||
255 | .hw_params = tfa9879_hw_params, | ||
256 | .digital_mute = tfa9879_digital_mute, | ||
257 | .set_fmt = tfa9879_set_fmt, | ||
258 | }; | ||
259 | |||
260 | #define TFA9879_RATES SNDRV_PCM_RATE_8000_96000 | ||
261 | |||
262 | #define TFA9879_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
263 | SNDRV_PCM_FMTBIT_S24_LE) | ||
264 | |||
265 | static struct snd_soc_dai_driver tfa9879_dai = { | ||
266 | .name = "tfa9879-hifi", | ||
267 | .playback = { | ||
268 | .stream_name = "Playback", | ||
269 | .channels_min = 2, | ||
270 | .channels_max = 2, | ||
271 | .rates = TFA9879_RATES, | ||
272 | .formats = TFA9879_FORMATS, }, | ||
273 | .ops = &tfa9879_dai_ops, | ||
274 | }; | ||
275 | |||
276 | static int tfa9879_i2c_probe(struct i2c_client *i2c, | ||
277 | const struct i2c_device_id *id) | ||
278 | { | ||
279 | struct tfa9879_priv *tfa9879; | ||
280 | int i; | ||
281 | |||
282 | tfa9879 = devm_kzalloc(&i2c->dev, sizeof(*tfa9879), GFP_KERNEL); | ||
283 | if (IS_ERR(tfa9879)) | ||
284 | return PTR_ERR(tfa9879); | ||
285 | |||
286 | i2c_set_clientdata(i2c, tfa9879); | ||
287 | |||
288 | tfa9879->regmap = devm_regmap_init_i2c(i2c, &tfa9879_regmap); | ||
289 | if (IS_ERR(tfa9879->regmap)) | ||
290 | return PTR_ERR(tfa9879->regmap); | ||
291 | |||
292 | /* Ensure the device is in reset state */ | ||
293 | for (i = 0; i < ARRAY_SIZE(tfa9879_regs); i++) | ||
294 | regmap_write(tfa9879->regmap, | ||
295 | tfa9879_regs[i].reg, tfa9879_regs[i].def); | ||
296 | |||
297 | return snd_soc_register_codec(&i2c->dev, &tfa9879_codec, | ||
298 | &tfa9879_dai, 1); | ||
299 | } | ||
300 | |||
301 | static int tfa9879_i2c_remove(struct i2c_client *client) | ||
302 | { | ||
303 | snd_soc_unregister_codec(&client->dev); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static const struct i2c_device_id tfa9879_i2c_id[] = { | ||
309 | { "tfa9879", 0 }, | ||
310 | { } | ||
311 | }; | ||
312 | MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id); | ||
313 | |||
314 | static struct i2c_driver tfa9879_i2c_driver = { | ||
315 | .driver = { | ||
316 | .name = "tfa9879", | ||
317 | .owner = THIS_MODULE, | ||
318 | }, | ||
319 | .probe = tfa9879_i2c_probe, | ||
320 | .remove = tfa9879_i2c_remove, | ||
321 | .id_table = tfa9879_i2c_id, | ||
322 | }; | ||
323 | |||
324 | module_i2c_driver(tfa9879_i2c_driver); | ||
325 | |||
326 | MODULE_DESCRIPTION("ASoC NXP Semiconductors TFA9879 driver"); | ||
327 | MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); | ||
328 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tfa9879.h b/sound/soc/codecs/tfa9879.h new file mode 100644 index 000000000000..3408c90c4628 --- /dev/null +++ b/sound/soc/codecs/tfa9879.h | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * tfa9879.h -- driver for NXP Semiconductors TFA9879 | ||
3 | * | ||
4 | * Copyright (C) 2014 Axentia Technologies AB | ||
5 | * Author: Peter Rosin <peda@axentia.se> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef _TFA9879_H | ||
15 | #define _TFA9879_H | ||
16 | |||
17 | #define TFA9879_DEVICE_CONTROL 0x00 | ||
18 | #define TFA9879_SERIAL_INTERFACE_1 0x01 | ||
19 | #define TFA9879_PCM_IOM2_FORMAT_1 0x02 | ||
20 | #define TFA9879_SERIAL_INTERFACE_2 0x03 | ||
21 | #define TFA9879_PCM_IOM2_FORMAT_2 0x04 | ||
22 | #define TFA9879_EQUALIZER_A1 0x05 | ||
23 | #define TFA9879_EQUALIZER_A2 0x06 | ||
24 | #define TFA9879_EQUALIZER_B1 0x07 | ||
25 | #define TFA9879_EQUALIZER_B2 0x08 | ||
26 | #define TFA9879_EQUALIZER_C1 0x09 | ||
27 | #define TFA9879_EQUALIZER_C2 0x0a | ||
28 | #define TFA9879_EQUALIZER_D1 0x0b | ||
29 | #define TFA9879_EQUALIZER_D2 0x0c | ||
30 | #define TFA9879_EQUALIZER_E1 0x0d | ||
31 | #define TFA9879_EQUALIZER_E2 0x0e | ||
32 | #define TFA9879_BYPASS_CONTROL 0x0f | ||
33 | #define TFA9879_DYNAMIC_RANGE_COMPR 0x10 | ||
34 | #define TFA9879_BASS_TREBLE 0x11 | ||
35 | #define TFA9879_HIGH_PASS_FILTER 0x12 | ||
36 | #define TFA9879_VOLUME_CONTROL 0x13 | ||
37 | #define TFA9879_MISC_CONTROL 0x14 | ||
38 | #define TFA9879_MISC_STATUS 0x15 | ||
39 | |||
40 | /* TFA9879_DEVICE_CONTROL */ | ||
41 | #define TFA9879_INPUT_SEL_MASK 0x0010 | ||
42 | #define TFA9879_INPUT_SEL_SHIFT 4 | ||
43 | #define TFA9879_OPMODE_MASK 0x0008 | ||
44 | #define TFA9879_OPMODE_SHIFT 3 | ||
45 | #define TFA9879_RESET_MASK 0x0002 | ||
46 | #define TFA9879_RESET_SHIFT 1 | ||
47 | #define TFA9879_POWERUP_MASK 0x0001 | ||
48 | #define TFA9879_POWERUP_SHIFT 0 | ||
49 | |||
50 | /* TFA9879_SERIAL_INTERFACE */ | ||
51 | #define TFA9879_MONO_SEL_MASK 0x0c00 | ||
52 | #define TFA9879_MONO_SEL_SHIFT 10 | ||
53 | #define TFA9879_MONO_SEL_LEFT 0 | ||
54 | #define TFA9879_MONO_SEL_RIGHT 1 | ||
55 | #define TFA9879_MONO_SEL_BOTH 2 | ||
56 | #define TFA9879_I2S_FS_MASK 0x03c0 | ||
57 | #define TFA9879_I2S_FS_SHIFT 6 | ||
58 | #define TFA9879_I2S_FS_8000 0 | ||
59 | #define TFA9879_I2S_FS_11025 1 | ||
60 | #define TFA9879_I2S_FS_12000 2 | ||
61 | #define TFA9879_I2S_FS_16000 3 | ||
62 | #define TFA9879_I2S_FS_22050 4 | ||
63 | #define TFA9879_I2S_FS_24000 5 | ||
64 | #define TFA9879_I2S_FS_32000 6 | ||
65 | #define TFA9879_I2S_FS_44100 7 | ||
66 | #define TFA9879_I2S_FS_48000 8 | ||
67 | #define TFA9879_I2S_FS_64000 9 | ||
68 | #define TFA9879_I2S_FS_88200 10 | ||
69 | #define TFA9879_I2S_FS_96000 11 | ||
70 | #define TFA9879_I2S_SET_MASK 0x0038 | ||
71 | #define TFA9879_I2S_SET_SHIFT 3 | ||
72 | #define TFA9879_I2S_SET_MSB_J_24 2 | ||
73 | #define TFA9879_I2S_SET_I2S_24 3 | ||
74 | #define TFA9879_I2S_SET_LSB_J_16 4 | ||
75 | #define TFA9879_I2S_SET_LSB_J_18 5 | ||
76 | #define TFA9879_I2S_SET_LSB_J_20 6 | ||
77 | #define TFA9879_I2S_SET_LSB_J_24 7 | ||
78 | #define TFA9879_SCK_POL_MASK 0x0004 | ||
79 | #define TFA9879_SCK_POL_SHIFT 2 | ||
80 | #define TFA9879_SCK_POL_NORMAL 0 | ||
81 | #define TFA9879_SCK_POL_INVERSE 1 | ||
82 | #define TFA9879_I_MODE_MASK 0x0003 | ||
83 | #define TFA9879_I_MODE_SHIFT 0 | ||
84 | #define TFA9879_I_MODE_I2S 0 | ||
85 | #define TFA9879_I_MODE_PCM_IOM2_SHORT 1 | ||
86 | #define TFA9879_I_MODE_PCM_IOM2_LONG 2 | ||
87 | |||
88 | /* TFA9879_PCM_IOM2_FORMAT */ | ||
89 | #define TFA9879_PCM_FS_MASK 0x0800 | ||
90 | #define TFA9879_PCM_FS_SHIFT 11 | ||
91 | #define TFA9879_A_LAW_MASK 0x0400 | ||
92 | #define TFA9879_A_LAW_SHIFT 10 | ||
93 | #define TFA9879_PCM_COMP_MASK 0x0200 | ||
94 | #define TFA9879_PCM_COMP_SHIFT 9 | ||
95 | #define TFA9879_PCM_DL_MASK 0x0100 | ||
96 | #define TFA9879_PCM_DL_SHIFT 8 | ||
97 | #define TFA9879_D1_SLOT_MASK 0x00f0 | ||
98 | #define TFA9879_D1_SLOT_SHIFT 4 | ||
99 | #define TFA9879_D2_SLOT_MASK 0x000f | ||
100 | #define TFA9879_D2_SLOT_SHIFT 0 | ||
101 | |||
102 | /* TFA9879_EQUALIZER_X1 */ | ||
103 | #define TFA9879_T1_MASK 0x8000 | ||
104 | #define TFA9879_T1_SHIFT 15 | ||
105 | #define TFA9879_K1M_MASK 0x7ff0 | ||
106 | #define TFA9879_K1M_SHIFT 4 | ||
107 | #define TFA9879_K1E_MASK 0x000f | ||
108 | #define TFA9879_K1E_SHIFT 0 | ||
109 | |||
110 | /* TFA9879_EQUALIZER_X2 */ | ||
111 | #define TFA9879_T2_MASK 0x8000 | ||
112 | #define TFA9879_T2_SHIFT 15 | ||
113 | #define TFA9879_K2M_MASK 0x7800 | ||
114 | #define TFA9879_K2M_SHIFT 11 | ||
115 | #define TFA9879_K2E_MASK 0x0700 | ||
116 | #define TFA9879_K2E_SHIFT 8 | ||
117 | #define TFA9879_K0_MASK 0x00fe | ||
118 | #define TFA9879_K0_SHIFT 1 | ||
119 | #define TFA9879_S_MASK 0x0001 | ||
120 | #define TFA9879_S_SHIFT 0 | ||
121 | |||
122 | /* TFA9879_BYPASS_CONTROL */ | ||
123 | #define TFA9879_L_OCP_MASK 0x00c0 | ||
124 | #define TFA9879_L_OCP_SHIFT 6 | ||
125 | #define TFA9879_L_OTP_MASK 0x0030 | ||
126 | #define TFA9879_L_OTP_SHIFT 4 | ||
127 | #define TFA9879_CLIPCTRL_MASK 0x0008 | ||
128 | #define TFA9879_CLIPCTRL_SHIFT 3 | ||
129 | #define TFA9879_HPF_BP_MASK 0x0004 | ||
130 | #define TFA9879_HPF_BP_SHIFT 2 | ||
131 | #define TFA9879_DRC_BP_MASK 0x0002 | ||
132 | #define TFA9879_DRC_BP_SHIFT 1 | ||
133 | #define TFA9879_EQ_BP_MASK 0x0001 | ||
134 | #define TFA9879_EQ_BP_SHIFT 0 | ||
135 | |||
136 | /* TFA9879_DYNAMIC_RANGE_COMPR */ | ||
137 | #define TFA9879_AT_LVL_MASK 0xf000 | ||
138 | #define TFA9879_AT_LVL_SHIFT 12 | ||
139 | #define TFA9879_AT_RATE_MASK 0x0f00 | ||
140 | #define TFA9879_AT_RATE_SHIFT 8 | ||
141 | #define TFA9879_RL_LVL_MASK 0x00f0 | ||
142 | #define TFA9879_RL_LVL_SHIFT 4 | ||
143 | #define TFA9879_RL_RATE_MASK 0x000f | ||
144 | #define TFA9879_RL_RATE_SHIFT 0 | ||
145 | |||
146 | /* TFA9879_BASS_TREBLE */ | ||
147 | #define TFA9879_G_TRBLE_MASK 0x3e00 | ||
148 | #define TFA9879_G_TRBLE_SHIFT 9 | ||
149 | #define TFA9879_F_TRBLE_MASK 0x0180 | ||
150 | #define TFA9879_F_TRBLE_SHIFT 7 | ||
151 | #define TFA9879_G_BASS_MASK 0x007c | ||
152 | #define TFA9879_G_BASS_SHIFT 2 | ||
153 | #define TFA9879_F_BASS_MASK 0x0003 | ||
154 | #define TFA9879_F_BASS_SHIFT 0 | ||
155 | |||
156 | /* TFA9879_HIGH_PASS_FILTER */ | ||
157 | #define TFA9879_HP_CTRL_MASK 0x00ff | ||
158 | #define TFA9879_HP_CTRL_SHIFT 0 | ||
159 | |||
160 | /* TFA9879_VOLUME_CONTROL */ | ||
161 | #define TFA9879_ZR_CRSS_MASK 0x1000 | ||
162 | #define TFA9879_ZR_CRSS_SHIFT 12 | ||
163 | #define TFA9879_VOL_MASK 0x00ff | ||
164 | #define TFA9879_VOL_SHIFT 0 | ||
165 | |||
166 | /* TFA9879_MISC_CONTROL */ | ||
167 | #define TFA9879_DE_PHAS_MASK 0x0c00 | ||
168 | #define TFA9879_DE_PHAS_SHIFT 10 | ||
169 | #define TFA9879_H_MUTE_MASK 0x0200 | ||
170 | #define TFA9879_H_MUTE_SHIFT 9 | ||
171 | #define TFA9879_S_MUTE_MASK 0x0100 | ||
172 | #define TFA9879_S_MUTE_SHIFT 8 | ||
173 | #define TFA9879_P_LIM_MASK 0x00ff | ||
174 | #define TFA9879_P_LIM_SHIFT 0 | ||
175 | |||
176 | /* TFA9879_MISC_STATUS */ | ||
177 | #define TFA9879_PS_MASK 0x4000 | ||
178 | #define TFA9879_PS_SHIFT 14 | ||
179 | #define TFA9879_PORA_MASK 0x2000 | ||
180 | #define TFA9879_PORA_SHIFT 13 | ||
181 | #define TFA9879_AMP_MASK 0x0600 | ||
182 | #define TFA9879_AMP_SHIFT 9 | ||
183 | #define TFA9879_IBP_2_MASK 0x0100 | ||
184 | #define TFA9879_IBP_2_SHIFT 8 | ||
185 | #define TFA9879_OFP_2_MASK 0x0080 | ||
186 | #define TFA9879_OFP_2_SHIFT 7 | ||
187 | #define TFA9879_UFP_2_MASK 0x0040 | ||
188 | #define TFA9879_UFP_2_SHIFT 6 | ||
189 | #define TFA9879_IBP_1_MASK 0x0020 | ||
190 | #define TFA9879_IBP_1_SHIFT 5 | ||
191 | #define TFA9879_OFP_1_MASK 0x0010 | ||
192 | #define TFA9879_OFP_1_SHIFT 4 | ||
193 | #define TFA9879_UFP_1_MASK 0x0008 | ||
194 | #define TFA9879_UFP_1_SHIFT 3 | ||
195 | #define TFA9879_OCPOKA_MASK 0x0004 | ||
196 | #define TFA9879_OCPOKA_SHIFT 2 | ||
197 | #define TFA9879_OCPOKB_MASK 0x0002 | ||
198 | #define TFA9879_OCPOKB_SHIFT 1 | ||
199 | #define TFA9879_OTPOK_MASK 0x0001 | ||
200 | #define TFA9879_OTPOK_SHIFT 0 | ||
201 | |||
202 | #endif | ||
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index d67167920c2f..cc17e7e5126e 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -540,19 +540,11 @@ static struct snd_soc_dai_driver tlv320aic23_dai = { | |||
540 | .ops = &tlv320aic23_dai_ops, | 540 | .ops = &tlv320aic23_dai_ops, |
541 | }; | 541 | }; |
542 | 542 | ||
543 | static int tlv320aic23_suspend(struct snd_soc_codec *codec) | ||
544 | { | ||
545 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int tlv320aic23_resume(struct snd_soc_codec *codec) | 543 | static int tlv320aic23_resume(struct snd_soc_codec *codec) |
551 | { | 544 | { |
552 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); | 545 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
553 | regcache_mark_dirty(aic23->regmap); | 546 | regcache_mark_dirty(aic23->regmap); |
554 | regcache_sync(aic23->regmap); | 547 | regcache_sync(aic23->regmap); |
555 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
556 | 548 | ||
557 | return 0; | 549 | return 0; |
558 | } | 550 | } |
@@ -562,9 +554,6 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) | |||
562 | /* Reset codec */ | 554 | /* Reset codec */ |
563 | snd_soc_write(codec, TLV320AIC23_RESET, 0); | 555 | snd_soc_write(codec, TLV320AIC23_RESET, 0); |
564 | 556 | ||
565 | /* power on device */ | ||
566 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
567 | |||
568 | snd_soc_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K); | 557 | snd_soc_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K); |
569 | 558 | ||
570 | /* Unmute input */ | 559 | /* Unmute input */ |
@@ -589,18 +578,12 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) | |||
589 | return 0; | 578 | return 0; |
590 | } | 579 | } |
591 | 580 | ||
592 | static int tlv320aic23_remove(struct snd_soc_codec *codec) | ||
593 | { | ||
594 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { | 581 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { |
599 | .probe = tlv320aic23_codec_probe, | 582 | .probe = tlv320aic23_codec_probe, |
600 | .remove = tlv320aic23_remove, | ||
601 | .suspend = tlv320aic23_suspend, | ||
602 | .resume = tlv320aic23_resume, | 583 | .resume = tlv320aic23_resume, |
603 | .set_bias_level = tlv320aic23_set_bias_level, | 584 | .set_bias_level = tlv320aic23_set_bias_level, |
585 | .suspend_bias_off = true, | ||
586 | |||
604 | .controls = tlv320aic23_snd_controls, | 587 | .controls = tlv320aic23_snd_controls, |
605 | .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls), | 588 | .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls), |
606 | .dapm_widgets = tlv320aic23_dapm_widgets, | 589 | .dapm_widgets = tlv320aic23_dapm_widgets, |
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 145fe5b253d4..dc3223d6eca1 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c | |||
@@ -911,12 +911,13 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
911 | } | 911 | } |
912 | aic31xx->p_div = i; | 912 | aic31xx->p_div = i; |
913 | 913 | ||
914 | for (i = 0; aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) { | 914 | for (i = 0; i < ARRAY_SIZE(aic31xx_divs) && |
915 | if (i == ARRAY_SIZE(aic31xx_divs)) { | 915 | aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) |
916 | dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", | 916 | ; |
917 | __func__, freq); | 917 | if (i == ARRAY_SIZE(aic31xx_divs)) { |
918 | return -EINVAL; | 918 | dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", |
919 | } | 919 | __func__, freq); |
920 | return -EINVAL; | ||
920 | } | 921 | } |
921 | 922 | ||
922 | /* set clock on MCLK, BCLK, or GPIO1 as PLL input */ | 923 | /* set clock on MCLK, BCLK, or GPIO1 as PLL input */ |
@@ -1056,18 +1057,6 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec, | |||
1056 | return 0; | 1057 | return 0; |
1057 | } | 1058 | } |
1058 | 1059 | ||
1059 | static int aic31xx_suspend(struct snd_soc_codec *codec) | ||
1060 | { | ||
1061 | aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | static int aic31xx_resume(struct snd_soc_codec *codec) | ||
1066 | { | ||
1067 | aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | static int aic31xx_codec_probe(struct snd_soc_codec *codec) | 1060 | static int aic31xx_codec_probe(struct snd_soc_codec *codec) |
1072 | { | 1061 | { |
1073 | int ret = 0; | 1062 | int ret = 0; |
@@ -1110,8 +1099,6 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec) | |||
1110 | { | 1099 | { |
1111 | struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); | 1100 | struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); |
1112 | int i; | 1101 | int i; |
1113 | /* power down chip */ | ||
1114 | aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1115 | 1102 | ||
1116 | for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) | 1103 | for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) |
1117 | regulator_unregister_notifier(aic31xx->supplies[i].consumer, | 1104 | regulator_unregister_notifier(aic31xx->supplies[i].consumer, |
@@ -1123,9 +1110,9 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec) | |||
1123 | static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { | 1110 | static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { |
1124 | .probe = aic31xx_codec_probe, | 1111 | .probe = aic31xx_codec_probe, |
1125 | .remove = aic31xx_codec_remove, | 1112 | .remove = aic31xx_codec_remove, |
1126 | .suspend = aic31xx_suspend, | ||
1127 | .resume = aic31xx_resume, | ||
1128 | .set_bias_level = aic31xx_set_bias_level, | 1113 | .set_bias_level = aic31xx_set_bias_level, |
1114 | .suspend_bias_off = true, | ||
1115 | |||
1129 | .controls = aic31xx_snd_controls, | 1116 | .controls = aic31xx_snd_controls, |
1130 | .num_controls = ARRAY_SIZE(aic31xx_snd_controls), | 1117 | .num_controls = ARRAY_SIZE(aic31xx_snd_controls), |
1131 | .dapm_widgets = aic31xx_dapm_widgets, | 1118 | .dapm_widgets = aic31xx_dapm_widgets, |
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 6ea662db2410..015467ed606b 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c | |||
@@ -597,18 +597,6 @@ static struct snd_soc_dai_driver aic32x4_dai = { | |||
597 | .symmetric_rates = 1, | 597 | .symmetric_rates = 1, |
598 | }; | 598 | }; |
599 | 599 | ||
600 | static int aic32x4_suspend(struct snd_soc_codec *codec) | ||
601 | { | ||
602 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static int aic32x4_resume(struct snd_soc_codec *codec) | ||
607 | { | ||
608 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int aic32x4_probe(struct snd_soc_codec *codec) | 600 | static int aic32x4_probe(struct snd_soc_codec *codec) |
613 | { | 601 | { |
614 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | 602 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); |
@@ -654,8 +642,6 @@ static int aic32x4_probe(struct snd_soc_codec *codec) | |||
654 | snd_soc_write(codec, AIC32X4_RMICPGANIN, | 642 | snd_soc_write(codec, AIC32X4_RMICPGANIN, |
655 | AIC32X4_RMICPGANIN_CM1R_10K); | 643 | AIC32X4_RMICPGANIN_CM1R_10K); |
656 | 644 | ||
657 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
658 | |||
659 | /* | 645 | /* |
660 | * Workaround: for an unknown reason, the ADC needs to be powered up | 646 | * Workaround: for an unknown reason, the ADC needs to be powered up |
661 | * and down for the first capture to work properly. It seems related to | 647 | * and down for the first capture to work properly. It seems related to |
@@ -669,18 +655,10 @@ static int aic32x4_probe(struct snd_soc_codec *codec) | |||
669 | return 0; | 655 | return 0; |
670 | } | 656 | } |
671 | 657 | ||
672 | static int aic32x4_remove(struct snd_soc_codec *codec) | ||
673 | { | ||
674 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { | 658 | static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { |
679 | .probe = aic32x4_probe, | 659 | .probe = aic32x4_probe, |
680 | .remove = aic32x4_remove, | ||
681 | .suspend = aic32x4_suspend, | ||
682 | .resume = aic32x4_resume, | ||
683 | .set_bias_level = aic32x4_set_bias_level, | 660 | .set_bias_level = aic32x4_set_bias_level, |
661 | .suspend_bias_off = true, | ||
684 | 662 | ||
685 | .controls = aic32x4_snd_controls, | 663 | .controls = aic32x4_snd_controls, |
686 | .num_controls = ARRAY_SIZE(aic32x4_snd_controls), | 664 | .num_controls = ARRAY_SIZE(aic32x4_snd_controls), |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index f7c2a575a892..b7ebce054b4e 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -78,6 +78,8 @@ struct aic3x_priv { | |||
78 | struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; | 78 | struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; |
79 | struct aic3x_setup_data *setup; | 79 | struct aic3x_setup_data *setup; |
80 | unsigned int sysclk; | 80 | unsigned int sysclk; |
81 | unsigned int dai_fmt; | ||
82 | unsigned int tdm_delay; | ||
81 | struct list_head list; | 83 | struct list_head list; |
82 | int master; | 84 | int master; |
83 | int gpio_reset; | 85 | int gpio_reset; |
@@ -214,61 +216,78 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, | |||
214 | return 0; | 216 | return 0; |
215 | } | 217 | } |
216 | 218 | ||
217 | static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; | 219 | static const char * const aic3x_left_dac_mux[] = { |
218 | static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; | 220 | "DAC_L1", "DAC_L3", "DAC_L2" }; |
219 | static const char *aic3x_left_hpcom_mux[] = | 221 | static SOC_ENUM_SINGLE_DECL(aic3x_left_dac_enum, DAC_LINE_MUX, 6, |
220 | { "differential of HPLOUT", "constant VCM", "single-ended" }; | 222 | aic3x_left_dac_mux); |
221 | static const char *aic3x_right_hpcom_mux[] = | 223 | |
222 | { "differential of HPROUT", "constant VCM", "single-ended", | 224 | static const char * const aic3x_right_dac_mux[] = { |
223 | "differential of HPLCOM", "external feedback" }; | 225 | "DAC_R1", "DAC_R3", "DAC_R2" }; |
224 | static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; | 226 | static SOC_ENUM_SINGLE_DECL(aic3x_right_dac_enum, DAC_LINE_MUX, 4, |
225 | static const char *aic3x_adc_hpf[] = | 227 | aic3x_right_dac_mux); |
226 | { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; | 228 | |
227 | 229 | static const char * const aic3x_left_hpcom_mux[] = { | |
228 | #define LDAC_ENUM 0 | 230 | "differential of HPLOUT", "constant VCM", "single-ended" }; |
229 | #define RDAC_ENUM 1 | 231 | static SOC_ENUM_SINGLE_DECL(aic3x_left_hpcom_enum, HPLCOM_CFG, 4, |
230 | #define LHPCOM_ENUM 2 | 232 | aic3x_left_hpcom_mux); |
231 | #define RHPCOM_ENUM 3 | 233 | |
232 | #define LINE1L_2_L_ENUM 4 | 234 | static const char * const aic3x_right_hpcom_mux[] = { |
233 | #define LINE1L_2_R_ENUM 5 | 235 | "differential of HPROUT", "constant VCM", "single-ended", |
234 | #define LINE1R_2_L_ENUM 6 | 236 | "differential of HPLCOM", "external feedback" }; |
235 | #define LINE1R_2_R_ENUM 7 | 237 | static SOC_ENUM_SINGLE_DECL(aic3x_right_hpcom_enum, HPRCOM_CFG, 3, |
236 | #define LINE2L_ENUM 8 | 238 | aic3x_right_hpcom_mux); |
237 | #define LINE2R_ENUM 9 | 239 | |
238 | #define ADC_HPF_ENUM 10 | 240 | static const char * const aic3x_linein_mode_mux[] = { |
239 | 241 | "single-ended", "differential" }; | |
240 | static const struct soc_enum aic3x_enum[] = { | 242 | static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_l_enum, LINE1L_2_LADC_CTRL, 7, |
241 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), | 243 | aic3x_linein_mode_mux); |
242 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux), | 244 | static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_r_enum, LINE1L_2_RADC_CTRL, 7, |
243 | SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), | 245 | aic3x_linein_mode_mux); |
244 | SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), | 246 | static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_l_enum, LINE1R_2_LADC_CTRL, 7, |
245 | SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 247 | aic3x_linein_mode_mux); |
246 | SOC_ENUM_SINGLE(LINE1L_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 248 | static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_r_enum, LINE1R_2_RADC_CTRL, 7, |
247 | SOC_ENUM_SINGLE(LINE1R_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 249 | aic3x_linein_mode_mux); |
248 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 250 | static SOC_ENUM_SINGLE_DECL(aic3x_line2l_2_ldac_enum, LINE2L_2_LADC_CTRL, 7, |
249 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 251 | aic3x_linein_mode_mux); |
250 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 252 | static SOC_ENUM_SINGLE_DECL(aic3x_line2r_2_rdac_enum, LINE2R_2_RADC_CTRL, 7, |
251 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), | 253 | aic3x_linein_mode_mux); |
252 | }; | 254 | |
253 | 255 | static const char * const aic3x_adc_hpf[] = { | |
254 | static const char *aic3x_agc_level[] = | 256 | "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; |
255 | { "-5.5dB", "-8dB", "-10dB", "-12dB", "-14dB", "-17dB", "-20dB", "-24dB" }; | 257 | static SOC_ENUM_DOUBLE_DECL(aic3x_adc_hpf_enum, AIC3X_CODEC_DFILT_CTRL, 6, 4, |
256 | static const struct soc_enum aic3x_agc_level_enum[] = { | 258 | aic3x_adc_hpf); |
257 | SOC_ENUM_SINGLE(LAGC_CTRL_A, 4, 8, aic3x_agc_level), | 259 | |
258 | SOC_ENUM_SINGLE(RAGC_CTRL_A, 4, 8, aic3x_agc_level), | 260 | static const char * const aic3x_agc_level[] = { |
259 | }; | 261 | "-5.5dB", "-8dB", "-10dB", "-12dB", |
260 | 262 | "-14dB", "-17dB", "-20dB", "-24dB" }; | |
261 | static const char *aic3x_agc_attack[] = { "8ms", "11ms", "16ms", "20ms" }; | 263 | static SOC_ENUM_SINGLE_DECL(aic3x_lagc_level_enum, LAGC_CTRL_A, 4, |
262 | static const struct soc_enum aic3x_agc_attack_enum[] = { | 264 | aic3x_agc_level); |
263 | SOC_ENUM_SINGLE(LAGC_CTRL_A, 2, 4, aic3x_agc_attack), | 265 | static SOC_ENUM_SINGLE_DECL(aic3x_ragc_level_enum, RAGC_CTRL_A, 4, |
264 | SOC_ENUM_SINGLE(RAGC_CTRL_A, 2, 4, aic3x_agc_attack), | 266 | aic3x_agc_level); |
265 | }; | 267 | |
266 | 268 | static const char * const aic3x_agc_attack[] = { | |
267 | static const char *aic3x_agc_decay[] = { "100ms", "200ms", "400ms", "500ms" }; | 269 | "8ms", "11ms", "16ms", "20ms" }; |
268 | static const struct soc_enum aic3x_agc_decay_enum[] = { | 270 | static SOC_ENUM_SINGLE_DECL(aic3x_lagc_attack_enum, LAGC_CTRL_A, 2, |
269 | SOC_ENUM_SINGLE(LAGC_CTRL_A, 0, 4, aic3x_agc_decay), | 271 | aic3x_agc_attack); |
270 | SOC_ENUM_SINGLE(RAGC_CTRL_A, 0, 4, aic3x_agc_decay), | 272 | static SOC_ENUM_SINGLE_DECL(aic3x_ragc_attack_enum, RAGC_CTRL_A, 2, |
271 | }; | 273 | aic3x_agc_attack); |
274 | |||
275 | static const char * const aic3x_agc_decay[] = { | ||
276 | "100ms", "200ms", "400ms", "500ms" }; | ||
277 | static SOC_ENUM_SINGLE_DECL(aic3x_lagc_decay_enum, LAGC_CTRL_A, 0, | ||
278 | aic3x_agc_decay); | ||
279 | static SOC_ENUM_SINGLE_DECL(aic3x_ragc_decay_enum, RAGC_CTRL_A, 0, | ||
280 | aic3x_agc_decay); | ||
281 | |||
282 | static const char * const aic3x_poweron_time[] = { | ||
283 | "0us", "10us", "100us", "1ms", "10ms", "50ms", | ||
284 | "100ms", "200ms", "400ms", "800ms", "2s", "4s" }; | ||
285 | static SOC_ENUM_SINGLE_DECL(aic3x_poweron_time_enum, HPOUT_POP_REDUCTION, 4, | ||
286 | aic3x_poweron_time); | ||
287 | |||
288 | static const char * const aic3x_rampup_step[] = { "0ms", "1ms", "2ms", "4ms" }; | ||
289 | static SOC_ENUM_SINGLE_DECL(aic3x_rampup_step_enum, HPOUT_POP_REDUCTION, 2, | ||
290 | aic3x_rampup_step); | ||
272 | 291 | ||
273 | /* | 292 | /* |
274 | * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps | 293 | * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps |
@@ -383,12 +402,12 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
383 | * adjust PGA to max value when ADC is on and will never go back. | 402 | * adjust PGA to max value when ADC is on and will never go back. |
384 | */ | 403 | */ |
385 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), | 404 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), |
386 | SOC_ENUM("Left AGC Target level", aic3x_agc_level_enum[0]), | 405 | SOC_ENUM("Left AGC Target level", aic3x_lagc_level_enum), |
387 | SOC_ENUM("Right AGC Target level", aic3x_agc_level_enum[1]), | 406 | SOC_ENUM("Right AGC Target level", aic3x_ragc_level_enum), |
388 | SOC_ENUM("Left AGC Attack time", aic3x_agc_attack_enum[0]), | 407 | SOC_ENUM("Left AGC Attack time", aic3x_lagc_attack_enum), |
389 | SOC_ENUM("Right AGC Attack time", aic3x_agc_attack_enum[1]), | 408 | SOC_ENUM("Right AGC Attack time", aic3x_ragc_attack_enum), |
390 | SOC_ENUM("Left AGC Decay time", aic3x_agc_decay_enum[0]), | 409 | SOC_ENUM("Left AGC Decay time", aic3x_lagc_decay_enum), |
391 | SOC_ENUM("Right AGC Decay time", aic3x_agc_decay_enum[1]), | 410 | SOC_ENUM("Right AGC Decay time", aic3x_ragc_decay_enum), |
392 | 411 | ||
393 | /* De-emphasis */ | 412 | /* De-emphasis */ |
394 | SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0), | 413 | SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0), |
@@ -398,7 +417,11 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
398 | 0, 119, 0, adc_tlv), | 417 | 0, 119, 0, adc_tlv), |
399 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), | 418 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), |
400 | 419 | ||
401 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | 420 | SOC_ENUM("ADC HPF Cut-off", aic3x_adc_hpf_enum), |
421 | |||
422 | /* Pop reduction */ | ||
423 | SOC_ENUM("Output Driver Power-On time", aic3x_poweron_time_enum), | ||
424 | SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum), | ||
402 | }; | 425 | }; |
403 | 426 | ||
404 | static const struct snd_kcontrol_new aic3x_mono_controls[] = { | 427 | static const struct snd_kcontrol_new aic3x_mono_controls[] = { |
@@ -425,19 +448,19 @@ static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = | |||
425 | 448 | ||
426 | /* Left DAC Mux */ | 449 | /* Left DAC Mux */ |
427 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = | 450 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = |
428 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); | 451 | SOC_DAPM_ENUM("Route", aic3x_left_dac_enum); |
429 | 452 | ||
430 | /* Right DAC Mux */ | 453 | /* Right DAC Mux */ |
431 | static const struct snd_kcontrol_new aic3x_right_dac_mux_controls = | 454 | static const struct snd_kcontrol_new aic3x_right_dac_mux_controls = |
432 | SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]); | 455 | SOC_DAPM_ENUM("Route", aic3x_right_dac_enum); |
433 | 456 | ||
434 | /* Left HPCOM Mux */ | 457 | /* Left HPCOM Mux */ |
435 | static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls = | 458 | static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls = |
436 | SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]); | 459 | SOC_DAPM_ENUM("Route", aic3x_left_hpcom_enum); |
437 | 460 | ||
438 | /* Right HPCOM Mux */ | 461 | /* Right HPCOM Mux */ |
439 | static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = | 462 | static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = |
440 | SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); | 463 | SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum); |
441 | 464 | ||
442 | /* Left Line Mixer */ | 465 | /* Left Line Mixer */ |
443 | static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = { | 466 | static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = { |
@@ -529,23 +552,23 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { | |||
529 | 552 | ||
530 | /* Left Line1 Mux */ | 553 | /* Left Line1 Mux */ |
531 | static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = | 554 | static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = |
532 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_L_ENUM]); | 555 | SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum); |
533 | static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls = | 556 | static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls = |
534 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_R_ENUM]); | 557 | SOC_DAPM_ENUM("Route", aic3x_line1l_2_r_enum); |
535 | 558 | ||
536 | /* Right Line1 Mux */ | 559 | /* Right Line1 Mux */ |
537 | static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls = | 560 | static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls = |
538 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_R_ENUM]); | 561 | SOC_DAPM_ENUM("Route", aic3x_line1r_2_r_enum); |
539 | static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls = | 562 | static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls = |
540 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_L_ENUM]); | 563 | SOC_DAPM_ENUM("Route", aic3x_line1r_2_l_enum); |
541 | 564 | ||
542 | /* Left Line2 Mux */ | 565 | /* Left Line2 Mux */ |
543 | static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = | 566 | static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = |
544 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]); | 567 | SOC_DAPM_ENUM("Route", aic3x_line2l_2_ldac_enum); |
545 | 568 | ||
546 | /* Right Line2 Mux */ | 569 | /* Right Line2 Mux */ |
547 | static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = | 570 | static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = |
548 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); | 571 | SOC_DAPM_ENUM("Route", aic3x_line2r_2_rdac_enum); |
549 | 572 | ||
550 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | 573 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { |
551 | /* Left DAC to Left Outputs */ | 574 | /* Left DAC to Left Outputs */ |
@@ -1009,6 +1032,25 @@ found: | |||
1009 | return 0; | 1032 | return 0; |
1010 | } | 1033 | } |
1011 | 1034 | ||
1035 | static int aic3x_prepare(struct snd_pcm_substream *substream, | ||
1036 | struct snd_soc_dai *dai) | ||
1037 | { | ||
1038 | struct snd_soc_codec *codec = dai->codec; | ||
1039 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | ||
1040 | int delay = 0; | ||
1041 | |||
1042 | /* TDM slot selection only valid in DSP_A/_B mode */ | ||
1043 | if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_A) | ||
1044 | delay += (aic3x->tdm_delay + 1); | ||
1045 | else if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_B) | ||
1046 | delay += aic3x->tdm_delay; | ||
1047 | |||
1048 | /* Configure data delay */ | ||
1049 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, aic3x->tdm_delay); | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1012 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) | 1054 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) |
1013 | { | 1055 | { |
1014 | struct snd_soc_codec *codec = dai->codec; | 1056 | struct snd_soc_codec *codec = dai->codec; |
@@ -1048,7 +1090,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1048 | struct snd_soc_codec *codec = codec_dai->codec; | 1090 | struct snd_soc_codec *codec = codec_dai->codec; |
1049 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 1091 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
1050 | u8 iface_areg, iface_breg; | 1092 | u8 iface_areg, iface_breg; |
1051 | int delay = 0; | ||
1052 | 1093 | ||
1053 | iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; | 1094 | iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; |
1054 | iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; | 1095 | iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; |
@@ -1076,7 +1117,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1076 | case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): | 1117 | case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): |
1077 | break; | 1118 | break; |
1078 | case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF): | 1119 | case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF): |
1079 | delay = 1; | ||
1080 | case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF): | 1120 | case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF): |
1081 | iface_breg |= (0x01 << 6); | 1121 | iface_breg |= (0x01 << 6); |
1082 | break; | 1122 | break; |
@@ -1090,10 +1130,45 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1090 | return -EINVAL; | 1130 | return -EINVAL; |
1091 | } | 1131 | } |
1092 | 1132 | ||
1133 | aic3x->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
1134 | |||
1093 | /* set iface */ | 1135 | /* set iface */ |
1094 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); | 1136 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); |
1095 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); | 1137 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); |
1096 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay); | 1138 | |
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, | ||
1143 | unsigned int tx_mask, unsigned int rx_mask, | ||
1144 | int slots, int slot_width) | ||
1145 | { | ||
1146 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1147 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | ||
1148 | unsigned int lsb; | ||
1149 | |||
1150 | if (tx_mask != rx_mask) { | ||
1151 | dev_err(codec->dev, "tx and rx masks must be symmetric\n"); | ||
1152 | return -EINVAL; | ||
1153 | } | ||
1154 | |||
1155 | if (unlikely(!tx_mask)) { | ||
1156 | dev_err(codec->dev, "tx and rx masks need to be non 0\n"); | ||
1157 | return -EINVAL; | ||
1158 | } | ||
1159 | |||
1160 | /* TDM based on DSP mode requires slots to be adjacent */ | ||
1161 | lsb = __ffs(tx_mask); | ||
1162 | if ((lsb + 1) != __fls(tx_mask)) { | ||
1163 | dev_err(codec->dev, "Invalid mask, slots must be adjacent\n"); | ||
1164 | return -EINVAL; | ||
1165 | } | ||
1166 | |||
1167 | aic3x->tdm_delay = lsb * slot_width; | ||
1168 | |||
1169 | /* DOUT in high-impedance on inactive bit clocks */ | ||
1170 | snd_soc_update_bits(codec, AIC3X_ASD_INTF_CTRLA, | ||
1171 | DOUT_TRISTATE, DOUT_TRISTATE); | ||
1097 | 1172 | ||
1098 | return 0; | 1173 | return 0; |
1099 | } | 1174 | } |
@@ -1212,9 +1287,11 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1212 | 1287 | ||
1213 | static const struct snd_soc_dai_ops aic3x_dai_ops = { | 1288 | static const struct snd_soc_dai_ops aic3x_dai_ops = { |
1214 | .hw_params = aic3x_hw_params, | 1289 | .hw_params = aic3x_hw_params, |
1290 | .prepare = aic3x_prepare, | ||
1215 | .digital_mute = aic3x_mute, | 1291 | .digital_mute = aic3x_mute, |
1216 | .set_sysclk = aic3x_set_dai_sysclk, | 1292 | .set_sysclk = aic3x_set_dai_sysclk, |
1217 | .set_fmt = aic3x_set_dai_fmt, | 1293 | .set_fmt = aic3x_set_dai_fmt, |
1294 | .set_tdm_slot = aic3x_set_dai_tdm_slot, | ||
1218 | }; | 1295 | }; |
1219 | 1296 | ||
1220 | static struct snd_soc_dai_driver aic3x_dai = { | 1297 | static struct snd_soc_dai_driver aic3x_dai = { |
@@ -1414,7 +1491,6 @@ static int aic3x_remove(struct snd_soc_codec *codec) | |||
1414 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 1491 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
1415 | int i; | 1492 | int i; |
1416 | 1493 | ||
1417 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1418 | list_del(&aic3x->list); | 1494 | list_del(&aic3x->list); |
1419 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | 1495 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) |
1420 | regulator_unregister_notifier(aic3x->supplies[i].consumer, | 1496 | regulator_unregister_notifier(aic3x->supplies[i].consumer, |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index e521ac3ddde8..89fa692df206 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -169,6 +169,7 @@ | |||
169 | /* Audio serial data interface control register A bits */ | 169 | /* Audio serial data interface control register A bits */ |
170 | #define BIT_CLK_MASTER 0x80 | 170 | #define BIT_CLK_MASTER 0x80 |
171 | #define WORD_CLK_MASTER 0x40 | 171 | #define WORD_CLK_MASTER 0x40 |
172 | #define DOUT_TRISTATE 0x20 | ||
172 | 173 | ||
173 | /* Codec Datapath setup register 7 */ | 174 | /* Codec Datapath setup register 7 */ |
174 | #define FSREF_44100 (1 << 7) | 175 | #define FSREF_44100 (1 << 7) |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index e21ed934bdbf..0fe2ced5b09f 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -1436,8 +1436,6 @@ static int dac33_soc_remove(struct snd_soc_codec *codec) | |||
1436 | { | 1436 | { |
1437 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 1437 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
1438 | 1438 | ||
1439 | dac33_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1440 | |||
1441 | if (dac33->irq >= 0) { | 1439 | if (dac33->irq >= 0) { |
1442 | free_irq(dac33->irq, dac33->codec); | 1440 | free_irq(dac33->irq, dac33->codec); |
1443 | destroy_workqueue(dac33->dac33_wq); | 1441 | destroy_workqueue(dac33->dac33_wq); |
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c new file mode 100644 index 000000000000..1d1205702d23 --- /dev/null +++ b/sound/soc/codecs/ts3a227e.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | * TS3A227E Autonomous Audio Accessory Detection and Configuration Switch | ||
3 | * | ||
4 | * Copyright (C) 2014 Google, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/gpio.h> | ||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/input.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of_gpio.h> | ||
17 | #include <linux/regmap.h> | ||
18 | |||
19 | #include <sound/core.h> | ||
20 | #include <sound/jack.h> | ||
21 | #include <sound/soc.h> | ||
22 | |||
23 | struct ts3a227e { | ||
24 | struct regmap *regmap; | ||
25 | struct snd_soc_jack *jack; | ||
26 | bool plugged; | ||
27 | bool mic_present; | ||
28 | unsigned int buttons_held; | ||
29 | }; | ||
30 | |||
31 | /* Button values to be reported on the jack */ | ||
32 | static const int ts3a227e_buttons[] = { | ||
33 | SND_JACK_BTN_0, | ||
34 | SND_JACK_BTN_1, | ||
35 | SND_JACK_BTN_2, | ||
36 | SND_JACK_BTN_3, | ||
37 | }; | ||
38 | |||
39 | #define TS3A227E_NUM_BUTTONS 4 | ||
40 | #define TS3A227E_JACK_MASK (SND_JACK_HEADPHONE | \ | ||
41 | SND_JACK_MICROPHONE | \ | ||
42 | SND_JACK_BTN_0 | \ | ||
43 | SND_JACK_BTN_1 | \ | ||
44 | SND_JACK_BTN_2 | \ | ||
45 | SND_JACK_BTN_3) | ||
46 | |||
47 | /* TS3A227E registers */ | ||
48 | #define TS3A227E_REG_DEVICE_ID 0x00 | ||
49 | #define TS3A227E_REG_INTERRUPT 0x01 | ||
50 | #define TS3A227E_REG_KP_INTERRUPT 0x02 | ||
51 | #define TS3A227E_REG_INTERRUPT_DISABLE 0x03 | ||
52 | #define TS3A227E_REG_SETTING_1 0x04 | ||
53 | #define TS3A227E_REG_SETTING_2 0x05 | ||
54 | #define TS3A227E_REG_SETTING_3 0x06 | ||
55 | #define TS3A227E_REG_SWITCH_CONTROL_1 0x07 | ||
56 | #define TS3A227E_REG_SWITCH_CONTROL_2 0x08 | ||
57 | #define TS3A227E_REG_SWITCH_STATUS_1 0x09 | ||
58 | #define TS3A227E_REG_SWITCH_STATUS_2 0x0a | ||
59 | #define TS3A227E_REG_ACCESSORY_STATUS 0x0b | ||
60 | #define TS3A227E_REG_ADC_OUTPUT 0x0c | ||
61 | #define TS3A227E_REG_KP_THRESHOLD_1 0x0d | ||
62 | #define TS3A227E_REG_KP_THRESHOLD_2 0x0e | ||
63 | #define TS3A227E_REG_KP_THRESHOLD_3 0x0f | ||
64 | |||
65 | /* TS3A227E_REG_INTERRUPT 0x01 */ | ||
66 | #define INS_REM_EVENT 0x01 | ||
67 | #define DETECTION_COMPLETE_EVENT 0x02 | ||
68 | |||
69 | /* TS3A227E_REG_KP_INTERRUPT 0x02 */ | ||
70 | #define PRESS_MASK(idx) (0x01 << (2 * (idx))) | ||
71 | #define RELEASE_MASK(idx) (0x02 << (2 * (idx))) | ||
72 | |||
73 | /* TS3A227E_REG_INTERRUPT_DISABLE 0x03 */ | ||
74 | #define INS_REM_INT_DISABLE 0x01 | ||
75 | #define DETECTION_COMPLETE_INT_DISABLE 0x02 | ||
76 | #define ADC_COMPLETE_INT_DISABLE 0x04 | ||
77 | #define INTB_DISABLE 0x08 | ||
78 | |||
79 | /* TS3A227E_REG_SETTING_2 0x05 */ | ||
80 | #define KP_ENABLE 0x04 | ||
81 | |||
82 | /* TS3A227E_REG_ACCESSORY_STATUS 0x0b */ | ||
83 | #define TYPE_3_POLE 0x01 | ||
84 | #define TYPE_4_POLE_OMTP 0x02 | ||
85 | #define TYPE_4_POLE_STANDARD 0x04 | ||
86 | #define JACK_INSERTED 0x08 | ||
87 | #define EITHER_MIC_MASK (TYPE_4_POLE_OMTP | TYPE_4_POLE_STANDARD) | ||
88 | |||
89 | static const struct reg_default ts3a227e_reg_defaults[] = { | ||
90 | { TS3A227E_REG_DEVICE_ID, 0x10 }, | ||
91 | { TS3A227E_REG_INTERRUPT, 0x00 }, | ||
92 | { TS3A227E_REG_KP_INTERRUPT, 0x00 }, | ||
93 | { TS3A227E_REG_INTERRUPT_DISABLE, 0x08 }, | ||
94 | { TS3A227E_REG_SETTING_1, 0x23 }, | ||
95 | { TS3A227E_REG_SETTING_2, 0x00 }, | ||
96 | { TS3A227E_REG_SETTING_3, 0x0e }, | ||
97 | { TS3A227E_REG_SWITCH_CONTROL_1, 0x00 }, | ||
98 | { TS3A227E_REG_SWITCH_CONTROL_2, 0x00 }, | ||
99 | { TS3A227E_REG_SWITCH_STATUS_1, 0x0c }, | ||
100 | { TS3A227E_REG_SWITCH_STATUS_2, 0x00 }, | ||
101 | { TS3A227E_REG_ACCESSORY_STATUS, 0x00 }, | ||
102 | { TS3A227E_REG_ADC_OUTPUT, 0x00 }, | ||
103 | { TS3A227E_REG_KP_THRESHOLD_1, 0x20 }, | ||
104 | { TS3A227E_REG_KP_THRESHOLD_2, 0x40 }, | ||
105 | { TS3A227E_REG_KP_THRESHOLD_3, 0x68 }, | ||
106 | }; | ||
107 | |||
108 | static bool ts3a227e_readable_reg(struct device *dev, unsigned int reg) | ||
109 | { | ||
110 | switch (reg) { | ||
111 | case TS3A227E_REG_DEVICE_ID ... TS3A227E_REG_KP_THRESHOLD_3: | ||
112 | return true; | ||
113 | default: | ||
114 | return false; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | static bool ts3a227e_writeable_reg(struct device *dev, unsigned int reg) | ||
119 | { | ||
120 | switch (reg) { | ||
121 | case TS3A227E_REG_INTERRUPT_DISABLE ... TS3A227E_REG_SWITCH_CONTROL_2: | ||
122 | case TS3A227E_REG_KP_THRESHOLD_1 ... TS3A227E_REG_KP_THRESHOLD_3: | ||
123 | return true; | ||
124 | default: | ||
125 | return false; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static bool ts3a227e_volatile_reg(struct device *dev, unsigned int reg) | ||
130 | { | ||
131 | switch (reg) { | ||
132 | case TS3A227E_REG_INTERRUPT ... TS3A227E_REG_INTERRUPT_DISABLE: | ||
133 | case TS3A227E_REG_SETTING_2: | ||
134 | case TS3A227E_REG_SWITCH_STATUS_1 ... TS3A227E_REG_ADC_OUTPUT: | ||
135 | return true; | ||
136 | default: | ||
137 | return false; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | static void ts3a227e_jack_report(struct ts3a227e *ts3a227e) | ||
142 | { | ||
143 | unsigned int i; | ||
144 | int report = 0; | ||
145 | |||
146 | if (!ts3a227e->jack) | ||
147 | return; | ||
148 | |||
149 | if (ts3a227e->plugged) | ||
150 | report = SND_JACK_HEADPHONE; | ||
151 | if (ts3a227e->mic_present) | ||
152 | report |= SND_JACK_MICROPHONE; | ||
153 | for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { | ||
154 | if (ts3a227e->buttons_held & (1 << i)) | ||
155 | report |= ts3a227e_buttons[i]; | ||
156 | } | ||
157 | snd_soc_jack_report(ts3a227e->jack, report, TS3A227E_JACK_MASK); | ||
158 | } | ||
159 | |||
160 | static void ts3a227e_new_jack_state(struct ts3a227e *ts3a227e, unsigned acc_reg) | ||
161 | { | ||
162 | bool plugged, mic_present; | ||
163 | |||
164 | plugged = !!(acc_reg & JACK_INSERTED); | ||
165 | mic_present = plugged && !!(acc_reg & EITHER_MIC_MASK); | ||
166 | |||
167 | ts3a227e->plugged = plugged; | ||
168 | |||
169 | if (mic_present != ts3a227e->mic_present) { | ||
170 | ts3a227e->mic_present = mic_present; | ||
171 | ts3a227e->buttons_held = 0; | ||
172 | if (mic_present) { | ||
173 | /* Enable key press detection. */ | ||
174 | regmap_update_bits(ts3a227e->regmap, | ||
175 | TS3A227E_REG_SETTING_2, | ||
176 | KP_ENABLE, KP_ENABLE); | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static irqreturn_t ts3a227e_interrupt(int irq, void *data) | ||
182 | { | ||
183 | struct ts3a227e *ts3a227e = (struct ts3a227e *)data; | ||
184 | struct regmap *regmap = ts3a227e->regmap; | ||
185 | unsigned int int_reg, kp_int_reg, acc_reg, i; | ||
186 | |||
187 | /* Check for plug/unplug. */ | ||
188 | regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg); | ||
189 | if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) { | ||
190 | regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg); | ||
191 | ts3a227e_new_jack_state(ts3a227e, acc_reg); | ||
192 | } | ||
193 | |||
194 | /* Report any key events. */ | ||
195 | regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg); | ||
196 | for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { | ||
197 | if (kp_int_reg & PRESS_MASK(i)) | ||
198 | ts3a227e->buttons_held |= (1 << i); | ||
199 | if (kp_int_reg & RELEASE_MASK(i)) | ||
200 | ts3a227e->buttons_held &= ~(1 << i); | ||
201 | } | ||
202 | |||
203 | ts3a227e_jack_report(ts3a227e); | ||
204 | |||
205 | return IRQ_HANDLED; | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * ts3a227e_enable_jack_detect - Specify a jack for event reporting | ||
210 | * | ||
211 | * @component: component to register the jack with | ||
212 | * @jack: jack to use to report headset and button events on | ||
213 | * | ||
214 | * After this function has been called the headset insert/remove and button | ||
215 | * events 0-3 will be routed to the given jack. Jack can be null to stop | ||
216 | * reporting. | ||
217 | */ | ||
218 | int ts3a227e_enable_jack_detect(struct snd_soc_component *component, | ||
219 | struct snd_soc_jack *jack) | ||
220 | { | ||
221 | struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component); | ||
222 | |||
223 | snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); | ||
224 | snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); | ||
225 | snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); | ||
226 | snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); | ||
227 | |||
228 | ts3a227e->jack = jack; | ||
229 | ts3a227e_jack_report(ts3a227e); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | EXPORT_SYMBOL_GPL(ts3a227e_enable_jack_detect); | ||
234 | |||
235 | static struct snd_soc_component_driver ts3a227e_soc_driver; | ||
236 | |||
237 | static const struct regmap_config ts3a227e_regmap_config = { | ||
238 | .val_bits = 8, | ||
239 | .reg_bits = 8, | ||
240 | |||
241 | .max_register = TS3A227E_REG_KP_THRESHOLD_3, | ||
242 | .readable_reg = ts3a227e_readable_reg, | ||
243 | .writeable_reg = ts3a227e_writeable_reg, | ||
244 | .volatile_reg = ts3a227e_volatile_reg, | ||
245 | |||
246 | .cache_type = REGCACHE_RBTREE, | ||
247 | .reg_defaults = ts3a227e_reg_defaults, | ||
248 | .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults), | ||
249 | }; | ||
250 | |||
251 | static int ts3a227e_i2c_probe(struct i2c_client *i2c, | ||
252 | const struct i2c_device_id *id) | ||
253 | { | ||
254 | struct ts3a227e *ts3a227e; | ||
255 | struct device *dev = &i2c->dev; | ||
256 | int ret; | ||
257 | |||
258 | ts3a227e = devm_kzalloc(&i2c->dev, sizeof(*ts3a227e), GFP_KERNEL); | ||
259 | if (ts3a227e == NULL) | ||
260 | return -ENOMEM; | ||
261 | |||
262 | i2c_set_clientdata(i2c, ts3a227e); | ||
263 | |||
264 | ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config); | ||
265 | if (IS_ERR(ts3a227e->regmap)) | ||
266 | return PTR_ERR(ts3a227e->regmap); | ||
267 | |||
268 | ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt, | ||
269 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
270 | "TS3A227E", ts3a227e); | ||
271 | if (ret) { | ||
272 | dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret); | ||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | ret = devm_snd_soc_register_component(&i2c->dev, &ts3a227e_soc_driver, | ||
277 | NULL, 0); | ||
278 | if (ret) | ||
279 | return ret; | ||
280 | |||
281 | /* Enable interrupts except for ADC complete. */ | ||
282 | regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_INTERRUPT_DISABLE, | ||
283 | INTB_DISABLE | ADC_COMPLETE_INT_DISABLE, | ||
284 | ADC_COMPLETE_INT_DISABLE); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static const struct i2c_device_id ts3a227e_i2c_ids[] = { | ||
290 | { "ts3a227e", 0 }, | ||
291 | { } | ||
292 | }; | ||
293 | MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids); | ||
294 | |||
295 | static const struct of_device_id ts3a227e_of_match[] = { | ||
296 | { .compatible = "ti,ts3a227e", }, | ||
297 | { } | ||
298 | }; | ||
299 | MODULE_DEVICE_TABLE(of, ts3a227e_of_match); | ||
300 | |||
301 | static struct i2c_driver ts3a227e_driver = { | ||
302 | .driver = { | ||
303 | .name = "ts3a227e", | ||
304 | .owner = THIS_MODULE, | ||
305 | .of_match_table = of_match_ptr(ts3a227e_of_match), | ||
306 | }, | ||
307 | .probe = ts3a227e_i2c_probe, | ||
308 | .id_table = ts3a227e_i2c_ids, | ||
309 | }; | ||
310 | module_i2c_driver(ts3a227e_driver); | ||
311 | |||
312 | MODULE_DESCRIPTION("ASoC ts3a227e driver"); | ||
313 | MODULE_AUTHOR("Dylan Reid <dgreid@chromium.org>"); | ||
314 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/ts3a227e.h b/sound/soc/codecs/ts3a227e.h new file mode 100644 index 000000000000..e2acf9c5bebe --- /dev/null +++ b/sound/soc/codecs/ts3a227e.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * TS3A227E Autonous Audio Accessory Detection and Configureation Switch | ||
3 | * | ||
4 | * Copyright (C) 2014 Google, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef _TS3A227E_H | ||
12 | #define _TS3A227E_H | ||
13 | |||
14 | int ts3a227e_enable_jack_detect(struct snd_soc_component *component, | ||
15 | struct snd_soc_jack *jack); | ||
16 | |||
17 | #endif | ||
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index b6b0cb399599..27f3b21effb2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -2177,8 +2177,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec) | |||
2177 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 2177 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
2178 | struct twl4030_codec_data *pdata = twl4030->pdata; | 2178 | struct twl4030_codec_data *pdata = twl4030->pdata; |
2179 | 2179 | ||
2180 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
2181 | |||
2182 | if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) | 2180 | if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) |
2183 | gpio_free(pdata->hs_extmute_gpio); | 2181 | gpio_free(pdata->hs_extmute_gpio); |
2184 | 2182 | ||
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 0f6067f04e29..5ff2b1e4638e 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -1095,25 +1095,6 @@ static struct snd_soc_dai_driver twl6040_dai[] = { | |||
1095 | }, | 1095 | }, |
1096 | }; | 1096 | }; |
1097 | 1097 | ||
1098 | #ifdef CONFIG_PM | ||
1099 | static int twl6040_suspend(struct snd_soc_codec *codec) | ||
1100 | { | ||
1101 | twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1102 | |||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | static int twl6040_resume(struct snd_soc_codec *codec) | ||
1107 | { | ||
1108 | twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1109 | |||
1110 | return 0; | ||
1111 | } | ||
1112 | #else | ||
1113 | #define twl6040_suspend NULL | ||
1114 | #define twl6040_resume NULL | ||
1115 | #endif | ||
1116 | |||
1117 | static int twl6040_probe(struct snd_soc_codec *codec) | 1098 | static int twl6040_probe(struct snd_soc_codec *codec) |
1118 | { | 1099 | { |
1119 | struct twl6040_data *priv; | 1100 | struct twl6040_data *priv; |
@@ -1160,7 +1141,6 @@ static int twl6040_remove(struct snd_soc_codec *codec) | |||
1160 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | 1141 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); |
1161 | 1142 | ||
1162 | free_irq(priv->plug_irq, codec); | 1143 | free_irq(priv->plug_irq, codec); |
1163 | twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1164 | 1144 | ||
1165 | return 0; | 1145 | return 0; |
1166 | } | 1146 | } |
@@ -1168,11 +1148,10 @@ static int twl6040_remove(struct snd_soc_codec *codec) | |||
1168 | static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { | 1148 | static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { |
1169 | .probe = twl6040_probe, | 1149 | .probe = twl6040_probe, |
1170 | .remove = twl6040_remove, | 1150 | .remove = twl6040_remove, |
1171 | .suspend = twl6040_suspend, | ||
1172 | .resume = twl6040_resume, | ||
1173 | .read = twl6040_read, | 1151 | .read = twl6040_read, |
1174 | .write = twl6040_write, | 1152 | .write = twl6040_write, |
1175 | .set_bias_level = twl6040_set_bias_level, | 1153 | .set_bias_level = twl6040_set_bias_level, |
1154 | .suspend_bias_off = true, | ||
1176 | .ignore_pmdown_time = true, | 1155 | .ignore_pmdown_time = true, |
1177 | 1156 | ||
1178 | .controls = twl6040_snd_controls, | 1157 | .controls = twl6040_snd_controls, |
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 32b2f78aa62c..4056260a502e 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -518,11 +518,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) | |||
518 | 518 | ||
519 | uda134x_reset(codec); | 519 | uda134x_reset(codec); |
520 | 520 | ||
521 | if (pd->is_powered_on_standby) | ||
522 | uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); | ||
523 | else | ||
524 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
525 | |||
526 | if (pd->model == UDA134X_UDA1341) { | 521 | if (pd->model == UDA134X_UDA1341) { |
527 | widgets = uda1341_dapm_widgets; | 522 | widgets = uda1341_dapm_widgets; |
528 | num_widgets = ARRAY_SIZE(uda1341_dapm_widgets); | 523 | num_widgets = ARRAY_SIZE(uda1341_dapm_widgets); |
@@ -574,44 +569,21 @@ static int uda134x_soc_remove(struct snd_soc_codec *codec) | |||
574 | { | 569 | { |
575 | struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); | 570 | struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); |
576 | 571 | ||
577 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
578 | uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
579 | |||
580 | kfree(uda134x); | 572 | kfree(uda134x); |
581 | return 0; | 573 | return 0; |
582 | } | 574 | } |
583 | 575 | ||
584 | #if defined(CONFIG_PM) | ||
585 | static int uda134x_soc_suspend(struct snd_soc_codec *codec) | ||
586 | { | ||
587 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
588 | uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int uda134x_soc_resume(struct snd_soc_codec *codec) | ||
593 | { | ||
594 | uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | ||
595 | uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); | ||
596 | return 0; | ||
597 | } | ||
598 | #else | ||
599 | #define uda134x_soc_suspend NULL | ||
600 | #define uda134x_soc_resume NULL | ||
601 | #endif /* CONFIG_PM */ | ||
602 | |||
603 | static struct snd_soc_codec_driver soc_codec_dev_uda134x = { | 576 | static struct snd_soc_codec_driver soc_codec_dev_uda134x = { |
604 | .probe = uda134x_soc_probe, | 577 | .probe = uda134x_soc_probe, |
605 | .remove = uda134x_soc_remove, | 578 | .remove = uda134x_soc_remove, |
606 | .suspend = uda134x_soc_suspend, | ||
607 | .resume = uda134x_soc_resume, | ||
608 | .reg_cache_size = sizeof(uda134x_reg), | 579 | .reg_cache_size = sizeof(uda134x_reg), |
609 | .reg_word_size = sizeof(u8), | 580 | .reg_word_size = sizeof(u8), |
610 | .reg_cache_default = uda134x_reg, | 581 | .reg_cache_default = uda134x_reg, |
611 | .reg_cache_step = 1, | 582 | .reg_cache_step = 1, |
612 | .read = uda134x_read_reg_cache, | 583 | .read = uda134x_read_reg_cache, |
613 | .write = uda134x_write, | ||
614 | .set_bias_level = uda134x_set_bias_level, | 584 | .set_bias_level = uda134x_set_bias_level, |
585 | .suspend_bias_off = true, | ||
586 | |||
615 | .dapm_widgets = uda134x_dapm_widgets, | 587 | .dapm_widgets = uda134x_dapm_widgets, |
616 | .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), | 588 | .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), |
617 | .dapm_routes = uda134x_dapm_routes, | 589 | .dapm_routes = uda134x_dapm_routes, |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index e62e70781ec2..dc7778b6dd7f 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -693,18 +693,6 @@ static struct snd_soc_dai_driver uda1380_dai[] = { | |||
693 | }, | 693 | }, |
694 | }; | 694 | }; |
695 | 695 | ||
696 | static int uda1380_suspend(struct snd_soc_codec *codec) | ||
697 | { | ||
698 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static int uda1380_resume(struct snd_soc_codec *codec) | ||
703 | { | ||
704 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | static int uda1380_probe(struct snd_soc_codec *codec) | 696 | static int uda1380_probe(struct snd_soc_codec *codec) |
709 | { | 697 | { |
710 | struct uda1380_platform_data *pdata =codec->dev->platform_data; | 698 | struct uda1380_platform_data *pdata =codec->dev->platform_data; |
@@ -739,8 +727,6 @@ static int uda1380_probe(struct snd_soc_codec *codec) | |||
739 | 727 | ||
740 | INIT_WORK(&uda1380->work, uda1380_flush_work); | 728 | INIT_WORK(&uda1380->work, uda1380_flush_work); |
741 | 729 | ||
742 | /* power on device */ | ||
743 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
744 | /* set clock input */ | 730 | /* set clock input */ |
745 | switch (pdata->dac_clk) { | 731 | switch (pdata->dac_clk) { |
746 | case UDA1380_DAC_CLK_SYSCLK: | 732 | case UDA1380_DAC_CLK_SYSCLK: |
@@ -766,8 +752,6 @@ static int uda1380_remove(struct snd_soc_codec *codec) | |||
766 | { | 752 | { |
767 | struct uda1380_platform_data *pdata =codec->dev->platform_data; | 753 | struct uda1380_platform_data *pdata =codec->dev->platform_data; |
768 | 754 | ||
769 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
770 | |||
771 | gpio_free(pdata->gpio_reset); | 755 | gpio_free(pdata->gpio_reset); |
772 | gpio_free(pdata->gpio_power); | 756 | gpio_free(pdata->gpio_power); |
773 | 757 | ||
@@ -777,11 +761,11 @@ static int uda1380_remove(struct snd_soc_codec *codec) | |||
777 | static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { | 761 | static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { |
778 | .probe = uda1380_probe, | 762 | .probe = uda1380_probe, |
779 | .remove = uda1380_remove, | 763 | .remove = uda1380_remove, |
780 | .suspend = uda1380_suspend, | ||
781 | .resume = uda1380_resume, | ||
782 | .read = uda1380_read_reg_cache, | 764 | .read = uda1380_read_reg_cache, |
783 | .write = uda1380_write, | 765 | .write = uda1380_write, |
784 | .set_bias_level = uda1380_set_bias_level, | 766 | .set_bias_level = uda1380_set_bias_level, |
767 | .suspend_bias_off = true, | ||
768 | |||
785 | .reg_cache_size = ARRAY_SIZE(uda1380_reg), | 769 | .reg_cache_size = ARRAY_SIZE(uda1380_reg), |
786 | .reg_word_size = sizeof(u16), | 770 | .reg_word_size = sizeof(u16), |
787 | .reg_cache_default = uda1380_reg, | 771 | .reg_cache_default = uda1380_reg, |
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index f3d4e88d0b7b..00aea4100bb3 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c | |||
@@ -452,7 +452,6 @@ static int wl1273_probe(struct snd_soc_codec *codec) | |||
452 | { | 452 | { |
453 | struct wl1273_core **core = codec->dev->platform_data; | 453 | struct wl1273_core **core = codec->dev->platform_data; |
454 | struct wl1273_priv *wl1273; | 454 | struct wl1273_priv *wl1273; |
455 | int r; | ||
456 | 455 | ||
457 | dev_dbg(codec->dev, "%s.\n", __func__); | 456 | dev_dbg(codec->dev, "%s.\n", __func__); |
458 | 457 | ||
@@ -470,12 +469,7 @@ static int wl1273_probe(struct snd_soc_codec *codec) | |||
470 | 469 | ||
471 | snd_soc_codec_set_drvdata(codec, wl1273); | 470 | snd_soc_codec_set_drvdata(codec, wl1273); |
472 | 471 | ||
473 | r = snd_soc_add_codec_controls(codec, wl1273_controls, | 472 | return 0; |
474 | ARRAY_SIZE(wl1273_controls)); | ||
475 | if (r) | ||
476 | kfree(wl1273); | ||
477 | |||
478 | return r; | ||
479 | } | 473 | } |
480 | 474 | ||
481 | static int wl1273_remove(struct snd_soc_codec *codec) | 475 | static int wl1273_remove(struct snd_soc_codec *codec) |
@@ -492,6 +486,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wl1273 = { | |||
492 | .probe = wl1273_probe, | 486 | .probe = wl1273_probe, |
493 | .remove = wl1273_remove, | 487 | .remove = wl1273_remove, |
494 | 488 | ||
489 | .controls = wl1273_controls, | ||
490 | .num_controls = ARRAY_SIZE(wl1273_controls), | ||
495 | .dapm_widgets = wl1273_dapm_widgets, | 491 | .dapm_widgets = wl1273_dapm_widgets, |
496 | .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), | 492 | .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), |
497 | .dapm_routes = wl1273_dapm_routes, | 493 | .dapm_routes = wl1273_dapm_routes, |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index f60234962527..d78fb8dffc8c 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
@@ -619,10 +619,10 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, | |||
619 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 619 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
620 | uint16_t data; | 620 | uint16_t data; |
621 | 621 | ||
622 | mutex_lock(&codec->mutex); | 622 | mutex_lock(&arizona->dac_comp_lock); |
623 | data = cpu_to_be16(arizona->dac_comp_coeff); | 623 | data = cpu_to_be16(arizona->dac_comp_coeff); |
624 | memcpy(ucontrol->value.bytes.data, &data, sizeof(data)); | 624 | memcpy(ucontrol->value.bytes.data, &data, sizeof(data)); |
625 | mutex_unlock(&codec->mutex); | 625 | mutex_unlock(&arizona->dac_comp_lock); |
626 | 626 | ||
627 | return 0; | 627 | return 0; |
628 | } | 628 | } |
@@ -633,11 +633,11 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, | |||
633 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 633 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
634 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 634 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
635 | 635 | ||
636 | mutex_lock(&codec->mutex); | 636 | mutex_lock(&arizona->dac_comp_lock); |
637 | memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data, | 637 | memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data, |
638 | sizeof(arizona->dac_comp_coeff)); | 638 | sizeof(arizona->dac_comp_coeff)); |
639 | arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff); | 639 | arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff); |
640 | mutex_unlock(&codec->mutex); | 640 | mutex_unlock(&arizona->dac_comp_lock); |
641 | 641 | ||
642 | return 0; | 642 | return 0; |
643 | } | 643 | } |
@@ -648,9 +648,9 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, | |||
648 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 648 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
649 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 649 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
650 | 650 | ||
651 | mutex_lock(&codec->mutex); | 651 | mutex_lock(&arizona->dac_comp_lock); |
652 | ucontrol->value.integer.value[0] = arizona->dac_comp_enabled; | 652 | ucontrol->value.integer.value[0] = arizona->dac_comp_enabled; |
653 | mutex_unlock(&codec->mutex); | 653 | mutex_unlock(&arizona->dac_comp_lock); |
654 | 654 | ||
655 | return 0; | 655 | return 0; |
656 | } | 656 | } |
@@ -661,9 +661,9 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol, | |||
661 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 661 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
662 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 662 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
663 | 663 | ||
664 | mutex_lock(&codec->mutex); | 664 | mutex_lock(&arizona->dac_comp_lock); |
665 | arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; | 665 | arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; |
666 | mutex_unlock(&codec->mutex); | 666 | mutex_unlock(&arizona->dac_comp_lock); |
667 | 667 | ||
668 | return 0; | 668 | return 0; |
669 | } | 669 | } |
@@ -1900,6 +1900,8 @@ static int wm5102_probe(struct platform_device *pdev) | |||
1900 | return -ENOMEM; | 1900 | return -ENOMEM; |
1901 | platform_set_drvdata(pdev, wm5102); | 1901 | platform_set_drvdata(pdev, wm5102); |
1902 | 1902 | ||
1903 | mutex_init(&arizona->dac_comp_lock); | ||
1904 | |||
1903 | wm5102->core.arizona = arizona; | 1905 | wm5102->core.arizona = arizona; |
1904 | wm5102->core.num_inputs = 6; | 1906 | wm5102->core.num_inputs = 6; |
1905 | 1907 | ||
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 628ec774cf22..87f664b9cc7d 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -1242,19 +1242,6 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec, | |||
1242 | return 0; | 1242 | return 0; |
1243 | } | 1243 | } |
1244 | 1244 | ||
1245 | static int wm8350_suspend(struct snd_soc_codec *codec) | ||
1246 | { | ||
1247 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | static int wm8350_resume(struct snd_soc_codec *codec) | ||
1252 | { | ||
1253 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1254 | |||
1255 | return 0; | ||
1256 | } | ||
1257 | |||
1258 | static void wm8350_hp_work(struct wm8350_data *priv, | 1245 | static void wm8350_hp_work(struct wm8350_data *priv, |
1259 | struct wm8350_jack_data *jack, | 1246 | struct wm8350_jack_data *jack, |
1260 | u16 mask) | 1247 | u16 mask) |
@@ -1565,9 +1552,6 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) | |||
1565 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, | 1552 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, |
1566 | wm8350_mic_handler, 0, "Microphone detect", priv); | 1553 | wm8350_mic_handler, 0, "Microphone detect", priv); |
1567 | 1554 | ||
1568 | |||
1569 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1570 | |||
1571 | return 0; | 1555 | return 0; |
1572 | } | 1556 | } |
1573 | 1557 | ||
@@ -1596,8 +1580,6 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) | |||
1596 | * wait for its completion */ | 1580 | * wait for its completion */ |
1597 | flush_delayed_work(&codec->dapm.delayed_work); | 1581 | flush_delayed_work(&codec->dapm.delayed_work); |
1598 | 1582 | ||
1599 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1600 | |||
1601 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); | 1583 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); |
1602 | 1584 | ||
1603 | return 0; | 1585 | return 0; |
@@ -1613,10 +1595,9 @@ static struct regmap *wm8350_get_regmap(struct device *dev) | |||
1613 | static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { | 1595 | static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { |
1614 | .probe = wm8350_codec_probe, | 1596 | .probe = wm8350_codec_probe, |
1615 | .remove = wm8350_codec_remove, | 1597 | .remove = wm8350_codec_remove, |
1616 | .suspend = wm8350_suspend, | ||
1617 | .resume = wm8350_resume, | ||
1618 | .get_regmap = wm8350_get_regmap, | 1598 | .get_regmap = wm8350_get_regmap, |
1619 | .set_bias_level = wm8350_set_bias_level, | 1599 | .set_bias_level = wm8350_set_bias_level, |
1600 | .suspend_bias_off = true, | ||
1620 | 1601 | ||
1621 | .controls = wm8350_snd_controls, | 1602 | .controls = wm8350_snd_controls, |
1622 | .num_controls = ARRAY_SIZE(wm8350_snd_controls), | 1603 | .num_controls = ARRAY_SIZE(wm8350_snd_controls), |
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 72471bef2e9a..385894f6e264 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c | |||
@@ -58,12 +58,10 @@ static struct regulator_bulk_data power[] = { | |||
58 | 58 | ||
59 | /* codec private data */ | 59 | /* codec private data */ |
60 | struct wm8400_priv { | 60 | struct wm8400_priv { |
61 | struct snd_soc_codec *codec; | ||
62 | struct wm8400 *wm8400; | 61 | struct wm8400 *wm8400; |
63 | u16 fake_register; | 62 | u16 fake_register; |
64 | unsigned int sysclk; | 63 | unsigned int sysclk; |
65 | unsigned int pcmclk; | 64 | unsigned int pcmclk; |
66 | struct work_struct work; | ||
67 | int fll_in, fll_out; | 65 | int fll_in, fll_out; |
68 | }; | 66 | }; |
69 | 67 | ||
@@ -1278,30 +1276,6 @@ static struct snd_soc_dai_driver wm8400_dai = { | |||
1278 | .ops = &wm8400_dai_ops, | 1276 | .ops = &wm8400_dai_ops, |
1279 | }; | 1277 | }; |
1280 | 1278 | ||
1281 | static int wm8400_suspend(struct snd_soc_codec *codec) | ||
1282 | { | ||
1283 | wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1284 | |||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | static int wm8400_resume(struct snd_soc_codec *codec) | ||
1289 | { | ||
1290 | wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1291 | |||
1292 | return 0; | ||
1293 | } | ||
1294 | |||
1295 | static void wm8400_probe_deferred(struct work_struct *work) | ||
1296 | { | ||
1297 | struct wm8400_priv *priv = container_of(work, struct wm8400_priv, | ||
1298 | work); | ||
1299 | struct snd_soc_codec *codec = priv->codec; | ||
1300 | |||
1301 | /* charge output caps */ | ||
1302 | wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1303 | } | ||
1304 | |||
1305 | static int wm8400_codec_probe(struct snd_soc_codec *codec) | 1279 | static int wm8400_codec_probe(struct snd_soc_codec *codec) |
1306 | { | 1280 | { |
1307 | struct wm8400 *wm8400 = dev_get_platdata(codec->dev); | 1281 | struct wm8400 *wm8400 = dev_get_platdata(codec->dev); |
@@ -1316,7 +1290,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) | |||
1316 | 1290 | ||
1317 | snd_soc_codec_set_drvdata(codec, priv); | 1291 | snd_soc_codec_set_drvdata(codec, priv); |
1318 | priv->wm8400 = wm8400; | 1292 | priv->wm8400 = wm8400; |
1319 | priv->codec = codec; | ||
1320 | 1293 | ||
1321 | ret = devm_regulator_bulk_get(wm8400->dev, | 1294 | ret = devm_regulator_bulk_get(wm8400->dev, |
1322 | ARRAY_SIZE(power), &power[0]); | 1295 | ARRAY_SIZE(power), &power[0]); |
@@ -1325,8 +1298,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) | |||
1325 | return ret; | 1298 | return ret; |
1326 | } | 1299 | } |
1327 | 1300 | ||
1328 | INIT_WORK(&priv->work, wm8400_probe_deferred); | ||
1329 | |||
1330 | wm8400_codec_reset(codec); | 1301 | wm8400_codec_reset(codec); |
1331 | 1302 | ||
1332 | reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1); | 1303 | reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1); |
@@ -1343,8 +1314,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) | |||
1343 | snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1314 | snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1344 | snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1315 | snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1345 | 1316 | ||
1346 | if (!schedule_work(&priv->work)) | ||
1347 | return -EINVAL; | ||
1348 | return 0; | 1317 | return 0; |
1349 | } | 1318 | } |
1350 | 1319 | ||
@@ -1369,10 +1338,9 @@ static struct regmap *wm8400_get_regmap(struct device *dev) | |||
1369 | static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { | 1338 | static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { |
1370 | .probe = wm8400_codec_probe, | 1339 | .probe = wm8400_codec_probe, |
1371 | .remove = wm8400_codec_remove, | 1340 | .remove = wm8400_codec_remove, |
1372 | .suspend = wm8400_suspend, | ||
1373 | .resume = wm8400_resume, | ||
1374 | .get_regmap = wm8400_get_regmap, | 1341 | .get_regmap = wm8400_get_regmap, |
1375 | .set_bias_level = wm8400_set_bias_level, | 1342 | .set_bias_level = wm8400_set_bias_level, |
1343 | .suspend_bias_off = true, | ||
1376 | 1344 | ||
1377 | .controls = wm8400_snd_controls, | 1345 | .controls = wm8400_snd_controls, |
1378 | .num_controls = ARRAY_SIZE(wm8400_snd_controls), | 1346 | .num_controls = ARRAY_SIZE(wm8400_snd_controls), |
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index e11127f9069e..8736ad094b24 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -575,41 +575,17 @@ static struct snd_soc_dai_driver wm8510_dai = { | |||
575 | .symmetric_rates = 1, | 575 | .symmetric_rates = 1, |
576 | }; | 576 | }; |
577 | 577 | ||
578 | static int wm8510_suspend(struct snd_soc_codec *codec) | ||
579 | { | ||
580 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static int wm8510_resume(struct snd_soc_codec *codec) | ||
585 | { | ||
586 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int wm8510_probe(struct snd_soc_codec *codec) | 578 | static int wm8510_probe(struct snd_soc_codec *codec) |
591 | { | 579 | { |
592 | wm8510_reset(codec); | 580 | wm8510_reset(codec); |
593 | 581 | ||
594 | /* power on device */ | ||
595 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | /* power down chip */ | ||
601 | static int wm8510_remove(struct snd_soc_codec *codec) | ||
602 | { | ||
603 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
604 | return 0; | 582 | return 0; |
605 | } | 583 | } |
606 | 584 | ||
607 | static struct snd_soc_codec_driver soc_codec_dev_wm8510 = { | 585 | static struct snd_soc_codec_driver soc_codec_dev_wm8510 = { |
608 | .probe = wm8510_probe, | 586 | .probe = wm8510_probe, |
609 | .remove = wm8510_remove, | ||
610 | .suspend = wm8510_suspend, | ||
611 | .resume = wm8510_resume, | ||
612 | .set_bias_level = wm8510_set_bias_level, | 587 | .set_bias_level = wm8510_set_bias_level, |
588 | .suspend_bias_off = true, | ||
613 | 589 | ||
614 | .controls = wm8510_snd_controls, | 590 | .controls = wm8510_snd_controls, |
615 | .num_controls = ARRAY_SIZE(wm8510_snd_controls), | 591 | .num_controls = ARRAY_SIZE(wm8510_snd_controls), |
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index ec1f5740dbd0..b1cc94f5fc4b 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c | |||
@@ -372,23 +372,6 @@ static struct snd_soc_dai_driver wm8523_dai = { | |||
372 | .ops = &wm8523_dai_ops, | 372 | .ops = &wm8523_dai_ops, |
373 | }; | 373 | }; |
374 | 374 | ||
375 | #ifdef CONFIG_PM | ||
376 | static int wm8523_suspend(struct snd_soc_codec *codec) | ||
377 | { | ||
378 | wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int wm8523_resume(struct snd_soc_codec *codec) | ||
383 | { | ||
384 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
385 | return 0; | ||
386 | } | ||
387 | #else | ||
388 | #define wm8523_suspend NULL | ||
389 | #define wm8523_resume NULL | ||
390 | #endif | ||
391 | |||
392 | static int wm8523_probe(struct snd_soc_codec *codec) | 375 | static int wm8523_probe(struct snd_soc_codec *codec) |
393 | { | 376 | { |
394 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); | 377 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); |
@@ -402,23 +385,13 @@ static int wm8523_probe(struct snd_soc_codec *codec) | |||
402 | WM8523_DACR_VU, WM8523_DACR_VU); | 385 | WM8523_DACR_VU, WM8523_DACR_VU); |
403 | snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC); | 386 | snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC); |
404 | 387 | ||
405 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static int wm8523_remove(struct snd_soc_codec *codec) | ||
411 | { | ||
412 | wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
413 | return 0; | 388 | return 0; |
414 | } | 389 | } |
415 | 390 | ||
416 | static struct snd_soc_codec_driver soc_codec_dev_wm8523 = { | 391 | static struct snd_soc_codec_driver soc_codec_dev_wm8523 = { |
417 | .probe = wm8523_probe, | 392 | .probe = wm8523_probe, |
418 | .remove = wm8523_remove, | ||
419 | .suspend = wm8523_suspend, | ||
420 | .resume = wm8523_resume, | ||
421 | .set_bias_level = wm8523_set_bias_level, | 393 | .set_bias_level = wm8523_set_bias_level, |
394 | .suspend_bias_off = true, | ||
422 | 395 | ||
423 | .controls = wm8523_controls, | 396 | .controls = wm8523_controls, |
424 | .num_controls = ARRAY_SIZE(wm8523_controls), | 397 | .num_controls = ARRAY_SIZE(wm8523_controls), |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 911605ee25b0..0a887c5ec83a 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -882,8 +882,6 @@ static int wm8580_probe(struct snd_soc_codec *codec) | |||
882 | goto err_regulator_enable; | 882 | goto err_regulator_enable; |
883 | } | 883 | } |
884 | 884 | ||
885 | wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
886 | |||
887 | return 0; | 885 | return 0; |
888 | 886 | ||
889 | err_regulator_enable: | 887 | err_regulator_enable: |
@@ -897,8 +895,6 @@ static int wm8580_remove(struct snd_soc_codec *codec) | |||
897 | { | 895 | { |
898 | struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); | 896 | struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); |
899 | 897 | ||
900 | wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
901 | |||
902 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | 898 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); |
903 | 899 | ||
904 | return 0; | 900 | return 0; |
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 32187e739b4f..121e46d53779 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
@@ -350,19 +350,6 @@ static struct snd_soc_dai_driver wm8711_dai = { | |||
350 | .ops = &wm8711_ops, | 350 | .ops = &wm8711_ops, |
351 | }; | 351 | }; |
352 | 352 | ||
353 | static int wm8711_suspend(struct snd_soc_codec *codec) | ||
354 | { | ||
355 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); | ||
356 | wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int wm8711_resume(struct snd_soc_codec *codec) | ||
361 | { | ||
362 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int wm8711_probe(struct snd_soc_codec *codec) | 353 | static int wm8711_probe(struct snd_soc_codec *codec) |
367 | { | 354 | { |
368 | int ret; | 355 | int ret; |
@@ -373,8 +360,6 @@ static int wm8711_probe(struct snd_soc_codec *codec) | |||
373 | return ret; | 360 | return ret; |
374 | } | 361 | } |
375 | 362 | ||
376 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
377 | |||
378 | /* Latch the update bits */ | 363 | /* Latch the update bits */ |
379 | snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100); | 364 | snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100); |
380 | snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100); | 365 | snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100); |
@@ -383,19 +368,11 @@ static int wm8711_probe(struct snd_soc_codec *codec) | |||
383 | 368 | ||
384 | } | 369 | } |
385 | 370 | ||
386 | /* power down chip */ | ||
387 | static int wm8711_remove(struct snd_soc_codec *codec) | ||
388 | { | ||
389 | wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static struct snd_soc_codec_driver soc_codec_dev_wm8711 = { | 371 | static struct snd_soc_codec_driver soc_codec_dev_wm8711 = { |
394 | .probe = wm8711_probe, | 372 | .probe = wm8711_probe, |
395 | .remove = wm8711_remove, | ||
396 | .suspend = wm8711_suspend, | ||
397 | .resume = wm8711_resume, | ||
398 | .set_bias_level = wm8711_set_bias_level, | 373 | .set_bias_level = wm8711_set_bias_level, |
374 | .suspend_bias_off = true, | ||
375 | |||
399 | .controls = wm8711_snd_controls, | 376 | .controls = wm8711_snd_controls, |
400 | .num_controls = ARRAY_SIZE(wm8711_snd_controls), | 377 | .num_controls = ARRAY_SIZE(wm8711_snd_controls), |
401 | .dapm_widgets = wm8711_dapm_widgets, | 378 | .dapm_widgets = wm8711_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 38ff826f589a..55c7fb4fc786 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c | |||
@@ -212,40 +212,10 @@ static struct snd_soc_dai_driver wm8728_dai = { | |||
212 | .ops = &wm8728_dai_ops, | 212 | .ops = &wm8728_dai_ops, |
213 | }; | 213 | }; |
214 | 214 | ||
215 | static int wm8728_suspend(struct snd_soc_codec *codec) | ||
216 | { | ||
217 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int wm8728_resume(struct snd_soc_codec *codec) | ||
223 | { | ||
224 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int wm8728_probe(struct snd_soc_codec *codec) | ||
230 | { | ||
231 | /* power on device */ | ||
232 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int wm8728_remove(struct snd_soc_codec *codec) | ||
238 | { | ||
239 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static struct snd_soc_codec_driver soc_codec_dev_wm8728 = { | 215 | static struct snd_soc_codec_driver soc_codec_dev_wm8728 = { |
244 | .probe = wm8728_probe, | ||
245 | .remove = wm8728_remove, | ||
246 | .suspend = wm8728_suspend, | ||
247 | .resume = wm8728_resume, | ||
248 | .set_bias_level = wm8728_set_bias_level, | 216 | .set_bias_level = wm8728_set_bias_level, |
217 | .suspend_bias_off = true, | ||
218 | |||
249 | .controls = wm8728_snd_controls, | 219 | .controls = wm8728_snd_controls, |
250 | .num_controls = ARRAY_SIZE(wm8728_snd_controls), | 220 | .num_controls = ARRAY_SIZE(wm8728_snd_controls), |
251 | .dapm_widgets = wm8728_dapm_widgets, | 221 | .dapm_widgets = wm8728_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index eebb3280bfad..b9211b42f6e9 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/regulator/consumer.h> | 24 | #include <linux/regulator/consumer.h> |
25 | #include <linux/spi/spi.h> | 25 | #include <linux/spi/spi.h> |
26 | #include <linux/of_device.h> | 26 | #include <linux/of_device.h> |
27 | #include <linux/mutex.h> | ||
27 | #include <sound/core.h> | 28 | #include <sound/core.h> |
28 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
29 | #include <sound/pcm_params.h> | 30 | #include <sound/pcm_params.h> |
@@ -50,6 +51,8 @@ struct wm8731_priv { | |||
50 | int sysclk_type; | 51 | int sysclk_type; |
51 | int playback_fs; | 52 | int playback_fs; |
52 | bool deemph; | 53 | bool deemph; |
54 | |||
55 | struct mutex lock; | ||
53 | }; | 56 | }; |
54 | 57 | ||
55 | 58 | ||
@@ -138,7 +141,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, | |||
138 | if (deemph > 1) | 141 | if (deemph > 1) |
139 | return -EINVAL; | 142 | return -EINVAL; |
140 | 143 | ||
141 | mutex_lock(&codec->mutex); | 144 | mutex_lock(&wm8731->lock); |
142 | if (wm8731->deemph != deemph) { | 145 | if (wm8731->deemph != deemph) { |
143 | wm8731->deemph = deemph; | 146 | wm8731->deemph = deemph; |
144 | 147 | ||
@@ -146,7 +149,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, | |||
146 | 149 | ||
147 | ret = 1; | 150 | ret = 1; |
148 | } | 151 | } |
149 | mutex_unlock(&codec->mutex); | 152 | mutex_unlock(&wm8731->lock); |
150 | 153 | ||
151 | return ret; | 154 | return ret; |
152 | } | 155 | } |
@@ -559,25 +562,6 @@ static struct snd_soc_dai_driver wm8731_dai = { | |||
559 | .symmetric_rates = 1, | 562 | .symmetric_rates = 1, |
560 | }; | 563 | }; |
561 | 564 | ||
562 | #ifdef CONFIG_PM | ||
563 | static int wm8731_suspend(struct snd_soc_codec *codec) | ||
564 | { | ||
565 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | static int wm8731_resume(struct snd_soc_codec *codec) | ||
571 | { | ||
572 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | #else | ||
577 | #define wm8731_suspend NULL | ||
578 | #define wm8731_resume NULL | ||
579 | #endif | ||
580 | |||
581 | static int wm8731_probe(struct snd_soc_codec *codec) | 565 | static int wm8731_probe(struct snd_soc_codec *codec) |
582 | { | 566 | { |
583 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); | 567 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); |
@@ -633,8 +617,6 @@ static int wm8731_remove(struct snd_soc_codec *codec) | |||
633 | { | 617 | { |
634 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); | 618 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); |
635 | 619 | ||
636 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
637 | |||
638 | regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | 620 | regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); |
639 | 621 | ||
640 | return 0; | 622 | return 0; |
@@ -643,9 +625,9 @@ static int wm8731_remove(struct snd_soc_codec *codec) | |||
643 | static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { | 625 | static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { |
644 | .probe = wm8731_probe, | 626 | .probe = wm8731_probe, |
645 | .remove = wm8731_remove, | 627 | .remove = wm8731_remove, |
646 | .suspend = wm8731_suspend, | ||
647 | .resume = wm8731_resume, | ||
648 | .set_bias_level = wm8731_set_bias_level, | 628 | .set_bias_level = wm8731_set_bias_level, |
629 | .suspend_bias_off = true, | ||
630 | |||
649 | .dapm_widgets = wm8731_dapm_widgets, | 631 | .dapm_widgets = wm8731_dapm_widgets, |
650 | .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), | 632 | .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), |
651 | .dapm_routes = wm8731_intercon, | 633 | .dapm_routes = wm8731_intercon, |
@@ -680,11 +662,12 @@ static int wm8731_spi_probe(struct spi_device *spi) | |||
680 | struct wm8731_priv *wm8731; | 662 | struct wm8731_priv *wm8731; |
681 | int ret; | 663 | int ret; |
682 | 664 | ||
683 | wm8731 = devm_kzalloc(&spi->dev, sizeof(struct wm8731_priv), | 665 | wm8731 = devm_kzalloc(&spi->dev, sizeof(*wm8731), GFP_KERNEL); |
684 | GFP_KERNEL); | ||
685 | if (wm8731 == NULL) | 666 | if (wm8731 == NULL) |
686 | return -ENOMEM; | 667 | return -ENOMEM; |
687 | 668 | ||
669 | mutex_init(&wm8731->lock); | ||
670 | |||
688 | wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); | 671 | wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); |
689 | if (IS_ERR(wm8731->regmap)) { | 672 | if (IS_ERR(wm8731->regmap)) { |
690 | ret = PTR_ERR(wm8731->regmap); | 673 | ret = PTR_ERR(wm8731->regmap); |
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 744a422ecb05..ada9ac1ba2c6 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c | |||
@@ -277,17 +277,6 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
277 | { "AIF", NULL, "ADCR" }, | 277 | { "AIF", NULL, "ADCR" }, |
278 | }; | 278 | }; |
279 | 279 | ||
280 | static int wm8737_add_widgets(struct snd_soc_codec *codec) | ||
281 | { | ||
282 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
283 | |||
284 | snd_soc_dapm_new_controls(dapm, wm8737_dapm_widgets, | ||
285 | ARRAY_SIZE(wm8737_dapm_widgets)); | ||
286 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | /* codec mclk clock divider coefficients */ | 280 | /* codec mclk clock divider coefficients */ |
292 | static const struct { | 281 | static const struct { |
293 | u32 mclk; | 282 | u32 mclk; |
@@ -548,23 +537,6 @@ static struct snd_soc_dai_driver wm8737_dai = { | |||
548 | .ops = &wm8737_dai_ops, | 537 | .ops = &wm8737_dai_ops, |
549 | }; | 538 | }; |
550 | 539 | ||
551 | #ifdef CONFIG_PM | ||
552 | static int wm8737_suspend(struct snd_soc_codec *codec) | ||
553 | { | ||
554 | wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int wm8737_resume(struct snd_soc_codec *codec) | ||
559 | { | ||
560 | wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
561 | return 0; | ||
562 | } | ||
563 | #else | ||
564 | #define wm8737_suspend NULL | ||
565 | #define wm8737_resume NULL | ||
566 | #endif | ||
567 | |||
568 | static int wm8737_probe(struct snd_soc_codec *codec) | 540 | static int wm8737_probe(struct snd_soc_codec *codec) |
569 | { | 541 | { |
570 | struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec); | 542 | struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec); |
@@ -593,10 +565,6 @@ static int wm8737_probe(struct snd_soc_codec *codec) | |||
593 | /* Bias level configuration will have done an extra enable */ | 565 | /* Bias level configuration will have done an extra enable */ |
594 | regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); | 566 | regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); |
595 | 567 | ||
596 | snd_soc_add_codec_controls(codec, wm8737_snd_controls, | ||
597 | ARRAY_SIZE(wm8737_snd_controls)); | ||
598 | wm8737_add_widgets(codec); | ||
599 | |||
600 | return 0; | 568 | return 0; |
601 | 569 | ||
602 | err_enable: | 570 | err_enable: |
@@ -605,18 +573,17 @@ err_get: | |||
605 | return ret; | 573 | return ret; |
606 | } | 574 | } |
607 | 575 | ||
608 | static int wm8737_remove(struct snd_soc_codec *codec) | ||
609 | { | ||
610 | wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | static struct snd_soc_codec_driver soc_codec_dev_wm8737 = { | 576 | static struct snd_soc_codec_driver soc_codec_dev_wm8737 = { |
615 | .probe = wm8737_probe, | 577 | .probe = wm8737_probe, |
616 | .remove = wm8737_remove, | ||
617 | .suspend = wm8737_suspend, | ||
618 | .resume = wm8737_resume, | ||
619 | .set_bias_level = wm8737_set_bias_level, | 578 | .set_bias_level = wm8737_set_bias_level, |
579 | .suspend_bias_off = true, | ||
580 | |||
581 | .controls = wm8737_snd_controls, | ||
582 | .num_controls = ARRAY_SIZE(wm8737_snd_controls), | ||
583 | .dapm_widgets = wm8737_dapm_widgets, | ||
584 | .num_dapm_widgets = ARRAY_SIZE(wm8737_dapm_widgets), | ||
585 | .dapm_routes = intercon, | ||
586 | .num_dapm_routes = ARRAY_SIZE(intercon), | ||
620 | }; | 587 | }; |
621 | 588 | ||
622 | static const struct of_device_id wm8737_of_match[] = { | 589 | static const struct of_device_id wm8737_of_match[] = { |
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 67653a2db223..f6847fdd6ddd 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -686,18 +686,6 @@ static struct snd_soc_dai_driver wm8750_dai = { | |||
686 | .ops = &wm8750_dai_ops, | 686 | .ops = &wm8750_dai_ops, |
687 | }; | 687 | }; |
688 | 688 | ||
689 | static int wm8750_suspend(struct snd_soc_codec *codec) | ||
690 | { | ||
691 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static int wm8750_resume(struct snd_soc_codec *codec) | ||
696 | { | ||
697 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static int wm8750_probe(struct snd_soc_codec *codec) | 689 | static int wm8750_probe(struct snd_soc_codec *codec) |
702 | { | 690 | { |
703 | int ret; | 691 | int ret; |
@@ -708,9 +696,6 @@ static int wm8750_probe(struct snd_soc_codec *codec) | |||
708 | return ret; | 696 | return ret; |
709 | } | 697 | } |
710 | 698 | ||
711 | /* charge output caps */ | ||
712 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
713 | |||
714 | /* set the update bits */ | 699 | /* set the update bits */ |
715 | snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100); | 700 | snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100); |
716 | snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100); | 701 | snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100); |
@@ -724,18 +709,10 @@ static int wm8750_probe(struct snd_soc_codec *codec) | |||
724 | return ret; | 709 | return ret; |
725 | } | 710 | } |
726 | 711 | ||
727 | static int wm8750_remove(struct snd_soc_codec *codec) | ||
728 | { | ||
729 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { | 712 | static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { |
734 | .probe = wm8750_probe, | 713 | .probe = wm8750_probe, |
735 | .remove = wm8750_remove, | ||
736 | .suspend = wm8750_suspend, | ||
737 | .resume = wm8750_resume, | ||
738 | .set_bias_level = wm8750_set_bias_level, | 714 | .set_bias_level = wm8750_set_bias_level, |
715 | .suspend_bias_off = true, | ||
739 | 716 | ||
740 | .controls = wm8750_snd_controls, | 717 | .controls = wm8750_snd_controls, |
741 | .num_controls = ARRAY_SIZE(wm8750_snd_controls), | 718 | .num_controls = ARRAY_SIZE(wm8750_snd_controls), |
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 70952ceb278b..c13050b77931 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c | |||
@@ -408,24 +408,6 @@ static struct snd_soc_dai_driver wm8776_dai[] = { | |||
408 | }, | 408 | }, |
409 | }; | 409 | }; |
410 | 410 | ||
411 | #ifdef CONFIG_PM | ||
412 | static int wm8776_suspend(struct snd_soc_codec *codec) | ||
413 | { | ||
414 | wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static int wm8776_resume(struct snd_soc_codec *codec) | ||
420 | { | ||
421 | wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
422 | return 0; | ||
423 | } | ||
424 | #else | ||
425 | #define wm8776_suspend NULL | ||
426 | #define wm8776_resume NULL | ||
427 | #endif | ||
428 | |||
429 | static int wm8776_probe(struct snd_soc_codec *codec) | 411 | static int wm8776_probe(struct snd_soc_codec *codec) |
430 | { | 412 | { |
431 | int ret = 0; | 413 | int ret = 0; |
@@ -436,8 +418,6 @@ static int wm8776_probe(struct snd_soc_codec *codec) | |||
436 | return ret; | 418 | return ret; |
437 | } | 419 | } |
438 | 420 | ||
439 | wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
440 | |||
441 | /* Latch the update bits; right channel only since we always | 421 | /* Latch the update bits; right channel only since we always |
442 | * update both. */ | 422 | * update both. */ |
443 | snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100); | 423 | snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100); |
@@ -446,19 +426,10 @@ static int wm8776_probe(struct snd_soc_codec *codec) | |||
446 | return ret; | 426 | return ret; |
447 | } | 427 | } |
448 | 428 | ||
449 | /* power down chip */ | ||
450 | static int wm8776_remove(struct snd_soc_codec *codec) | ||
451 | { | ||
452 | wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static struct snd_soc_codec_driver soc_codec_dev_wm8776 = { | 429 | static struct snd_soc_codec_driver soc_codec_dev_wm8776 = { |
457 | .probe = wm8776_probe, | 430 | .probe = wm8776_probe, |
458 | .remove = wm8776_remove, | ||
459 | .suspend = wm8776_suspend, | ||
460 | .resume = wm8776_resume, | ||
461 | .set_bias_level = wm8776_set_bias_level, | 431 | .set_bias_level = wm8776_set_bias_level, |
432 | .suspend_bias_off = true, | ||
462 | 433 | ||
463 | .controls = wm8776_snd_controls, | 434 | .controls = wm8776_snd_controls, |
464 | .num_controls = ARRAY_SIZE(wm8776_snd_controls), | 435 | .num_controls = ARRAY_SIZE(wm8776_snd_controls), |
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 3addc5fe5cb2..1315f7642503 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
@@ -524,7 +524,6 @@ static int wm8804_remove(struct snd_soc_codec *codec) | |||
524 | int i; | 524 | int i; |
525 | 525 | ||
526 | wm8804 = snd_soc_codec_get_drvdata(codec); | 526 | wm8804 = snd_soc_codec_get_drvdata(codec); |
527 | wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
528 | 527 | ||
529 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) | 528 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) |
530 | regulator_unregister_notifier(wm8804->supplies[i].consumer, | 529 | regulator_unregister_notifier(wm8804->supplies[i].consumer, |
@@ -606,8 +605,6 @@ static int wm8804_probe(struct snd_soc_codec *codec) | |||
606 | goto err_reg_enable; | 605 | goto err_reg_enable; |
607 | } | 606 | } |
608 | 607 | ||
609 | wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
610 | |||
611 | return 0; | 608 | return 0; |
612 | 609 | ||
613 | err_reg_enable: | 610 | err_reg_enable: |
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 44a5f1511f0f..3a0d4b7d692f 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -1209,16 +1209,8 @@ static int wm8900_probe(struct snd_soc_codec *codec) | |||
1209 | return 0; | 1209 | return 0; |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | /* power down chip */ | ||
1213 | static int wm8900_remove(struct snd_soc_codec *codec) | ||
1214 | { | ||
1215 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1216 | return 0; | ||
1217 | } | ||
1218 | |||
1219 | static struct snd_soc_codec_driver soc_codec_dev_wm8900 = { | 1212 | static struct snd_soc_codec_driver soc_codec_dev_wm8900 = { |
1220 | .probe = wm8900_probe, | 1213 | .probe = wm8900_probe, |
1221 | .remove = wm8900_remove, | ||
1222 | .suspend = wm8900_suspend, | 1214 | .suspend = wm8900_suspend, |
1223 | .resume = wm8900_resume, | 1215 | .resume = wm8900_resume, |
1224 | .set_bias_level = wm8900_set_bias_level, | 1216 | .set_bias_level = wm8900_set_bias_level, |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index c038b3e04398..cc6b0ef98a34 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/irq.h> | 28 | #include <linux/irq.h> |
29 | #include <linux/mutex.h> | ||
29 | #include <sound/core.h> | 30 | #include <sound/core.h> |
30 | #include <sound/jack.h> | 31 | #include <sound/jack.h> |
31 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
@@ -117,12 +118,12 @@ static const struct reg_default wm8903_reg_defaults[] = { | |||
117 | struct wm8903_priv { | 118 | struct wm8903_priv { |
118 | struct wm8903_platform_data *pdata; | 119 | struct wm8903_platform_data *pdata; |
119 | struct device *dev; | 120 | struct device *dev; |
120 | struct snd_soc_codec *codec; | ||
121 | struct regmap *regmap; | 121 | struct regmap *regmap; |
122 | 122 | ||
123 | int sysclk; | 123 | int sysclk; |
124 | int irq; | 124 | int irq; |
125 | 125 | ||
126 | struct mutex lock; | ||
126 | int fs; | 127 | int fs; |
127 | int deemph; | 128 | int deemph; |
128 | 129 | ||
@@ -457,7 +458,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, | |||
457 | if (deemph > 1) | 458 | if (deemph > 1) |
458 | return -EINVAL; | 459 | return -EINVAL; |
459 | 460 | ||
460 | mutex_lock(&codec->mutex); | 461 | mutex_lock(&wm8903->lock); |
461 | if (wm8903->deemph != deemph) { | 462 | if (wm8903->deemph != deemph) { |
462 | wm8903->deemph = deemph; | 463 | wm8903->deemph = deemph; |
463 | 464 | ||
@@ -465,7 +466,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, | |||
465 | 466 | ||
466 | ret = 1; | 467 | ret = 1; |
467 | } | 468 | } |
468 | mutex_unlock(&codec->mutex); | 469 | mutex_unlock(&wm8903->lock); |
469 | 470 | ||
470 | return ret; | 471 | return ret; |
471 | } | 472 | } |
@@ -1757,21 +1758,12 @@ static struct snd_soc_dai_driver wm8903_dai = { | |||
1757 | .symmetric_rates = 1, | 1758 | .symmetric_rates = 1, |
1758 | }; | 1759 | }; |
1759 | 1760 | ||
1760 | static int wm8903_suspend(struct snd_soc_codec *codec) | ||
1761 | { | ||
1762 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1763 | |||
1764 | return 0; | ||
1765 | } | ||
1766 | |||
1767 | static int wm8903_resume(struct snd_soc_codec *codec) | 1761 | static int wm8903_resume(struct snd_soc_codec *codec) |
1768 | { | 1762 | { |
1769 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | 1763 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); |
1770 | 1764 | ||
1771 | regcache_sync(wm8903->regmap); | 1765 | regcache_sync(wm8903->regmap); |
1772 | 1766 | ||
1773 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1774 | |||
1775 | return 0; | 1767 | return 0; |
1776 | } | 1768 | } |
1777 | 1769 | ||
@@ -1889,33 +1881,12 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903) | |||
1889 | } | 1881 | } |
1890 | #endif | 1882 | #endif |
1891 | 1883 | ||
1892 | static int wm8903_probe(struct snd_soc_codec *codec) | ||
1893 | { | ||
1894 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
1895 | |||
1896 | wm8903->codec = codec; | ||
1897 | |||
1898 | /* power on device */ | ||
1899 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1900 | |||
1901 | return 0; | ||
1902 | } | ||
1903 | |||
1904 | /* power down chip */ | ||
1905 | static int wm8903_remove(struct snd_soc_codec *codec) | ||
1906 | { | ||
1907 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1908 | |||
1909 | return 0; | ||
1910 | } | ||
1911 | |||
1912 | static struct snd_soc_codec_driver soc_codec_dev_wm8903 = { | 1884 | static struct snd_soc_codec_driver soc_codec_dev_wm8903 = { |
1913 | .probe = wm8903_probe, | ||
1914 | .remove = wm8903_remove, | ||
1915 | .suspend = wm8903_suspend, | ||
1916 | .resume = wm8903_resume, | 1885 | .resume = wm8903_resume, |
1917 | .set_bias_level = wm8903_set_bias_level, | 1886 | .set_bias_level = wm8903_set_bias_level, |
1918 | .seq_notifier = wm8903_seq_notifier, | 1887 | .seq_notifier = wm8903_seq_notifier, |
1888 | .suspend_bias_off = true, | ||
1889 | |||
1919 | .controls = wm8903_snd_controls, | 1890 | .controls = wm8903_snd_controls, |
1920 | .num_controls = ARRAY_SIZE(wm8903_snd_controls), | 1891 | .num_controls = ARRAY_SIZE(wm8903_snd_controls), |
1921 | .dapm_widgets = wm8903_dapm_widgets, | 1892 | .dapm_widgets = wm8903_dapm_widgets, |
@@ -2023,6 +1994,8 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, | |||
2023 | GFP_KERNEL); | 1994 | GFP_KERNEL); |
2024 | if (wm8903 == NULL) | 1995 | if (wm8903 == NULL) |
2025 | return -ENOMEM; | 1996 | return -ENOMEM; |
1997 | |||
1998 | mutex_init(&wm8903->lock); | ||
2026 | wm8903->dev = &i2c->dev; | 1999 | wm8903->dev = &i2c->dev; |
2027 | 2000 | ||
2028 | wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap); | 2001 | wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap); |
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 52011043e54c..e4142b4309eb 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -695,17 +695,6 @@ static struct snd_soc_dai_driver wm8940_dai = { | |||
695 | .symmetric_rates = 1, | 695 | .symmetric_rates = 1, |
696 | }; | 696 | }; |
697 | 697 | ||
698 | static int wm8940_suspend(struct snd_soc_codec *codec) | ||
699 | { | ||
700 | return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
701 | } | ||
702 | |||
703 | static int wm8940_resume(struct snd_soc_codec *codec) | ||
704 | { | ||
705 | wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static int wm8940_probe(struct snd_soc_codec *codec) | 698 | static int wm8940_probe(struct snd_soc_codec *codec) |
710 | { | 699 | { |
711 | struct wm8940_setup_data *pdata = codec->dev->platform_data; | 700 | struct wm8940_setup_data *pdata = codec->dev->platform_data; |
@@ -736,18 +725,11 @@ static int wm8940_probe(struct snd_soc_codec *codec) | |||
736 | return ret; | 725 | return ret; |
737 | } | 726 | } |
738 | 727 | ||
739 | static int wm8940_remove(struct snd_soc_codec *codec) | ||
740 | { | ||
741 | wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { | 728 | static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { |
746 | .probe = wm8940_probe, | 729 | .probe = wm8940_probe, |
747 | .remove = wm8940_remove, | ||
748 | .suspend = wm8940_suspend, | ||
749 | .resume = wm8940_resume, | ||
750 | .set_bias_level = wm8940_set_bias_level, | 730 | .set_bias_level = wm8940_set_bias_level, |
731 | .suspend_bias_off = true, | ||
732 | |||
751 | .controls = wm8940_snd_controls, | 733 | .controls = wm8940_snd_controls, |
752 | .num_controls = ARRAY_SIZE(wm8940_snd_controls), | 734 | .num_controls = ARRAY_SIZE(wm8940_snd_controls), |
753 | .dapm_widgets = wm8940_dapm_widgets, | 735 | .dapm_widgets = wm8940_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 09d91d9dc4ee..1173f7fef5a7 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c | |||
@@ -866,29 +866,6 @@ static struct snd_soc_dai_driver wm8955_dai = { | |||
866 | .ops = &wm8955_dai_ops, | 866 | .ops = &wm8955_dai_ops, |
867 | }; | 867 | }; |
868 | 868 | ||
869 | #ifdef CONFIG_PM | ||
870 | static int wm8955_suspend(struct snd_soc_codec *codec) | ||
871 | { | ||
872 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); | ||
873 | |||
874 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
875 | |||
876 | regcache_mark_dirty(wm8955->regmap); | ||
877 | |||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | static int wm8955_resume(struct snd_soc_codec *codec) | ||
882 | { | ||
883 | wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | #else | ||
888 | #define wm8955_suspend NULL | ||
889 | #define wm8955_resume NULL | ||
890 | #endif | ||
891 | |||
892 | static int wm8955_probe(struct snd_soc_codec *codec) | 869 | static int wm8955_probe(struct snd_soc_codec *codec) |
893 | { | 870 | { |
894 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); | 871 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); |
@@ -964,18 +941,10 @@ err_enable: | |||
964 | return ret; | 941 | return ret; |
965 | } | 942 | } |
966 | 943 | ||
967 | static int wm8955_remove(struct snd_soc_codec *codec) | ||
968 | { | ||
969 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { | 944 | static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { |
974 | .probe = wm8955_probe, | 945 | .probe = wm8955_probe, |
975 | .remove = wm8955_remove, | ||
976 | .suspend = wm8955_suspend, | ||
977 | .resume = wm8955_resume, | ||
978 | .set_bias_level = wm8955_set_bias_level, | 946 | .set_bias_level = wm8955_set_bias_level, |
947 | .suspend_bias_off = true, | ||
979 | 948 | ||
980 | .controls = wm8955_snd_controls, | 949 | .controls = wm8955_snd_controls, |
981 | .num_controls = ARRAY_SIZE(wm8955_snd_controls), | 950 | .num_controls = ARRAY_SIZE(wm8955_snd_controls), |
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 0dada7f0105e..3cbc82b33292 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c | |||
@@ -867,9 +867,9 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context) | |||
867 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 867 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
868 | 868 | ||
869 | if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) { | 869 | if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) { |
870 | mutex_lock(&codec->mutex); | 870 | mutex_lock(&wm8994->fw_lock); |
871 | wm8994->enh_eq = fw; | 871 | wm8994->enh_eq = fw; |
872 | mutex_unlock(&codec->mutex); | 872 | mutex_unlock(&wm8994->fw_lock); |
873 | } | 873 | } |
874 | } | 874 | } |
875 | 875 | ||
@@ -879,9 +879,9 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) | |||
879 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 879 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
880 | 880 | ||
881 | if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) { | 881 | if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) { |
882 | mutex_lock(&codec->mutex); | 882 | mutex_lock(&wm8994->fw_lock); |
883 | wm8994->mbc_vss = fw; | 883 | wm8994->mbc_vss = fw; |
884 | mutex_unlock(&codec->mutex); | 884 | mutex_unlock(&wm8994->fw_lock); |
885 | } | 885 | } |
886 | } | 886 | } |
887 | 887 | ||
@@ -891,9 +891,9 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context) | |||
891 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 891 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
892 | 892 | ||
893 | if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) { | 893 | if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) { |
894 | mutex_lock(&codec->mutex); | 894 | mutex_lock(&wm8994->fw_lock); |
895 | wm8994->mbc = fw; | 895 | wm8994->mbc = fw; |
896 | mutex_unlock(&codec->mutex); | 896 | mutex_unlock(&wm8994->fw_lock); |
897 | } | 897 | } |
898 | } | 898 | } |
899 | 899 | ||
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 4dc4e85116cd..031a1ae71d94 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -125,9 +125,10 @@ struct wm8960_priv { | |||
125 | struct snd_soc_dapm_widget *out3; | 125 | struct snd_soc_dapm_widget *out3; |
126 | bool deemph; | 126 | bool deemph; |
127 | int playback_fs; | 127 | int playback_fs; |
128 | struct wm8960_data pdata; | ||
128 | }; | 129 | }; |
129 | 130 | ||
130 | #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) | 131 | #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) |
131 | 132 | ||
132 | /* enumerated controls */ | 133 | /* enumerated controls */ |
133 | static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", | 134 | static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", |
@@ -440,8 +441,8 @@ static const struct snd_soc_dapm_route audio_paths_capless[] = { | |||
440 | 441 | ||
441 | static int wm8960_add_widgets(struct snd_soc_codec *codec) | 442 | static int wm8960_add_widgets(struct snd_soc_codec *codec) |
442 | { | 443 | { |
443 | struct wm8960_data *pdata = codec->dev->platform_data; | ||
444 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | 444 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); |
445 | struct wm8960_data *pdata = &wm8960->pdata; | ||
445 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 446 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
446 | struct snd_soc_dapm_widget *w; | 447 | struct snd_soc_dapm_widget *w; |
447 | 448 | ||
@@ -942,56 +943,15 @@ static struct snd_soc_dai_driver wm8960_dai = { | |||
942 | .symmetric_rates = 1, | 943 | .symmetric_rates = 1, |
943 | }; | 944 | }; |
944 | 945 | ||
945 | static int wm8960_suspend(struct snd_soc_codec *codec) | ||
946 | { | ||
947 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
948 | |||
949 | wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | static int wm8960_resume(struct snd_soc_codec *codec) | ||
954 | { | ||
955 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
956 | |||
957 | wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | static int wm8960_probe(struct snd_soc_codec *codec) | 946 | static int wm8960_probe(struct snd_soc_codec *codec) |
962 | { | 947 | { |
963 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | 948 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); |
964 | struct wm8960_data *pdata = dev_get_platdata(codec->dev); | 949 | struct wm8960_data *pdata = &wm8960->pdata; |
965 | int ret; | ||
966 | |||
967 | wm8960->set_bias_level = wm8960_set_bias_level_out3; | ||
968 | |||
969 | if (!pdata) { | ||
970 | dev_warn(codec->dev, "No platform data supplied\n"); | ||
971 | } else { | ||
972 | if (pdata->capless) | ||
973 | wm8960->set_bias_level = wm8960_set_bias_level_capless; | ||
974 | } | ||
975 | |||
976 | ret = wm8960_reset(codec); | ||
977 | if (ret < 0) { | ||
978 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
979 | return ret; | ||
980 | } | ||
981 | |||
982 | wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
983 | 950 | ||
984 | /* Latch the update bits */ | 951 | if (pdata->capless) |
985 | snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100); | 952 | wm8960->set_bias_level = wm8960_set_bias_level_capless; |
986 | snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100); | 953 | else |
987 | snd_soc_update_bits(codec, WM8960_LADC, 0x100, 0x100); | 954 | wm8960->set_bias_level = wm8960_set_bias_level_out3; |
988 | snd_soc_update_bits(codec, WM8960_RADC, 0x100, 0x100); | ||
989 | snd_soc_update_bits(codec, WM8960_LDAC, 0x100, 0x100); | ||
990 | snd_soc_update_bits(codec, WM8960_RDAC, 0x100, 0x100); | ||
991 | snd_soc_update_bits(codec, WM8960_LOUT1, 0x100, 0x100); | ||
992 | snd_soc_update_bits(codec, WM8960_ROUT1, 0x100, 0x100); | ||
993 | snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100); | ||
994 | snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100); | ||
995 | 955 | ||
996 | snd_soc_add_codec_controls(codec, wm8960_snd_controls, | 956 | snd_soc_add_codec_controls(codec, wm8960_snd_controls, |
997 | ARRAY_SIZE(wm8960_snd_controls)); | 957 | ARRAY_SIZE(wm8960_snd_controls)); |
@@ -1000,21 +960,10 @@ static int wm8960_probe(struct snd_soc_codec *codec) | |||
1000 | return 0; | 960 | return 0; |
1001 | } | 961 | } |
1002 | 962 | ||
1003 | /* power down chip */ | ||
1004 | static int wm8960_remove(struct snd_soc_codec *codec) | ||
1005 | { | ||
1006 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
1007 | |||
1008 | wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | static struct snd_soc_codec_driver soc_codec_dev_wm8960 = { | 963 | static struct snd_soc_codec_driver soc_codec_dev_wm8960 = { |
1013 | .probe = wm8960_probe, | 964 | .probe = wm8960_probe, |
1014 | .remove = wm8960_remove, | ||
1015 | .suspend = wm8960_suspend, | ||
1016 | .resume = wm8960_resume, | ||
1017 | .set_bias_level = wm8960_set_bias_level, | 965 | .set_bias_level = wm8960_set_bias_level, |
966 | .suspend_bias_off = true, | ||
1018 | }; | 967 | }; |
1019 | 968 | ||
1020 | static const struct regmap_config wm8960_regmap = { | 969 | static const struct regmap_config wm8960_regmap = { |
@@ -1029,6 +978,18 @@ static const struct regmap_config wm8960_regmap = { | |||
1029 | .volatile_reg = wm8960_volatile, | 978 | .volatile_reg = wm8960_volatile, |
1030 | }; | 979 | }; |
1031 | 980 | ||
981 | static void wm8960_set_pdata_from_of(struct i2c_client *i2c, | ||
982 | struct wm8960_data *pdata) | ||
983 | { | ||
984 | const struct device_node *np = i2c->dev.of_node; | ||
985 | |||
986 | if (of_property_read_bool(np, "wlf,capless")) | ||
987 | pdata->capless = true; | ||
988 | |||
989 | if (of_property_read_bool(np, "wlf,shared-lrclk")) | ||
990 | pdata->shared_lrclk = true; | ||
991 | } | ||
992 | |||
1032 | static int wm8960_i2c_probe(struct i2c_client *i2c, | 993 | static int wm8960_i2c_probe(struct i2c_client *i2c, |
1033 | const struct i2c_device_id *id) | 994 | const struct i2c_device_id *id) |
1034 | { | 995 | { |
@@ -1045,7 +1006,18 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, | |||
1045 | if (IS_ERR(wm8960->regmap)) | 1006 | if (IS_ERR(wm8960->regmap)) |
1046 | return PTR_ERR(wm8960->regmap); | 1007 | return PTR_ERR(wm8960->regmap); |
1047 | 1008 | ||
1048 | if (pdata && pdata->shared_lrclk) { | 1009 | if (pdata) |
1010 | memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data)); | ||
1011 | else if (i2c->dev.of_node) | ||
1012 | wm8960_set_pdata_from_of(i2c, &wm8960->pdata); | ||
1013 | |||
1014 | ret = wm8960_reset(wm8960->regmap); | ||
1015 | if (ret != 0) { | ||
1016 | dev_err(&i2c->dev, "Failed to issue reset\n"); | ||
1017 | return ret; | ||
1018 | } | ||
1019 | |||
1020 | if (wm8960->pdata.shared_lrclk) { | ||
1049 | ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, | 1021 | ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, |
1050 | 0x4, 0x4); | 1022 | 0x4, 0x4); |
1051 | if (ret != 0) { | 1023 | if (ret != 0) { |
@@ -1055,6 +1027,18 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, | |||
1055 | } | 1027 | } |
1056 | } | 1028 | } |
1057 | 1029 | ||
1030 | /* Latch the update bits */ | ||
1031 | regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x100, 0x100); | ||
1032 | regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x100, 0x100); | ||
1033 | regmap_update_bits(wm8960->regmap, WM8960_LADC, 0x100, 0x100); | ||
1034 | regmap_update_bits(wm8960->regmap, WM8960_RADC, 0x100, 0x100); | ||
1035 | regmap_update_bits(wm8960->regmap, WM8960_LDAC, 0x100, 0x100); | ||
1036 | regmap_update_bits(wm8960->regmap, WM8960_RDAC, 0x100, 0x100); | ||
1037 | regmap_update_bits(wm8960->regmap, WM8960_LOUT1, 0x100, 0x100); | ||
1038 | regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100); | ||
1039 | regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100); | ||
1040 | regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100); | ||
1041 | |||
1058 | i2c_set_clientdata(i2c, wm8960); | 1042 | i2c_set_clientdata(i2c, wm8960); |
1059 | 1043 | ||
1060 | ret = snd_soc_register_codec(&i2c->dev, | 1044 | ret = snd_soc_register_codec(&i2c->dev, |
@@ -1075,10 +1059,17 @@ static const struct i2c_device_id wm8960_i2c_id[] = { | |||
1075 | }; | 1059 | }; |
1076 | MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); | 1060 | MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); |
1077 | 1061 | ||
1062 | static const struct of_device_id wm8960_of_match[] = { | ||
1063 | { .compatible = "wlf,wm8960", }, | ||
1064 | { } | ||
1065 | }; | ||
1066 | MODULE_DEVICE_TABLE(of, wm8960_of_match); | ||
1067 | |||
1078 | static struct i2c_driver wm8960_i2c_driver = { | 1068 | static struct i2c_driver wm8960_i2c_driver = { |
1079 | .driver = { | 1069 | .driver = { |
1080 | .name = "wm8960", | 1070 | .name = "wm8960", |
1081 | .owner = THIS_MODULE, | 1071 | .owner = THIS_MODULE, |
1072 | .of_match_table = wm8960_of_match, | ||
1082 | }, | 1073 | }, |
1083 | .probe = wm8960_i2c_probe, | 1074 | .probe = wm8960_i2c_probe, |
1084 | .remove = wm8960_i2c_remove, | 1075 | .remove = wm8960_i2c_remove, |
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 41d23e920ad5..eeffd05384b4 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c | |||
@@ -835,7 +835,6 @@ static struct snd_soc_dai_driver wm8961_dai = { | |||
835 | 835 | ||
836 | static int wm8961_probe(struct snd_soc_codec *codec) | 836 | static int wm8961_probe(struct snd_soc_codec *codec) |
837 | { | 837 | { |
838 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
839 | u16 reg; | 838 | u16 reg; |
840 | 839 | ||
841 | /* Enable class W */ | 840 | /* Enable class W */ |
@@ -871,50 +870,33 @@ static int wm8961_probe(struct snd_soc_codec *codec) | |||
871 | reg &= ~WM8961_MANUAL_MODE; | 870 | reg &= ~WM8961_MANUAL_MODE; |
872 | snd_soc_write(codec, WM8961_CLOCKING_3, reg); | 871 | snd_soc_write(codec, WM8961_CLOCKING_3, reg); |
873 | 872 | ||
874 | wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
875 | |||
876 | snd_soc_add_codec_controls(codec, wm8961_snd_controls, | ||
877 | ARRAY_SIZE(wm8961_snd_controls)); | ||
878 | snd_soc_dapm_new_controls(dapm, wm8961_dapm_widgets, | ||
879 | ARRAY_SIZE(wm8961_dapm_widgets)); | ||
880 | snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); | ||
881 | |||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | static int wm8961_remove(struct snd_soc_codec *codec) | ||
886 | { | ||
887 | wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
888 | return 0; | 873 | return 0; |
889 | } | 874 | } |
890 | 875 | ||
891 | #ifdef CONFIG_PM | 876 | #ifdef CONFIG_PM |
892 | static int wm8961_suspend(struct snd_soc_codec *codec) | ||
893 | { | ||
894 | wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
895 | |||
896 | return 0; | ||
897 | } | ||
898 | 877 | ||
899 | static int wm8961_resume(struct snd_soc_codec *codec) | 878 | static int wm8961_resume(struct snd_soc_codec *codec) |
900 | { | 879 | { |
901 | snd_soc_cache_sync(codec); | 880 | snd_soc_cache_sync(codec); |
902 | 881 | ||
903 | wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
904 | |||
905 | return 0; | 882 | return 0; |
906 | } | 883 | } |
907 | #else | 884 | #else |
908 | #define wm8961_suspend NULL | ||
909 | #define wm8961_resume NULL | 885 | #define wm8961_resume NULL |
910 | #endif | 886 | #endif |
911 | 887 | ||
912 | static struct snd_soc_codec_driver soc_codec_dev_wm8961 = { | 888 | static struct snd_soc_codec_driver soc_codec_dev_wm8961 = { |
913 | .probe = wm8961_probe, | 889 | .probe = wm8961_probe, |
914 | .remove = wm8961_remove, | ||
915 | .suspend = wm8961_suspend, | ||
916 | .resume = wm8961_resume, | 890 | .resume = wm8961_resume, |
917 | .set_bias_level = wm8961_set_bias_level, | 891 | .set_bias_level = wm8961_set_bias_level, |
892 | .suspend_bias_off = true, | ||
893 | |||
894 | .controls = wm8961_snd_controls, | ||
895 | .num_controls = ARRAY_SIZE(wm8961_snd_controls), | ||
896 | .dapm_widgets = wm8961_dapm_widgets, | ||
897 | .num_dapm_widgets = ARRAY_SIZE(wm8961_dapm_widgets), | ||
898 | .dapm_routes = audio_paths, | ||
899 | .num_dapm_routes = ARRAY_SIZE(audio_paths), | ||
918 | }; | 900 | }; |
919 | 901 | ||
920 | static const struct regmap_config wm8961_regmap = { | 902 | static const struct regmap_config wm8961_regmap = { |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 9077411e62ce..1534d88a66e9 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/regulator/consumer.h> | 26 | #include <linux/regulator/consumer.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/mutex.h> | ||
29 | #include <sound/core.h> | 30 | #include <sound/core.h> |
30 | #include <sound/jack.h> | 31 | #include <sound/jack.h> |
31 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
@@ -67,6 +68,7 @@ struct wm8962_priv { | |||
67 | int fll_fref; | 68 | int fll_fref; |
68 | int fll_fout; | 69 | int fll_fout; |
69 | 70 | ||
71 | struct mutex dsp2_ena_lock; | ||
70 | u16 dsp2_ena; | 72 | u16 dsp2_ena; |
71 | 73 | ||
72 | struct delayed_work mic_work; | 74 | struct delayed_work mic_work; |
@@ -1570,7 +1572,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, | |||
1570 | int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) & | 1572 | int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) & |
1571 | WM8962_DSP2_ENA; | 1573 | WM8962_DSP2_ENA; |
1572 | 1574 | ||
1573 | mutex_lock(&codec->mutex); | 1575 | mutex_lock(&wm8962->dsp2_ena_lock); |
1574 | 1576 | ||
1575 | if (ucontrol->value.integer.value[0]) | 1577 | if (ucontrol->value.integer.value[0]) |
1576 | wm8962->dsp2_ena |= 1 << shift; | 1578 | wm8962->dsp2_ena |= 1 << shift; |
@@ -1590,7 +1592,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, | |||
1590 | } | 1592 | } |
1591 | 1593 | ||
1592 | out: | 1594 | out: |
1593 | mutex_unlock(&codec->mutex); | 1595 | mutex_unlock(&wm8962->dsp2_ena_lock); |
1594 | 1596 | ||
1595 | return ret; | 1597 | return ret; |
1596 | } | 1598 | } |
@@ -3552,11 +3554,12 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, | |||
3552 | unsigned int reg; | 3554 | unsigned int reg; |
3553 | int ret, i, irq_pol, trigger; | 3555 | int ret, i, irq_pol, trigger; |
3554 | 3556 | ||
3555 | wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv), | 3557 | wm8962 = devm_kzalloc(&i2c->dev, sizeof(*wm8962), GFP_KERNEL); |
3556 | GFP_KERNEL); | ||
3557 | if (wm8962 == NULL) | 3558 | if (wm8962 == NULL) |
3558 | return -ENOMEM; | 3559 | return -ENOMEM; |
3559 | 3560 | ||
3561 | mutex_init(&wm8962->dsp2_ena_lock); | ||
3562 | |||
3560 | i2c_set_clientdata(i2c, wm8962); | 3563 | i2c_set_clientdata(i2c, wm8962); |
3561 | 3564 | ||
3562 | INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work); | 3565 | INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work); |
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 682e9eda1019..ff0e4646b934 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c | |||
@@ -568,18 +568,6 @@ static struct snd_soc_dai_driver wm8974_dai = { | |||
568 | .symmetric_rates = 1, | 568 | .symmetric_rates = 1, |
569 | }; | 569 | }; |
570 | 570 | ||
571 | static int wm8974_suspend(struct snd_soc_codec *codec) | ||
572 | { | ||
573 | wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static int wm8974_resume(struct snd_soc_codec *codec) | ||
578 | { | ||
579 | wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static const struct regmap_config wm8974_regmap = { | 571 | static const struct regmap_config wm8974_regmap = { |
584 | .reg_bits = 7, | 572 | .reg_bits = 7, |
585 | .val_bits = 9, | 573 | .val_bits = 9, |
@@ -599,24 +587,13 @@ static int wm8974_probe(struct snd_soc_codec *codec) | |||
599 | return ret; | 587 | return ret; |
600 | } | 588 | } |
601 | 589 | ||
602 | wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
603 | |||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | /* power down chip */ | ||
608 | static int wm8974_remove(struct snd_soc_codec *codec) | ||
609 | { | ||
610 | wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
611 | return 0; | 590 | return 0; |
612 | } | 591 | } |
613 | 592 | ||
614 | static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { | 593 | static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { |
615 | .probe = wm8974_probe, | 594 | .probe = wm8974_probe, |
616 | .remove = wm8974_remove, | ||
617 | .suspend = wm8974_suspend, | ||
618 | .resume = wm8974_resume, | ||
619 | .set_bias_level = wm8974_set_bias_level, | 595 | .set_bias_level = wm8974_set_bias_level, |
596 | .suspend_bias_off = true, | ||
620 | 597 | ||
621 | .controls = wm8974_snd_controls, | 598 | .controls = wm8974_snd_controls, |
622 | .num_controls = ARRAY_SIZE(wm8974_snd_controls), | 599 | .num_controls = ARRAY_SIZE(wm8974_snd_controls), |
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index ee2ba574952b..cf7032911721 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c | |||
@@ -991,21 +991,11 @@ static int wm8978_probe(struct snd_soc_codec *codec) | |||
991 | for (i = 0; i < ARRAY_SIZE(update_reg); i++) | 991 | for (i = 0; i < ARRAY_SIZE(update_reg); i++) |
992 | snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100); | 992 | snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100); |
993 | 993 | ||
994 | wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | /* power down chip */ | ||
1000 | static int wm8978_remove(struct snd_soc_codec *codec) | ||
1001 | { | ||
1002 | wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1003 | return 0; | 994 | return 0; |
1004 | } | 995 | } |
1005 | 996 | ||
1006 | static struct snd_soc_codec_driver soc_codec_dev_wm8978 = { | 997 | static struct snd_soc_codec_driver soc_codec_dev_wm8978 = { |
1007 | .probe = wm8978_probe, | 998 | .probe = wm8978_probe, |
1008 | .remove = wm8978_remove, | ||
1009 | .suspend = wm8978_suspend, | 999 | .suspend = wm8978_suspend, |
1010 | .resume = wm8978_resume, | 1000 | .resume = wm8978_resume, |
1011 | .set_bias_level = wm8978_set_bias_level, | 1001 | .set_bias_level = wm8978_set_bias_level, |
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index ac5defda8824..5d1cf08a72b8 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c | |||
@@ -967,29 +967,6 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec, | |||
967 | return 0; | 967 | return 0; |
968 | } | 968 | } |
969 | 969 | ||
970 | #ifdef CONFIG_PM | ||
971 | static int wm8983_suspend(struct snd_soc_codec *codec) | ||
972 | { | ||
973 | wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | static int wm8983_resume(struct snd_soc_codec *codec) | ||
978 | { | ||
979 | wm8983_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
980 | return 0; | ||
981 | } | ||
982 | #else | ||
983 | #define wm8983_suspend NULL | ||
984 | #define wm8983_resume NULL | ||
985 | #endif | ||
986 | |||
987 | static int wm8983_remove(struct snd_soc_codec *codec) | ||
988 | { | ||
989 | wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static int wm8983_probe(struct snd_soc_codec *codec) | 970 | static int wm8983_probe(struct snd_soc_codec *codec) |
994 | { | 971 | { |
995 | int ret; | 972 | int ret; |
@@ -1055,10 +1032,8 @@ static struct snd_soc_dai_driver wm8983_dai = { | |||
1055 | 1032 | ||
1056 | static struct snd_soc_codec_driver soc_codec_dev_wm8983 = { | 1033 | static struct snd_soc_codec_driver soc_codec_dev_wm8983 = { |
1057 | .probe = wm8983_probe, | 1034 | .probe = wm8983_probe, |
1058 | .remove = wm8983_remove, | ||
1059 | .suspend = wm8983_suspend, | ||
1060 | .resume = wm8983_resume, | ||
1061 | .set_bias_level = wm8983_set_bias_level, | 1035 | .set_bias_level = wm8983_set_bias_level, |
1036 | .suspend_bias_off = true, | ||
1062 | .controls = wm8983_snd_controls, | 1037 | .controls = wm8983_snd_controls, |
1063 | .num_controls = ARRAY_SIZE(wm8983_snd_controls), | 1038 | .num_controls = ARRAY_SIZE(wm8983_snd_controls), |
1064 | .dapm_widgets = wm8983_dapm_widgets, | 1039 | .dapm_widgets = wm8983_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index ee380190399f..0b3b54c9971d 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c | |||
@@ -961,29 +961,6 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec, | |||
961 | return 0; | 961 | return 0; |
962 | } | 962 | } |
963 | 963 | ||
964 | #ifdef CONFIG_PM | ||
965 | static int wm8985_suspend(struct snd_soc_codec *codec) | ||
966 | { | ||
967 | wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static int wm8985_resume(struct snd_soc_codec *codec) | ||
972 | { | ||
973 | wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
974 | return 0; | ||
975 | } | ||
976 | #else | ||
977 | #define wm8985_suspend NULL | ||
978 | #define wm8985_resume NULL | ||
979 | #endif | ||
980 | |||
981 | static int wm8985_remove(struct snd_soc_codec *codec) | ||
982 | { | ||
983 | wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
984 | return 0; | ||
985 | } | ||
986 | |||
987 | static int wm8985_probe(struct snd_soc_codec *codec) | 964 | static int wm8985_probe(struct snd_soc_codec *codec) |
988 | { | 965 | { |
989 | size_t i; | 966 | size_t i; |
@@ -1023,7 +1000,6 @@ static int wm8985_probe(struct snd_soc_codec *codec) | |||
1023 | snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT, | 1000 | snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT, |
1024 | WM8985_BIASCUT); | 1001 | WM8985_BIASCUT); |
1025 | 1002 | ||
1026 | wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1027 | return 0; | 1003 | return 0; |
1028 | 1004 | ||
1029 | err_reg_enable: | 1005 | err_reg_enable: |
@@ -1064,10 +1040,8 @@ static struct snd_soc_dai_driver wm8985_dai = { | |||
1064 | 1040 | ||
1065 | static struct snd_soc_codec_driver soc_codec_dev_wm8985 = { | 1041 | static struct snd_soc_codec_driver soc_codec_dev_wm8985 = { |
1066 | .probe = wm8985_probe, | 1042 | .probe = wm8985_probe, |
1067 | .remove = wm8985_remove, | ||
1068 | .suspend = wm8985_suspend, | ||
1069 | .resume = wm8985_resume, | ||
1070 | .set_bias_level = wm8985_set_bias_level, | 1043 | .set_bias_level = wm8985_set_bias_level, |
1044 | .suspend_bias_off = true, | ||
1071 | 1045 | ||
1072 | .controls = wm8985_snd_controls, | 1046 | .controls = wm8985_snd_controls, |
1073 | .num_controls = ARRAY_SIZE(wm8985_snd_controls), | 1047 | .num_controls = ARRAY_SIZE(wm8985_snd_controls), |
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index a5130d965146..e418199155a8 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c | |||
@@ -793,21 +793,6 @@ static struct snd_soc_dai_driver wm8988_dai = { | |||
793 | .symmetric_rates = 1, | 793 | .symmetric_rates = 1, |
794 | }; | 794 | }; |
795 | 795 | ||
796 | static int wm8988_suspend(struct snd_soc_codec *codec) | ||
797 | { | ||
798 | struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); | ||
799 | |||
800 | wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
801 | regcache_mark_dirty(wm8988->regmap); | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int wm8988_resume(struct snd_soc_codec *codec) | ||
806 | { | ||
807 | wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | static int wm8988_probe(struct snd_soc_codec *codec) | 796 | static int wm8988_probe(struct snd_soc_codec *codec) |
812 | { | 797 | { |
813 | int ret = 0; | 798 | int ret = 0; |
@@ -825,23 +810,13 @@ static int wm8988_probe(struct snd_soc_codec *codec) | |||
825 | snd_soc_update_bits(codec, WM8988_ROUT2V, 0x0100, 0x0100); | 810 | snd_soc_update_bits(codec, WM8988_ROUT2V, 0x0100, 0x0100); |
826 | snd_soc_update_bits(codec, WM8988_RINVOL, 0x0100, 0x0100); | 811 | snd_soc_update_bits(codec, WM8988_RINVOL, 0x0100, 0x0100); |
827 | 812 | ||
828 | wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | static int wm8988_remove(struct snd_soc_codec *codec) | ||
834 | { | ||
835 | wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
836 | return 0; | 813 | return 0; |
837 | } | 814 | } |
838 | 815 | ||
839 | static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { | 816 | static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { |
840 | .probe = wm8988_probe, | 817 | .probe = wm8988_probe, |
841 | .remove = wm8988_remove, | ||
842 | .suspend = wm8988_suspend, | ||
843 | .resume = wm8988_resume, | ||
844 | .set_bias_level = wm8988_set_bias_level, | 818 | .set_bias_level = wm8988_set_bias_level, |
819 | .suspend_bias_off = true, | ||
845 | 820 | ||
846 | .controls = wm8988_snd_controls, | 821 | .controls = wm8988_snd_controls, |
847 | .num_controls = ARRAY_SIZE(wm8988_snd_controls), | 822 | .num_controls = ARRAY_SIZE(wm8988_snd_controls), |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 03e43e3f395e..8a584229310a 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -1271,18 +1271,6 @@ static struct snd_soc_dai_driver wm8990_dai = { | |||
1271 | .ops = &wm8990_dai_ops, | 1271 | .ops = &wm8990_dai_ops, |
1272 | }; | 1272 | }; |
1273 | 1273 | ||
1274 | static int wm8990_suspend(struct snd_soc_codec *codec) | ||
1275 | { | ||
1276 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1280 | static int wm8990_resume(struct snd_soc_codec *codec) | ||
1281 | { | ||
1282 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1283 | return 0; | ||
1284 | } | ||
1285 | |||
1286 | /* | 1274 | /* |
1287 | * initialise the WM8990 driver | 1275 | * initialise the WM8990 driver |
1288 | * register the mixer and dsp interfaces with the kernel | 1276 | * register the mixer and dsp interfaces with the kernel |
@@ -1309,19 +1297,11 @@ static int wm8990_probe(struct snd_soc_codec *codec) | |||
1309 | return 0; | 1297 | return 0; |
1310 | } | 1298 | } |
1311 | 1299 | ||
1312 | /* power down chip */ | ||
1313 | static int wm8990_remove(struct snd_soc_codec *codec) | ||
1314 | { | ||
1315 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | static struct snd_soc_codec_driver soc_codec_dev_wm8990 = { | 1300 | static struct snd_soc_codec_driver soc_codec_dev_wm8990 = { |
1320 | .probe = wm8990_probe, | 1301 | .probe = wm8990_probe, |
1321 | .remove = wm8990_remove, | ||
1322 | .suspend = wm8990_suspend, | ||
1323 | .resume = wm8990_resume, | ||
1324 | .set_bias_level = wm8990_set_bias_level, | 1302 | .set_bias_level = wm8990_set_bias_level, |
1303 | .suspend_bias_off = true, | ||
1304 | |||
1325 | .controls = wm8990_snd_controls, | 1305 | .controls = wm8990_snd_controls, |
1326 | .num_controls = ARRAY_SIZE(wm8990_snd_controls), | 1306 | .num_controls = ARRAY_SIZE(wm8990_snd_controls), |
1327 | .dapm_widgets = wm8990_dapm_widgets, | 1307 | .dapm_widgets = wm8990_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index d0be89731cdb..b0ac2c3e31b9 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c | |||
@@ -1227,32 +1227,6 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec, | |||
1227 | return 0; | 1227 | return 0; |
1228 | } | 1228 | } |
1229 | 1229 | ||
1230 | static int wm8991_suspend(struct snd_soc_codec *codec) | ||
1231 | { | ||
1232 | wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1233 | return 0; | ||
1234 | } | ||
1235 | |||
1236 | static int wm8991_resume(struct snd_soc_codec *codec) | ||
1237 | { | ||
1238 | wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1239 | return 0; | ||
1240 | } | ||
1241 | |||
1242 | /* power down chip */ | ||
1243 | static int wm8991_remove(struct snd_soc_codec *codec) | ||
1244 | { | ||
1245 | wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1246 | return 0; | ||
1247 | } | ||
1248 | |||
1249 | static int wm8991_probe(struct snd_soc_codec *codec) | ||
1250 | { | ||
1251 | wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1252 | |||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | #define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1230 | #define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
1257 | SNDRV_PCM_FMTBIT_S24_LE) | 1231 | SNDRV_PCM_FMTBIT_S24_LE) |
1258 | 1232 | ||
@@ -1293,11 +1267,9 @@ static struct snd_soc_dai_driver wm8991_dai = { | |||
1293 | }; | 1267 | }; |
1294 | 1268 | ||
1295 | static struct snd_soc_codec_driver soc_codec_dev_wm8991 = { | 1269 | static struct snd_soc_codec_driver soc_codec_dev_wm8991 = { |
1296 | .probe = wm8991_probe, | ||
1297 | .remove = wm8991_remove, | ||
1298 | .suspend = wm8991_suspend, | ||
1299 | .resume = wm8991_resume, | ||
1300 | .set_bias_level = wm8991_set_bias_level, | 1270 | .set_bias_level = wm8991_set_bias_level, |
1271 | .suspend_bias_off = true, | ||
1272 | |||
1301 | .controls = wm8991_snd_controls, | 1273 | .controls = wm8991_snd_controls, |
1302 | .num_controls = ARRAY_SIZE(wm8991_snd_controls), | 1274 | .num_controls = ARRAY_SIZE(wm8991_snd_controls), |
1303 | .dapm_widgets = wm8991_dapm_widgets, | 1275 | .dapm_widgets = wm8991_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 93b14eda355a..53c6fe359496 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -1486,7 +1486,6 @@ static int wm8993_probe(struct snd_soc_codec *codec) | |||
1486 | { | 1486 | { |
1487 | struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); | 1487 | struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); |
1488 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 1488 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
1489 | int ret; | ||
1490 | 1489 | ||
1491 | wm8993->hubs_data.hp_startup_mode = 1; | 1490 | wm8993->hubs_data.hp_startup_mode = 1; |
1492 | wm8993->hubs_data.dcs_codes_l = -2; | 1491 | wm8993->hubs_data.dcs_codes_l = -2; |
@@ -1518,10 +1517,6 @@ static int wm8993_probe(struct snd_soc_codec *codec) | |||
1518 | wm8993->pdata.micbias1_lvl, | 1517 | wm8993->pdata.micbias1_lvl, |
1519 | wm8993->pdata.micbias2_lvl); | 1518 | wm8993->pdata.micbias2_lvl); |
1520 | 1519 | ||
1521 | ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1522 | if (ret != 0) | ||
1523 | return ret; | ||
1524 | |||
1525 | snd_soc_add_codec_controls(codec, wm8993_snd_controls, | 1520 | snd_soc_add_codec_controls(codec, wm8993_snd_controls, |
1526 | ARRAY_SIZE(wm8993_snd_controls)); | 1521 | ARRAY_SIZE(wm8993_snd_controls)); |
1527 | if (wm8993->pdata.num_retune_configs != 0) { | 1522 | if (wm8993->pdata.num_retune_configs != 0) { |
@@ -1550,12 +1545,6 @@ static int wm8993_probe(struct snd_soc_codec *codec) | |||
1550 | 1545 | ||
1551 | } | 1546 | } |
1552 | 1547 | ||
1553 | static int wm8993_remove(struct snd_soc_codec *codec) | ||
1554 | { | ||
1555 | wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1556 | return 0; | ||
1557 | } | ||
1558 | |||
1559 | #ifdef CONFIG_PM | 1548 | #ifdef CONFIG_PM |
1560 | static int wm8993_suspend(struct snd_soc_codec *codec) | 1549 | static int wm8993_suspend(struct snd_soc_codec *codec) |
1561 | { | 1550 | { |
@@ -1629,7 +1618,6 @@ static const struct regmap_config wm8993_regmap = { | |||
1629 | 1618 | ||
1630 | static struct snd_soc_codec_driver soc_codec_dev_wm8993 = { | 1619 | static struct snd_soc_codec_driver soc_codec_dev_wm8993 = { |
1631 | .probe = wm8993_probe, | 1620 | .probe = wm8993_probe, |
1632 | .remove = wm8993_remove, | ||
1633 | .suspend = wm8993_suspend, | 1621 | .suspend = wm8993_suspend, |
1634 | .resume = wm8993_resume, | 1622 | .resume = wm8993_resume, |
1635 | .set_bias_level = wm8993_set_bias_level, | 1623 | .set_bias_level = wm8993_set_bias_level, |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index c3a2e751513f..36b767fa37a6 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -4455,6 +4455,8 @@ static int wm8994_probe(struct platform_device *pdev) | |||
4455 | return -ENOMEM; | 4455 | return -ENOMEM; |
4456 | platform_set_drvdata(pdev, wm8994); | 4456 | platform_set_drvdata(pdev, wm8994); |
4457 | 4457 | ||
4458 | mutex_init(&wm8994->fw_lock); | ||
4459 | |||
4458 | wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); | 4460 | wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); |
4459 | 4461 | ||
4460 | pm_runtime_enable(&pdev->dev); | 4462 | pm_runtime_enable(&pdev->dev); |
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 6536f8d45ac6..dd73387b1cc4 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/firmware.h> | 13 | #include <linux/firmware.h> |
14 | #include <linux/completion.h> | 14 | #include <linux/completion.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/mutex.h> | ||
16 | 17 | ||
17 | #include "wm_hubs.h" | 18 | #include "wm_hubs.h" |
18 | 19 | ||
@@ -156,6 +157,7 @@ struct wm8994_priv { | |||
156 | unsigned int aif1clk_disable:1; | 157 | unsigned int aif1clk_disable:1; |
157 | unsigned int aif2clk_disable:1; | 158 | unsigned int aif2clk_disable:1; |
158 | 159 | ||
160 | struct mutex fw_lock; | ||
159 | int dsp_active; | 161 | int dsp_active; |
160 | const struct firmware *cur_fw; | 162 | const struct firmware *cur_fw; |
161 | const struct firmware *mbc; | 163 | const struct firmware *mbc; |
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 1288edeb8c7d..c280f0a3a424 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c | |||
@@ -2004,7 +2004,6 @@ static int wm8995_remove(struct snd_soc_codec *codec) | |||
2004 | int i; | 2004 | int i; |
2005 | 2005 | ||
2006 | wm8995 = snd_soc_codec_get_drvdata(codec); | 2006 | wm8995 = snd_soc_codec_get_drvdata(codec); |
2007 | wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
2008 | 2007 | ||
2009 | for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i) | 2008 | for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i) |
2010 | regulator_unregister_notifier(wm8995->supplies[i].consumer, | 2009 | regulator_unregister_notifier(wm8995->supplies[i].consumer, |
@@ -2078,8 +2077,6 @@ static int wm8995_probe(struct snd_soc_codec *codec) | |||
2078 | goto err_reg_enable; | 2077 | goto err_reg_enable; |
2079 | } | 2078 | } |
2080 | 2079 | ||
2081 | wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2082 | |||
2083 | /* Latch volume updates (right only; we always do left then right). */ | 2080 | /* Latch volume updates (right only; we always do left then right). */ |
2084 | snd_soc_update_bits(codec, WM8995_AIF1_DAC1_RIGHT_VOLUME, | 2081 | snd_soc_update_bits(codec, WM8995_AIF1_DAC1_RIGHT_VOLUME, |
2085 | WM8995_AIF1DAC1_VU_MASK, WM8995_AIF1DAC1_VU); | 2082 | WM8995_AIF1DAC1_VU_MASK, WM8995_AIF1DAC1_VU); |
@@ -2102,13 +2099,6 @@ static int wm8995_probe(struct snd_soc_codec *codec) | |||
2102 | 2099 | ||
2103 | wm8995_update_class_w(codec); | 2100 | wm8995_update_class_w(codec); |
2104 | 2101 | ||
2105 | snd_soc_add_codec_controls(codec, wm8995_snd_controls, | ||
2106 | ARRAY_SIZE(wm8995_snd_controls)); | ||
2107 | snd_soc_dapm_new_controls(&codec->dapm, wm8995_dapm_widgets, | ||
2108 | ARRAY_SIZE(wm8995_dapm_widgets)); | ||
2109 | snd_soc_dapm_add_routes(&codec->dapm, wm8995_intercon, | ||
2110 | ARRAY_SIZE(wm8995_intercon)); | ||
2111 | |||
2112 | return 0; | 2102 | return 0; |
2113 | 2103 | ||
2114 | err_reg_enable: | 2104 | err_reg_enable: |
@@ -2205,6 +2195,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { | |||
2205 | .remove = wm8995_remove, | 2195 | .remove = wm8995_remove, |
2206 | .set_bias_level = wm8995_set_bias_level, | 2196 | .set_bias_level = wm8995_set_bias_level, |
2207 | .idle_bias_off = true, | 2197 | .idle_bias_off = true, |
2198 | |||
2199 | .controls = wm8995_snd_controls, | ||
2200 | .num_controls = ARRAY_SIZE(wm8995_snd_controls), | ||
2201 | .dapm_widgets = wm8995_dapm_widgets, | ||
2202 | .num_dapm_widgets = ARRAY_SIZE(wm8995_dapm_widgets), | ||
2203 | .dapm_routes = wm8995_intercon, | ||
2204 | .num_dapm_routes = ARRAY_SIZE(wm8995_intercon), | ||
2208 | }; | 2205 | }; |
2209 | 2206 | ||
2210 | static struct regmap_config wm8995_regmap = { | 2207 | static struct regmap_config wm8995_regmap = { |
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 0cdc9e2184ab..b1d946facd57 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -1277,15 +1277,8 @@ static int wm9081_probe(struct snd_soc_codec *codec) | |||
1277 | return 0; | 1277 | return 0; |
1278 | } | 1278 | } |
1279 | 1279 | ||
1280 | static int wm9081_remove(struct snd_soc_codec *codec) | ||
1281 | { | ||
1282 | wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1283 | return 0; | ||
1284 | } | ||
1285 | |||
1286 | static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { | 1280 | static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { |
1287 | .probe = wm9081_probe, | 1281 | .probe = wm9081_probe, |
1288 | .remove = wm9081_remove, | ||
1289 | 1282 | ||
1290 | .set_sysclk = wm9081_set_sysclk, | 1283 | .set_sysclk = wm9081_set_sysclk, |
1291 | .set_bias_level = wm9081_set_bias_level, | 1284 | .set_bias_level = wm9081_set_bias_level, |
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index c0b7f45dfa37..d3a800fa6f06 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c | |||
@@ -203,13 +203,14 @@ static const struct snd_soc_dapm_route wm9705_audio_map[] = { | |||
203 | /* We use a register cache to enhance read performance. */ | 203 | /* We use a register cache to enhance read performance. */ |
204 | static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) | 204 | static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) |
205 | { | 205 | { |
206 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
206 | u16 *cache = codec->reg_cache; | 207 | u16 *cache = codec->reg_cache; |
207 | 208 | ||
208 | switch (reg) { | 209 | switch (reg) { |
209 | case AC97_RESET: | 210 | case AC97_RESET: |
210 | case AC97_VENDOR_ID1: | 211 | case AC97_VENDOR_ID1: |
211 | case AC97_VENDOR_ID2: | 212 | case AC97_VENDOR_ID2: |
212 | return soc_ac97_ops->read(codec->ac97, reg); | 213 | return soc_ac97_ops->read(ac97, reg); |
213 | default: | 214 | default: |
214 | reg = reg >> 1; | 215 | reg = reg >> 1; |
215 | 216 | ||
@@ -223,9 +224,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) | |||
223 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 224 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
224 | unsigned int val) | 225 | unsigned int val) |
225 | { | 226 | { |
227 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
226 | u16 *cache = codec->reg_cache; | 228 | u16 *cache = codec->reg_cache; |
227 | 229 | ||
228 | soc_ac97_ops->write(codec->ac97, reg, val); | 230 | soc_ac97_ops->write(ac97, reg, val); |
229 | reg = reg >> 1; | 231 | reg = reg >> 1; |
230 | if (reg < (ARRAY_SIZE(wm9705_reg))) | 232 | if (reg < (ARRAY_SIZE(wm9705_reg))) |
231 | cache[reg] = val; | 233 | cache[reg] = val; |
@@ -263,7 +265,6 @@ static const struct snd_soc_dai_ops wm9705_dai_ops = { | |||
263 | static struct snd_soc_dai_driver wm9705_dai[] = { | 265 | static struct snd_soc_dai_driver wm9705_dai[] = { |
264 | { | 266 | { |
265 | .name = "wm9705-hifi", | 267 | .name = "wm9705-hifi", |
266 | .ac97_control = 1, | ||
267 | .playback = { | 268 | .playback = { |
268 | .stream_name = "HiFi Playback", | 269 | .stream_name = "HiFi Playback", |
269 | .channels_min = 1, | 270 | .channels_min = 1, |
@@ -294,36 +295,41 @@ static struct snd_soc_dai_driver wm9705_dai[] = { | |||
294 | 295 | ||
295 | static int wm9705_reset(struct snd_soc_codec *codec) | 296 | static int wm9705_reset(struct snd_soc_codec *codec) |
296 | { | 297 | { |
298 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
299 | |||
297 | if (soc_ac97_ops->reset) { | 300 | if (soc_ac97_ops->reset) { |
298 | soc_ac97_ops->reset(codec->ac97); | 301 | soc_ac97_ops->reset(ac97); |
299 | if (ac97_read(codec, 0) == wm9705_reg[0]) | 302 | if (ac97_read(codec, 0) == wm9705_reg[0]) |
300 | return 0; /* Success */ | 303 | return 0; /* Success */ |
301 | } | 304 | } |
302 | 305 | ||
306 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); | ||
307 | |||
303 | return -EIO; | 308 | return -EIO; |
304 | } | 309 | } |
305 | 310 | ||
306 | #ifdef CONFIG_PM | 311 | #ifdef CONFIG_PM |
307 | static int wm9705_soc_suspend(struct snd_soc_codec *codec) | 312 | static int wm9705_soc_suspend(struct snd_soc_codec *codec) |
308 | { | 313 | { |
309 | soc_ac97_ops->write(codec->ac97, AC97_POWERDOWN, 0xffff); | 314 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
315 | |||
316 | soc_ac97_ops->write(ac97, AC97_POWERDOWN, 0xffff); | ||
310 | 317 | ||
311 | return 0; | 318 | return 0; |
312 | } | 319 | } |
313 | 320 | ||
314 | static int wm9705_soc_resume(struct snd_soc_codec *codec) | 321 | static int wm9705_soc_resume(struct snd_soc_codec *codec) |
315 | { | 322 | { |
323 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
316 | int i, ret; | 324 | int i, ret; |
317 | u16 *cache = codec->reg_cache; | 325 | u16 *cache = codec->reg_cache; |
318 | 326 | ||
319 | ret = wm9705_reset(codec); | 327 | ret = wm9705_reset(codec); |
320 | if (ret < 0) { | 328 | if (ret < 0) |
321 | printk(KERN_ERR "could not reset AC97 codec\n"); | ||
322 | return ret; | 329 | return ret; |
323 | } | ||
324 | 330 | ||
325 | for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { | 331 | for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { |
326 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); | 332 | soc_ac97_ops->write(ac97, i, cache[i>>1]); |
327 | } | 333 | } |
328 | 334 | ||
329 | return 0; | 335 | return 0; |
@@ -335,31 +341,34 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) | |||
335 | 341 | ||
336 | static int wm9705_soc_probe(struct snd_soc_codec *codec) | 342 | static int wm9705_soc_probe(struct snd_soc_codec *codec) |
337 | { | 343 | { |
344 | struct snd_ac97 *ac97; | ||
338 | int ret = 0; | 345 | int ret = 0; |
339 | 346 | ||
340 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | 347 | ac97 = snd_soc_new_ac97_codec(codec); |
341 | if (ret < 0) { | 348 | if (IS_ERR(ac97)) { |
342 | printk(KERN_ERR "wm9705: failed to register AC97 codec\n"); | 349 | ret = PTR_ERR(ac97); |
350 | dev_err(codec->dev, "Failed to register AC97 codec\n"); | ||
343 | return ret; | 351 | return ret; |
344 | } | 352 | } |
345 | 353 | ||
354 | snd_soc_codec_set_drvdata(codec, ac97); | ||
355 | |||
346 | ret = wm9705_reset(codec); | 356 | ret = wm9705_reset(codec); |
347 | if (ret) | 357 | if (ret) |
348 | goto reset_err; | 358 | goto reset_err; |
349 | 359 | ||
350 | snd_soc_add_codec_controls(codec, wm9705_snd_ac97_controls, | ||
351 | ARRAY_SIZE(wm9705_snd_ac97_controls)); | ||
352 | |||
353 | return 0; | 360 | return 0; |
354 | 361 | ||
355 | reset_err: | 362 | reset_err: |
356 | snd_soc_free_ac97_codec(codec); | 363 | snd_soc_free_ac97_codec(ac97); |
357 | return ret; | 364 | return ret; |
358 | } | 365 | } |
359 | 366 | ||
360 | static int wm9705_soc_remove(struct snd_soc_codec *codec) | 367 | static int wm9705_soc_remove(struct snd_soc_codec *codec) |
361 | { | 368 | { |
362 | snd_soc_free_ac97_codec(codec); | 369 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
370 | |||
371 | snd_soc_free_ac97_codec(ac97); | ||
363 | return 0; | 372 | return 0; |
364 | } | 373 | } |
365 | 374 | ||
@@ -374,6 +383,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = { | |||
374 | .reg_word_size = sizeof(u16), | 383 | .reg_word_size = sizeof(u16), |
375 | .reg_cache_step = 2, | 384 | .reg_cache_step = 2, |
376 | .reg_cache_default = wm9705_reg, | 385 | .reg_cache_default = wm9705_reg, |
386 | |||
387 | .controls = wm9705_snd_ac97_controls, | ||
388 | .num_controls = ARRAY_SIZE(wm9705_snd_ac97_controls), | ||
377 | .dapm_widgets = wm9705_dapm_widgets, | 389 | .dapm_widgets = wm9705_dapm_widgets, |
378 | .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets), | 390 | .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets), |
379 | .dapm_routes = wm9705_audio_map, | 391 | .dapm_routes = wm9705_audio_map, |
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index c5eb746087b4..52a211be5b47 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -23,6 +23,12 @@ | |||
23 | #include <sound/tlv.h> | 23 | #include <sound/tlv.h> |
24 | #include "wm9712.h" | 24 | #include "wm9712.h" |
25 | 25 | ||
26 | struct wm9712_priv { | ||
27 | struct snd_ac97 *ac97; | ||
28 | unsigned int hp_mixer[2]; | ||
29 | struct mutex lock; | ||
30 | }; | ||
31 | |||
26 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 32 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
27 | unsigned int reg); | 33 | unsigned int reg); |
28 | static int ac97_write(struct snd_soc_codec *codec, | 34 | static int ac97_write(struct snd_soc_codec *codec, |
@@ -48,12 +54,10 @@ static const u16 wm9712_reg[] = { | |||
48 | 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ | 54 | 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ |
49 | 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ | 55 | 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ |
50 | 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */ | 56 | 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */ |
51 | 0x0000, 0x0000 /* virtual hp mixers */ | ||
52 | }; | 57 | }; |
53 | 58 | ||
54 | /* virtual HP mixers regs */ | 59 | #define HPL_MIXER 0x0 |
55 | #define HPL_MIXER 0x80 | 60 | #define HPR_MIXER 0x1 |
56 | #define HPR_MIXER 0x82 | ||
57 | 61 | ||
58 | static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"}; | 62 | static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"}; |
59 | static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"}; | 63 | static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"}; |
@@ -157,75 +161,108 @@ SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv), | |||
157 | SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv), | 161 | SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv), |
158 | }; | 162 | }; |
159 | 163 | ||
164 | static const unsigned int wm9712_mixer_mute_regs[] = { | ||
165 | AC97_VIDEO, | ||
166 | AC97_PCM, | ||
167 | AC97_LINE, | ||
168 | AC97_PHONE, | ||
169 | AC97_CD, | ||
170 | AC97_PC_BEEP, | ||
171 | }; | ||
172 | |||
160 | /* We have to create a fake left and right HP mixers because | 173 | /* We have to create a fake left and right HP mixers because |
161 | * the codec only has a single control that is shared by both channels. | 174 | * the codec only has a single control that is shared by both channels. |
162 | * This makes it impossible to determine the audio path. | 175 | * This makes it impossible to determine the audio path. |
163 | */ | 176 | */ |
164 | static int mixer_event(struct snd_soc_dapm_widget *w, | 177 | static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, |
165 | struct snd_kcontrol *k, int event) | 178 | struct snd_ctl_elem_value *ucontrol) |
166 | { | 179 | { |
167 | u16 l, r, beep, line, phone, mic, pcm, aux; | 180 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
168 | 181 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | |
169 | l = ac97_read(w->codec, HPL_MIXER); | 182 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); |
170 | r = ac97_read(w->codec, HPR_MIXER); | 183 | unsigned int val = ucontrol->value.enumerated.item[0]; |
171 | beep = ac97_read(w->codec, AC97_PC_BEEP); | 184 | struct soc_mixer_control *mc = |
172 | mic = ac97_read(w->codec, AC97_VIDEO); | 185 | (struct soc_mixer_control *)kcontrol->private_value; |
173 | phone = ac97_read(w->codec, AC97_PHONE); | 186 | unsigned int mixer, mask, shift, old; |
174 | line = ac97_read(w->codec, AC97_LINE); | 187 | struct snd_soc_dapm_update update; |
175 | pcm = ac97_read(w->codec, AC97_PCM); | 188 | bool change; |
176 | aux = ac97_read(w->codec, AC97_CD); | 189 | |
177 | 190 | mixer = mc->shift >> 8; | |
178 | if (l & 0x1 || r & 0x1) | 191 | shift = mc->shift & 0xff; |
179 | ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff); | 192 | mask = 1 << shift; |
193 | |||
194 | mutex_lock(&wm9712->lock); | ||
195 | old = wm9712->hp_mixer[mixer]; | ||
196 | if (ucontrol->value.enumerated.item[0]) | ||
197 | wm9712->hp_mixer[mixer] |= mask; | ||
180 | else | 198 | else |
181 | ac97_write(w->codec, AC97_VIDEO, mic | 0x8000); | 199 | wm9712->hp_mixer[mixer] &= ~mask; |
200 | |||
201 | change = old != wm9712->hp_mixer[mixer]; | ||
202 | if (change) { | ||
203 | update.kcontrol = kcontrol; | ||
204 | update.reg = wm9712_mixer_mute_regs[shift]; | ||
205 | update.mask = 0x8000; | ||
206 | if ((wm9712->hp_mixer[0] & mask) || | ||
207 | (wm9712->hp_mixer[1] & mask)) | ||
208 | update.val = 0x0; | ||
209 | else | ||
210 | update.val = 0x8000; | ||
211 | |||
212 | snd_soc_dapm_mixer_update_power(dapm, kcontrol, val, | ||
213 | &update); | ||
214 | } | ||
182 | 215 | ||
183 | if (l & 0x2 || r & 0x2) | 216 | mutex_unlock(&wm9712->lock); |
184 | ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); | ||
185 | else | ||
186 | ac97_write(w->codec, AC97_PCM, pcm | 0x8000); | ||
187 | 217 | ||
188 | if (l & 0x4 || r & 0x4) | 218 | return change; |
189 | ac97_write(w->codec, AC97_LINE, line & 0x7fff); | 219 | } |
190 | else | ||
191 | ac97_write(w->codec, AC97_LINE, line | 0x8000); | ||
192 | 220 | ||
193 | if (l & 0x8 || r & 0x8) | 221 | static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol, |
194 | ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); | 222 | struct snd_ctl_elem_value *ucontrol) |
195 | else | 223 | { |
196 | ac97_write(w->codec, AC97_PHONE, phone | 0x8000); | 224 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
225 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | ||
226 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
227 | struct soc_mixer_control *mc = | ||
228 | (struct soc_mixer_control *)kcontrol->private_value; | ||
229 | unsigned int shift, mixer; | ||
197 | 230 | ||
198 | if (l & 0x10 || r & 0x10) | 231 | mixer = mc->shift >> 8; |
199 | ac97_write(w->codec, AC97_CD, aux & 0x7fff); | 232 | shift = mc->shift & 0xff; |
200 | else | ||
201 | ac97_write(w->codec, AC97_CD, aux | 0x8000); | ||
202 | 233 | ||
203 | if (l & 0x20 || r & 0x20) | 234 | ucontrol->value.enumerated.item[0] = |
204 | ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); | 235 | (wm9712->hp_mixer[mixer] >> shift) & 1; |
205 | else | ||
206 | ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); | ||
207 | 236 | ||
208 | return 0; | 237 | return 0; |
209 | } | 238 | } |
210 | 239 | ||
240 | #define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \ | ||
241 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
242 | .info = snd_soc_info_volsw, \ | ||
243 | .get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \ | ||
244 | .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \ | ||
245 | (xmixer << 8) | xshift, 1, 0, 0) \ | ||
246 | } | ||
247 | |||
211 | /* Left Headphone Mixers */ | 248 | /* Left Headphone Mixers */ |
212 | static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = { | 249 | static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = { |
213 | SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0), | 250 | WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPL_MIXER, 5), |
214 | SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0), | 251 | WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 4), |
215 | SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0), | 252 | WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPL_MIXER, 3), |
216 | SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0), | 253 | WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPL_MIXER, 2), |
217 | SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0), | 254 | WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 1), |
218 | SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0), | 255 | WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPL_MIXER, 0), |
219 | }; | 256 | }; |
220 | 257 | ||
221 | /* Right Headphone Mixers */ | 258 | /* Right Headphone Mixers */ |
222 | static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = { | 259 | static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = { |
223 | SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0), | 260 | WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPR_MIXER, 5), |
224 | SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0), | 261 | WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 4), |
225 | SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0), | 262 | WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPR_MIXER, 3), |
226 | SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0), | 263 | WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPR_MIXER, 2), |
227 | SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0), | 264 | WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 1), |
228 | SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0), | 265 | WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPR_MIXER, 0), |
229 | }; | 266 | }; |
230 | 267 | ||
231 | /* Speaker Mixer */ | 268 | /* Speaker Mixer */ |
@@ -299,12 +336,10 @@ SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0, | |||
299 | SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0, | 336 | SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0, |
300 | &wm9712_diff_sel_controls), | 337 | &wm9712_diff_sel_controls), |
301 | SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | 338 | SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), |
302 | SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1, | 339 | SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_INT_PAGING, 9, 1, |
303 | &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls), | 340 | &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls)), |
304 | mixer_event, SND_SOC_DAPM_POST_REG), | 341 | SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_INT_PAGING, 8, 1, |
305 | SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1, | 342 | &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls)), |
306 | &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls), | ||
307 | mixer_event, SND_SOC_DAPM_POST_REG), | ||
308 | SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1, | 343 | SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1, |
309 | &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)), | 344 | &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)), |
310 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1, | 345 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1, |
@@ -450,12 +485,13 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = { | |||
450 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 485 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
451 | unsigned int reg) | 486 | unsigned int reg) |
452 | { | 487 | { |
488 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
453 | u16 *cache = codec->reg_cache; | 489 | u16 *cache = codec->reg_cache; |
454 | 490 | ||
455 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | 491 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || |
456 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || | 492 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || |
457 | reg == AC97_REC_GAIN) | 493 | reg == AC97_REC_GAIN) |
458 | return soc_ac97_ops->read(codec->ac97, reg); | 494 | return soc_ac97_ops->read(wm9712->ac97, reg); |
459 | else { | 495 | else { |
460 | reg = reg >> 1; | 496 | reg = reg >> 1; |
461 | 497 | ||
@@ -469,10 +505,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
469 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 505 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
470 | unsigned int val) | 506 | unsigned int val) |
471 | { | 507 | { |
508 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
472 | u16 *cache = codec->reg_cache; | 509 | u16 *cache = codec->reg_cache; |
473 | 510 | ||
474 | if (reg < 0x7c) | 511 | soc_ac97_ops->write(wm9712->ac97, reg, val); |
475 | soc_ac97_ops->write(codec->ac97, reg, val); | ||
476 | reg = reg >> 1; | 512 | reg = reg >> 1; |
477 | if (reg < (ARRAY_SIZE(wm9712_reg))) | 513 | if (reg < (ARRAY_SIZE(wm9712_reg))) |
478 | cache[reg] = val; | 514 | cache[reg] = val; |
@@ -532,7 +568,6 @@ static const struct snd_soc_dai_ops wm9712_dai_ops_aux = { | |||
532 | static struct snd_soc_dai_driver wm9712_dai[] = { | 568 | static struct snd_soc_dai_driver wm9712_dai[] = { |
533 | { | 569 | { |
534 | .name = "wm9712-hifi", | 570 | .name = "wm9712-hifi", |
535 | .ac97_control = 1, | ||
536 | .playback = { | 571 | .playback = { |
537 | .stream_name = "HiFi Playback", | 572 | .stream_name = "HiFi Playback", |
538 | .channels_min = 1, | 573 | .channels_min = 1, |
@@ -581,21 +616,23 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, | |||
581 | 616 | ||
582 | static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) | 617 | static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) |
583 | { | 618 | { |
619 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
620 | |||
584 | if (try_warm && soc_ac97_ops->warm_reset) { | 621 | if (try_warm && soc_ac97_ops->warm_reset) { |
585 | soc_ac97_ops->warm_reset(codec->ac97); | 622 | soc_ac97_ops->warm_reset(wm9712->ac97); |
586 | if (ac97_read(codec, 0) == wm9712_reg[0]) | 623 | if (ac97_read(codec, 0) == wm9712_reg[0]) |
587 | return 1; | 624 | return 1; |
588 | } | 625 | } |
589 | 626 | ||
590 | soc_ac97_ops->reset(codec->ac97); | 627 | soc_ac97_ops->reset(wm9712->ac97); |
591 | if (soc_ac97_ops->warm_reset) | 628 | if (soc_ac97_ops->warm_reset) |
592 | soc_ac97_ops->warm_reset(codec->ac97); | 629 | soc_ac97_ops->warm_reset(wm9712->ac97); |
593 | if (ac97_read(codec, 0) != wm9712_reg[0]) | 630 | if (ac97_read(codec, 0) != wm9712_reg[0]) |
594 | goto err; | 631 | goto err; |
595 | return 0; | 632 | return 0; |
596 | 633 | ||
597 | err: | 634 | err: |
598 | printk(KERN_ERR "WM9712 AC97 reset failed\n"); | 635 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); |
599 | return -EIO; | 636 | return -EIO; |
600 | } | 637 | } |
601 | 638 | ||
@@ -607,14 +644,13 @@ static int wm9712_soc_suspend(struct snd_soc_codec *codec) | |||
607 | 644 | ||
608 | static int wm9712_soc_resume(struct snd_soc_codec *codec) | 645 | static int wm9712_soc_resume(struct snd_soc_codec *codec) |
609 | { | 646 | { |
647 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
610 | int i, ret; | 648 | int i, ret; |
611 | u16 *cache = codec->reg_cache; | 649 | u16 *cache = codec->reg_cache; |
612 | 650 | ||
613 | ret = wm9712_reset(codec, 1); | 651 | ret = wm9712_reset(codec, 1); |
614 | if (ret < 0) { | 652 | if (ret < 0) |
615 | printk(KERN_ERR "could not reset AC97 codec\n"); | ||
616 | return ret; | 653 | return ret; |
617 | } | ||
618 | 654 | ||
619 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 655 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
620 | 656 | ||
@@ -624,7 +660,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) | |||
624 | if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || | 660 | if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || |
625 | (i > 0x58 && i != 0x5c)) | 661 | (i > 0x58 && i != 0x5c)) |
626 | continue; | 662 | continue; |
627 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); | 663 | soc_ac97_ops->write(wm9712->ac97, i, cache[i>>1]); |
628 | } | 664 | } |
629 | } | 665 | } |
630 | 666 | ||
@@ -633,37 +669,37 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) | |||
633 | 669 | ||
634 | static int wm9712_soc_probe(struct snd_soc_codec *codec) | 670 | static int wm9712_soc_probe(struct snd_soc_codec *codec) |
635 | { | 671 | { |
672 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
636 | int ret = 0; | 673 | int ret = 0; |
637 | 674 | ||
638 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | 675 | wm9712->ac97 = snd_soc_new_ac97_codec(codec); |
639 | if (ret < 0) { | 676 | if (IS_ERR(wm9712->ac97)) { |
640 | printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); | 677 | ret = PTR_ERR(wm9712->ac97); |
678 | dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); | ||
641 | return ret; | 679 | return ret; |
642 | } | 680 | } |
643 | 681 | ||
644 | ret = wm9712_reset(codec, 0); | 682 | ret = wm9712_reset(codec, 0); |
645 | if (ret < 0) { | 683 | if (ret < 0) |
646 | printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n"); | ||
647 | goto reset_err; | 684 | goto reset_err; |
648 | } | ||
649 | 685 | ||
650 | /* set alc mux to none */ | 686 | /* set alc mux to none */ |
651 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); | 687 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); |
652 | 688 | ||
653 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 689 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
654 | snd_soc_add_codec_controls(codec, wm9712_snd_ac97_controls, | ||
655 | ARRAY_SIZE(wm9712_snd_ac97_controls)); | ||
656 | 690 | ||
657 | return 0; | 691 | return 0; |
658 | 692 | ||
659 | reset_err: | 693 | reset_err: |
660 | snd_soc_free_ac97_codec(codec); | 694 | snd_soc_free_ac97_codec(wm9712->ac97); |
661 | return ret; | 695 | return ret; |
662 | } | 696 | } |
663 | 697 | ||
664 | static int wm9712_soc_remove(struct snd_soc_codec *codec) | 698 | static int wm9712_soc_remove(struct snd_soc_codec *codec) |
665 | { | 699 | { |
666 | snd_soc_free_ac97_codec(codec); | 700 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); |
701 | |||
702 | snd_soc_free_ac97_codec(wm9712->ac97); | ||
667 | return 0; | 703 | return 0; |
668 | } | 704 | } |
669 | 705 | ||
@@ -679,6 +715,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { | |||
679 | .reg_word_size = sizeof(u16), | 715 | .reg_word_size = sizeof(u16), |
680 | .reg_cache_step = 2, | 716 | .reg_cache_step = 2, |
681 | .reg_cache_default = wm9712_reg, | 717 | .reg_cache_default = wm9712_reg, |
718 | |||
719 | .controls = wm9712_snd_ac97_controls, | ||
720 | .num_controls = ARRAY_SIZE(wm9712_snd_ac97_controls), | ||
682 | .dapm_widgets = wm9712_dapm_widgets, | 721 | .dapm_widgets = wm9712_dapm_widgets, |
683 | .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets), | 722 | .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets), |
684 | .dapm_routes = wm9712_audio_map, | 723 | .dapm_routes = wm9712_audio_map, |
@@ -687,6 +726,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { | |||
687 | 726 | ||
688 | static int wm9712_probe(struct platform_device *pdev) | 727 | static int wm9712_probe(struct platform_device *pdev) |
689 | { | 728 | { |
729 | struct wm9712_priv *wm9712; | ||
730 | |||
731 | wm9712 = devm_kzalloc(&pdev->dev, sizeof(*wm9712), GFP_KERNEL); | ||
732 | if (wm9712 == NULL) | ||
733 | return -ENOMEM; | ||
734 | |||
735 | mutex_init(&wm9712->lock); | ||
736 | |||
737 | platform_set_drvdata(pdev, wm9712); | ||
738 | |||
690 | return snd_soc_register_codec(&pdev->dev, | 739 | return snd_soc_register_codec(&pdev->dev, |
691 | &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai)); | 740 | &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai)); |
692 | } | 741 | } |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index bddee30a4bc7..6c95d98b0eb1 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -30,7 +30,10 @@ | |||
30 | #include "wm9713.h" | 30 | #include "wm9713.h" |
31 | 31 | ||
32 | struct wm9713_priv { | 32 | struct wm9713_priv { |
33 | struct snd_ac97 *ac97; | ||
33 | u32 pll_in; /* PLL input frequency */ | 34 | u32 pll_in; /* PLL input frequency */ |
35 | unsigned int hp_mixer[2]; | ||
36 | struct mutex lock; | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 39 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
@@ -59,13 +62,10 @@ static const u16 wm9713_reg[] = { | |||
59 | 0x0000, 0x0000, 0x0000, 0x0000, | 62 | 0x0000, 0x0000, 0x0000, 0x0000, |
60 | 0x0000, 0x0000, 0x0000, 0x0006, | 63 | 0x0000, 0x0000, 0x0000, 0x0006, |
61 | 0x0001, 0x0000, 0x574d, 0x4c13, | 64 | 0x0001, 0x0000, 0x574d, 0x4c13, |
62 | 0x0000, 0x0000, 0x0000 | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | /* virtual HP mixers regs */ | 67 | #define HPL_MIXER 0 |
66 | #define HPL_MIXER 0x80 | 68 | #define HPR_MIXER 1 |
67 | #define HPR_MIXER 0x82 | ||
68 | #define MICB_MUX 0x82 | ||
69 | 69 | ||
70 | static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"}; | 70 | static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"}; |
71 | static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; | 71 | static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; |
@@ -110,7 +110,7 @@ SOC_ENUM_SINGLE(AC97_REC_GAIN_MIC, 10, 8, wm9713_dac_inv), /* dac invert 2 15 */ | |||
110 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */ | 110 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */ |
111 | SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */ | 111 | SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */ |
112 | SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */ | 112 | SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */ |
113 | SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */ | 113 | SOC_ENUM_SINGLE_VIRT(2, wm9713_micb_select), /* mic selection 19 */ |
114 | }; | 114 | }; |
115 | 115 | ||
116 | static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); | 116 | static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); |
@@ -234,6 +234,14 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, | |||
234 | return 0; | 234 | return 0; |
235 | } | 235 | } |
236 | 236 | ||
237 | static const unsigned int wm9713_mixer_mute_regs[] = { | ||
238 | AC97_PC_BEEP, | ||
239 | AC97_MASTER_TONE, | ||
240 | AC97_PHONE, | ||
241 | AC97_REC_SEL, | ||
242 | AC97_PCM, | ||
243 | AC97_AUX, | ||
244 | }; | ||
237 | 245 | ||
238 | /* We have to create a fake left and right HP mixers because | 246 | /* We have to create a fake left and right HP mixers because |
239 | * the codec only has a single control that is shared by both channels. | 247 | * the codec only has a single control that is shared by both channels. |
@@ -241,73 +249,95 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, | |||
241 | * register map, thus we add a new (virtual) register to help determine the | 249 | * register map, thus we add a new (virtual) register to help determine the |
242 | * audio route within the device. | 250 | * audio route within the device. |
243 | */ | 251 | */ |
244 | static int mixer_event(struct snd_soc_dapm_widget *w, | 252 | static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, |
245 | struct snd_kcontrol *kcontrol, int event) | 253 | struct snd_ctl_elem_value *ucontrol) |
246 | { | 254 | { |
247 | u16 l, r, beep, tone, phone, rec, pcm, aux; | 255 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
248 | 256 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | |
249 | l = ac97_read(w->codec, HPL_MIXER); | 257 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); |
250 | r = ac97_read(w->codec, HPR_MIXER); | 258 | unsigned int val = ucontrol->value.enumerated.item[0]; |
251 | beep = ac97_read(w->codec, AC97_PC_BEEP); | 259 | struct soc_mixer_control *mc = |
252 | tone = ac97_read(w->codec, AC97_MASTER_TONE); | 260 | (struct soc_mixer_control *)kcontrol->private_value; |
253 | phone = ac97_read(w->codec, AC97_PHONE); | 261 | unsigned int mixer, mask, shift, old; |
254 | rec = ac97_read(w->codec, AC97_REC_SEL); | 262 | struct snd_soc_dapm_update update; |
255 | pcm = ac97_read(w->codec, AC97_PCM); | 263 | bool change; |
256 | aux = ac97_read(w->codec, AC97_AUX); | 264 | |
257 | 265 | mixer = mc->shift >> 8; | |
258 | if (event & SND_SOC_DAPM_PRE_REG) | 266 | shift = mc->shift & 0xff; |
259 | return 0; | 267 | mask = (1 << shift); |
260 | if ((l & 0x1) || (r & 0x1)) | 268 | |
261 | ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); | 269 | mutex_lock(&wm9713->lock); |
270 | old = wm9713->hp_mixer[mixer]; | ||
271 | if (ucontrol->value.enumerated.item[0]) | ||
272 | wm9713->hp_mixer[mixer] |= mask; | ||
262 | else | 273 | else |
263 | ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); | 274 | wm9713->hp_mixer[mixer] &= ~mask; |
275 | |||
276 | change = old != wm9713->hp_mixer[mixer]; | ||
277 | if (change) { | ||
278 | update.kcontrol = kcontrol; | ||
279 | update.reg = wm9713_mixer_mute_regs[shift]; | ||
280 | update.mask = 0x8000; | ||
281 | if ((wm9713->hp_mixer[0] & mask) || | ||
282 | (wm9713->hp_mixer[1] & mask)) | ||
283 | update.val = 0x0; | ||
284 | else | ||
285 | update.val = 0x8000; | ||
286 | |||
287 | snd_soc_dapm_mixer_update_power(dapm, kcontrol, val, | ||
288 | &update); | ||
289 | } | ||
264 | 290 | ||
265 | if ((l & 0x2) || (r & 0x2)) | 291 | mutex_unlock(&wm9713->lock); |
266 | ac97_write(w->codec, AC97_MASTER_TONE, tone & 0x7fff); | ||
267 | else | ||
268 | ac97_write(w->codec, AC97_MASTER_TONE, tone | 0x8000); | ||
269 | 292 | ||
270 | if ((l & 0x4) || (r & 0x4)) | 293 | return change; |
271 | ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); | 294 | } |
272 | else | ||
273 | ac97_write(w->codec, AC97_PHONE, phone | 0x8000); | ||
274 | 295 | ||
275 | if ((l & 0x8) || (r & 0x8)) | 296 | static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol, |
276 | ac97_write(w->codec, AC97_REC_SEL, rec & 0x7fff); | 297 | struct snd_ctl_elem_value *ucontrol) |
277 | else | 298 | { |
278 | ac97_write(w->codec, AC97_REC_SEL, rec | 0x8000); | 299 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
300 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | ||
301 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
302 | struct soc_mixer_control *mc = | ||
303 | (struct soc_mixer_control *)kcontrol->private_value; | ||
304 | unsigned int mixer, shift; | ||
279 | 305 | ||
280 | if ((l & 0x10) || (r & 0x10)) | 306 | mixer = mc->shift >> 8; |
281 | ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); | 307 | shift = mc->shift & 0xff; |
282 | else | ||
283 | ac97_write(w->codec, AC97_PCM, pcm | 0x8000); | ||
284 | 308 | ||
285 | if ((l & 0x20) || (r & 0x20)) | 309 | ucontrol->value.enumerated.item[0] = |
286 | ac97_write(w->codec, AC97_AUX, aux & 0x7fff); | 310 | (wm9713->hp_mixer[mixer] >> shift) & 1; |
287 | else | ||
288 | ac97_write(w->codec, AC97_AUX, aux | 0x8000); | ||
289 | 311 | ||
290 | return 0; | 312 | return 0; |
291 | } | 313 | } |
292 | 314 | ||
315 | #define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) { \ | ||
316 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
317 | .info = snd_soc_info_volsw, \ | ||
318 | .get = wm9713_hp_mixer_get, .put = wm9713_hp_mixer_put, \ | ||
319 | .private_value = SOC_DOUBLE_VALUE(SND_SOC_NOPM, \ | ||
320 | xshift, xmixer, 1, 0, 0) \ | ||
321 | } | ||
322 | |||
293 | /* Left Headphone Mixers */ | 323 | /* Left Headphone Mixers */ |
294 | static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { | 324 | static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { |
295 | SOC_DAPM_SINGLE("Beep Playback Switch", HPL_MIXER, 5, 1, 0), | 325 | WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPL_MIXER, 5), |
296 | SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0), | 326 | WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPL_MIXER, 4), |
297 | SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0), | 327 | WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 3), |
298 | SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0), | 328 | WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 2), |
299 | SOC_DAPM_SINGLE("MonoIn Playback Switch", HPL_MIXER, 1, 1, 0), | 329 | WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPL_MIXER, 1), |
300 | SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0), | 330 | WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPL_MIXER, 0), |
301 | }; | 331 | }; |
302 | 332 | ||
303 | /* Right Headphone Mixers */ | 333 | /* Right Headphone Mixers */ |
304 | static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { | 334 | static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { |
305 | SOC_DAPM_SINGLE("Beep Playback Switch", HPR_MIXER, 5, 1, 0), | 335 | WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPR_MIXER, 5), |
306 | SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0), | 336 | WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPR_MIXER, 4), |
307 | SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0), | 337 | WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 3), |
308 | SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0), | 338 | WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 2), |
309 | SOC_DAPM_SINGLE("MonoIn Playback Switch", HPR_MIXER, 1, 1, 0), | 339 | WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPR_MIXER, 1), |
310 | SOC_DAPM_SINGLE("Bypass Playback Switch", HPR_MIXER, 0, 1, 0), | 340 | WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPR_MIXER, 0), |
311 | }; | 341 | }; |
312 | 342 | ||
313 | /* headphone capture mux */ | 343 | /* headphone capture mux */ |
@@ -429,12 +459,10 @@ SND_SOC_DAPM_MUX("Mic A Source", SND_SOC_NOPM, 0, 0, | |||
429 | &wm9713_mic_sel_mux_controls), | 459 | &wm9713_mic_sel_mux_controls), |
430 | SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0, | 460 | SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0, |
431 | &wm9713_micb_sel_mux_controls), | 461 | &wm9713_micb_sel_mux_controls), |
432 | SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_EXTENDED_MID, 3, 1, | 462 | SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_EXTENDED_MID, 3, 1, |
433 | &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls), | 463 | &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls)), |
434 | mixer_event, SND_SOC_DAPM_POST_REG), | 464 | SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_EXTENDED_MID, 2, 1, |
435 | SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_EXTENDED_MID, 2, 1, | 465 | &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls)), |
436 | &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls), | ||
437 | mixer_event, SND_SOC_DAPM_POST_REG), | ||
438 | SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1, | 466 | SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1, |
439 | &wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)), | 467 | &wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)), |
440 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1, | 468 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1, |
@@ -647,12 +675,13 @@ static const struct snd_soc_dapm_route wm9713_audio_map[] = { | |||
647 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 675 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
648 | unsigned int reg) | 676 | unsigned int reg) |
649 | { | 677 | { |
678 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
650 | u16 *cache = codec->reg_cache; | 679 | u16 *cache = codec->reg_cache; |
651 | 680 | ||
652 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | 681 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || |
653 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || | 682 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || |
654 | reg == AC97_CD) | 683 | reg == AC97_CD) |
655 | return soc_ac97_ops->read(codec->ac97, reg); | 684 | return soc_ac97_ops->read(wm9713->ac97, reg); |
656 | else { | 685 | else { |
657 | reg = reg >> 1; | 686 | reg = reg >> 1; |
658 | 687 | ||
@@ -666,9 +695,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
666 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 695 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
667 | unsigned int val) | 696 | unsigned int val) |
668 | { | 697 | { |
698 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
699 | |||
669 | u16 *cache = codec->reg_cache; | 700 | u16 *cache = codec->reg_cache; |
670 | if (reg < 0x7c) | 701 | soc_ac97_ops->write(wm9713->ac97, reg, val); |
671 | soc_ac97_ops->write(codec->ac97, reg, val); | ||
672 | reg = reg >> 1; | 702 | reg = reg >> 1; |
673 | if (reg < (ARRAY_SIZE(wm9713_reg))) | 703 | if (reg < (ARRAY_SIZE(wm9713_reg))) |
674 | cache[reg] = val; | 704 | cache[reg] = val; |
@@ -689,7 +719,8 @@ struct _pll_div { | |||
689 | * to allow rounding later */ | 719 | * to allow rounding later */ |
690 | #define FIXED_PLL_SIZE ((1 << 22) * 10) | 720 | #define FIXED_PLL_SIZE ((1 << 22) * 10) |
691 | 721 | ||
692 | static void pll_factors(struct _pll_div *pll_div, unsigned int source) | 722 | static void pll_factors(struct snd_soc_codec *codec, |
723 | struct _pll_div *pll_div, unsigned int source) | ||
693 | { | 724 | { |
694 | u64 Kpart; | 725 | u64 Kpart; |
695 | unsigned int K, Ndiv, Nmod, target; | 726 | unsigned int K, Ndiv, Nmod, target; |
@@ -724,7 +755,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int source) | |||
724 | 755 | ||
725 | Ndiv = target / source; | 756 | Ndiv = target / source; |
726 | if ((Ndiv < 5) || (Ndiv > 12)) | 757 | if ((Ndiv < 5) || (Ndiv > 12)) |
727 | printk(KERN_WARNING | 758 | dev_warn(codec->dev, |
728 | "WM9713 PLL N value %u out of recommended range!\n", | 759 | "WM9713 PLL N value %u out of recommended range!\n", |
729 | Ndiv); | 760 | Ndiv); |
730 | 761 | ||
@@ -768,7 +799,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
768 | return 0; | 799 | return 0; |
769 | } | 800 | } |
770 | 801 | ||
771 | pll_factors(&pll_div, freq_in); | 802 | pll_factors(codec, &pll_div, freq_in); |
772 | 803 | ||
773 | if (pll_div.k == 0) { | 804 | if (pll_div.k == 0) { |
774 | reg = (pll_div.n << 12) | (pll_div.lf << 11) | | 805 | reg = (pll_div.n << 12) | (pll_div.lf << 11) | |
@@ -1049,7 +1080,6 @@ static const struct snd_soc_dai_ops wm9713_dai_ops_voice = { | |||
1049 | static struct snd_soc_dai_driver wm9713_dai[] = { | 1080 | static struct snd_soc_dai_driver wm9713_dai[] = { |
1050 | { | 1081 | { |
1051 | .name = "wm9713-hifi", | 1082 | .name = "wm9713-hifi", |
1052 | .ac97_control = 1, | ||
1053 | .playback = { | 1083 | .playback = { |
1054 | .stream_name = "HiFi Playback", | 1084 | .stream_name = "HiFi Playback", |
1055 | .channels_min = 1, | 1085 | .channels_min = 1, |
@@ -1095,17 +1125,22 @@ static struct snd_soc_dai_driver wm9713_dai[] = { | |||
1095 | 1125 | ||
1096 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm) | 1126 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm) |
1097 | { | 1127 | { |
1128 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
1129 | |||
1098 | if (try_warm && soc_ac97_ops->warm_reset) { | 1130 | if (try_warm && soc_ac97_ops->warm_reset) { |
1099 | soc_ac97_ops->warm_reset(codec->ac97); | 1131 | soc_ac97_ops->warm_reset(wm9713->ac97); |
1100 | if (ac97_read(codec, 0) == wm9713_reg[0]) | 1132 | if (ac97_read(codec, 0) == wm9713_reg[0]) |
1101 | return 1; | 1133 | return 1; |
1102 | } | 1134 | } |
1103 | 1135 | ||
1104 | soc_ac97_ops->reset(codec->ac97); | 1136 | soc_ac97_ops->reset(wm9713->ac97); |
1105 | if (soc_ac97_ops->warm_reset) | 1137 | if (soc_ac97_ops->warm_reset) |
1106 | soc_ac97_ops->warm_reset(codec->ac97); | 1138 | soc_ac97_ops->warm_reset(wm9713->ac97); |
1107 | if (ac97_read(codec, 0) != wm9713_reg[0]) | 1139 | if (ac97_read(codec, 0) != wm9713_reg[0]) { |
1140 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); | ||
1108 | return -EIO; | 1141 | return -EIO; |
1142 | } | ||
1143 | |||
1109 | return 0; | 1144 | return 0; |
1110 | } | 1145 | } |
1111 | EXPORT_SYMBOL_GPL(wm9713_reset); | 1146 | EXPORT_SYMBOL_GPL(wm9713_reset); |
@@ -1163,10 +1198,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1163 | u16 *cache = codec->reg_cache; | 1198 | u16 *cache = codec->reg_cache; |
1164 | 1199 | ||
1165 | ret = wm9713_reset(codec, 1); | 1200 | ret = wm9713_reset(codec, 1); |
1166 | if (ret < 0) { | 1201 | if (ret < 0) |
1167 | printk(KERN_ERR "could not reset AC97 codec\n"); | ||
1168 | return ret; | 1202 | return ret; |
1169 | } | ||
1170 | 1203 | ||
1171 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1204 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1172 | 1205 | ||
@@ -1180,7 +1213,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1180 | if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || | 1213 | if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || |
1181 | i == AC97_EXTENDED_MSTATUS || i > 0x66) | 1214 | i == AC97_EXTENDED_MSTATUS || i > 0x66) |
1182 | continue; | 1215 | continue; |
1183 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); | 1216 | soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]); |
1184 | } | 1217 | } |
1185 | } | 1218 | } |
1186 | 1219 | ||
@@ -1189,26 +1222,19 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1189 | 1222 | ||
1190 | static int wm9713_soc_probe(struct snd_soc_codec *codec) | 1223 | static int wm9713_soc_probe(struct snd_soc_codec *codec) |
1191 | { | 1224 | { |
1192 | struct wm9713_priv *wm9713; | 1225 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); |
1193 | int ret = 0, reg; | 1226 | int ret = 0, reg; |
1194 | 1227 | ||
1195 | wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL); | 1228 | wm9713->ac97 = snd_soc_new_ac97_codec(codec); |
1196 | if (wm9713 == NULL) | 1229 | if (IS_ERR(wm9713->ac97)) |
1197 | return -ENOMEM; | 1230 | return PTR_ERR(wm9713->ac97); |
1198 | snd_soc_codec_set_drvdata(codec, wm9713); | ||
1199 | |||
1200 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | ||
1201 | if (ret < 0) | ||
1202 | goto codec_err; | ||
1203 | 1231 | ||
1204 | /* do a cold reset for the controller and then try | 1232 | /* do a cold reset for the controller and then try |
1205 | * a warm reset followed by an optional cold reset for codec */ | 1233 | * a warm reset followed by an optional cold reset for codec */ |
1206 | wm9713_reset(codec, 0); | 1234 | wm9713_reset(codec, 0); |
1207 | ret = wm9713_reset(codec, 1); | 1235 | ret = wm9713_reset(codec, 1); |
1208 | if (ret < 0) { | 1236 | if (ret < 0) |
1209 | printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n"); | ||
1210 | goto reset_err; | 1237 | goto reset_err; |
1211 | } | ||
1212 | 1238 | ||
1213 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1239 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1214 | 1240 | ||
@@ -1216,23 +1242,18 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) | |||
1216 | reg = ac97_read(codec, AC97_CD) & 0x7fff; | 1242 | reg = ac97_read(codec, AC97_CD) & 0x7fff; |
1217 | ac97_write(codec, AC97_CD, reg); | 1243 | ac97_write(codec, AC97_CD, reg); |
1218 | 1244 | ||
1219 | snd_soc_add_codec_controls(codec, wm9713_snd_ac97_controls, | ||
1220 | ARRAY_SIZE(wm9713_snd_ac97_controls)); | ||
1221 | |||
1222 | return 0; | 1245 | return 0; |
1223 | 1246 | ||
1224 | reset_err: | 1247 | reset_err: |
1225 | snd_soc_free_ac97_codec(codec); | 1248 | snd_soc_free_ac97_codec(wm9713->ac97); |
1226 | codec_err: | ||
1227 | kfree(wm9713); | ||
1228 | return ret; | 1249 | return ret; |
1229 | } | 1250 | } |
1230 | 1251 | ||
1231 | static int wm9713_soc_remove(struct snd_soc_codec *codec) | 1252 | static int wm9713_soc_remove(struct snd_soc_codec *codec) |
1232 | { | 1253 | { |
1233 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | 1254 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); |
1234 | snd_soc_free_ac97_codec(codec); | 1255 | |
1235 | kfree(wm9713); | 1256 | snd_soc_free_ac97_codec(wm9713->ac97); |
1236 | return 0; | 1257 | return 0; |
1237 | } | 1258 | } |
1238 | 1259 | ||
@@ -1248,6 +1269,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { | |||
1248 | .reg_word_size = sizeof(u16), | 1269 | .reg_word_size = sizeof(u16), |
1249 | .reg_cache_step = 2, | 1270 | .reg_cache_step = 2, |
1250 | .reg_cache_default = wm9713_reg, | 1271 | .reg_cache_default = wm9713_reg, |
1272 | |||
1273 | .controls = wm9713_snd_ac97_controls, | ||
1274 | .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls), | ||
1251 | .dapm_widgets = wm9713_dapm_widgets, | 1275 | .dapm_widgets = wm9713_dapm_widgets, |
1252 | .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), | 1276 | .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), |
1253 | .dapm_routes = wm9713_audio_map, | 1277 | .dapm_routes = wm9713_audio_map, |
@@ -1256,6 +1280,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { | |||
1256 | 1280 | ||
1257 | static int wm9713_probe(struct platform_device *pdev) | 1281 | static int wm9713_probe(struct platform_device *pdev) |
1258 | { | 1282 | { |
1283 | struct wm9713_priv *wm9713; | ||
1284 | |||
1285 | wm9713 = devm_kzalloc(&pdev->dev, sizeof(*wm9713), GFP_KERNEL); | ||
1286 | if (wm9713 == NULL) | ||
1287 | return -ENOMEM; | ||
1288 | |||
1289 | mutex_init(&wm9713->lock); | ||
1290 | |||
1291 | platform_set_drvdata(pdev, wm9713); | ||
1292 | |||
1259 | return snd_soc_register_codec(&pdev->dev, | 1293 | return snd_soc_register_codec(&pdev->dev, |
1260 | &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai)); | 1294 | &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai)); |
1261 | } | 1295 | } |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 67124783558a..720d6e852986 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/regmap.h> | 21 | #include <linux/regmap.h> |
22 | #include <linux/regulator/consumer.h> | 22 | #include <linux/regulator/consumer.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/vmalloc.h> | ||
24 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
25 | #include <sound/core.h> | 26 | #include <sound/core.h> |
26 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
@@ -169,11 +170,12 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, | |||
169 | if (buf == NULL) | 170 | if (buf == NULL) |
170 | return NULL; | 171 | return NULL; |
171 | 172 | ||
172 | buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA); | 173 | buf->buf = vmalloc(len); |
173 | if (!buf->buf) { | 174 | if (!buf->buf) { |
174 | kfree(buf); | 175 | vfree(buf); |
175 | return NULL; | 176 | return NULL; |
176 | } | 177 | } |
178 | memcpy(buf->buf, src, len); | ||
177 | 179 | ||
178 | if (list) | 180 | if (list) |
179 | list_add_tail(&buf->list, list); | 181 | list_add_tail(&buf->list, list); |
@@ -188,7 +190,7 @@ static void wm_adsp_buf_free(struct list_head *list) | |||
188 | struct wm_adsp_buf, | 190 | struct wm_adsp_buf, |
189 | list); | 191 | list); |
190 | list_del(&buf->list); | 192 | list_del(&buf->list); |
191 | kfree(buf->buf); | 193 | vfree(buf->buf); |
192 | kfree(buf); | 194 | kfree(buf); |
193 | } | 195 | } |
194 | } | 196 | } |
@@ -684,38 +686,24 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
684 | } | 686 | } |
685 | 687 | ||
686 | if (reg) { | 688 | if (reg) { |
687 | size_t to_write = PAGE_SIZE; | 689 | buf = wm_adsp_buf_alloc(region->data, |
688 | size_t remain = le32_to_cpu(region->len); | 690 | le32_to_cpu(region->len), |
689 | const u8 *data = region->data; | 691 | &buf_list); |
690 | 692 | if (!buf) { | |
691 | while (remain > 0) { | 693 | adsp_err(dsp, "Out of memory\n"); |
692 | if (remain < PAGE_SIZE) | 694 | ret = -ENOMEM; |
693 | to_write = remain; | 695 | goto out_fw; |
694 | 696 | } | |
695 | buf = wm_adsp_buf_alloc(data, | ||
696 | to_write, | ||
697 | &buf_list); | ||
698 | if (!buf) { | ||
699 | adsp_err(dsp, "Out of memory\n"); | ||
700 | ret = -ENOMEM; | ||
701 | goto out_fw; | ||
702 | } | ||
703 | |||
704 | ret = regmap_raw_write_async(regmap, reg, | ||
705 | buf->buf, | ||
706 | to_write); | ||
707 | if (ret != 0) { | ||
708 | adsp_err(dsp, | ||
709 | "%s.%d: Failed to write %zd bytes at %d in %s: %d\n", | ||
710 | file, regions, | ||
711 | to_write, offset, | ||
712 | region_name, ret); | ||
713 | goto out_fw; | ||
714 | } | ||
715 | 697 | ||
716 | data += to_write; | 698 | ret = regmap_raw_write_async(regmap, reg, buf->buf, |
717 | reg += to_write / 2; | 699 | le32_to_cpu(region->len)); |
718 | remain -= to_write; | 700 | if (ret != 0) { |
701 | adsp_err(dsp, | ||
702 | "%s.%d: Failed to write %d bytes at %d in %s: %d\n", | ||
703 | file, regions, | ||
704 | le32_to_cpu(region->len), offset, | ||
705 | region_name, ret); | ||
706 | goto out_fw; | ||
719 | } | 707 | } |
720 | } | 708 | } |
721 | 709 | ||
@@ -1065,8 +1053,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1065 | be32_to_cpu(adsp1_alg[i].zm)); | 1053 | be32_to_cpu(adsp1_alg[i].zm)); |
1066 | 1054 | ||
1067 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1055 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1068 | if (!region) | 1056 | if (!region) { |
1069 | return -ENOMEM; | 1057 | ret = -ENOMEM; |
1058 | goto out; | ||
1059 | } | ||
1070 | region->type = WMFW_ADSP1_DM; | 1060 | region->type = WMFW_ADSP1_DM; |
1071 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | 1061 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); |
1072 | region->base = be32_to_cpu(adsp1_alg[i].dm); | 1062 | region->base = be32_to_cpu(adsp1_alg[i].dm); |
@@ -1083,8 +1073,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1083 | } | 1073 | } |
1084 | 1074 | ||
1085 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1075 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1086 | if (!region) | 1076 | if (!region) { |
1087 | return -ENOMEM; | 1077 | ret = -ENOMEM; |
1078 | goto out; | ||
1079 | } | ||
1088 | region->type = WMFW_ADSP1_ZM; | 1080 | region->type = WMFW_ADSP1_ZM; |
1089 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | 1081 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); |
1090 | region->base = be32_to_cpu(adsp1_alg[i].zm); | 1082 | region->base = be32_to_cpu(adsp1_alg[i].zm); |
@@ -1113,8 +1105,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1113 | be32_to_cpu(adsp2_alg[i].zm)); | 1105 | be32_to_cpu(adsp2_alg[i].zm)); |
1114 | 1106 | ||
1115 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1107 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1116 | if (!region) | 1108 | if (!region) { |
1117 | return -ENOMEM; | 1109 | ret = -ENOMEM; |
1110 | goto out; | ||
1111 | } | ||
1118 | region->type = WMFW_ADSP2_XM; | 1112 | region->type = WMFW_ADSP2_XM; |
1119 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1113 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); |
1120 | region->base = be32_to_cpu(adsp2_alg[i].xm); | 1114 | region->base = be32_to_cpu(adsp2_alg[i].xm); |
@@ -1131,8 +1125,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1131 | } | 1125 | } |
1132 | 1126 | ||
1133 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1127 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1134 | if (!region) | 1128 | if (!region) { |
1135 | return -ENOMEM; | 1129 | ret = -ENOMEM; |
1130 | goto out; | ||
1131 | } | ||
1136 | region->type = WMFW_ADSP2_YM; | 1132 | region->type = WMFW_ADSP2_YM; |
1137 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1133 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); |
1138 | region->base = be32_to_cpu(adsp2_alg[i].ym); | 1134 | region->base = be32_to_cpu(adsp2_alg[i].ym); |
@@ -1149,8 +1145,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1149 | } | 1145 | } |
1150 | 1146 | ||
1151 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1147 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1152 | if (!region) | 1148 | if (!region) { |
1153 | return -ENOMEM; | 1149 | ret = -ENOMEM; |
1150 | goto out; | ||
1151 | } | ||
1154 | region->type = WMFW_ADSP2_ZM; | 1152 | region->type = WMFW_ADSP2_ZM; |
1155 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1153 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); |
1156 | region->base = be32_to_cpu(adsp2_alg[i].zm); | 1154 | region->base = be32_to_cpu(adsp2_alg[i].zm); |
@@ -1595,13 +1593,6 @@ static void wm_adsp2_boot_work(struct work_struct *work) | |||
1595 | if (ret != 0) | 1593 | if (ret != 0) |
1596 | goto err; | 1594 | goto err; |
1597 | 1595 | ||
1598 | ret = regmap_update_bits_async(dsp->regmap, | ||
1599 | dsp->base + ADSP2_CONTROL, | ||
1600 | ADSP2_CORE_ENA, | ||
1601 | ADSP2_CORE_ENA); | ||
1602 | if (ret != 0) | ||
1603 | goto err; | ||
1604 | |||
1605 | dsp->running = true; | 1596 | dsp->running = true; |
1606 | 1597 | ||
1607 | return; | 1598 | return; |
@@ -1651,8 +1642,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1651 | 1642 | ||
1652 | ret = regmap_update_bits(dsp->regmap, | 1643 | ret = regmap_update_bits(dsp->regmap, |
1653 | dsp->base + ADSP2_CONTROL, | 1644 | dsp->base + ADSP2_CONTROL, |
1654 | ADSP2_START, | 1645 | ADSP2_CORE_ENA | ADSP2_START, |
1655 | ADSP2_START); | 1646 | ADSP2_CORE_ENA | ADSP2_START); |
1656 | if (ret != 0) | 1647 | if (ret != 0) |
1657 | goto err; | 1648 | goto err; |
1658 | break; | 1649 | break; |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 0eed9b1b24e1..0dab382ba147 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -70,6 +70,7 @@ struct davinci_mcasp { | |||
70 | void __iomem *base; | 70 | void __iomem *base; |
71 | u32 fifo_base; | 71 | u32 fifo_base; |
72 | struct device *dev; | 72 | struct device *dev; |
73 | struct snd_pcm_substream *substreams[2]; | ||
73 | 74 | ||
74 | /* McASP specific data */ | 75 | /* McASP specific data */ |
75 | int tdm_slots; | 76 | int tdm_slots; |
@@ -80,6 +81,7 @@ struct davinci_mcasp { | |||
80 | u8 bclk_div; | 81 | u8 bclk_div; |
81 | u16 bclk_lrclk_ratio; | 82 | u16 bclk_lrclk_ratio; |
82 | int streams; | 83 | int streams; |
84 | u32 irq_request[2]; | ||
83 | 85 | ||
84 | int sysclk_freq; | 86 | int sysclk_freq; |
85 | bool bclk_master; | 87 | bool bclk_master; |
@@ -90,6 +92,9 @@ struct davinci_mcasp { | |||
90 | 92 | ||
91 | bool dat_port; | 93 | bool dat_port; |
92 | 94 | ||
95 | /* Used for comstraint setting on the second stream */ | ||
96 | u32 channels; | ||
97 | |||
93 | #ifdef CONFIG_PM_SLEEP | 98 | #ifdef CONFIG_PM_SLEEP |
94 | struct davinci_mcasp_context context; | 99 | struct davinci_mcasp_context context; |
95 | #endif | 100 | #endif |
@@ -154,9 +159,16 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp) | |||
154 | 159 | ||
155 | static void mcasp_start_rx(struct davinci_mcasp *mcasp) | 160 | static void mcasp_start_rx(struct davinci_mcasp *mcasp) |
156 | { | 161 | { |
162 | if (mcasp->rxnumevt) { /* enable FIFO */ | ||
163 | u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
164 | |||
165 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
166 | mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | ||
167 | } | ||
168 | |||
169 | /* Start clocks */ | ||
157 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); | 170 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); |
158 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); | 171 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); |
159 | |||
160 | /* | 172 | /* |
161 | * When ASYNC == 0 the transmit and receive sections operate | 173 | * When ASYNC == 0 the transmit and receive sections operate |
162 | * synchronously from the transmit clock and frame sync. We need to make | 174 | * synchronously from the transmit clock and frame sync. We need to make |
@@ -167,74 +179,69 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp) | |||
167 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); | 179 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); |
168 | } | 180 | } |
169 | 181 | ||
182 | /* Activate serializer(s) */ | ||
170 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); | 183 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); |
171 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0); | 184 | /* Release RX state machine */ |
172 | |||
173 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); | ||
174 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); | ||
175 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0); | ||
176 | |||
177 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); | 185 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); |
186 | /* Release Frame Sync generator */ | ||
178 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); | 187 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); |
179 | |||
180 | if (mcasp_is_synchronous(mcasp)) | 188 | if (mcasp_is_synchronous(mcasp)) |
181 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | 189 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); |
190 | |||
191 | /* enable receive IRQs */ | ||
192 | mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, | ||
193 | mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); | ||
182 | } | 194 | } |
183 | 195 | ||
184 | static void mcasp_start_tx(struct davinci_mcasp *mcasp) | 196 | static void mcasp_start_tx(struct davinci_mcasp *mcasp) |
185 | { | 197 | { |
186 | u8 offset = 0, i; | ||
187 | u32 cnt; | 198 | u32 cnt; |
188 | 199 | ||
200 | if (mcasp->txnumevt) { /* enable FIFO */ | ||
201 | u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
202 | |||
203 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
204 | mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | ||
205 | } | ||
206 | |||
207 | /* Start clocks */ | ||
189 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); | 208 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); |
190 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); | 209 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); |
210 | /* Activate serializer(s) */ | ||
191 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); | 211 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); |
192 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | ||
193 | 212 | ||
194 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); | 213 | /* wait for XDATA to be cleared */ |
195 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | ||
196 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | ||
197 | for (i = 0; i < mcasp->num_serializer; i++) { | ||
198 | if (mcasp->serial_dir[i] == TX_MODE) { | ||
199 | offset = i; | ||
200 | break; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /* wait for TX ready */ | ||
205 | cnt = 0; | 214 | cnt = 0; |
206 | while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(offset)) & | 215 | while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & |
207 | TXSTATE) && (cnt < 100000)) | 216 | ~XRDATA) && (cnt < 100000)) |
208 | cnt++; | 217 | cnt++; |
209 | 218 | ||
210 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | 219 | /* Release TX state machine */ |
220 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); | ||
221 | /* Release Frame Sync generator */ | ||
222 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | ||
223 | |||
224 | /* enable transmit IRQs */ | ||
225 | mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, | ||
226 | mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); | ||
211 | } | 227 | } |
212 | 228 | ||
213 | static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) | 229 | static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) |
214 | { | 230 | { |
215 | u32 reg; | ||
216 | |||
217 | mcasp->streams++; | 231 | mcasp->streams++; |
218 | 232 | ||
219 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 233 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
220 | if (mcasp->txnumevt) { /* enable FIFO */ | ||
221 | reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
222 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
223 | mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | ||
224 | } | ||
225 | mcasp_start_tx(mcasp); | 234 | mcasp_start_tx(mcasp); |
226 | } else { | 235 | else |
227 | if (mcasp->rxnumevt) { /* enable FIFO */ | ||
228 | reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
229 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
230 | mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | ||
231 | } | ||
232 | mcasp_start_rx(mcasp); | 236 | mcasp_start_rx(mcasp); |
233 | } | ||
234 | } | 237 | } |
235 | 238 | ||
236 | static void mcasp_stop_rx(struct davinci_mcasp *mcasp) | 239 | static void mcasp_stop_rx(struct davinci_mcasp *mcasp) |
237 | { | 240 | { |
241 | /* disable IRQ sources */ | ||
242 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, | ||
243 | mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); | ||
244 | |||
238 | /* | 245 | /* |
239 | * In synchronous mode stop the TX clocks if no other stream is | 246 | * In synchronous mode stop the TX clocks if no other stream is |
240 | * running | 247 | * running |
@@ -244,12 +251,22 @@ static void mcasp_stop_rx(struct davinci_mcasp *mcasp) | |||
244 | 251 | ||
245 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); | 252 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); |
246 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); | 253 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); |
254 | |||
255 | if (mcasp->rxnumevt) { /* disable FIFO */ | ||
256 | u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
257 | |||
258 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
259 | } | ||
247 | } | 260 | } |
248 | 261 | ||
249 | static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | 262 | static void mcasp_stop_tx(struct davinci_mcasp *mcasp) |
250 | { | 263 | { |
251 | u32 val = 0; | 264 | u32 val = 0; |
252 | 265 | ||
266 | /* disable IRQ sources */ | ||
267 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, | ||
268 | mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); | ||
269 | |||
253 | /* | 270 | /* |
254 | * In synchronous mode keep TX clocks running if the capture stream is | 271 | * In synchronous mode keep TX clocks running if the capture stream is |
255 | * still running. | 272 | * still running. |
@@ -259,27 +276,92 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | |||
259 | 276 | ||
260 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); | 277 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); |
261 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); | 278 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); |
279 | |||
280 | if (mcasp->txnumevt) { /* disable FIFO */ | ||
281 | u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
282 | |||
283 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
284 | } | ||
262 | } | 285 | } |
263 | 286 | ||
264 | static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) | 287 | static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) |
265 | { | 288 | { |
266 | u32 reg; | ||
267 | |||
268 | mcasp->streams--; | 289 | mcasp->streams--; |
269 | 290 | ||
270 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 291 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
271 | if (mcasp->txnumevt) { /* disable FIFO */ | ||
272 | reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
273 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
274 | } | ||
275 | mcasp_stop_tx(mcasp); | 292 | mcasp_stop_tx(mcasp); |
276 | } else { | 293 | else |
277 | if (mcasp->rxnumevt) { /* disable FIFO */ | ||
278 | reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
279 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
280 | } | ||
281 | mcasp_stop_rx(mcasp); | 294 | mcasp_stop_rx(mcasp); |
295 | } | ||
296 | |||
297 | static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data) | ||
298 | { | ||
299 | struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; | ||
300 | struct snd_pcm_substream *substream; | ||
301 | u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]; | ||
302 | u32 handled_mask = 0; | ||
303 | u32 stat; | ||
304 | |||
305 | stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG); | ||
306 | if (stat & XUNDRN & irq_mask) { | ||
307 | dev_warn(mcasp->dev, "Transmit buffer underflow\n"); | ||
308 | handled_mask |= XUNDRN; | ||
309 | |||
310 | substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]; | ||
311 | if (substream) { | ||
312 | snd_pcm_stream_lock_irq(substream); | ||
313 | if (snd_pcm_running(substream)) | ||
314 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
315 | snd_pcm_stream_unlock_irq(substream); | ||
316 | } | ||
282 | } | 317 | } |
318 | |||
319 | if (!handled_mask) | ||
320 | dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n", | ||
321 | stat); | ||
322 | |||
323 | if (stat & XRERR) | ||
324 | handled_mask |= XRERR; | ||
325 | |||
326 | /* Ack the handled event only */ | ||
327 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask); | ||
328 | |||
329 | return IRQ_RETVAL(handled_mask); | ||
330 | } | ||
331 | |||
332 | static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data) | ||
333 | { | ||
334 | struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; | ||
335 | struct snd_pcm_substream *substream; | ||
336 | u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]; | ||
337 | u32 handled_mask = 0; | ||
338 | u32 stat; | ||
339 | |||
340 | stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG); | ||
341 | if (stat & ROVRN & irq_mask) { | ||
342 | dev_warn(mcasp->dev, "Receive buffer overflow\n"); | ||
343 | handled_mask |= ROVRN; | ||
344 | |||
345 | substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]; | ||
346 | if (substream) { | ||
347 | snd_pcm_stream_lock_irq(substream); | ||
348 | if (snd_pcm_running(substream)) | ||
349 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
350 | snd_pcm_stream_unlock_irq(substream); | ||
351 | } | ||
352 | } | ||
353 | |||
354 | if (!handled_mask) | ||
355 | dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n", | ||
356 | stat); | ||
357 | |||
358 | if (stat & XRERR) | ||
359 | handled_mask |= XRERR; | ||
360 | |||
361 | /* Ack the handled event only */ | ||
362 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask); | ||
363 | |||
364 | return IRQ_RETVAL(handled_mask); | ||
283 | } | 365 | } |
284 | 366 | ||
285 | static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 367 | static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
@@ -500,8 +582,17 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, | |||
500 | * both left and right channels), so it has to be divided by number of | 582 | * both left and right channels), so it has to be divided by number of |
501 | * tdm-slots (for I2S - divided by 2). | 583 | * tdm-slots (for I2S - divided by 2). |
502 | */ | 584 | */ |
503 | if (mcasp->bclk_lrclk_ratio) | 585 | if (mcasp->bclk_lrclk_ratio) { |
504 | word_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; | 586 | u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; |
587 | |||
588 | /* | ||
589 | * When we have more bclk then it is needed for the data, we | ||
590 | * need to use the rotation to move the received samples to have | ||
591 | * correct alignment. | ||
592 | */ | ||
593 | rx_rotate = (slot_length - word_length) / 4; | ||
594 | word_length = slot_length; | ||
595 | } | ||
505 | 596 | ||
506 | /* mapping of the XSSZ bit-field as described in the datasheet */ | 597 | /* mapping of the XSSZ bit-field as described in the datasheet */ |
507 | fmt = (word_length >> 1) - 1; | 598 | fmt = (word_length >> 1) - 1; |
@@ -635,19 +726,29 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, | |||
635 | return 0; | 726 | return 0; |
636 | } | 727 | } |
637 | 728 | ||
638 | static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) | 729 | static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, |
730 | int channels) | ||
639 | { | 731 | { |
640 | int i, active_slots; | 732 | int i, active_slots; |
733 | int total_slots; | ||
734 | int active_serializers; | ||
641 | u32 mask = 0; | 735 | u32 mask = 0; |
642 | u32 busel = 0; | 736 | u32 busel = 0; |
643 | 737 | ||
644 | if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) { | 738 | total_slots = mcasp->tdm_slots; |
645 | dev_err(mcasp->dev, "tdm slot %d not supported\n", | 739 | |
646 | mcasp->tdm_slots); | 740 | /* |
647 | return -EINVAL; | 741 | * If more than one serializer is needed, then use them with |
648 | } | 742 | * their specified tdm_slots count. Otherwise, one serializer |
743 | * can cope with the transaction using as many slots as channels | ||
744 | * in the stream, requires channels symmetry | ||
745 | */ | ||
746 | active_serializers = (channels + total_slots - 1) / total_slots; | ||
747 | if (active_serializers == 1) | ||
748 | active_slots = channels; | ||
749 | else | ||
750 | active_slots = total_slots; | ||
649 | 751 | ||
650 | active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots; | ||
651 | for (i = 0; i < active_slots; i++) | 752 | for (i = 0; i < active_slots; i++) |
652 | mask |= (1 << i); | 753 | mask |= (1 << i); |
653 | 754 | ||
@@ -659,12 +760,12 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) | |||
659 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); | 760 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); |
660 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); | 761 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); |
661 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, | 762 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, |
662 | FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); | 763 | FSXMOD(total_slots), FSXMOD(0x1FF)); |
663 | 764 | ||
664 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); | 765 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); |
665 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); | 766 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); |
666 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, | 767 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, |
667 | FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); | 768 | FSRMOD(total_slots), FSRMOD(0x1FF)); |
668 | 769 | ||
669 | return 0; | 770 | return 0; |
670 | } | 771 | } |
@@ -778,7 +879,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
778 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | 879 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) |
779 | ret = mcasp_dit_hw_param(mcasp, params_rate(params)); | 880 | ret = mcasp_dit_hw_param(mcasp, params_rate(params)); |
780 | else | 881 | else |
781 | ret = mcasp_i2s_hw_param(mcasp, substream->stream); | 882 | ret = mcasp_i2s_hw_param(mcasp, substream->stream, |
883 | channels); | ||
782 | 884 | ||
783 | if (ret) | 885 | if (ret) |
784 | return ret; | 886 | return ret; |
@@ -826,6 +928,9 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
826 | 928 | ||
827 | davinci_config_channel_size(mcasp, word_length); | 929 | davinci_config_channel_size(mcasp, word_length); |
828 | 930 | ||
931 | if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) | ||
932 | mcasp->channels = channels; | ||
933 | |||
829 | return 0; | 934 | return 0; |
830 | } | 935 | } |
831 | 936 | ||
@@ -854,7 +959,65 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, | |||
854 | return ret; | 959 | return ret; |
855 | } | 960 | } |
856 | 961 | ||
962 | static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | ||
963 | struct snd_soc_dai *cpu_dai) | ||
964 | { | ||
965 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); | ||
966 | u32 max_channels = 0; | ||
967 | int i, dir; | ||
968 | |||
969 | mcasp->substreams[substream->stream] = substream; | ||
970 | |||
971 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | ||
972 | return 0; | ||
973 | |||
974 | /* | ||
975 | * Limit the maximum allowed channels for the first stream: | ||
976 | * number of serializers for the direction * tdm slots per serializer | ||
977 | */ | ||
978 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
979 | dir = TX_MODE; | ||
980 | else | ||
981 | dir = RX_MODE; | ||
982 | |||
983 | for (i = 0; i < mcasp->num_serializer; i++) { | ||
984 | if (mcasp->serial_dir[i] == dir) | ||
985 | max_channels++; | ||
986 | } | ||
987 | max_channels *= mcasp->tdm_slots; | ||
988 | /* | ||
989 | * If the already active stream has less channels than the calculated | ||
990 | * limnit based on the seirializers * tdm_slots, we need to use that as | ||
991 | * a constraint for the second stream. | ||
992 | * Otherwise (first stream or less allowed channels) we use the | ||
993 | * calculated constraint. | ||
994 | */ | ||
995 | if (mcasp->channels && mcasp->channels < max_channels) | ||
996 | max_channels = mcasp->channels; | ||
997 | |||
998 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
999 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1000 | 2, max_channels); | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, | ||
1005 | struct snd_soc_dai *cpu_dai) | ||
1006 | { | ||
1007 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); | ||
1008 | |||
1009 | mcasp->substreams[substream->stream] = NULL; | ||
1010 | |||
1011 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | ||
1012 | return; | ||
1013 | |||
1014 | if (!cpu_dai->active) | ||
1015 | mcasp->channels = 0; | ||
1016 | } | ||
1017 | |||
857 | static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { | 1018 | static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { |
1019 | .startup = davinci_mcasp_startup, | ||
1020 | .shutdown = davinci_mcasp_shutdown, | ||
858 | .trigger = davinci_mcasp_trigger, | 1021 | .trigger = davinci_mcasp_trigger, |
859 | .hw_params = davinci_mcasp_hw_params, | 1022 | .hw_params = davinci_mcasp_hw_params, |
860 | .set_fmt = davinci_mcasp_set_dai_fmt, | 1023 | .set_fmt = davinci_mcasp_set_dai_fmt, |
@@ -971,6 +1134,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { | |||
971 | }, | 1134 | }, |
972 | .ops = &davinci_mcasp_dai_ops, | 1135 | .ops = &davinci_mcasp_dai_ops, |
973 | 1136 | ||
1137 | .symmetric_samplebits = 1, | ||
974 | }, | 1138 | }, |
975 | { | 1139 | { |
976 | .name = "davinci-mcasp.1", | 1140 | .name = "davinci-mcasp.1", |
@@ -1194,6 +1358,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1194 | struct resource *mem, *ioarea, *res, *dat; | 1358 | struct resource *mem, *ioarea, *res, *dat; |
1195 | struct davinci_mcasp_pdata *pdata; | 1359 | struct davinci_mcasp_pdata *pdata; |
1196 | struct davinci_mcasp *mcasp; | 1360 | struct davinci_mcasp *mcasp; |
1361 | char *irq_name; | ||
1362 | int irq; | ||
1197 | int ret; | 1363 | int ret; |
1198 | 1364 | ||
1199 | if (!pdev->dev.platform_data && !pdev->dev.of_node) { | 1365 | if (!pdev->dev.platform_data && !pdev->dev.of_node) { |
@@ -1235,6 +1401,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1235 | ret = pm_runtime_get_sync(&pdev->dev); | 1401 | ret = pm_runtime_get_sync(&pdev->dev); |
1236 | if (IS_ERR_VALUE(ret)) { | 1402 | if (IS_ERR_VALUE(ret)) { |
1237 | dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); | 1403 | dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); |
1404 | pm_runtime_disable(&pdev->dev); | ||
1238 | return ret; | 1405 | return ret; |
1239 | } | 1406 | } |
1240 | 1407 | ||
@@ -1246,7 +1413,21 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1246 | } | 1413 | } |
1247 | 1414 | ||
1248 | mcasp->op_mode = pdata->op_mode; | 1415 | mcasp->op_mode = pdata->op_mode; |
1249 | mcasp->tdm_slots = pdata->tdm_slots; | 1416 | /* sanity check for tdm slots parameter */ |
1417 | if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { | ||
1418 | if (pdata->tdm_slots < 2) { | ||
1419 | dev_err(&pdev->dev, "invalid tdm slots: %d\n", | ||
1420 | pdata->tdm_slots); | ||
1421 | mcasp->tdm_slots = 2; | ||
1422 | } else if (pdata->tdm_slots > 32) { | ||
1423 | dev_err(&pdev->dev, "invalid tdm slots: %d\n", | ||
1424 | pdata->tdm_slots); | ||
1425 | mcasp->tdm_slots = 32; | ||
1426 | } else { | ||
1427 | mcasp->tdm_slots = pdata->tdm_slots; | ||
1428 | } | ||
1429 | } | ||
1430 | |||
1250 | mcasp->num_serializer = pdata->num_serializer; | 1431 | mcasp->num_serializer = pdata->num_serializer; |
1251 | #ifdef CONFIG_PM_SLEEP | 1432 | #ifdef CONFIG_PM_SLEEP |
1252 | mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev, | 1433 | mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev, |
@@ -1260,6 +1441,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1260 | 1441 | ||
1261 | mcasp->dev = &pdev->dev; | 1442 | mcasp->dev = &pdev->dev; |
1262 | 1443 | ||
1444 | irq = platform_get_irq_byname(pdev, "rx"); | ||
1445 | if (irq >= 0) { | ||
1446 | irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n", | ||
1447 | dev_name(&pdev->dev)); | ||
1448 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
1449 | davinci_mcasp_rx_irq_handler, | ||
1450 | IRQF_ONESHOT, irq_name, mcasp); | ||
1451 | if (ret) { | ||
1452 | dev_err(&pdev->dev, "RX IRQ request failed\n"); | ||
1453 | goto err; | ||
1454 | } | ||
1455 | |||
1456 | mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; | ||
1457 | } | ||
1458 | |||
1459 | irq = platform_get_irq_byname(pdev, "tx"); | ||
1460 | if (irq >= 0) { | ||
1461 | irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx\n", | ||
1462 | dev_name(&pdev->dev)); | ||
1463 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
1464 | davinci_mcasp_tx_irq_handler, | ||
1465 | IRQF_ONESHOT, irq_name, mcasp); | ||
1466 | if (ret) { | ||
1467 | dev_err(&pdev->dev, "TX IRQ request failed\n"); | ||
1468 | goto err; | ||
1469 | } | ||
1470 | |||
1471 | mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; | ||
1472 | } | ||
1473 | |||
1263 | dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); | 1474 | dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); |
1264 | if (dat) | 1475 | if (dat) |
1265 | mcasp->dat_port = true; | 1476 | mcasp->dat_port = true; |
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 98fbc451892a..79dc511180bf 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h | |||
@@ -253,6 +253,13 @@ | |||
253 | #define TXFSRST BIT(12) /* Frame Sync Generator Reset */ | 253 | #define TXFSRST BIT(12) /* Frame Sync Generator Reset */ |
254 | 254 | ||
255 | /* | 255 | /* |
256 | * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits | ||
257 | * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits | ||
258 | */ | ||
259 | #define XRERR BIT(8) /* Transmit/Receive error */ | ||
260 | #define XRDATA BIT(5) /* Transmit/Receive data ready */ | ||
261 | |||
262 | /* | ||
256 | * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits | 263 | * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits |
257 | */ | 264 | */ |
258 | #define MUTENA(val) (val) | 265 | #define MUTENA(val) (val) |
@@ -279,6 +286,16 @@ | |||
279 | #define TXDATADMADIS BIT(0) | 286 | #define TXDATADMADIS BIT(0) |
280 | 287 | ||
281 | /* | 288 | /* |
289 | * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits | ||
290 | */ | ||
291 | #define ROVRN BIT(0) | ||
292 | |||
293 | /* | ||
294 | * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits | ||
295 | */ | ||
296 | #define XUNDRN BIT(0) | ||
297 | |||
298 | /* | ||
282 | * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits | 299 | * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits |
283 | */ | 300 | */ |
284 | #define FIFO_ENABLE BIT(16) | 301 | #define FIFO_ENABLE BIT(16) |
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index e961388e6e9c..08f0229f8d68 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c | |||
@@ -338,31 +338,34 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
338 | return -EINVAL; | 338 | return -EINVAL; |
339 | } | 339 | } |
340 | 340 | ||
341 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
342 | if (!res) { | ||
343 | dev_err(&pdev->dev, "no i2s resource defined\n"); | ||
344 | return -ENODEV; | ||
345 | } | ||
346 | |||
347 | if (!devm_request_mem_region(&pdev->dev, res->start, | ||
348 | resource_size(res), pdev->name)) { | ||
349 | dev_err(&pdev->dev, "i2s region already claimed\n"); | ||
350 | return -EBUSY; | ||
351 | } | ||
352 | |||
353 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); | 341 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); |
354 | if (!dev) { | 342 | if (!dev) { |
355 | dev_warn(&pdev->dev, "kzalloc fail\n"); | 343 | dev_warn(&pdev->dev, "kzalloc fail\n"); |
356 | return -ENOMEM; | 344 | return -ENOMEM; |
357 | } | 345 | } |
358 | 346 | ||
359 | dev->i2s_base = devm_ioremap(&pdev->dev, res->start, | 347 | dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL); |
360 | resource_size(res)); | 348 | if (!dw_i2s_dai) { |
361 | if (!dev->i2s_base) { | 349 | dev_err(&pdev->dev, "mem allocation failed for dai driver\n"); |
362 | dev_err(&pdev->dev, "ioremap fail for i2s_region\n"); | ||
363 | return -ENOMEM; | 350 | return -ENOMEM; |
364 | } | 351 | } |
365 | 352 | ||
353 | dw_i2s_dai->ops = &dw_i2s_dai_ops; | ||
354 | dw_i2s_dai->suspend = dw_i2s_suspend; | ||
355 | dw_i2s_dai->resume = dw_i2s_resume; | ||
356 | |||
357 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
358 | if (!res) { | ||
359 | dev_err(&pdev->dev, "no i2s resource defined\n"); | ||
360 | return -ENODEV; | ||
361 | } | ||
362 | |||
363 | dev->i2s_base = devm_ioremap_resource(&pdev->dev, res); | ||
364 | if (IS_ERR(dev->i2s_base)) { | ||
365 | dev_err(&pdev->dev, "ioremap fail for i2s_region\n"); | ||
366 | return PTR_ERR(dev->i2s_base); | ||
367 | } | ||
368 | |||
366 | cap = pdata->cap; | 369 | cap = pdata->cap; |
367 | dev->capability = cap; | 370 | dev->capability = cap; |
368 | dev->i2s_clk_cfg = pdata->i2s_clk_cfg; | 371 | dev->i2s_clk_cfg = pdata->i2s_clk_cfg; |
@@ -388,13 +391,6 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
388 | if (ret < 0) | 391 | if (ret < 0) |
389 | goto err_clk_put; | 392 | goto err_clk_put; |
390 | 393 | ||
391 | dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL); | ||
392 | if (!dw_i2s_dai) { | ||
393 | dev_err(&pdev->dev, "mem allocation failed for dai driver\n"); | ||
394 | ret = -ENOMEM; | ||
395 | goto err_clk_disable; | ||
396 | } | ||
397 | |||
398 | if (cap & DWC_I2S_PLAY) { | 394 | if (cap & DWC_I2S_PLAY) { |
399 | dev_dbg(&pdev->dev, " designware: play supported\n"); | 395 | dev_dbg(&pdev->dev, " designware: play supported\n"); |
400 | dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; | 396 | dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; |
@@ -411,10 +407,6 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
411 | dw_i2s_dai->capture.rates = pdata->snd_rates; | 407 | dw_i2s_dai->capture.rates = pdata->snd_rates; |
412 | } | 408 | } |
413 | 409 | ||
414 | dw_i2s_dai->ops = &dw_i2s_dai_ops; | ||
415 | dw_i2s_dai->suspend = dw_i2s_suspend; | ||
416 | dw_i2s_dai->resume = dw_i2s_resume; | ||
417 | |||
418 | dev->dev = &pdev->dev; | 410 | dev->dev = &pdev->dev; |
419 | dev_set_drvdata(&pdev->dev, dev); | 411 | dev_set_drvdata(&pdev->dev, dev); |
420 | ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, | 412 | ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, |
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index eb093d5b85c4..b175b0145a42 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c | |||
@@ -105,7 +105,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
105 | int ret; | 105 | int ret; |
106 | int int_port = 0, ext_port; | 106 | int int_port = 0, ext_port; |
107 | struct device_node *np = pdev->dev.of_node; | 107 | struct device_node *np = pdev->dev.of_node; |
108 | struct device_node *ssi_np, *codec_np; | 108 | struct device_node *ssi_np = NULL, *codec_np = NULL; |
109 | 109 | ||
110 | eukrea_tlv320.dev = &pdev->dev; | 110 | eukrea_tlv320.dev = &pdev->dev; |
111 | if (np) { | 111 | if (np) { |
@@ -217,8 +217,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
217 | err: | 217 | err: |
218 | if (ret) | 218 | if (ret) |
219 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); | 219 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); |
220 | if (np) | 220 | of_node_put(ssi_np); |
221 | of_node_put(ssi_np); | ||
222 | 221 | ||
223 | return ret; | 222 | return ret; |
224 | } | 223 | } |
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 007c772f3cef..3f6959c8e2f7 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c | |||
@@ -51,6 +51,7 @@ struct codec_priv { | |||
51 | * @sysclk_freq[2]: SYSCLK rates for set_sysclk() | 51 | * @sysclk_freq[2]: SYSCLK rates for set_sysclk() |
52 | * @sysclk_dir[2]: SYSCLK directions for set_sysclk() | 52 | * @sysclk_dir[2]: SYSCLK directions for set_sysclk() |
53 | * @sysclk_id[2]: SYSCLK ids for set_sysclk() | 53 | * @sysclk_id[2]: SYSCLK ids for set_sysclk() |
54 | * @slot_width: Slot width of each frame | ||
54 | * | 55 | * |
55 | * Note: [1] for tx and [0] for rx | 56 | * Note: [1] for tx and [0] for rx |
56 | */ | 57 | */ |
@@ -58,6 +59,7 @@ struct cpu_priv { | |||
58 | unsigned long sysclk_freq[2]; | 59 | unsigned long sysclk_freq[2]; |
59 | u32 sysclk_dir[2]; | 60 | u32 sysclk_dir[2]; |
60 | u32 sysclk_id[2]; | 61 | u32 sysclk_id[2]; |
62 | u32 slot_width; | ||
61 | }; | 63 | }; |
62 | 64 | ||
63 | /** | 65 | /** |
@@ -125,7 +127,12 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, | |||
125 | priv->sample_rate = params_rate(params); | 127 | priv->sample_rate = params_rate(params); |
126 | priv->sample_format = params_format(params); | 128 | priv->sample_format = params_format(params); |
127 | 129 | ||
128 | if (priv->card.set_bias_level) | 130 | /* |
131 | * If codec-dai is DAI Master and all configurations are already in the | ||
132 | * set_bias_level(), bypass the remaining settings in hw_params(). | ||
133 | * Note: (dai_fmt & CBM_CFM) includes CBM_CFM and CBM_CFS. | ||
134 | */ | ||
135 | if (priv->card.set_bias_level && priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM) | ||
129 | return 0; | 136 | return 0; |
130 | 137 | ||
131 | /* Specific configurations of DAIs starts from here */ | 138 | /* Specific configurations of DAIs starts from here */ |
@@ -137,6 +144,15 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, | |||
137 | return ret; | 144 | return ret; |
138 | } | 145 | } |
139 | 146 | ||
147 | if (cpu_priv->slot_width) { | ||
148 | ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, | ||
149 | cpu_priv->slot_width); | ||
150 | if (ret) { | ||
151 | dev_err(dev, "failed to set TDM slot for cpu dai\n"); | ||
152 | return ret; | ||
153 | } | ||
154 | } | ||
155 | |||
140 | return 0; | 156 | return 0; |
141 | } | 157 | } |
142 | 158 | ||
@@ -448,6 +464,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) | |||
448 | priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; | 464 | priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; |
449 | priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; | 465 | priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; |
450 | priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; | 466 | priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; |
467 | priv->cpu_priv.slot_width = 32; | ||
451 | priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; | 468 | priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; |
452 | } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { | 469 | } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { |
453 | priv->codec_priv.mclk_id = SGTL5000_SYSCLK; | 470 | priv->codec_priv.mclk_id = SGTL5000_SYSCLK; |
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index a645e296199e..ca319d59f843 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c | |||
@@ -513,10 +513,15 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | |||
513 | u32 width = snd_pcm_format_width(params_format(params)); | 513 | u32 width = snd_pcm_format_width(params_format(params)); |
514 | u32 channels = params_channels(params); | 514 | u32 channels = params_channels(params); |
515 | u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); | 515 | u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); |
516 | u32 slot_width = width; | ||
516 | u32 bclk, mask, val; | 517 | u32 bclk, mask, val; |
517 | int ret; | 518 | int ret; |
518 | 519 | ||
519 | bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots; | 520 | /* Override slot_width if being specifially set */ |
521 | if (esai_priv->slot_width) | ||
522 | slot_width = esai_priv->slot_width; | ||
523 | |||
524 | bclk = params_rate(params) * slot_width * esai_priv->slots; | ||
520 | 525 | ||
521 | ret = fsl_esai_set_bclk(dai, tx, bclk); | 526 | ret = fsl_esai_set_bclk(dai, tx, bclk); |
522 | if (ret) | 527 | if (ret) |
@@ -538,7 +543,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | |||
538 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); | 543 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); |
539 | 544 | ||
540 | mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); | 545 | mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); |
541 | val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0); | 546 | val = ESAI_xCR_xSWS(slot_width, width) | (tx ? ESAI_xCR_PADC : 0); |
542 | 547 | ||
543 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); | 548 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); |
544 | 549 | ||
@@ -780,9 +785,6 @@ static int fsl_esai_probe(struct platform_device *pdev) | |||
780 | return ret; | 785 | return ret; |
781 | } | 786 | } |
782 | 787 | ||
783 | /* Set a default slot size */ | ||
784 | esai_priv->slot_width = 32; | ||
785 | |||
786 | /* Set a default slot number */ | 788 | /* Set a default slot number */ |
787 | esai_priv->slots = 2; | 789 | esai_priv->slots = 2; |
788 | 790 | ||
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e6955170dc42..b6b0d25f6ace 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -67,8 +67,6 @@ | |||
67 | /** | 67 | /** |
68 | * FSLSSI_I2S_FORMATS: audio formats supported by the SSI | 68 | * FSLSSI_I2S_FORMATS: audio formats supported by the SSI |
69 | * | 69 | * |
70 | * This driver currently only supports the SSI running in I2S slave mode. | ||
71 | * | ||
72 | * The SSI has a limitation in that the samples must be in the same byte | 70 | * The SSI has a limitation in that the samples must be in the same byte |
73 | * order as the host CPU. This is because when multiple bytes are written | 71 | * order as the host CPU. This is because when multiple bytes are written |
74 | * to the STX register, the bytes and bits must be written in the same | 72 | * to the STX register, the bytes and bits must be written in the same |
@@ -1099,7 +1097,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = { | |||
1099 | }; | 1097 | }; |
1100 | 1098 | ||
1101 | static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { | 1099 | static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { |
1102 | .ac97_control = 1, | 1100 | .bus_control = true, |
1103 | .playback = { | 1101 | .playback = { |
1104 | .stream_name = "AC97 Playback", | 1102 | .stream_name = "AC97 Playback", |
1105 | .channels_min = 2, | 1103 | .channels_min = 2, |
@@ -1363,7 +1361,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1363 | return PTR_ERR(ssi_private->regs); | 1361 | return PTR_ERR(ssi_private->regs); |
1364 | } | 1362 | } |
1365 | 1363 | ||
1366 | ssi_private->irq = irq_of_parse_and_map(np, 0); | 1364 | ssi_private->irq = platform_get_irq(pdev, 0); |
1367 | if (!ssi_private->irq) { | 1365 | if (!ssi_private->irq) { |
1368 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); | 1366 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); |
1369 | return -ENXIO; | 1367 | return -ENXIO; |
@@ -1389,7 +1387,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1389 | if (ssi_private->soc->imx) { | 1387 | if (ssi_private->soc->imx) { |
1390 | ret = fsl_ssi_imx_probe(pdev, ssi_private, iomem); | 1388 | ret = fsl_ssi_imx_probe(pdev, ssi_private, iomem); |
1391 | if (ret) | 1389 | if (ret) |
1392 | goto error_irqmap; | 1390 | return ret; |
1393 | } | 1391 | } |
1394 | 1392 | ||
1395 | ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component, | 1393 | ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component, |
@@ -1412,7 +1410,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1412 | 1410 | ||
1413 | ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev); | 1411 | ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev); |
1414 | if (ret) | 1412 | if (ret) |
1415 | goto error_asoc_register; | 1413 | goto error_irq; |
1416 | 1414 | ||
1417 | /* | 1415 | /* |
1418 | * If codec-handle property is missing from SSI node, we assume | 1416 | * If codec-handle property is missing from SSI node, we assume |
@@ -1460,10 +1458,6 @@ error_asoc_register: | |||
1460 | if (ssi_private->soc->imx) | 1458 | if (ssi_private->soc->imx) |
1461 | fsl_ssi_imx_clean(pdev, ssi_private); | 1459 | fsl_ssi_imx_clean(pdev, ssi_private); |
1462 | 1460 | ||
1463 | error_irqmap: | ||
1464 | if (ssi_private->use_dma) | ||
1465 | irq_dispose_mapping(ssi_private->irq); | ||
1466 | |||
1467 | return ret; | 1461 | return ret; |
1468 | } | 1462 | } |
1469 | 1463 | ||
@@ -1480,9 +1474,6 @@ static int fsl_ssi_remove(struct platform_device *pdev) | |||
1480 | if (ssi_private->soc->imx) | 1474 | if (ssi_private->soc->imx) |
1481 | fsl_ssi_imx_clean(pdev, ssi_private); | 1475 | fsl_ssi_imx_clean(pdev, ssi_private); |
1482 | 1476 | ||
1483 | if (ssi_private->use_dma) | ||
1484 | irq_dispose_mapping(ssi_private->irq); | ||
1485 | |||
1486 | return 0; | 1477 | return 0; |
1487 | } | 1478 | } |
1488 | 1479 | ||
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 1cb22dd034eb..1dab963a59f7 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c | |||
@@ -175,10 +175,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) | |||
175 | fail: | 175 | fail: |
176 | if (data && !IS_ERR(data->codec_clk)) | 176 | if (data && !IS_ERR(data->codec_clk)) |
177 | clk_put(data->codec_clk); | 177 | clk_put(data->codec_clk); |
178 | if (ssi_np) | 178 | of_node_put(ssi_np); |
179 | of_node_put(ssi_np); | 179 | of_node_put(codec_np); |
180 | if (codec_np) | ||
181 | of_node_put(codec_np); | ||
182 | 180 | ||
183 | return ret; | 181 | return ret; |
184 | } | 182 | } |
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index e1dc40143600..0c9068ebe1e7 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c | |||
@@ -74,8 +74,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) | |||
74 | platform_set_drvdata(pdev, data); | 74 | platform_set_drvdata(pdev, data); |
75 | 75 | ||
76 | end: | 76 | end: |
77 | if (spdif_np) | 77 | of_node_put(spdif_np); |
78 | of_node_put(spdif_np); | ||
79 | 78 | ||
80 | return ret; | 79 | return ret; |
81 | } | 80 | } |
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index ab2fdd76b693..60b0a5b1f1f1 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c | |||
@@ -382,7 +382,7 @@ static struct snd_soc_dai_driver imx_ssi_dai = { | |||
382 | 382 | ||
383 | static struct snd_soc_dai_driver imx_ac97_dai = { | 383 | static struct snd_soc_dai_driver imx_ac97_dai = { |
384 | .probe = imx_ssi_dai_probe, | 384 | .probe = imx_ssi_dai_probe, |
385 | .ac97_control = 1, | 385 | .bus_control = true, |
386 | .playback = { | 386 | .playback = { |
387 | .stream_name = "AC97 Playback", | 387 | .stream_name = "AC97 Playback", |
388 | .channels_min = 2, | 388 | .channels_min = 2, |
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 3a3d17ce6ba4..48179ffe1543 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c | |||
@@ -281,10 +281,8 @@ static int imx_wm8962_probe(struct platform_device *pdev) | |||
281 | clk_fail: | 281 | clk_fail: |
282 | clk_disable_unprepare(data->codec_clk); | 282 | clk_disable_unprepare(data->codec_clk); |
283 | fail: | 283 | fail: |
284 | if (ssi_np) | 284 | of_node_put(ssi_np); |
285 | of_node_put(ssi_np); | 285 | of_node_put(codec_np); |
286 | if (codec_np) | ||
287 | of_node_put(codec_np); | ||
288 | 286 | ||
289 | return ret; | 287 | return ret; |
290 | } | 288 | } |
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index f2b5d756b1f3..0b82e209b6e3 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c | |||
@@ -327,9 +327,6 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) | |||
327 | goto capture_alloc_err; | 327 | goto capture_alloc_err; |
328 | } | 328 | } |
329 | 329 | ||
330 | if (rtd->codec->ac97) | ||
331 | rtd->codec->ac97->private_data = psc_dma; | ||
332 | |||
333 | return 0; | 330 | return 0; |
334 | 331 | ||
335 | capture_alloc_err: | 332 | capture_alloc_err: |
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 24eafa2cfbf4..c6ed6ba965a9 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c | |||
@@ -237,7 +237,7 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = { | |||
237 | static struct snd_soc_dai_driver psc_ac97_dai[] = { | 237 | static struct snd_soc_dai_driver psc_ac97_dai[] = { |
238 | { | 238 | { |
239 | .name = "mpc5200-psc-ac97.0", | 239 | .name = "mpc5200-psc-ac97.0", |
240 | .ac97_control = 1, | 240 | .bus_control = true, |
241 | .probe = psc_ac97_probe, | 241 | .probe = psc_ac97_probe, |
242 | .playback = { | 242 | .playback = { |
243 | .stream_name = "AC97 Playback", | 243 | .stream_name = "AC97 Playback", |
@@ -257,7 +257,7 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = { | |||
257 | }, | 257 | }, |
258 | { | 258 | { |
259 | .name = "mpc5200-psc-ac97.1", | 259 | .name = "mpc5200-psc-ac97.1", |
260 | .ac97_control = 1, | 260 | .bus_control = true, |
261 | .playback = { | 261 | .playback = { |
262 | .stream_name = "AC97 SPDIF", | 262 | .stream_name = "AC97 SPDIF", |
263 | .channels_min = 1, | 263 | .channels_min = 1, |
@@ -282,7 +282,6 @@ static const struct snd_soc_component_driver psc_ac97_component = { | |||
282 | static int psc_ac97_of_probe(struct platform_device *op) | 282 | static int psc_ac97_of_probe(struct platform_device *op) |
283 | { | 283 | { |
284 | int rc; | 284 | int rc; |
285 | struct snd_ac97 ac97; | ||
286 | struct mpc52xx_psc __iomem *regs; | 285 | struct mpc52xx_psc __iomem *regs; |
287 | 286 | ||
288 | rc = mpc5200_audio_dma_create(op); | 287 | rc = mpc5200_audio_dma_create(op); |
@@ -304,7 +303,6 @@ static int psc_ac97_of_probe(struct platform_device *op) | |||
304 | 303 | ||
305 | psc_dma = dev_get_drvdata(&op->dev); | 304 | psc_dma = dev_get_drvdata(&op->dev); |
306 | regs = psc_dma->psc_regs; | 305 | regs = psc_dma->psc_regs; |
307 | ac97.private_data = psc_dma; | ||
308 | 306 | ||
309 | psc_dma->imr = 0; | 307 | psc_dma->imr = 0; |
310 | out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); | 308 | out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); |
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d1b7293c133e..ece22d55ba82 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -29,7 +29,9 @@ struct simple_card_data { | |||
29 | } *dai_props; | 29 | } *dai_props; |
30 | unsigned int mclk_fs; | 30 | unsigned int mclk_fs; |
31 | int gpio_hp_det; | 31 | int gpio_hp_det; |
32 | int gpio_hp_det_invert; | ||
32 | int gpio_mic_det; | 33 | int gpio_mic_det; |
34 | int gpio_mic_det_invert; | ||
33 | struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ | 35 | struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ |
34 | }; | 36 | }; |
35 | 37 | ||
@@ -148,6 +150,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | |||
148 | simple_card_hp_jack_pins); | 150 | simple_card_hp_jack_pins); |
149 | 151 | ||
150 | simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; | 152 | simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; |
153 | simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert; | ||
151 | snd_soc_jack_add_gpios(&simple_card_hp_jack, 1, | 154 | snd_soc_jack_add_gpios(&simple_card_hp_jack, 1, |
152 | &simple_card_hp_jack_gpio); | 155 | &simple_card_hp_jack_gpio); |
153 | } | 156 | } |
@@ -159,6 +162,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | |||
159 | ARRAY_SIZE(simple_card_mic_jack_pins), | 162 | ARRAY_SIZE(simple_card_mic_jack_pins), |
160 | simple_card_mic_jack_pins); | 163 | simple_card_mic_jack_pins); |
161 | simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; | 164 | simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; |
165 | simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert; | ||
162 | snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, | 166 | snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, |
163 | &simple_card_mic_jack_gpio); | 167 | &simple_card_mic_jack_gpio); |
164 | } | 168 | } |
@@ -226,6 +230,52 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
226 | return 0; | 230 | return 0; |
227 | } | 231 | } |
228 | 232 | ||
233 | static int asoc_simple_card_parse_daifmt(struct device_node *node, | ||
234 | struct simple_card_data *priv, | ||
235 | struct device_node *codec, | ||
236 | char *prefix, int idx) | ||
237 | { | ||
238 | struct device *dev = simple_priv_to_dev(priv); | ||
239 | struct device_node *bitclkmaster = NULL; | ||
240 | struct device_node *framemaster = NULL; | ||
241 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); | ||
242 | struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; | ||
243 | struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; | ||
244 | unsigned int daifmt; | ||
245 | |||
246 | daifmt = snd_soc_of_parse_daifmt(node, prefix, | ||
247 | &bitclkmaster, &framemaster); | ||
248 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; | ||
249 | |||
250 | if (strlen(prefix) && !bitclkmaster && !framemaster) { | ||
251 | /* | ||
252 | * No dai-link level and master setting was not found from | ||
253 | * sound node level, revert back to legacy DT parsing and | ||
254 | * take the settings from codec node. | ||
255 | */ | ||
256 | dev_dbg(dev, "Revert to legacy daifmt parsing\n"); | ||
257 | |||
258 | cpu_dai->fmt = codec_dai->fmt = | ||
259 | snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | | ||
260 | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); | ||
261 | } else { | ||
262 | if (codec == bitclkmaster) | ||
263 | daifmt |= (codec == framemaster) ? | ||
264 | SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; | ||
265 | else | ||
266 | daifmt |= (codec == framemaster) ? | ||
267 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; | ||
268 | |||
269 | cpu_dai->fmt = daifmt; | ||
270 | codec_dai->fmt = daifmt; | ||
271 | } | ||
272 | |||
273 | of_node_put(bitclkmaster); | ||
274 | of_node_put(framemaster); | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
229 | static int asoc_simple_card_dai_link_of(struct device_node *node, | 279 | static int asoc_simple_card_dai_link_of(struct device_node *node, |
230 | struct simple_card_data *priv, | 280 | struct simple_card_data *priv, |
231 | int idx, | 281 | int idx, |
@@ -234,10 +284,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
234 | struct device *dev = simple_priv_to_dev(priv); | 284 | struct device *dev = simple_priv_to_dev(priv); |
235 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); | 285 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); |
236 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); | 286 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); |
237 | struct device_node *np = NULL; | 287 | struct device_node *cpu = NULL; |
238 | struct device_node *bitclkmaster = NULL; | 288 | struct device_node *codec = NULL; |
239 | struct device_node *framemaster = NULL; | ||
240 | unsigned int daifmt; | ||
241 | char *name; | 289 | char *name; |
242 | char prop[128]; | 290 | char prop[128]; |
243 | char *prefix = ""; | 291 | char *prefix = ""; |
@@ -247,85 +295,36 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
247 | if (is_top_level_node) | 295 | if (is_top_level_node) |
248 | prefix = "simple-audio-card,"; | 296 | prefix = "simple-audio-card,"; |
249 | 297 | ||
250 | daifmt = snd_soc_of_parse_daifmt(node, prefix, | ||
251 | &bitclkmaster, &framemaster); | ||
252 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; | ||
253 | |||
254 | snprintf(prop, sizeof(prop), "%scpu", prefix); | 298 | snprintf(prop, sizeof(prop), "%scpu", prefix); |
255 | np = of_get_child_by_name(node, prop); | 299 | cpu = of_get_child_by_name(node, prop); |
256 | if (!np) { | 300 | |
301 | snprintf(prop, sizeof(prop), "%scodec", prefix); | ||
302 | codec = of_get_child_by_name(node, prop); | ||
303 | |||
304 | if (!cpu || !codec) { | ||
257 | ret = -EINVAL; | 305 | ret = -EINVAL; |
258 | dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); | 306 | dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); |
259 | goto dai_link_of_err; | 307 | goto dai_link_of_err; |
260 | } | 308 | } |
261 | 309 | ||
262 | ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai, | 310 | ret = asoc_simple_card_parse_daifmt(node, priv, |
311 | codec, prefix, idx); | ||
312 | if (ret < 0) | ||
313 | goto dai_link_of_err; | ||
314 | |||
315 | ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai, | ||
263 | &dai_link->cpu_of_node, | 316 | &dai_link->cpu_of_node, |
264 | &dai_link->cpu_dai_name, | 317 | &dai_link->cpu_dai_name, |
265 | &cpu_args); | 318 | &cpu_args); |
266 | if (ret < 0) | 319 | if (ret < 0) |
267 | goto dai_link_of_err; | 320 | goto dai_link_of_err; |
268 | 321 | ||
269 | dai_props->cpu_dai.fmt = daifmt; | 322 | ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai, |
270 | switch (((np == bitclkmaster) << 4) | (np == framemaster)) { | ||
271 | case 0x11: | ||
272 | dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS; | ||
273 | break; | ||
274 | case 0x10: | ||
275 | dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM; | ||
276 | break; | ||
277 | case 0x01: | ||
278 | dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS; | ||
279 | break; | ||
280 | default: | ||
281 | dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM; | ||
282 | break; | ||
283 | } | ||
284 | |||
285 | of_node_put(np); | ||
286 | snprintf(prop, sizeof(prop), "%scodec", prefix); | ||
287 | np = of_get_child_by_name(node, prop); | ||
288 | if (!np) { | ||
289 | ret = -EINVAL; | ||
290 | dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); | ||
291 | goto dai_link_of_err; | ||
292 | } | ||
293 | |||
294 | ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai, | ||
295 | &dai_link->codec_of_node, | 323 | &dai_link->codec_of_node, |
296 | &dai_link->codec_dai_name, NULL); | 324 | &dai_link->codec_dai_name, NULL); |
297 | if (ret < 0) | 325 | if (ret < 0) |
298 | goto dai_link_of_err; | 326 | goto dai_link_of_err; |
299 | 327 | ||
300 | if (strlen(prefix) && !bitclkmaster && !framemaster) { | ||
301 | /* | ||
302 | * No DAI link level and master setting was found | ||
303 | * from sound node level, revert back to legacy DT | ||
304 | * parsing and take the settings from codec node. | ||
305 | */ | ||
306 | dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n", | ||
307 | __func__); | ||
308 | dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt = | ||
309 | snd_soc_of_parse_daifmt(np, NULL, NULL, NULL) | | ||
310 | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); | ||
311 | } else { | ||
312 | dai_props->codec_dai.fmt = daifmt; | ||
313 | switch (((np == bitclkmaster) << 4) | (np == framemaster)) { | ||
314 | case 0x11: | ||
315 | dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM; | ||
316 | break; | ||
317 | case 0x10: | ||
318 | dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS; | ||
319 | break; | ||
320 | case 0x01: | ||
321 | dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM; | ||
322 | break; | ||
323 | default: | ||
324 | dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS; | ||
325 | break; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { | 328 | if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { |
330 | ret = -EINVAL; | 329 | ret = -EINVAL; |
331 | goto dai_link_of_err; | 330 | goto dai_link_of_err; |
@@ -368,12 +367,9 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
368 | dai_link->cpu_dai_name = NULL; | 367 | dai_link->cpu_dai_name = NULL; |
369 | 368 | ||
370 | dai_link_of_err: | 369 | dai_link_of_err: |
371 | if (np) | 370 | of_node_put(cpu); |
372 | of_node_put(np); | 371 | of_node_put(codec); |
373 | if (bitclkmaster) | 372 | |
374 | of_node_put(bitclkmaster); | ||
375 | if (framemaster) | ||
376 | of_node_put(framemaster); | ||
377 | return ret; | 373 | return ret; |
378 | } | 374 | } |
379 | 375 | ||
@@ -381,6 +377,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
381 | struct simple_card_data *priv) | 377 | struct simple_card_data *priv) |
382 | { | 378 | { |
383 | struct device *dev = simple_priv_to_dev(priv); | 379 | struct device *dev = simple_priv_to_dev(priv); |
380 | enum of_gpio_flags flags; | ||
384 | u32 val; | 381 | u32 val; |
385 | int ret; | 382 | int ret; |
386 | 383 | ||
@@ -436,13 +433,15 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
436 | return ret; | 433 | return ret; |
437 | } | 434 | } |
438 | 435 | ||
439 | priv->gpio_hp_det = of_get_named_gpio(node, | 436 | priv->gpio_hp_det = of_get_named_gpio_flags(node, |
440 | "simple-audio-card,hp-det-gpio", 0); | 437 | "simple-audio-card,hp-det-gpio", 0, &flags); |
438 | priv->gpio_hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); | ||
441 | if (priv->gpio_hp_det == -EPROBE_DEFER) | 439 | if (priv->gpio_hp_det == -EPROBE_DEFER) |
442 | return -EPROBE_DEFER; | 440 | return -EPROBE_DEFER; |
443 | 441 | ||
444 | priv->gpio_mic_det = of_get_named_gpio(node, | 442 | priv->gpio_mic_det = of_get_named_gpio_flags(node, |
445 | "simple-audio-card,mic-det-gpio", 0); | 443 | "simple-audio-card,mic-det-gpio", 0, &flags); |
444 | priv->gpio_mic_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); | ||
446 | if (priv->gpio_mic_det == -EPROBE_DEFER) | 445 | if (priv->gpio_mic_det == -EPROBE_DEFER) |
447 | return -EPROBE_DEFER; | 446 | return -EPROBE_DEFER; |
448 | 447 | ||
@@ -457,18 +456,13 @@ static int asoc_simple_card_unref(struct platform_device *pdev) | |||
457 | { | 456 | { |
458 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 457 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
459 | struct snd_soc_dai_link *dai_link; | 458 | struct snd_soc_dai_link *dai_link; |
460 | struct device_node *np; | ||
461 | int num_links; | 459 | int num_links; |
462 | 460 | ||
463 | for (num_links = 0, dai_link = card->dai_link; | 461 | for (num_links = 0, dai_link = card->dai_link; |
464 | num_links < card->num_links; | 462 | num_links < card->num_links; |
465 | num_links++, dai_link++) { | 463 | num_links++, dai_link++) { |
466 | np = (struct device_node *) dai_link->cpu_of_node; | 464 | of_node_put(dai_link->cpu_of_node); |
467 | if (np) | 465 | of_node_put(dai_link->codec_of_node); |
468 | of_node_put(np); | ||
469 | np = (struct device_node *) dai_link->codec_of_node; | ||
470 | if (np) | ||
471 | of_node_put(np); | ||
472 | } | 466 | } |
473 | return 0; | 467 | return 0; |
474 | } | 468 | } |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index f5b4a9c79cdf..e989ecf046c9 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -3,6 +3,7 @@ config SND_MFLD_MACHINE | |||
3 | depends on INTEL_SCU_IPC | 3 | depends on INTEL_SCU_IPC |
4 | select SND_SOC_SN95031 | 4 | select SND_SOC_SN95031 |
5 | select SND_SST_MFLD_PLATFORM | 5 | select SND_SST_MFLD_PLATFORM |
6 | select SND_SST_IPC_PCI | ||
6 | help | 7 | help |
7 | This adds support for ASoC machine driver for Intel(R) MID Medfield platform | 8 | This adds support for ASoC machine driver for Intel(R) MID Medfield platform |
8 | used as alsa device in audio substem in Intel(R) MID devices | 9 | used as alsa device in audio substem in Intel(R) MID devices |
@@ -12,10 +13,23 @@ config SND_MFLD_MACHINE | |||
12 | config SND_SST_MFLD_PLATFORM | 13 | config SND_SST_MFLD_PLATFORM |
13 | tristate | 14 | tristate |
14 | 15 | ||
16 | config SND_SST_IPC | ||
17 | tristate | ||
18 | |||
19 | config SND_SST_IPC_PCI | ||
20 | tristate | ||
21 | select SND_SST_IPC | ||
22 | |||
23 | config SND_SST_IPC_ACPI | ||
24 | tristate | ||
25 | select SND_SST_IPC | ||
26 | depends on ACPI | ||
27 | |||
15 | config SND_SOC_INTEL_SST | 28 | config SND_SOC_INTEL_SST |
16 | tristate "ASoC support for Intel(R) Smart Sound Technology" | 29 | tristate "ASoC support for Intel(R) Smart Sound Technology" |
17 | select SND_SOC_INTEL_SST_ACPI if ACPI | 30 | select SND_SOC_INTEL_SST_ACPI if ACPI |
18 | depends on (X86 || COMPILE_TEST) | 31 | depends on (X86 || COMPILE_TEST) |
32 | depends on DW_DMAC_CORE | ||
19 | help | 33 | help |
20 | This adds support for Intel(R) Smart Sound Technology (SST). | 34 | This adds support for Intel(R) Smart Sound Technology (SST). |
21 | Say Y if you have such a device | 35 | Say Y if you have such a device |
@@ -32,7 +46,8 @@ config SND_SOC_INTEL_BAYTRAIL | |||
32 | 46 | ||
33 | config SND_SOC_INTEL_HASWELL_MACH | 47 | config SND_SOC_INTEL_HASWELL_MACH |
34 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" | 48 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" |
35 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C | 49 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\ |
50 | I2C_DESIGNWARE_PLATFORM | ||
36 | select SND_SOC_INTEL_HASWELL | 51 | select SND_SOC_INTEL_HASWELL |
37 | select SND_SOC_RT5640 | 52 | select SND_SOC_RT5640 |
38 | help | 53 | help |
@@ -61,7 +76,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH | |||
61 | 76 | ||
62 | config SND_SOC_INTEL_BROADWELL_MACH | 77 | config SND_SOC_INTEL_BROADWELL_MACH |
63 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" | 78 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" |
64 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC | 79 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\ |
80 | I2C_DESIGNWARE_PLATFORM | ||
65 | select SND_SOC_INTEL_HASWELL | 81 | select SND_SOC_INTEL_HASWELL |
66 | select SND_COMPRESS_OFFLOAD | 82 | select SND_COMPRESS_OFFLOAD |
67 | select SND_SOC_RT286 | 83 | select SND_SOC_RT286 |
@@ -70,3 +86,27 @@ config SND_SOC_INTEL_BROADWELL_MACH | |||
70 | Ultrabook platforms. | 86 | Ultrabook platforms. |
71 | Say Y if you have such a device | 87 | Say Y if you have such a device |
72 | If unsure select "N". | 88 | If unsure select "N". |
89 | |||
90 | config SND_SOC_INTEL_BYTCR_RT5640_MACH | ||
91 | tristate "ASoC Audio DSP Support for MID BYT Platform" | ||
92 | depends on X86 | ||
93 | select SND_SOC_RT5640 | ||
94 | select SND_SST_MFLD_PLATFORM | ||
95 | select SND_SST_IPC_ACPI | ||
96 | help | ||
97 | This adds support for ASoC machine driver for Intel(R) MID Baytrail platform | ||
98 | used as alsa device in audio substem in Intel(R) MID devices | ||
99 | Say Y if you have such a device | ||
100 | If unsure select "N". | ||
101 | |||
102 | config SND_SOC_INTEL_CHT_BSW_RT5672_MACH | ||
103 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" | ||
104 | depends on X86_INTEL_LPSS | ||
105 | select SND_SOC_RT5670 | ||
106 | select SND_SST_MFLD_PLATFORM | ||
107 | select SND_SST_IPC_ACPI | ||
108 | help | ||
109 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell | ||
110 | platforms with RT5672 audio codec. | ||
111 | Say Y if you have such a device | ||
112 | If unsure select "N". | ||
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index f841786dad15..e928ec385300 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
@@ -26,8 +26,15 @@ snd-soc-sst-haswell-objs := haswell.o | |||
26 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | 26 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o |
27 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | 27 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o |
28 | snd-soc-sst-broadwell-objs := broadwell.o | 28 | snd-soc-sst-broadwell-objs := broadwell.o |
29 | snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o | ||
30 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o | ||
29 | 31 | ||
30 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | 32 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o |
31 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | 33 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o |
32 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | 34 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o |
33 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | 35 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o |
36 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o | ||
37 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o | ||
38 | |||
39 | # DSP driver | ||
40 | obj-$(CONFIG_SND_SST_IPC) += sst/ | ||
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 0e550f14028f..c256764e3c4b 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <sound/core.h> | 19 | #include <sound/core.h> |
20 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
21 | #include <sound/soc.h> | 21 | #include <sound/soc.h> |
22 | #include <sound/jack.h> | ||
22 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
23 | 24 | ||
24 | #include "sst-dsp.h" | 25 | #include "sst-dsp.h" |
@@ -26,8 +27,26 @@ | |||
26 | 27 | ||
27 | #include "../codecs/rt286.h" | 28 | #include "../codecs/rt286.h" |
28 | 29 | ||
30 | static struct snd_soc_jack broadwell_headset; | ||
31 | /* Headset jack detection DAPM pins */ | ||
32 | static struct snd_soc_jack_pin broadwell_headset_pins[] = { | ||
33 | { | ||
34 | .pin = "Mic Jack", | ||
35 | .mask = SND_JACK_MICROPHONE, | ||
36 | }, | ||
37 | { | ||
38 | .pin = "Headphone Jack", | ||
39 | .mask = SND_JACK_HEADPHONE, | ||
40 | }, | ||
41 | }; | ||
42 | |||
43 | static const struct snd_kcontrol_new broadwell_controls[] = { | ||
44 | SOC_DAPM_PIN_SWITCH("Speaker"), | ||
45 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
46 | }; | ||
47 | |||
29 | static const struct snd_soc_dapm_widget broadwell_widgets[] = { | 48 | static const struct snd_soc_dapm_widget broadwell_widgets[] = { |
30 | SND_SOC_DAPM_HP("Headphones", NULL), | 49 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
31 | SND_SOC_DAPM_SPK("Speaker", NULL), | 50 | SND_SOC_DAPM_SPK("Speaker", NULL), |
32 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 51 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
33 | SND_SOC_DAPM_MIC("DMIC1", NULL), | 52 | SND_SOC_DAPM_MIC("DMIC1", NULL), |
@@ -42,7 +61,7 @@ static const struct snd_soc_dapm_route broadwell_rt286_map[] = { | |||
42 | {"Speaker", NULL, "SPOL"}, | 61 | {"Speaker", NULL, "SPOL"}, |
43 | 62 | ||
44 | /* HP jack connectors - unknown if we have jack deteck */ | 63 | /* HP jack connectors - unknown if we have jack deteck */ |
45 | {"Headphones", NULL, "HPO Pin"}, | 64 | {"Headphone Jack", NULL, "HPO Pin"}, |
46 | 65 | ||
47 | /* other jacks */ | 66 | /* other jacks */ |
48 | {"MIC1", NULL, "Mic Jack"}, | 67 | {"MIC1", NULL, "Mic Jack"}, |
@@ -57,6 +76,27 @@ static const struct snd_soc_dapm_route broadwell_rt286_map[] = { | |||
57 | {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, | 76 | {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, |
58 | }; | 77 | }; |
59 | 78 | ||
79 | static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) | ||
80 | { | ||
81 | struct snd_soc_codec *codec = rtd->codec; | ||
82 | int ret = 0; | ||
83 | ret = snd_soc_jack_new(codec, "Headset", | ||
84 | SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset); | ||
85 | |||
86 | if (ret) | ||
87 | return ret; | ||
88 | |||
89 | ret = snd_soc_jack_add_pins(&broadwell_headset, | ||
90 | ARRAY_SIZE(broadwell_headset_pins), | ||
91 | broadwell_headset_pins); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | rt286_mic_detect(codec, &broadwell_headset); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | |||
60 | static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | 100 | static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, |
61 | struct snd_pcm_hw_params *params) | 101 | struct snd_pcm_hw_params *params) |
62 | { | 102 | { |
@@ -116,7 +156,7 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) | |||
116 | } | 156 | } |
117 | 157 | ||
118 | /* always connected - check HP for jack detect */ | 158 | /* always connected - check HP for jack detect */ |
119 | snd_soc_dapm_enable_pin(dapm, "Headphones"); | 159 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
120 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 160 | snd_soc_dapm_enable_pin(dapm, "Speaker"); |
121 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 161 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
122 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | 162 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); |
@@ -131,7 +171,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
131 | /* Front End DAI links */ | 171 | /* Front End DAI links */ |
132 | { | 172 | { |
133 | .name = "System PCM", | 173 | .name = "System PCM", |
134 | .stream_name = "System Playback", | 174 | .stream_name = "System Playback/Capture", |
135 | .cpu_dai_name = "System Pin", | 175 | .cpu_dai_name = "System Pin", |
136 | .platform_name = "haswell-pcm-audio", | 176 | .platform_name = "haswell-pcm-audio", |
137 | .dynamic = 1, | 177 | .dynamic = 1, |
@@ -140,6 +180,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
140 | .init = broadwell_rtd_init, | 180 | .init = broadwell_rtd_init, |
141 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 181 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
142 | .dpcm_playback = 1, | 182 | .dpcm_playback = 1, |
183 | .dpcm_capture = 1, | ||
143 | }, | 184 | }, |
144 | { | 185 | { |
145 | .name = "Offload0", | 186 | .name = "Offload0", |
@@ -174,18 +215,6 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
174 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 215 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
175 | .dpcm_capture = 1, | 216 | .dpcm_capture = 1, |
176 | }, | 217 | }, |
177 | { | ||
178 | .name = "Capture PCM", | ||
179 | .stream_name = "Capture", | ||
180 | .cpu_dai_name = "Capture Pin", | ||
181 | .platform_name = "haswell-pcm-audio", | ||
182 | .dynamic = 1, | ||
183 | .codec_name = "snd-soc-dummy", | ||
184 | .codec_dai_name = "snd-soc-dummy-dai", | ||
185 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
186 | .dpcm_capture = 1, | ||
187 | }, | ||
188 | |||
189 | /* Back End DAI links */ | 218 | /* Back End DAI links */ |
190 | { | 219 | { |
191 | /* SSP0 - Codec */ | 220 | /* SSP0 - Codec */ |
@@ -196,6 +225,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
196 | .no_pcm = 1, | 225 | .no_pcm = 1, |
197 | .codec_name = "i2c-INT343A:00", | 226 | .codec_name = "i2c-INT343A:00", |
198 | .codec_dai_name = "rt286-aif1", | 227 | .codec_dai_name = "rt286-aif1", |
228 | .init = broadwell_rt286_codec_init, | ||
199 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 229 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
200 | SND_SOC_DAIFMT_CBS_CFS, | 230 | SND_SOC_DAIFMT_CBS_CFS, |
201 | .ignore_suspend = 1, | 231 | .ignore_suspend = 1, |
@@ -213,6 +243,8 @@ static struct snd_soc_card broadwell_rt286 = { | |||
213 | .owner = THIS_MODULE, | 243 | .owner = THIS_MODULE, |
214 | .dai_link = broadwell_rt286_dais, | 244 | .dai_link = broadwell_rt286_dais, |
215 | .num_links = ARRAY_SIZE(broadwell_rt286_dais), | 245 | .num_links = ARRAY_SIZE(broadwell_rt286_dais), |
246 | .controls = broadwell_controls, | ||
247 | .num_controls = ARRAY_SIZE(broadwell_controls), | ||
216 | .dapm_widgets = broadwell_widgets, | 248 | .dapm_widgets = broadwell_widgets, |
217 | .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets), | 249 | .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets), |
218 | .dapm_routes = broadwell_rt286_map, | 250 | .dapm_routes = broadwell_rt286_map, |
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c new file mode 100644 index 000000000000..f5d0fc1ab10c --- /dev/null +++ b/sound/soc/intel/bytcr_dpcm_rt5640.c | |||
@@ -0,0 +1,230 @@ | |||
1 | /* | ||
2 | * byt_cr_dpcm_rt5640.c - ASoc Machine driver for Intel Byt CR platform | ||
3 | * | ||
4 | * Copyright (C) 2014 Intel Corp | ||
5 | * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com> | ||
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
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 as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/device.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/input.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include "../codecs/rt5640.h" | ||
30 | #include "sst-atom-controls.h" | ||
31 | |||
32 | static const struct snd_soc_dapm_widget byt_dapm_widgets[] = { | ||
33 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
34 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
35 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
36 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
37 | }; | ||
38 | |||
39 | static const struct snd_soc_dapm_route byt_audio_map[] = { | ||
40 | {"IN2P", NULL, "Headset Mic"}, | ||
41 | {"IN2N", NULL, "Headset Mic"}, | ||
42 | {"Headset Mic", NULL, "MICBIAS1"}, | ||
43 | {"IN1P", NULL, "MICBIAS1"}, | ||
44 | {"LDO2", NULL, "Int Mic"}, | ||
45 | {"Headphone", NULL, "HPOL"}, | ||
46 | {"Headphone", NULL, "HPOR"}, | ||
47 | {"Ext Spk", NULL, "SPOLP"}, | ||
48 | {"Ext Spk", NULL, "SPOLN"}, | ||
49 | {"Ext Spk", NULL, "SPORP"}, | ||
50 | {"Ext Spk", NULL, "SPORN"}, | ||
51 | |||
52 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | ||
53 | {"ssp2 Tx", NULL, "codec_out0"}, | ||
54 | {"ssp2 Tx", NULL, "codec_out1"}, | ||
55 | {"codec_in0", NULL, "ssp2 Rx"}, | ||
56 | {"codec_in1", NULL, "ssp2 Rx"}, | ||
57 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | ||
58 | }; | ||
59 | |||
60 | static const struct snd_kcontrol_new byt_mc_controls[] = { | ||
61 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
62 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
63 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
64 | SOC_DAPM_PIN_SWITCH("Ext Spk"), | ||
65 | }; | ||
66 | |||
67 | static int byt_aif1_hw_params(struct snd_pcm_substream *substream, | ||
68 | struct snd_pcm_hw_params *params) | ||
69 | { | ||
70 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
71 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
72 | int ret; | ||
73 | |||
74 | snd_soc_dai_set_bclk_ratio(codec_dai, 50); | ||
75 | |||
76 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, | ||
77 | params_rate(params) * 512, | ||
78 | SND_SOC_CLOCK_IN); | ||
79 | if (ret < 0) { | ||
80 | dev_err(rtd->dev, "can't set codec clock %d\n", ret); | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, | ||
85 | params_rate(params) * 50, | ||
86 | params_rate(params) * 512); | ||
87 | if (ret < 0) { | ||
88 | dev_err(rtd->dev, "can't set codec pll: %d\n", ret); | ||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static const struct snd_soc_pcm_stream byt_dai_params = { | ||
96 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
97 | .rate_min = 48000, | ||
98 | .rate_max = 48000, | ||
99 | .channels_min = 2, | ||
100 | .channels_max = 2, | ||
101 | }; | ||
102 | |||
103 | static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, | ||
104 | struct snd_pcm_hw_params *params) | ||
105 | { | ||
106 | struct snd_interval *rate = hw_param_interval(params, | ||
107 | SNDRV_PCM_HW_PARAM_RATE); | ||
108 | struct snd_interval *channels = hw_param_interval(params, | ||
109 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
110 | |||
111 | /* The DSP will covert the FE rate to 48k, stereo, 24bits */ | ||
112 | rate->min = rate->max = 48000; | ||
113 | channels->min = channels->max = 2; | ||
114 | |||
115 | /* set SSP2 to 24-bit */ | ||
116 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
117 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
118 | SNDRV_PCM_FORMAT_S24_LE); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static unsigned int rates_48000[] = { | ||
123 | 48000, | ||
124 | }; | ||
125 | |||
126 | static struct snd_pcm_hw_constraint_list constraints_48000 = { | ||
127 | .count = ARRAY_SIZE(rates_48000), | ||
128 | .list = rates_48000, | ||
129 | }; | ||
130 | |||
131 | static int byt_aif1_startup(struct snd_pcm_substream *substream) | ||
132 | { | ||
133 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
134 | SNDRV_PCM_HW_PARAM_RATE, | ||
135 | &constraints_48000); | ||
136 | } | ||
137 | |||
138 | static struct snd_soc_ops byt_aif1_ops = { | ||
139 | .startup = byt_aif1_startup, | ||
140 | }; | ||
141 | |||
142 | static struct snd_soc_ops byt_be_ssp2_ops = { | ||
143 | .hw_params = byt_aif1_hw_params, | ||
144 | }; | ||
145 | |||
146 | static struct snd_soc_dai_link byt_dailink[] = { | ||
147 | [MERR_DPCM_AUDIO] = { | ||
148 | .name = "Baytrail Audio Port", | ||
149 | .stream_name = "Baytrail Audio", | ||
150 | .cpu_dai_name = "media-cpu-dai", | ||
151 | .codec_dai_name = "snd-soc-dummy-dai", | ||
152 | .codec_name = "snd-soc-dummy", | ||
153 | .platform_name = "sst-mfld-platform", | ||
154 | .ignore_suspend = 1, | ||
155 | .dynamic = 1, | ||
156 | .dpcm_playback = 1, | ||
157 | .dpcm_capture = 1, | ||
158 | .ops = &byt_aif1_ops, | ||
159 | }, | ||
160 | [MERR_DPCM_COMPR] = { | ||
161 | .name = "Baytrail Compressed Port", | ||
162 | .stream_name = "Baytrail Compress", | ||
163 | .cpu_dai_name = "compress-cpu-dai", | ||
164 | .codec_dai_name = "snd-soc-dummy-dai", | ||
165 | .codec_name = "snd-soc-dummy", | ||
166 | .platform_name = "sst-mfld-platform", | ||
167 | }, | ||
168 | /* back ends */ | ||
169 | { | ||
170 | .name = "SSP2-Codec", | ||
171 | .be_id = 1, | ||
172 | .cpu_dai_name = "ssp2-port", | ||
173 | .platform_name = "sst-mfld-platform", | ||
174 | .no_pcm = 1, | ||
175 | .codec_dai_name = "rt5640-aif1", | ||
176 | .codec_name = "i2c-10EC5640:00", | ||
177 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ||
178 | | SND_SOC_DAIFMT_CBS_CFS, | ||
179 | .be_hw_params_fixup = byt_codec_fixup, | ||
180 | .ignore_suspend = 1, | ||
181 | .dpcm_playback = 1, | ||
182 | .dpcm_capture = 1, | ||
183 | .ops = &byt_be_ssp2_ops, | ||
184 | }, | ||
185 | }; | ||
186 | |||
187 | /* SoC card */ | ||
188 | static struct snd_soc_card snd_soc_card_byt = { | ||
189 | .name = "baytrailcraudio", | ||
190 | .dai_link = byt_dailink, | ||
191 | .num_links = ARRAY_SIZE(byt_dailink), | ||
192 | .dapm_widgets = byt_dapm_widgets, | ||
193 | .num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets), | ||
194 | .dapm_routes = byt_audio_map, | ||
195 | .num_dapm_routes = ARRAY_SIZE(byt_audio_map), | ||
196 | .controls = byt_mc_controls, | ||
197 | .num_controls = ARRAY_SIZE(byt_mc_controls), | ||
198 | }; | ||
199 | |||
200 | static int snd_byt_mc_probe(struct platform_device *pdev) | ||
201 | { | ||
202 | int ret_val = 0; | ||
203 | |||
204 | /* register the soc card */ | ||
205 | snd_soc_card_byt.dev = &pdev->dev; | ||
206 | |||
207 | ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt); | ||
208 | if (ret_val) { | ||
209 | dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val); | ||
210 | return ret_val; | ||
211 | } | ||
212 | platform_set_drvdata(pdev, &snd_soc_card_byt); | ||
213 | return ret_val; | ||
214 | } | ||
215 | |||
216 | static struct platform_driver snd_byt_mc_driver = { | ||
217 | .driver = { | ||
218 | .owner = THIS_MODULE, | ||
219 | .name = "bytt100_rt5640", | ||
220 | .pm = &snd_soc_pm_ops, | ||
221 | }, | ||
222 | .probe = snd_byt_mc_probe, | ||
223 | }; | ||
224 | |||
225 | module_platform_driver(snd_byt_mc_driver); | ||
226 | |||
227 | MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); | ||
228 | MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>"); | ||
229 | MODULE_LICENSE("GPL v2"); | ||
230 | MODULE_ALIAS("platform:bytrt5640-audio"); | ||
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c new file mode 100644 index 000000000000..9b8b561171b7 --- /dev/null +++ b/sound/soc/intel/cht_bsw_rt5672.c | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms | ||
3 | * Cherrytrail and Braswell, with RT5672 codec. | ||
4 | * | ||
5 | * Copyright (C) 2014 Intel Corp | ||
6 | * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com> | ||
7 | * Mengdong Lin <mengdong.lin@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include "../codecs/rt5670.h" | ||
26 | #include "sst-atom-controls.h" | ||
27 | |||
28 | /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ | ||
29 | #define CHT_PLAT_CLK_3_HZ 19200000 | ||
30 | #define CHT_CODEC_DAI "rt5670-aif1" | ||
31 | |||
32 | static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) | ||
33 | { | ||
34 | int i; | ||
35 | |||
36 | for (i = 0; i < card->num_rtd; i++) { | ||
37 | struct snd_soc_pcm_runtime *rtd; | ||
38 | |||
39 | rtd = card->rtd + i; | ||
40 | if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, | ||
41 | strlen(CHT_CODEC_DAI))) | ||
42 | return rtd->codec_dai; | ||
43 | } | ||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | static int platform_clock_control(struct snd_soc_dapm_widget *w, | ||
48 | struct snd_kcontrol *k, int event) | ||
49 | { | ||
50 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
51 | struct snd_soc_card *card = dapm->card; | ||
52 | struct snd_soc_dai *codec_dai; | ||
53 | |||
54 | codec_dai = cht_get_codec_dai(card); | ||
55 | if (!codec_dai) { | ||
56 | dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); | ||
57 | return -EIO; | ||
58 | } | ||
59 | |||
60 | if (!SND_SOC_DAPM_EVENT_OFF(event)) | ||
61 | return 0; | ||
62 | |||
63 | /* Set codec sysclk source to its internal clock because codec PLL will | ||
64 | * be off when idle and MCLK will also be off by ACPI when codec is | ||
65 | * runtime suspended. Codec needs clock for jack detection and button | ||
66 | * press. | ||
67 | */ | ||
68 | snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, | ||
69 | 0, SND_SOC_CLOCK_IN); | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { | ||
75 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
76 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
77 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
78 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
79 | SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, | ||
80 | platform_clock_control, SND_SOC_DAPM_POST_PMD), | ||
81 | }; | ||
82 | |||
83 | static const struct snd_soc_dapm_route cht_audio_map[] = { | ||
84 | {"IN1P", NULL, "Headset Mic"}, | ||
85 | {"IN1N", NULL, "Headset Mic"}, | ||
86 | {"DMIC L1", NULL, "Int Mic"}, | ||
87 | {"DMIC R1", NULL, "Int Mic"}, | ||
88 | {"Headphone", NULL, "HPOL"}, | ||
89 | {"Headphone", NULL, "HPOR"}, | ||
90 | {"Ext Spk", NULL, "SPOLP"}, | ||
91 | {"Ext Spk", NULL, "SPOLN"}, | ||
92 | {"Ext Spk", NULL, "SPORP"}, | ||
93 | {"Ext Spk", NULL, "SPORN"}, | ||
94 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | ||
95 | {"ssp2 Tx", NULL, "codec_out0"}, | ||
96 | {"ssp2 Tx", NULL, "codec_out1"}, | ||
97 | {"codec_in0", NULL, "ssp2 Rx"}, | ||
98 | {"codec_in1", NULL, "ssp2 Rx"}, | ||
99 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | ||
100 | {"Headphone", NULL, "Platform Clock"}, | ||
101 | {"Headset Mic", NULL, "Platform Clock"}, | ||
102 | {"Int Mic", NULL, "Platform Clock"}, | ||
103 | {"Ext Spk", NULL, "Platform Clock"}, | ||
104 | }; | ||
105 | |||
106 | static const struct snd_kcontrol_new cht_mc_controls[] = { | ||
107 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
108 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
109 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
110 | SOC_DAPM_PIN_SWITCH("Ext Spk"), | ||
111 | }; | ||
112 | |||
113 | static int cht_aif1_hw_params(struct snd_pcm_substream *substream, | ||
114 | struct snd_pcm_hw_params *params) | ||
115 | { | ||
116 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
117 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
118 | int ret; | ||
119 | |||
120 | /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ | ||
121 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, | ||
122 | CHT_PLAT_CLK_3_HZ, params_rate(params) * 512); | ||
123 | if (ret < 0) { | ||
124 | dev_err(rtd->dev, "can't set codec pll: %d\n", ret); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | /* set codec sysclk source to PLL */ | ||
129 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1, | ||
130 | params_rate(params) * 512, | ||
131 | SND_SOC_CLOCK_IN); | ||
132 | if (ret < 0) { | ||
133 | dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); | ||
134 | return ret; | ||
135 | } | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | ||
140 | { | ||
141 | int ret; | ||
142 | struct snd_soc_dai *codec_dai = runtime->codec_dai; | ||
143 | |||
144 | /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ | ||
145 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); | ||
146 | if (ret < 0) { | ||
147 | dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, | ||
155 | struct snd_pcm_hw_params *params) | ||
156 | { | ||
157 | struct snd_interval *rate = hw_param_interval(params, | ||
158 | SNDRV_PCM_HW_PARAM_RATE); | ||
159 | struct snd_interval *channels = hw_param_interval(params, | ||
160 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
161 | |||
162 | /* The DSP will covert the FE rate to 48k, stereo, 24bits */ | ||
163 | rate->min = rate->max = 48000; | ||
164 | channels->min = channels->max = 2; | ||
165 | |||
166 | /* set SSP2 to 24-bit */ | ||
167 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
168 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
169 | SNDRV_PCM_FORMAT_S24_LE); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static unsigned int rates_48000[] = { | ||
174 | 48000, | ||
175 | }; | ||
176 | |||
177 | static struct snd_pcm_hw_constraint_list constraints_48000 = { | ||
178 | .count = ARRAY_SIZE(rates_48000), | ||
179 | .list = rates_48000, | ||
180 | }; | ||
181 | |||
182 | static int cht_aif1_startup(struct snd_pcm_substream *substream) | ||
183 | { | ||
184 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
185 | SNDRV_PCM_HW_PARAM_RATE, | ||
186 | &constraints_48000); | ||
187 | } | ||
188 | |||
189 | static struct snd_soc_ops cht_aif1_ops = { | ||
190 | .startup = cht_aif1_startup, | ||
191 | }; | ||
192 | |||
193 | static struct snd_soc_ops cht_be_ssp2_ops = { | ||
194 | .hw_params = cht_aif1_hw_params, | ||
195 | }; | ||
196 | |||
197 | static struct snd_soc_dai_link cht_dailink[] = { | ||
198 | /* Front End DAI links */ | ||
199 | [MERR_DPCM_AUDIO] = { | ||
200 | .name = "Audio Port", | ||
201 | .stream_name = "Audio", | ||
202 | .cpu_dai_name = "media-cpu-dai", | ||
203 | .codec_dai_name = "snd-soc-dummy-dai", | ||
204 | .codec_name = "snd-soc-dummy", | ||
205 | .platform_name = "sst-mfld-platform", | ||
206 | .ignore_suspend = 1, | ||
207 | .dynamic = 1, | ||
208 | .dpcm_playback = 1, | ||
209 | .dpcm_capture = 1, | ||
210 | .ops = &cht_aif1_ops, | ||
211 | }, | ||
212 | [MERR_DPCM_COMPR] = { | ||
213 | .name = "Compressed Port", | ||
214 | .stream_name = "Compress", | ||
215 | .cpu_dai_name = "compress-cpu-dai", | ||
216 | .codec_dai_name = "snd-soc-dummy-dai", | ||
217 | .codec_name = "snd-soc-dummy", | ||
218 | .platform_name = "sst-mfld-platform", | ||
219 | }, | ||
220 | |||
221 | /* Back End DAI links */ | ||
222 | { | ||
223 | /* SSP2 - Codec */ | ||
224 | .name = "SSP2-Codec", | ||
225 | .be_id = 1, | ||
226 | .cpu_dai_name = "ssp2-port", | ||
227 | .platform_name = "sst-mfld-platform", | ||
228 | .no_pcm = 1, | ||
229 | .codec_dai_name = "rt5670-aif1", | ||
230 | .codec_name = "i2c-10EC5670:00", | ||
231 | .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | ||
232 | | SND_SOC_DAIFMT_CBS_CFS, | ||
233 | .init = cht_codec_init, | ||
234 | .be_hw_params_fixup = cht_codec_fixup, | ||
235 | .ignore_suspend = 1, | ||
236 | .dpcm_playback = 1, | ||
237 | .dpcm_capture = 1, | ||
238 | .ops = &cht_be_ssp2_ops, | ||
239 | }, | ||
240 | }; | ||
241 | |||
242 | /* SoC card */ | ||
243 | static struct snd_soc_card snd_soc_card_cht = { | ||
244 | .name = "cherrytrailcraudio", | ||
245 | .dai_link = cht_dailink, | ||
246 | .num_links = ARRAY_SIZE(cht_dailink), | ||
247 | .dapm_widgets = cht_dapm_widgets, | ||
248 | .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), | ||
249 | .dapm_routes = cht_audio_map, | ||
250 | .num_dapm_routes = ARRAY_SIZE(cht_audio_map), | ||
251 | .controls = cht_mc_controls, | ||
252 | .num_controls = ARRAY_SIZE(cht_mc_controls), | ||
253 | }; | ||
254 | |||
255 | static int snd_cht_mc_probe(struct platform_device *pdev) | ||
256 | { | ||
257 | int ret_val = 0; | ||
258 | |||
259 | /* register the soc card */ | ||
260 | snd_soc_card_cht.dev = &pdev->dev; | ||
261 | ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); | ||
262 | if (ret_val) { | ||
263 | dev_err(&pdev->dev, | ||
264 | "snd_soc_register_card failed %d\n", ret_val); | ||
265 | return ret_val; | ||
266 | } | ||
267 | platform_set_drvdata(pdev, &snd_soc_card_cht); | ||
268 | return ret_val; | ||
269 | } | ||
270 | |||
271 | static struct platform_driver snd_cht_mc_driver = { | ||
272 | .driver = { | ||
273 | .owner = THIS_MODULE, | ||
274 | .name = "cht-bsw-rt5672", | ||
275 | .pm = &snd_soc_pm_ops, | ||
276 | }, | ||
277 | .probe = snd_cht_mc_probe, | ||
278 | }; | ||
279 | |||
280 | module_platform_driver(snd_cht_mc_driver); | ||
281 | |||
282 | MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); | ||
283 | MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin"); | ||
284 | MODULE_LICENSE("GPL v2"); | ||
285 | MODULE_ALIAS("platform:cht-bsw-rt5672"); | ||
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c index 3981982674ac..cb8a482b5f30 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/haswell.c | |||
@@ -109,7 +109,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { | |||
109 | /* Front End DAI links */ | 109 | /* Front End DAI links */ |
110 | { | 110 | { |
111 | .name = "System", | 111 | .name = "System", |
112 | .stream_name = "System Playback", | 112 | .stream_name = "System Playback/Capture", |
113 | .cpu_dai_name = "System Pin", | 113 | .cpu_dai_name = "System Pin", |
114 | .platform_name = "haswell-pcm-audio", | 114 | .platform_name = "haswell-pcm-audio", |
115 | .dynamic = 1, | 115 | .dynamic = 1, |
@@ -118,6 +118,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { | |||
118 | .init = haswell_rtd_init, | 118 | .init = haswell_rtd_init, |
119 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 119 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
120 | .dpcm_playback = 1, | 120 | .dpcm_playback = 1, |
121 | .dpcm_capture = 1, | ||
121 | }, | 122 | }, |
122 | { | 123 | { |
123 | .name = "Offload0", | 124 | .name = "Offload0", |
@@ -152,17 +153,6 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { | |||
152 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 153 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
153 | .dpcm_capture = 1, | 154 | .dpcm_capture = 1, |
154 | }, | 155 | }, |
155 | { | ||
156 | .name = "Capture", | ||
157 | .stream_name = "Capture", | ||
158 | .cpu_dai_name = "Capture Pin", | ||
159 | .platform_name = "haswell-pcm-audio", | ||
160 | .dynamic = 1, | ||
161 | .codec_name = "snd-soc-dummy", | ||
162 | .codec_dai_name = "snd-soc-dummy-dai", | ||
163 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
164 | .dpcm_capture = 1, | ||
165 | }, | ||
166 | 156 | ||
167 | /* Back End DAI links */ | 157 | /* Back End DAI links */ |
168 | { | 158 | { |
diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c index 7104a34181a9..90aa5c0476f3 100644 --- a/sound/soc/intel/sst-atom-controls.c +++ b/sound/soc/intel/sst-atom-controls.c | |||
@@ -15,6 +15,9 @@ | |||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * General Public License for more details. | 16 | * General Public License for more details. |
17 | * | 17 | * |
18 | * In the dpcm driver modelling when a particular FE/BE/Mixer/Pipe is active | ||
19 | * we forward the settings and parameters, rest we keep the values in | ||
20 | * driver and forward when DAPM enables them | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 21 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
19 | */ | 22 | */ |
20 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -81,6 +84,183 @@ static int sst_fill_and_send_cmd(struct sst_data *drv, | |||
81 | return ret; | 84 | return ret; |
82 | } | 85 | } |
83 | 86 | ||
87 | /** | ||
88 | * tx map value is a bitfield where each bit represents a FW channel | ||
89 | * | ||
90 | * 3 2 1 0 # 0 = codec0, 1 = codec1 | ||
91 | * RLRLRLRL # 3, 4 = reserved | ||
92 | * | ||
93 | * e.g. slot 0 rx map = 00001100b -> data from slot 0 goes into codec_in1 L,R | ||
94 | */ | ||
95 | static u8 sst_ssp_tx_map[SST_MAX_TDM_SLOTS] = { | ||
96 | 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default rx map */ | ||
97 | }; | ||
98 | |||
99 | /** | ||
100 | * rx map value is a bitfield where each bit represents a slot | ||
101 | * | ||
102 | * 76543210 # 0 = slot 0, 1 = slot 1 | ||
103 | * | ||
104 | * e.g. codec1_0 tx map = 00000101b -> data from codec_out1_0 goes into slot 0, 2 | ||
105 | */ | ||
106 | static u8 sst_ssp_rx_map[SST_MAX_TDM_SLOTS] = { | ||
107 | 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default tx map */ | ||
108 | }; | ||
109 | |||
110 | /** | ||
111 | * NOTE: this is invoked with lock held | ||
112 | */ | ||
113 | static int sst_send_slot_map(struct sst_data *drv) | ||
114 | { | ||
115 | struct sst_param_sba_ssp_slot_map cmd; | ||
116 | |||
117 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
118 | cmd.header.command_id = SBA_SET_SSP_SLOT_MAP; | ||
119 | cmd.header.length = sizeof(struct sst_param_sba_ssp_slot_map) | ||
120 | - sizeof(struct sst_dsp_header); | ||
121 | |||
122 | cmd.param_id = SBA_SET_SSP_SLOT_MAP; | ||
123 | cmd.param_len = sizeof(cmd.rx_slot_map) + sizeof(cmd.tx_slot_map) | ||
124 | + sizeof(cmd.ssp_index); | ||
125 | cmd.ssp_index = SSP_CODEC; | ||
126 | |||
127 | memcpy(cmd.rx_slot_map, &sst_ssp_tx_map[0], sizeof(cmd.rx_slot_map)); | ||
128 | memcpy(cmd.tx_slot_map, &sst_ssp_rx_map[0], sizeof(cmd.tx_slot_map)); | ||
129 | |||
130 | return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS, | ||
131 | SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd, | ||
132 | sizeof(cmd.header) + cmd.header.length); | ||
133 | } | ||
134 | |||
135 | int sst_slot_enum_info(struct snd_kcontrol *kcontrol, | ||
136 | struct snd_ctl_elem_info *uinfo) | ||
137 | { | ||
138 | struct sst_enum *e = (struct sst_enum *)kcontrol->private_value; | ||
139 | |||
140 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
141 | uinfo->count = 1; | ||
142 | uinfo->value.enumerated.items = e->max; | ||
143 | |||
144 | if (uinfo->value.enumerated.item > e->max - 1) | ||
145 | uinfo->value.enumerated.item = e->max - 1; | ||
146 | strcpy(uinfo->value.enumerated.name, | ||
147 | e->texts[uinfo->value.enumerated.item]); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * sst_slot_get - get the status of the interleaver/deinterleaver control | ||
154 | * | ||
155 | * Searches the map where the control status is stored, and gets the | ||
156 | * channel/slot which is currently set for this enumerated control. Since it is | ||
157 | * an enumerated control, there is only one possible value. | ||
158 | */ | ||
159 | static int sst_slot_get(struct snd_kcontrol *kcontrol, | ||
160 | struct snd_ctl_elem_value *ucontrol) | ||
161 | { | ||
162 | struct sst_enum *e = (void *)kcontrol->private_value; | ||
163 | struct snd_soc_component *c = snd_kcontrol_chip(kcontrol); | ||
164 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
165 | unsigned int ctl_no = e->reg; | ||
166 | unsigned int is_tx = e->tx; | ||
167 | unsigned int val, mux; | ||
168 | u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map; | ||
169 | |||
170 | mutex_lock(&drv->lock); | ||
171 | val = 1 << ctl_no; | ||
172 | /* search which slot/channel has this bit set - there should be only one */ | ||
173 | for (mux = e->max; mux > 0; mux--) | ||
174 | if (map[mux - 1] & val) | ||
175 | break; | ||
176 | |||
177 | ucontrol->value.enumerated.item[0] = mux; | ||
178 | mutex_unlock(&drv->lock); | ||
179 | |||
180 | dev_dbg(c->dev, "%s - %s map = %#x\n", | ||
181 | is_tx ? "tx channel" : "rx slot", | ||
182 | e->texts[mux], mux ? map[mux - 1] : -1); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /* sst_check_and_send_slot_map - helper for checking power state and sending | ||
187 | * slot map cmd | ||
188 | * | ||
189 | * called with lock held | ||
190 | */ | ||
191 | static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol *kcontrol) | ||
192 | { | ||
193 | struct sst_enum *e = (void *)kcontrol->private_value; | ||
194 | int ret = 0; | ||
195 | |||
196 | if (e->w && e->w->power) | ||
197 | ret = sst_send_slot_map(drv); | ||
198 | else | ||
199 | dev_err(&drv->pdev->dev, "Slot control: %s doesn't have DAPM widget!!!\n", | ||
200 | kcontrol->id.name); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * sst_slot_put - set the status of interleaver/deinterleaver control | ||
206 | * | ||
207 | * (de)interleaver controls are defined in opposite sense to be user-friendly | ||
208 | * | ||
209 | * Instead of the enum value being the value written to the register, it is the | ||
210 | * register address; and the kcontrol number (register num) is the value written | ||
211 | * to the register. This is so that there can be only one value for each | ||
212 | * slot/channel since there is only one control for each slot/channel. | ||
213 | * | ||
214 | * This means that whenever an enum is set, we need to clear the bit | ||
215 | * for that kcontrol_no for all the interleaver OR deinterleaver registers | ||
216 | */ | ||
217 | static int sst_slot_put(struct snd_kcontrol *kcontrol, | ||
218 | struct snd_ctl_elem_value *ucontrol) | ||
219 | { | ||
220 | struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); | ||
221 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
222 | struct sst_enum *e = (void *)kcontrol->private_value; | ||
223 | int i, ret = 0; | ||
224 | unsigned int ctl_no = e->reg; | ||
225 | unsigned int is_tx = e->tx; | ||
226 | unsigned int slot_channel_no; | ||
227 | unsigned int val, mux; | ||
228 | u8 *map; | ||
229 | |||
230 | map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map; | ||
231 | |||
232 | val = 1 << ctl_no; | ||
233 | mux = ucontrol->value.enumerated.item[0]; | ||
234 | if (mux > e->max - 1) | ||
235 | return -EINVAL; | ||
236 | |||
237 | mutex_lock(&drv->lock); | ||
238 | /* first clear all registers of this bit */ | ||
239 | for (i = 0; i < e->max; i++) | ||
240 | map[i] &= ~val; | ||
241 | |||
242 | if (mux == 0) { | ||
243 | /* kctl set to 'none' and we reset the bits so send IPC */ | ||
244 | ret = sst_check_and_send_slot_map(drv, kcontrol); | ||
245 | |||
246 | mutex_unlock(&drv->lock); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | /* offset by one to take "None" into account */ | ||
251 | slot_channel_no = mux - 1; | ||
252 | map[slot_channel_no] |= val; | ||
253 | |||
254 | dev_dbg(c->dev, "%s %s map = %#x\n", | ||
255 | is_tx ? "tx channel" : "rx slot", | ||
256 | e->texts[mux], map[slot_channel_no]); | ||
257 | |||
258 | ret = sst_check_and_send_slot_map(drv, kcontrol); | ||
259 | |||
260 | mutex_unlock(&drv->lock); | ||
261 | return ret; | ||
262 | } | ||
263 | |||
84 | static int sst_send_algo_cmd(struct sst_data *drv, | 264 | static int sst_send_algo_cmd(struct sst_data *drv, |
85 | struct sst_algo_control *bc) | 265 | struct sst_algo_control *bc) |
86 | { | 266 | { |
@@ -104,6 +284,34 @@ static int sst_send_algo_cmd(struct sst_data *drv, | |||
104 | return ret; | 284 | return ret; |
105 | } | 285 | } |
106 | 286 | ||
287 | /** | ||
288 | * sst_find_and_send_pipe_algo - send all the algo parameters for a pipe | ||
289 | * | ||
290 | * The algos which are in each pipeline are sent to the firmware one by one | ||
291 | * | ||
292 | * Called with lock held | ||
293 | */ | ||
294 | static int sst_find_and_send_pipe_algo(struct sst_data *drv, | ||
295 | const char *pipe, struct sst_ids *ids) | ||
296 | { | ||
297 | int ret = 0; | ||
298 | struct sst_algo_control *bc; | ||
299 | struct sst_module *algo = NULL; | ||
300 | |||
301 | dev_dbg(&drv->pdev->dev, "Enter: widget=%s\n", pipe); | ||
302 | |||
303 | list_for_each_entry(algo, &ids->algo_list, node) { | ||
304 | bc = (void *)algo->kctl->private_value; | ||
305 | |||
306 | dev_dbg(&drv->pdev->dev, "Found algo control name=%s pipe=%s\n", | ||
307 | algo->kctl->id.name, pipe); | ||
308 | ret = sst_send_algo_cmd(drv, bc); | ||
309 | if (ret) | ||
310 | return ret; | ||
311 | } | ||
312 | return ret; | ||
313 | } | ||
314 | |||
107 | static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol, | 315 | static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol, |
108 | struct snd_ctl_elem_info *uinfo) | 316 | struct snd_ctl_elem_info *uinfo) |
109 | { | 317 | { |
@@ -162,6 +370,743 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol, | |||
162 | return ret; | 370 | return ret; |
163 | } | 371 | } |
164 | 372 | ||
373 | static int sst_gain_ctl_info(struct snd_kcontrol *kcontrol, | ||
374 | struct snd_ctl_elem_info *uinfo) | ||
375 | { | ||
376 | struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value; | ||
377 | |||
378 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
379 | uinfo->count = mc->stereo ? 2 : 1; | ||
380 | uinfo->value.integer.min = mc->min; | ||
381 | uinfo->value.integer.max = mc->max; | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * sst_send_gain_cmd - send the gain algorithm IPC to the FW | ||
388 | * @gv: the stored value of gain (also contains rampduration) | ||
389 | * @mute: flag that indicates whether this was called from the | ||
390 | * digital_mute callback or directly. If called from the | ||
391 | * digital_mute callback, module will be muted/unmuted based on this | ||
392 | * flag. The flag is always 0 if called directly. | ||
393 | * | ||
394 | * Called with sst_data.lock held | ||
395 | * | ||
396 | * The user-set gain value is sent only if the user-controllable 'mute' control | ||
397 | * is OFF (indicated by gv->mute). Otherwise, the mute value (MIN value) is | ||
398 | * sent. | ||
399 | */ | ||
400 | static int sst_send_gain_cmd(struct sst_data *drv, struct sst_gain_value *gv, | ||
401 | u16 task_id, u16 loc_id, u16 module_id, int mute) | ||
402 | { | ||
403 | struct sst_cmd_set_gain_dual cmd; | ||
404 | |||
405 | dev_dbg(&drv->pdev->dev, "Enter\n"); | ||
406 | |||
407 | cmd.header.command_id = MMX_SET_GAIN; | ||
408 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
409 | cmd.gain_cell_num = 1; | ||
410 | |||
411 | if (mute || gv->mute) { | ||
412 | cmd.cell_gains[0].cell_gain_left = SST_GAIN_MIN_VALUE; | ||
413 | cmd.cell_gains[0].cell_gain_right = SST_GAIN_MIN_VALUE; | ||
414 | } else { | ||
415 | cmd.cell_gains[0].cell_gain_left = gv->l_gain; | ||
416 | cmd.cell_gains[0].cell_gain_right = gv->r_gain; | ||
417 | } | ||
418 | |||
419 | SST_FILL_DESTINATION(2, cmd.cell_gains[0].dest, | ||
420 | loc_id, module_id); | ||
421 | cmd.cell_gains[0].gain_time_constant = gv->ramp_duration; | ||
422 | |||
423 | cmd.header.length = sizeof(struct sst_cmd_set_gain_dual) | ||
424 | - sizeof(struct sst_dsp_header); | ||
425 | |||
426 | /* we are with lock held, so call the unlocked api to send */ | ||
427 | return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS, | ||
428 | SST_FLAG_BLOCKED, task_id, 0, &cmd, | ||
429 | sizeof(cmd.header) + cmd.header.length); | ||
430 | } | ||
431 | |||
432 | static int sst_gain_get(struct snd_kcontrol *kcontrol, | ||
433 | struct snd_ctl_elem_value *ucontrol) | ||
434 | { | ||
435 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
436 | struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value; | ||
437 | struct sst_gain_value *gv = mc->gain_val; | ||
438 | |||
439 | switch (mc->type) { | ||
440 | case SST_GAIN_TLV: | ||
441 | ucontrol->value.integer.value[0] = gv->l_gain; | ||
442 | ucontrol->value.integer.value[1] = gv->r_gain; | ||
443 | break; | ||
444 | |||
445 | case SST_GAIN_MUTE: | ||
446 | ucontrol->value.integer.value[0] = gv->mute ? 1 : 0; | ||
447 | break; | ||
448 | |||
449 | case SST_GAIN_RAMP_DURATION: | ||
450 | ucontrol->value.integer.value[0] = gv->ramp_duration; | ||
451 | break; | ||
452 | |||
453 | default: | ||
454 | dev_err(component->dev, "Invalid Input- gain type:%d\n", | ||
455 | mc->type); | ||
456 | return -EINVAL; | ||
457 | } | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int sst_gain_put(struct snd_kcontrol *kcontrol, | ||
463 | struct snd_ctl_elem_value *ucontrol) | ||
464 | { | ||
465 | int ret = 0; | ||
466 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | ||
467 | struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); | ||
468 | struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value; | ||
469 | struct sst_gain_value *gv = mc->gain_val; | ||
470 | |||
471 | mutex_lock(&drv->lock); | ||
472 | |||
473 | switch (mc->type) { | ||
474 | case SST_GAIN_TLV: | ||
475 | gv->l_gain = ucontrol->value.integer.value[0]; | ||
476 | gv->r_gain = ucontrol->value.integer.value[1]; | ||
477 | dev_dbg(cmpnt->dev, "%s: Volume %d, %d\n", | ||
478 | mc->pname, gv->l_gain, gv->r_gain); | ||
479 | break; | ||
480 | |||
481 | case SST_GAIN_MUTE: | ||
482 | gv->mute = !!ucontrol->value.integer.value[0]; | ||
483 | dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute); | ||
484 | break; | ||
485 | |||
486 | case SST_GAIN_RAMP_DURATION: | ||
487 | gv->ramp_duration = ucontrol->value.integer.value[0]; | ||
488 | dev_dbg(cmpnt->dev, "%s: Ramp Delay%d\n", | ||
489 | mc->pname, gv->ramp_duration); | ||
490 | break; | ||
491 | |||
492 | default: | ||
493 | mutex_unlock(&drv->lock); | ||
494 | dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n", | ||
495 | mc->type); | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | |||
499 | if (mc->w && mc->w->power) | ||
500 | ret = sst_send_gain_cmd(drv, gv, mc->task_id, | ||
501 | mc->pipe_id | mc->instance_id, mc->module_id, 0); | ||
502 | mutex_unlock(&drv->lock); | ||
503 | |||
504 | return ret; | ||
505 | } | ||
506 | |||
507 | static int sst_set_pipe_gain(struct sst_ids *ids, | ||
508 | struct sst_data *drv, int mute); | ||
509 | |||
510 | static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w, | ||
511 | struct snd_kcontrol *kcontrol) | ||
512 | { | ||
513 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
514 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
515 | struct sst_ids *ids = w->priv; | ||
516 | |||
517 | mutex_lock(&drv->lock); | ||
518 | sst_find_and_send_pipe_algo(drv, w->name, ids); | ||
519 | sst_set_pipe_gain(ids, drv, 0); | ||
520 | mutex_unlock(&drv->lock); | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int sst_generic_modules_event(struct snd_soc_dapm_widget *w, | ||
526 | struct snd_kcontrol *k, int event) | ||
527 | { | ||
528 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
529 | return sst_send_pipe_module_params(w, k); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common, SST_GAIN_MIN_VALUE * 10, 10, 0); | ||
534 | |||
535 | /* Look up table to convert MIXER SW bit regs to SWM inputs */ | ||
536 | static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = { | ||
537 | [SST_IP_CODEC0] = SST_SWM_IN_CODEC0, | ||
538 | [SST_IP_CODEC1] = SST_SWM_IN_CODEC1, | ||
539 | [SST_IP_LOOP0] = SST_SWM_IN_SPROT_LOOP, | ||
540 | [SST_IP_LOOP1] = SST_SWM_IN_MEDIA_LOOP1, | ||
541 | [SST_IP_LOOP2] = SST_SWM_IN_MEDIA_LOOP2, | ||
542 | [SST_IP_PCM0] = SST_SWM_IN_PCM0, | ||
543 | [SST_IP_PCM1] = SST_SWM_IN_PCM1, | ||
544 | [SST_IP_MEDIA0] = SST_SWM_IN_MEDIA0, | ||
545 | [SST_IP_MEDIA1] = SST_SWM_IN_MEDIA1, | ||
546 | [SST_IP_MEDIA2] = SST_SWM_IN_MEDIA2, | ||
547 | [SST_IP_MEDIA3] = SST_SWM_IN_MEDIA3, | ||
548 | }; | ||
549 | |||
550 | /** | ||
551 | * fill_swm_input - fill in the SWM input ids given the register | ||
552 | * | ||
553 | * The register value is a bit-field inicated which mixer inputs are ON. Use the | ||
554 | * lookup table to get the input-id and fill it in the structure. | ||
555 | */ | ||
556 | static int fill_swm_input(struct snd_soc_component *cmpnt, | ||
557 | struct swm_input_ids *swm_input, unsigned int reg) | ||
558 | { | ||
559 | uint i, is_set, nb_inputs = 0; | ||
560 | u16 input_loc_id; | ||
561 | |||
562 | dev_dbg(cmpnt->dev, "reg: %#x\n", reg); | ||
563 | for (i = 0; i < SST_SWM_INPUT_COUNT; i++) { | ||
564 | is_set = reg & BIT(i); | ||
565 | if (!is_set) | ||
566 | continue; | ||
567 | |||
568 | input_loc_id = swm_mixer_input_ids[i]; | ||
569 | SST_FILL_DESTINATION(2, swm_input->input_id, | ||
570 | input_loc_id, SST_DEFAULT_MODULE_ID); | ||
571 | nb_inputs++; | ||
572 | swm_input++; | ||
573 | dev_dbg(cmpnt->dev, "input id: %#x, nb_inputs: %d\n", | ||
574 | input_loc_id, nb_inputs); | ||
575 | |||
576 | if (nb_inputs == SST_CMD_SWM_MAX_INPUTS) { | ||
577 | dev_warn(cmpnt->dev, "SET_SWM cmd max inputs reached"); | ||
578 | break; | ||
579 | } | ||
580 | } | ||
581 | return nb_inputs; | ||
582 | } | ||
583 | |||
584 | |||
585 | /** | ||
586 | * called with lock held | ||
587 | */ | ||
588 | static int sst_set_pipe_gain(struct sst_ids *ids, | ||
589 | struct sst_data *drv, int mute) | ||
590 | { | ||
591 | int ret = 0; | ||
592 | struct sst_gain_mixer_control *mc; | ||
593 | struct sst_gain_value *gv; | ||
594 | struct sst_module *gain = NULL; | ||
595 | |||
596 | list_for_each_entry(gain, &ids->gain_list, node) { | ||
597 | struct snd_kcontrol *kctl = gain->kctl; | ||
598 | |||
599 | dev_dbg(&drv->pdev->dev, "control name=%s\n", kctl->id.name); | ||
600 | mc = (void *)kctl->private_value; | ||
601 | gv = mc->gain_val; | ||
602 | |||
603 | ret = sst_send_gain_cmd(drv, gv, mc->task_id, | ||
604 | mc->pipe_id | mc->instance_id, mc->module_id, mute); | ||
605 | if (ret) | ||
606 | return ret; | ||
607 | } | ||
608 | return ret; | ||
609 | } | ||
610 | |||
611 | static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, | ||
612 | struct snd_kcontrol *k, int event) | ||
613 | { | ||
614 | struct sst_cmd_set_swm cmd; | ||
615 | struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); | ||
616 | struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); | ||
617 | struct sst_ids *ids = w->priv; | ||
618 | bool set_mixer = false; | ||
619 | struct soc_mixer_control *mc; | ||
620 | int val = 0; | ||
621 | int i = 0; | ||
622 | |||
623 | dev_dbg(cmpnt->dev, "widget = %s\n", w->name); | ||
624 | /* | ||
625 | * Identify which mixer input is on and send the bitmap of the | ||
626 | * inputs as an IPC to the DSP. | ||
627 | */ | ||
628 | for (i = 0; i < w->num_kcontrols; i++) { | ||
629 | if (dapm_kcontrol_get_value(w->kcontrols[i])) { | ||
630 | mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value; | ||
631 | val |= 1 << mc->shift; | ||
632 | } | ||
633 | } | ||
634 | dev_dbg(cmpnt->dev, "val = %#x\n", val); | ||
635 | |||
636 | switch (event) { | ||
637 | case SND_SOC_DAPM_PRE_PMU: | ||
638 | case SND_SOC_DAPM_POST_PMD: | ||
639 | set_mixer = true; | ||
640 | break; | ||
641 | case SND_SOC_DAPM_POST_REG: | ||
642 | if (w->power) | ||
643 | set_mixer = true; | ||
644 | break; | ||
645 | default: | ||
646 | set_mixer = false; | ||
647 | } | ||
648 | |||
649 | if (set_mixer == false) | ||
650 | return 0; | ||
651 | |||
652 | if (SND_SOC_DAPM_EVENT_ON(event) || | ||
653 | event == SND_SOC_DAPM_POST_REG) | ||
654 | cmd.switch_state = SST_SWM_ON; | ||
655 | else | ||
656 | cmd.switch_state = SST_SWM_OFF; | ||
657 | |||
658 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
659 | /* MMX_SET_SWM == SBA_SET_SWM */ | ||
660 | cmd.header.command_id = SBA_SET_SWM; | ||
661 | |||
662 | SST_FILL_DESTINATION(2, cmd.output_id, | ||
663 | ids->location_id, SST_DEFAULT_MODULE_ID); | ||
664 | cmd.nb_inputs = fill_swm_input(cmpnt, &cmd.input[0], val); | ||
665 | cmd.header.length = offsetof(struct sst_cmd_set_swm, input) | ||
666 | - sizeof(struct sst_dsp_header) | ||
667 | + (cmd.nb_inputs * sizeof(cmd.input[0])); | ||
668 | |||
669 | return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | ||
670 | ids->task_id, 0, &cmd, | ||
671 | sizeof(cmd.header) + cmd.header.length); | ||
672 | } | ||
673 | |||
674 | /* SBA mixers - 16 inputs */ | ||
675 | #define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name) \ | ||
676 | static const struct snd_kcontrol_new kctl_name[] = { \ | ||
677 | SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0), \ | ||
678 | SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0), \ | ||
679 | SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0), \ | ||
680 | SOC_DAPM_SINGLE("media_loop1_in Switch", SND_SOC_NOPM, SST_IP_LOOP1, 1, 0), \ | ||
681 | SOC_DAPM_SINGLE("media_loop2_in Switch", SND_SOC_NOPM, SST_IP_LOOP2, 1, 0), \ | ||
682 | SOC_DAPM_SINGLE("pcm0_in Switch", SND_SOC_NOPM, SST_IP_PCM0, 1, 0), \ | ||
683 | SOC_DAPM_SINGLE("pcm1_in Switch", SND_SOC_NOPM, SST_IP_PCM1, 1, 0), \ | ||
684 | } | ||
685 | |||
686 | #define SST_SBA_MIXER_GRAPH_MAP(mix_name) \ | ||
687 | { mix_name, "codec_in0 Switch", "codec_in0" }, \ | ||
688 | { mix_name, "codec_in1 Switch", "codec_in1" }, \ | ||
689 | { mix_name, "sprot_loop_in Switch", "sprot_loop_in" }, \ | ||
690 | { mix_name, "media_loop1_in Switch", "media_loop1_in" }, \ | ||
691 | { mix_name, "media_loop2_in Switch", "media_loop2_in" }, \ | ||
692 | { mix_name, "pcm0_in Switch", "pcm0_in" }, \ | ||
693 | { mix_name, "pcm1_in Switch", "pcm1_in" } | ||
694 | |||
695 | #define SST_MMX_DECLARE_MIX_CONTROLS(kctl_name) \ | ||
696 | static const struct snd_kcontrol_new kctl_name[] = { \ | ||
697 | SOC_DAPM_SINGLE("media0_in Switch", SND_SOC_NOPM, SST_IP_MEDIA0, 1, 0), \ | ||
698 | SOC_DAPM_SINGLE("media1_in Switch", SND_SOC_NOPM, SST_IP_MEDIA1, 1, 0), \ | ||
699 | SOC_DAPM_SINGLE("media2_in Switch", SND_SOC_NOPM, SST_IP_MEDIA2, 1, 0), \ | ||
700 | SOC_DAPM_SINGLE("media3_in Switch", SND_SOC_NOPM, SST_IP_MEDIA3, 1, 0), \ | ||
701 | } | ||
702 | |||
703 | SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media0_controls); | ||
704 | SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media1_controls); | ||
705 | |||
706 | /* 18 SBA mixers */ | ||
707 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm0_controls); | ||
708 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm1_controls); | ||
709 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm2_controls); | ||
710 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_sprot_l0_controls); | ||
711 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l1_controls); | ||
712 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls); | ||
713 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls); | ||
714 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls); | ||
715 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls); | ||
716 | |||
717 | /* | ||
718 | * sst_handle_vb_timer - Start/Stop the DSP scheduler | ||
719 | * | ||
720 | * The DSP expects first cmd to be SBA_VB_START, so at first startup send | ||
721 | * that. | ||
722 | * DSP expects last cmd to be SBA_VB_IDLE, so at last shutdown send that. | ||
723 | * | ||
724 | * Do refcount internally so that we send command only at first start | ||
725 | * and last end. Since SST driver does its own ref count, invoke sst's | ||
726 | * power ops always! | ||
727 | */ | ||
728 | int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable) | ||
729 | { | ||
730 | int ret = 0; | ||
731 | struct sst_cmd_generic cmd; | ||
732 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); | ||
733 | static int timer_usage; | ||
734 | |||
735 | if (enable) | ||
736 | cmd.header.command_id = SBA_VB_START; | ||
737 | else | ||
738 | cmd.header.command_id = SBA_IDLE; | ||
739 | dev_dbg(dai->dev, "enable=%u, usage=%d\n", enable, timer_usage); | ||
740 | |||
741 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
742 | cmd.header.length = 0; | ||
743 | |||
744 | if (enable) { | ||
745 | ret = sst->ops->power(sst->dev, true); | ||
746 | if (ret < 0) | ||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | mutex_lock(&drv->lock); | ||
751 | if (enable) | ||
752 | timer_usage++; | ||
753 | else | ||
754 | timer_usage--; | ||
755 | |||
756 | /* | ||
757 | * Send the command only if this call is the first enable or last | ||
758 | * disable | ||
759 | */ | ||
760 | if ((enable && (timer_usage == 1)) || | ||
761 | (!enable && (timer_usage == 0))) { | ||
762 | ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD, | ||
763 | SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd, | ||
764 | sizeof(cmd.header) + cmd.header.length); | ||
765 | if (ret && enable) { | ||
766 | timer_usage--; | ||
767 | enable = false; | ||
768 | } | ||
769 | } | ||
770 | mutex_unlock(&drv->lock); | ||
771 | |||
772 | if (!enable) | ||
773 | sst->ops->power(sst->dev, false); | ||
774 | return ret; | ||
775 | } | ||
776 | |||
777 | /** | ||
778 | * sst_ssp_config - contains SSP configuration for media UC | ||
779 | */ | ||
780 | static const struct sst_ssp_config sst_ssp_configs = { | ||
781 | .ssp_id = SSP_CODEC, | ||
782 | .bits_per_slot = 24, | ||
783 | .slots = 4, | ||
784 | .ssp_mode = SSP_MODE_MASTER, | ||
785 | .pcm_mode = SSP_PCM_MODE_NETWORK, | ||
786 | .duplex = SSP_DUPLEX, | ||
787 | .ssp_protocol = SSP_MODE_PCM, | ||
788 | .fs_width = 1, | ||
789 | .fs_frequency = SSP_FS_48_KHZ, | ||
790 | .active_slot_map = 0xF, | ||
791 | .start_delay = 0, | ||
792 | }; | ||
793 | |||
794 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) | ||
795 | { | ||
796 | struct sst_cmd_sba_hw_set_ssp cmd; | ||
797 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); | ||
798 | const struct sst_ssp_config *config; | ||
799 | |||
800 | dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); | ||
801 | |||
802 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
803 | cmd.header.command_id = SBA_HW_SET_SSP; | ||
804 | cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) | ||
805 | - sizeof(struct sst_dsp_header); | ||
806 | |||
807 | config = &sst_ssp_configs; | ||
808 | dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id); | ||
809 | |||
810 | if (enable) | ||
811 | cmd.switch_state = SST_SWITCH_ON; | ||
812 | else | ||
813 | cmd.switch_state = SST_SWITCH_OFF; | ||
814 | |||
815 | cmd.selection = config->ssp_id; | ||
816 | cmd.nb_bits_per_slots = config->bits_per_slot; | ||
817 | cmd.nb_slots = config->slots; | ||
818 | cmd.mode = config->ssp_mode | (config->pcm_mode << 1); | ||
819 | cmd.duplex = config->duplex; | ||
820 | cmd.active_tx_slot_map = config->active_slot_map; | ||
821 | cmd.active_rx_slot_map = config->active_slot_map; | ||
822 | cmd.frame_sync_frequency = config->fs_frequency; | ||
823 | cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH; | ||
824 | cmd.data_polarity = 1; | ||
825 | cmd.frame_sync_width = config->fs_width; | ||
826 | cmd.ssp_protocol = config->ssp_protocol; | ||
827 | cmd.start_delay = config->start_delay; | ||
828 | cmd.reserved1 = cmd.reserved2 = 0xFF; | ||
829 | |||
830 | return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | ||
831 | SST_TASK_SBA, 0, &cmd, | ||
832 | sizeof(cmd.header) + cmd.header.length); | ||
833 | } | ||
834 | |||
835 | static int sst_set_be_modules(struct snd_soc_dapm_widget *w, | ||
836 | struct snd_kcontrol *k, int event) | ||
837 | { | ||
838 | int ret = 0; | ||
839 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
840 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
841 | |||
842 | dev_dbg(c->dev, "Enter: widget=%s\n", w->name); | ||
843 | |||
844 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
845 | ret = sst_send_slot_map(drv); | ||
846 | if (ret) | ||
847 | return ret; | ||
848 | ret = sst_send_pipe_module_params(w, k); | ||
849 | } | ||
850 | return ret; | ||
851 | } | ||
852 | |||
853 | static int sst_set_media_path(struct snd_soc_dapm_widget *w, | ||
854 | struct snd_kcontrol *k, int event) | ||
855 | { | ||
856 | int ret = 0; | ||
857 | struct sst_cmd_set_media_path cmd; | ||
858 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
859 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
860 | struct sst_ids *ids = w->priv; | ||
861 | |||
862 | dev_dbg(c->dev, "widget=%s\n", w->name); | ||
863 | dev_dbg(c->dev, "task=%u, location=%#x\n", | ||
864 | ids->task_id, ids->location_id); | ||
865 | |||
866 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
867 | cmd.switch_state = SST_PATH_ON; | ||
868 | else | ||
869 | cmd.switch_state = SST_PATH_OFF; | ||
870 | |||
871 | SST_FILL_DESTINATION(2, cmd.header.dst, | ||
872 | ids->location_id, SST_DEFAULT_MODULE_ID); | ||
873 | |||
874 | /* MMX_SET_MEDIA_PATH == SBA_SET_MEDIA_PATH */ | ||
875 | cmd.header.command_id = MMX_SET_MEDIA_PATH; | ||
876 | cmd.header.length = sizeof(struct sst_cmd_set_media_path) | ||
877 | - sizeof(struct sst_dsp_header); | ||
878 | |||
879 | ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | ||
880 | ids->task_id, 0, &cmd, | ||
881 | sizeof(cmd.header) + cmd.header.length); | ||
882 | if (ret) | ||
883 | return ret; | ||
884 | |||
885 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
886 | ret = sst_send_pipe_module_params(w, k); | ||
887 | return ret; | ||
888 | } | ||
889 | |||
890 | static int sst_set_media_loop(struct snd_soc_dapm_widget *w, | ||
891 | struct snd_kcontrol *k, int event) | ||
892 | { | ||
893 | int ret = 0; | ||
894 | struct sst_cmd_sba_set_media_loop_map cmd; | ||
895 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
896 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
897 | struct sst_ids *ids = w->priv; | ||
898 | |||
899 | dev_dbg(c->dev, "Enter:widget=%s\n", w->name); | ||
900 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
901 | cmd.switch_state = SST_SWITCH_ON; | ||
902 | else | ||
903 | cmd.switch_state = SST_SWITCH_OFF; | ||
904 | |||
905 | SST_FILL_DESTINATION(2, cmd.header.dst, | ||
906 | ids->location_id, SST_DEFAULT_MODULE_ID); | ||
907 | |||
908 | cmd.header.command_id = SBA_SET_MEDIA_LOOP_MAP; | ||
909 | cmd.header.length = sizeof(struct sst_cmd_sba_set_media_loop_map) | ||
910 | - sizeof(struct sst_dsp_header); | ||
911 | cmd.param.part.cfg.rate = 2; /* 48khz */ | ||
912 | |||
913 | cmd.param.part.cfg.format = ids->format; /* stereo/Mono */ | ||
914 | cmd.param.part.cfg.s_length = 1; /* 24bit left justified */ | ||
915 | cmd.map = 0; /* Algo sequence: Gain - DRP - FIR - IIR */ | ||
916 | |||
917 | ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | ||
918 | SST_TASK_SBA, 0, &cmd, | ||
919 | sizeof(cmd.header) + cmd.header.length); | ||
920 | if (ret) | ||
921 | return ret; | ||
922 | |||
923 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
924 | ret = sst_send_pipe_module_params(w, k); | ||
925 | return ret; | ||
926 | } | ||
927 | |||
928 | static const struct snd_soc_dapm_widget sst_dapm_widgets[] = { | ||
929 | SST_AIF_IN("codec_in0", sst_set_be_modules), | ||
930 | SST_AIF_IN("codec_in1", sst_set_be_modules), | ||
931 | SST_AIF_OUT("codec_out0", sst_set_be_modules), | ||
932 | SST_AIF_OUT("codec_out1", sst_set_be_modules), | ||
933 | |||
934 | /* Media Paths */ | ||
935 | /* MediaX IN paths are set via ALLOC, so no SET_MEDIA_PATH command */ | ||
936 | SST_PATH_INPUT("media0_in", SST_TASK_MMX, SST_SWM_IN_MEDIA0, sst_generic_modules_event), | ||
937 | SST_PATH_INPUT("media1_in", SST_TASK_MMX, SST_SWM_IN_MEDIA1, NULL), | ||
938 | SST_PATH_INPUT("media2_in", SST_TASK_MMX, SST_SWM_IN_MEDIA2, sst_set_media_path), | ||
939 | SST_PATH_INPUT("media3_in", SST_TASK_MMX, SST_SWM_IN_MEDIA3, NULL), | ||
940 | SST_PATH_OUTPUT("media0_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA0, sst_set_media_path), | ||
941 | SST_PATH_OUTPUT("media1_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA1, sst_set_media_path), | ||
942 | |||
943 | /* SBA PCM Paths */ | ||
944 | SST_PATH_INPUT("pcm0_in", SST_TASK_SBA, SST_SWM_IN_PCM0, sst_set_media_path), | ||
945 | SST_PATH_INPUT("pcm1_in", SST_TASK_SBA, SST_SWM_IN_PCM1, sst_set_media_path), | ||
946 | SST_PATH_OUTPUT("pcm0_out", SST_TASK_SBA, SST_SWM_OUT_PCM0, sst_set_media_path), | ||
947 | SST_PATH_OUTPUT("pcm1_out", SST_TASK_SBA, SST_SWM_OUT_PCM1, sst_set_media_path), | ||
948 | SST_PATH_OUTPUT("pcm2_out", SST_TASK_SBA, SST_SWM_OUT_PCM2, sst_set_media_path), | ||
949 | |||
950 | /* SBA Loops */ | ||
951 | SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA, SST_SWM_IN_SPROT_LOOP, NULL), | ||
952 | SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP1, NULL), | ||
953 | SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP2, NULL), | ||
954 | SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_MONO, sst_set_media_loop), | ||
955 | SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_MONO, sst_set_media_loop), | ||
956 | SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, SST_FMT_STEREO, sst_set_media_loop), | ||
957 | |||
958 | /* Media Mixers */ | ||
959 | SST_SWM_MIXER("media0_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA0, | ||
960 | sst_mix_media0_controls, sst_swm_mixer_event), | ||
961 | SST_SWM_MIXER("media1_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA1, | ||
962 | sst_mix_media1_controls, sst_swm_mixer_event), | ||
963 | |||
964 | /* SBA PCM mixers */ | ||
965 | SST_SWM_MIXER("pcm0_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM0, | ||
966 | sst_mix_pcm0_controls, sst_swm_mixer_event), | ||
967 | SST_SWM_MIXER("pcm1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM1, | ||
968 | sst_mix_pcm1_controls, sst_swm_mixer_event), | ||
969 | SST_SWM_MIXER("pcm2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM2, | ||
970 | sst_mix_pcm2_controls, sst_swm_mixer_event), | ||
971 | |||
972 | /* SBA Loop mixers */ | ||
973 | SST_SWM_MIXER("sprot_loop_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, | ||
974 | sst_mix_sprot_l0_controls, sst_swm_mixer_event), | ||
975 | SST_SWM_MIXER("media_loop1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, | ||
976 | sst_mix_media_l1_controls, sst_swm_mixer_event), | ||
977 | SST_SWM_MIXER("media_loop2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, | ||
978 | sst_mix_media_l2_controls, sst_swm_mixer_event), | ||
979 | |||
980 | /* SBA Backend mixers */ | ||
981 | SST_SWM_MIXER("codec_out0 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC0, | ||
982 | sst_mix_codec0_controls, sst_swm_mixer_event), | ||
983 | SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC1, | ||
984 | sst_mix_codec1_controls, sst_swm_mixer_event), | ||
985 | }; | ||
986 | |||
987 | static const struct snd_soc_dapm_route intercon[] = { | ||
988 | {"media0_in", NULL, "Compress Playback"}, | ||
989 | {"media1_in", NULL, "Headset Playback"}, | ||
990 | {"media2_in", NULL, "pcm0_out"}, | ||
991 | |||
992 | {"media0_out mix 0", "media0_in Switch", "media0_in"}, | ||
993 | {"media0_out mix 0", "media1_in Switch", "media1_in"}, | ||
994 | {"media0_out mix 0", "media2_in Switch", "media2_in"}, | ||
995 | {"media0_out mix 0", "media3_in Switch", "media3_in"}, | ||
996 | {"media1_out mix 0", "media0_in Switch", "media0_in"}, | ||
997 | {"media1_out mix 0", "media1_in Switch", "media1_in"}, | ||
998 | {"media1_out mix 0", "media2_in Switch", "media2_in"}, | ||
999 | {"media1_out mix 0", "media3_in Switch", "media3_in"}, | ||
1000 | |||
1001 | {"media0_out", NULL, "media0_out mix 0"}, | ||
1002 | {"media1_out", NULL, "media1_out mix 0"}, | ||
1003 | {"pcm0_in", NULL, "media0_out"}, | ||
1004 | {"pcm1_in", NULL, "media1_out"}, | ||
1005 | |||
1006 | {"Headset Capture", NULL, "pcm1_out"}, | ||
1007 | {"Headset Capture", NULL, "pcm2_out"}, | ||
1008 | {"pcm0_out", NULL, "pcm0_out mix 0"}, | ||
1009 | SST_SBA_MIXER_GRAPH_MAP("pcm0_out mix 0"), | ||
1010 | {"pcm1_out", NULL, "pcm1_out mix 0"}, | ||
1011 | SST_SBA_MIXER_GRAPH_MAP("pcm1_out mix 0"), | ||
1012 | {"pcm2_out", NULL, "pcm2_out mix 0"}, | ||
1013 | SST_SBA_MIXER_GRAPH_MAP("pcm2_out mix 0"), | ||
1014 | |||
1015 | {"media_loop1_in", NULL, "media_loop1_out"}, | ||
1016 | {"media_loop1_out", NULL, "media_loop1_out mix 0"}, | ||
1017 | SST_SBA_MIXER_GRAPH_MAP("media_loop1_out mix 0"), | ||
1018 | {"media_loop2_in", NULL, "media_loop2_out"}, | ||
1019 | {"media_loop2_out", NULL, "media_loop2_out mix 0"}, | ||
1020 | SST_SBA_MIXER_GRAPH_MAP("media_loop2_out mix 0"), | ||
1021 | {"sprot_loop_in", NULL, "sprot_loop_out"}, | ||
1022 | {"sprot_loop_out", NULL, "sprot_loop_out mix 0"}, | ||
1023 | SST_SBA_MIXER_GRAPH_MAP("sprot_loop_out mix 0"), | ||
1024 | |||
1025 | {"codec_out0", NULL, "codec_out0 mix 0"}, | ||
1026 | SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"), | ||
1027 | {"codec_out1", NULL, "codec_out1 mix 0"}, | ||
1028 | SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"), | ||
1029 | |||
1030 | }; | ||
1031 | static const char * const slot_names[] = { | ||
1032 | "none", | ||
1033 | "slot 0", "slot 1", "slot 2", "slot 3", | ||
1034 | "slot 4", "slot 5", "slot 6", "slot 7", /* not supported by FW */ | ||
1035 | }; | ||
1036 | |||
1037 | static const char * const channel_names[] = { | ||
1038 | "none", | ||
1039 | "codec_out0_0", "codec_out0_1", "codec_out1_0", "codec_out1_1", | ||
1040 | "codec_out2_0", "codec_out2_1", "codec_out3_0", "codec_out3_1", /* not supported by FW */ | ||
1041 | }; | ||
1042 | |||
1043 | #define SST_INTERLEAVER(xpname, slot_name, slotno) \ | ||
1044 | SST_SSP_SLOT_CTL(xpname, "tx interleaver", slot_name, slotno, true, \ | ||
1045 | channel_names, sst_slot_get, sst_slot_put) | ||
1046 | |||
1047 | #define SST_DEINTERLEAVER(xpname, channel_name, channel_no) \ | ||
1048 | SST_SSP_SLOT_CTL(xpname, "rx deinterleaver", channel_name, channel_no, false, \ | ||
1049 | slot_names, sst_slot_get, sst_slot_put) | ||
1050 | |||
1051 | static const struct snd_kcontrol_new sst_slot_controls[] = { | ||
1052 | SST_INTERLEAVER("codec_out", "slot 0", 0), | ||
1053 | SST_INTERLEAVER("codec_out", "slot 1", 1), | ||
1054 | SST_INTERLEAVER("codec_out", "slot 2", 2), | ||
1055 | SST_INTERLEAVER("codec_out", "slot 3", 3), | ||
1056 | SST_DEINTERLEAVER("codec_in", "codec_in0_0", 0), | ||
1057 | SST_DEINTERLEAVER("codec_in", "codec_in0_1", 1), | ||
1058 | SST_DEINTERLEAVER("codec_in", "codec_in1_0", 2), | ||
1059 | SST_DEINTERLEAVER("codec_in", "codec_in1_1", 3), | ||
1060 | }; | ||
1061 | |||
1062 | /* Gain helper with min/max set */ | ||
1063 | #define SST_GAIN(name, path_id, task_id, instance, gain_var) \ | ||
1064 | SST_GAIN_KCONTROLS(name, "Gain", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE, \ | ||
1065 | SST_GAIN_TC_MIN, SST_GAIN_TC_MAX, \ | ||
1066 | sst_gain_get, sst_gain_put, \ | ||
1067 | SST_MODULE_ID_GAIN_CELL, path_id, instance, task_id, \ | ||
1068 | sst_gain_tlv_common, gain_var) | ||
1069 | |||
1070 | #define SST_VOLUME(name, path_id, task_id, instance, gain_var) \ | ||
1071 | SST_GAIN_KCONTROLS(name, "Volume", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE, \ | ||
1072 | SST_GAIN_TC_MIN, SST_GAIN_TC_MAX, \ | ||
1073 | sst_gain_get, sst_gain_put, \ | ||
1074 | SST_MODULE_ID_VOLUME, path_id, instance, task_id, \ | ||
1075 | sst_gain_tlv_common, gain_var) | ||
1076 | |||
1077 | static struct sst_gain_value sst_gains[]; | ||
1078 | |||
1079 | static const struct snd_kcontrol_new sst_gain_controls[] = { | ||
1080 | SST_GAIN("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[0]), | ||
1081 | SST_GAIN("media1_in", SST_PATH_INDEX_MEDIA1_IN, SST_TASK_MMX, 0, &sst_gains[1]), | ||
1082 | SST_GAIN("media2_in", SST_PATH_INDEX_MEDIA2_IN, SST_TASK_MMX, 0, &sst_gains[2]), | ||
1083 | SST_GAIN("media3_in", SST_PATH_INDEX_MEDIA3_IN, SST_TASK_MMX, 0, &sst_gains[3]), | ||
1084 | |||
1085 | SST_GAIN("pcm0_in", SST_PATH_INDEX_PCM0_IN, SST_TASK_SBA, 0, &sst_gains[4]), | ||
1086 | SST_GAIN("pcm1_in", SST_PATH_INDEX_PCM1_IN, SST_TASK_SBA, 0, &sst_gains[5]), | ||
1087 | SST_GAIN("pcm1_out", SST_PATH_INDEX_PCM1_OUT, SST_TASK_SBA, 0, &sst_gains[6]), | ||
1088 | SST_GAIN("pcm2_out", SST_PATH_INDEX_PCM2_OUT, SST_TASK_SBA, 0, &sst_gains[7]), | ||
1089 | |||
1090 | SST_GAIN("codec_in0", SST_PATH_INDEX_CODEC_IN0, SST_TASK_SBA, 0, &sst_gains[8]), | ||
1091 | SST_GAIN("codec_in1", SST_PATH_INDEX_CODEC_IN1, SST_TASK_SBA, 0, &sst_gains[9]), | ||
1092 | SST_GAIN("codec_out0", SST_PATH_INDEX_CODEC_OUT0, SST_TASK_SBA, 0, &sst_gains[10]), | ||
1093 | SST_GAIN("codec_out1", SST_PATH_INDEX_CODEC_OUT1, SST_TASK_SBA, 0, &sst_gains[11]), | ||
1094 | SST_GAIN("media_loop1_out", SST_PATH_INDEX_MEDIA_LOOP1_OUT, SST_TASK_SBA, 0, &sst_gains[12]), | ||
1095 | SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT, SST_TASK_SBA, 0, &sst_gains[13]), | ||
1096 | SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT, SST_TASK_SBA, 0, &sst_gains[14]), | ||
1097 | SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[15]), | ||
1098 | }; | ||
1099 | |||
1100 | #define SST_GAIN_NUM_CONTROLS 3 | ||
1101 | /* the SST_GAIN macro above will create three alsa controls for each | ||
1102 | * instance invoked, gain, mute and ramp duration, which use the same gain | ||
1103 | * cell sst_gain to keep track of data | ||
1104 | * To calculate number of gain cell instances we need to device by 3 in | ||
1105 | * below caulcation for gain cell memory. | ||
1106 | * This gets rid of static number and issues while adding new controls | ||
1107 | */ | ||
1108 | static struct sst_gain_value sst_gains[ARRAY_SIZE(sst_gain_controls)/SST_GAIN_NUM_CONTROLS]; | ||
1109 | |||
165 | static const struct snd_kcontrol_new sst_algo_controls[] = { | 1110 | static const struct snd_kcontrol_new sst_algo_controls[] = { |
166 | SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24, | 1111 | SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24, |
167 | SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), | 1112 | SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), |
@@ -198,21 +1143,280 @@ static int sst_algo_control_init(struct device *dev) | |||
198 | return 0; | 1143 | return 0; |
199 | } | 1144 | } |
200 | 1145 | ||
201 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) | 1146 | static bool is_sst_dapm_widget(struct snd_soc_dapm_widget *w) |
1147 | { | ||
1148 | switch (w->id) { | ||
1149 | case snd_soc_dapm_pga: | ||
1150 | case snd_soc_dapm_aif_in: | ||
1151 | case snd_soc_dapm_aif_out: | ||
1152 | case snd_soc_dapm_input: | ||
1153 | case snd_soc_dapm_output: | ||
1154 | case snd_soc_dapm_mixer: | ||
1155 | return true; | ||
1156 | default: | ||
1157 | return false; | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | /** | ||
1162 | * sst_send_pipe_gains - send gains for the front-end DAIs | ||
1163 | * | ||
1164 | * The gains in the pipes connected to the front-ends are muted/unmuted | ||
1165 | * automatically via the digital_mute() DAPM callback. This function sends the | ||
1166 | * gains for the front-end pipes. | ||
1167 | */ | ||
1168 | int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) | ||
1169 | { | ||
1170 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); | ||
1171 | struct snd_soc_dapm_widget *w; | ||
1172 | struct snd_soc_dapm_path *p = NULL; | ||
1173 | |||
1174 | dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream); | ||
1175 | |||
1176 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1177 | dev_dbg(dai->dev, "Stream name=%s\n", | ||
1178 | dai->playback_widget->name); | ||
1179 | w = dai->playback_widget; | ||
1180 | list_for_each_entry(p, &w->sinks, list_source) { | ||
1181 | if (p->connected && !p->connected(w, p->sink)) | ||
1182 | continue; | ||
1183 | |||
1184 | if (p->connect && p->sink->power && | ||
1185 | is_sst_dapm_widget(p->sink)) { | ||
1186 | struct sst_ids *ids = p->sink->priv; | ||
1187 | |||
1188 | dev_dbg(dai->dev, "send gains for widget=%s\n", | ||
1189 | p->sink->name); | ||
1190 | mutex_lock(&drv->lock); | ||
1191 | sst_set_pipe_gain(ids, drv, mute); | ||
1192 | mutex_unlock(&drv->lock); | ||
1193 | } | ||
1194 | } | ||
1195 | } else { | ||
1196 | dev_dbg(dai->dev, "Stream name=%s\n", | ||
1197 | dai->capture_widget->name); | ||
1198 | w = dai->capture_widget; | ||
1199 | list_for_each_entry(p, &w->sources, list_sink) { | ||
1200 | if (p->connected && !p->connected(w, p->sink)) | ||
1201 | continue; | ||
1202 | |||
1203 | if (p->connect && p->source->power && | ||
1204 | is_sst_dapm_widget(p->source)) { | ||
1205 | struct sst_ids *ids = p->source->priv; | ||
1206 | |||
1207 | dev_dbg(dai->dev, "send gain for widget=%s\n", | ||
1208 | p->source->name); | ||
1209 | mutex_lock(&drv->lock); | ||
1210 | sst_set_pipe_gain(ids, drv, mute); | ||
1211 | mutex_unlock(&drv->lock); | ||
1212 | } | ||
1213 | } | ||
1214 | } | ||
1215 | return 0; | ||
1216 | } | ||
1217 | |||
1218 | /** | ||
1219 | * sst_fill_module_list - populate the list of modules/gains for a pipe | ||
1220 | * | ||
1221 | * | ||
1222 | * Fills the widget pointer in the kcontrol private data, and also fills the | ||
1223 | * kcontrol pointer in the widget private data. | ||
1224 | * | ||
1225 | * Widget pointer is used to send the algo/gain in the .put() handler if the | ||
1226 | * widget is powerd on. | ||
1227 | * | ||
1228 | * Kcontrol pointer is used to send the algo/gain in the widget power ON/OFF | ||
1229 | * event handler. Each widget (pipe) has multiple algos stored in the algo_list. | ||
1230 | */ | ||
1231 | static int sst_fill_module_list(struct snd_kcontrol *kctl, | ||
1232 | struct snd_soc_dapm_widget *w, int type) | ||
202 | { | 1233 | { |
1234 | struct sst_module *module = NULL; | ||
1235 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
1236 | struct sst_ids *ids = w->priv; | ||
203 | int ret = 0; | 1237 | int ret = 0; |
1238 | |||
1239 | module = devm_kzalloc(c->dev, sizeof(*module), GFP_KERNEL); | ||
1240 | if (!module) | ||
1241 | return -ENOMEM; | ||
1242 | |||
1243 | if (type == SST_MODULE_GAIN) { | ||
1244 | struct sst_gain_mixer_control *mc = (void *)kctl->private_value; | ||
1245 | |||
1246 | mc->w = w; | ||
1247 | module->kctl = kctl; | ||
1248 | list_add_tail(&module->node, &ids->gain_list); | ||
1249 | } else if (type == SST_MODULE_ALGO) { | ||
1250 | struct sst_algo_control *bc = (void *)kctl->private_value; | ||
1251 | |||
1252 | bc->w = w; | ||
1253 | module->kctl = kctl; | ||
1254 | list_add_tail(&module->node, &ids->algo_list); | ||
1255 | } else { | ||
1256 | dev_err(c->dev, "invoked for unknown type %d module %s", | ||
1257 | type, kctl->id.name); | ||
1258 | ret = -EINVAL; | ||
1259 | } | ||
1260 | |||
1261 | return ret; | ||
1262 | } | ||
1263 | |||
1264 | /** | ||
1265 | * sst_fill_widget_module_info - fill list of gains/algos for the pipe | ||
1266 | * @widget: pipe modelled as a DAPM widget | ||
1267 | * | ||
1268 | * Fill the list of gains/algos for the widget by looking at all the card | ||
1269 | * controls and comparing the name of the widget with the first part of control | ||
1270 | * name. First part of control name contains the pipe name (widget name). | ||
1271 | */ | ||
1272 | static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, | ||
1273 | struct snd_soc_platform *platform) | ||
1274 | { | ||
1275 | struct snd_kcontrol *kctl; | ||
1276 | int index, ret = 0; | ||
1277 | struct snd_card *card = platform->component.card->snd_card; | ||
1278 | char *idx; | ||
1279 | |||
1280 | down_read(&card->controls_rwsem); | ||
1281 | |||
1282 | list_for_each_entry(kctl, &card->controls, list) { | ||
1283 | idx = strstr(kctl->id.name, " "); | ||
1284 | if (idx == NULL) | ||
1285 | continue; | ||
1286 | index = strlen(kctl->id.name) - strlen(idx); | ||
1287 | |||
1288 | if (strstr(kctl->id.name, "Volume") && | ||
1289 | !strncmp(kctl->id.name, w->name, index)) | ||
1290 | ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN); | ||
1291 | |||
1292 | else if (strstr(kctl->id.name, "params") && | ||
1293 | !strncmp(kctl->id.name, w->name, index)) | ||
1294 | ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO); | ||
1295 | |||
1296 | else if (strstr(kctl->id.name, "Switch") && | ||
1297 | !strncmp(kctl->id.name, w->name, index) && | ||
1298 | strstr(kctl->id.name, "Gain")) { | ||
1299 | struct sst_gain_mixer_control *mc = | ||
1300 | (void *)kctl->private_value; | ||
1301 | |||
1302 | mc->w = w; | ||
1303 | |||
1304 | } else if (strstr(kctl->id.name, "interleaver") && | ||
1305 | !strncmp(kctl->id.name, w->name, index)) { | ||
1306 | struct sst_enum *e = (void *)kctl->private_value; | ||
1307 | |||
1308 | e->w = w; | ||
1309 | |||
1310 | } else if (strstr(kctl->id.name, "deinterleaver") && | ||
1311 | !strncmp(kctl->id.name, w->name, index)) { | ||
1312 | |||
1313 | struct sst_enum *e = (void *)kctl->private_value; | ||
1314 | |||
1315 | e->w = w; | ||
1316 | } | ||
1317 | |||
1318 | if (ret < 0) { | ||
1319 | up_read(&card->controls_rwsem); | ||
1320 | return ret; | ||
1321 | } | ||
1322 | } | ||
1323 | |||
1324 | up_read(&card->controls_rwsem); | ||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | /** | ||
1329 | * sst_fill_linked_widgets - fill the parent pointer for the linked widget | ||
1330 | */ | ||
1331 | static void sst_fill_linked_widgets(struct snd_soc_platform *platform, | ||
1332 | struct sst_ids *ids) | ||
1333 | { | ||
1334 | struct snd_soc_dapm_widget *w; | ||
1335 | unsigned int len = strlen(ids->parent_wname); | ||
1336 | |||
1337 | list_for_each_entry(w, &platform->component.card->widgets, list) { | ||
1338 | if (!strncmp(ids->parent_wname, w->name, len)) { | ||
1339 | ids->parent_w = w; | ||
1340 | break; | ||
1341 | } | ||
1342 | } | ||
1343 | } | ||
1344 | |||
1345 | /** | ||
1346 | * sst_map_modules_to_pipe - fill algo/gains list for all pipes | ||
1347 | */ | ||
1348 | static int sst_map_modules_to_pipe(struct snd_soc_platform *platform) | ||
1349 | { | ||
1350 | struct snd_soc_dapm_widget *w; | ||
1351 | int ret = 0; | ||
1352 | |||
1353 | list_for_each_entry(w, &platform->component.card->widgets, list) { | ||
1354 | if (is_sst_dapm_widget(w) && (w->priv)) { | ||
1355 | struct sst_ids *ids = w->priv; | ||
1356 | |||
1357 | dev_dbg(platform->dev, "widget type=%d name=%s\n", | ||
1358 | w->id, w->name); | ||
1359 | INIT_LIST_HEAD(&ids->algo_list); | ||
1360 | INIT_LIST_HEAD(&ids->gain_list); | ||
1361 | ret = sst_fill_widget_module_info(w, platform); | ||
1362 | |||
1363 | if (ret < 0) | ||
1364 | return ret; | ||
1365 | |||
1366 | /* fill linked widgets */ | ||
1367 | if (ids->parent_wname != NULL) | ||
1368 | sst_fill_linked_widgets(platform, ids); | ||
1369 | } | ||
1370 | } | ||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) | ||
1375 | { | ||
1376 | int i, ret = 0; | ||
1377 | struct snd_soc_dapm_context *dapm = | ||
1378 | snd_soc_component_get_dapm(&platform->component); | ||
204 | struct sst_data *drv = snd_soc_platform_get_drvdata(platform); | 1379 | struct sst_data *drv = snd_soc_platform_get_drvdata(platform); |
1380 | unsigned int gains = ARRAY_SIZE(sst_gain_controls)/3; | ||
205 | 1381 | ||
206 | drv->byte_stream = devm_kzalloc(platform->dev, | 1382 | drv->byte_stream = devm_kzalloc(platform->dev, |
207 | SST_MAX_BIN_BYTES, GFP_KERNEL); | 1383 | SST_MAX_BIN_BYTES, GFP_KERNEL); |
208 | if (!drv->byte_stream) | 1384 | if (!drv->byte_stream) |
209 | return -ENOMEM; | 1385 | return -ENOMEM; |
210 | 1386 | ||
211 | /*Initialize algo control params*/ | 1387 | snd_soc_dapm_new_controls(dapm, sst_dapm_widgets, |
1388 | ARRAY_SIZE(sst_dapm_widgets)); | ||
1389 | snd_soc_dapm_add_routes(dapm, intercon, | ||
1390 | ARRAY_SIZE(intercon)); | ||
1391 | snd_soc_dapm_new_widgets(dapm->card); | ||
1392 | |||
1393 | for (i = 0; i < gains; i++) { | ||
1394 | sst_gains[i].mute = SST_GAIN_MUTE_DEFAULT; | ||
1395 | sst_gains[i].l_gain = SST_GAIN_VOLUME_DEFAULT; | ||
1396 | sst_gains[i].r_gain = SST_GAIN_VOLUME_DEFAULT; | ||
1397 | sst_gains[i].ramp_duration = SST_GAIN_RAMP_DURATION_DEFAULT; | ||
1398 | } | ||
1399 | |||
1400 | ret = snd_soc_add_platform_controls(platform, sst_gain_controls, | ||
1401 | ARRAY_SIZE(sst_gain_controls)); | ||
1402 | if (ret) | ||
1403 | return ret; | ||
1404 | |||
1405 | /* Initialize algo control params */ | ||
212 | ret = sst_algo_control_init(platform->dev); | 1406 | ret = sst_algo_control_init(platform->dev); |
213 | if (ret) | 1407 | if (ret) |
214 | return ret; | 1408 | return ret; |
215 | ret = snd_soc_add_platform_controls(platform, sst_algo_controls, | 1409 | ret = snd_soc_add_platform_controls(platform, sst_algo_controls, |
216 | ARRAY_SIZE(sst_algo_controls)); | 1410 | ARRAY_SIZE(sst_algo_controls)); |
1411 | if (ret) | ||
1412 | return ret; | ||
1413 | |||
1414 | ret = snd_soc_add_platform_controls(platform, sst_slot_controls, | ||
1415 | ARRAY_SIZE(sst_slot_controls)); | ||
1416 | if (ret) | ||
1417 | return ret; | ||
1418 | |||
1419 | ret = sst_map_modules_to_pipe(platform); | ||
1420 | |||
217 | return ret; | 1421 | return ret; |
218 | } | 1422 | } |
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index a73e894b175c..dfebfdd5eb2a 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h | |||
@@ -23,6 +23,9 @@ | |||
23 | #ifndef __SST_ATOM_CONTROLS_H__ | 23 | #ifndef __SST_ATOM_CONTROLS_H__ |
24 | #define __SST_ATOM_CONTROLS_H__ | 24 | #define __SST_ATOM_CONTROLS_H__ |
25 | 25 | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/tlv.h> | ||
28 | |||
26 | enum { | 29 | enum { |
27 | MERR_DPCM_AUDIO = 0, | 30 | MERR_DPCM_AUDIO = 0, |
28 | MERR_DPCM_COMPR, | 31 | MERR_DPCM_COMPR, |
@@ -360,16 +363,416 @@ struct sst_dsp_header { | |||
360 | struct sst_cmd_generic { | 363 | struct sst_cmd_generic { |
361 | struct sst_dsp_header header; | 364 | struct sst_dsp_header header; |
362 | } __packed; | 365 | } __packed; |
366 | |||
367 | struct swm_input_ids { | ||
368 | struct sst_destination_id input_id; | ||
369 | } __packed; | ||
370 | |||
371 | struct sst_cmd_set_swm { | ||
372 | struct sst_dsp_header header; | ||
373 | struct sst_destination_id output_id; | ||
374 | u16 switch_state; | ||
375 | u16 nb_inputs; | ||
376 | struct swm_input_ids input[SST_CMD_SWM_MAX_INPUTS]; | ||
377 | } __packed; | ||
378 | |||
379 | struct sst_cmd_set_media_path { | ||
380 | struct sst_dsp_header header; | ||
381 | u16 switch_state; | ||
382 | } __packed; | ||
383 | |||
384 | struct pcm_cfg { | ||
385 | u8 s_length:2; | ||
386 | u8 rate:3; | ||
387 | u8 format:3; | ||
388 | } __packed; | ||
389 | |||
390 | struct sst_cmd_set_speech_path { | ||
391 | struct sst_dsp_header header; | ||
392 | u16 switch_state; | ||
393 | struct { | ||
394 | u16 rsvd:8; | ||
395 | struct pcm_cfg cfg; | ||
396 | } config; | ||
397 | } __packed; | ||
398 | |||
399 | struct gain_cell { | ||
400 | struct sst_destination_id dest; | ||
401 | s16 cell_gain_left; | ||
402 | s16 cell_gain_right; | ||
403 | u16 gain_time_constant; | ||
404 | } __packed; | ||
405 | |||
406 | #define NUM_GAIN_CELLS 1 | ||
407 | struct sst_cmd_set_gain_dual { | ||
408 | struct sst_dsp_header header; | ||
409 | u16 gain_cell_num; | ||
410 | struct gain_cell cell_gains[NUM_GAIN_CELLS]; | ||
411 | } __packed; | ||
363 | struct sst_cmd_set_params { | 412 | struct sst_cmd_set_params { |
364 | struct sst_destination_id dst; | 413 | struct sst_destination_id dst; |
365 | u16 command_id; | 414 | u16 command_id; |
366 | char params[0]; | 415 | char params[0]; |
367 | } __packed; | 416 | } __packed; |
417 | |||
418 | |||
419 | struct sst_cmd_sba_vb_start { | ||
420 | struct sst_dsp_header header; | ||
421 | } __packed; | ||
422 | |||
423 | union sba_media_loop_params { | ||
424 | struct { | ||
425 | u16 rsvd:8; | ||
426 | struct pcm_cfg cfg; | ||
427 | } part; | ||
428 | u16 full; | ||
429 | } __packed; | ||
430 | |||
431 | struct sst_cmd_sba_set_media_loop_map { | ||
432 | struct sst_dsp_header header; | ||
433 | u16 switch_state; | ||
434 | union sba_media_loop_params param; | ||
435 | u16 map; | ||
436 | } __packed; | ||
437 | |||
438 | struct sst_cmd_tone_stop { | ||
439 | struct sst_dsp_header header; | ||
440 | u16 switch_state; | ||
441 | } __packed; | ||
442 | |||
443 | enum sst_ssp_mode { | ||
444 | SSP_MODE_MASTER = 0, | ||
445 | SSP_MODE_SLAVE = 1, | ||
446 | }; | ||
447 | |||
448 | enum sst_ssp_pcm_mode { | ||
449 | SSP_PCM_MODE_NORMAL = 0, | ||
450 | SSP_PCM_MODE_NETWORK = 1, | ||
451 | }; | ||
452 | |||
453 | enum sst_ssp_duplex { | ||
454 | SSP_DUPLEX = 0, | ||
455 | SSP_RX = 1, | ||
456 | SSP_TX = 2, | ||
457 | }; | ||
458 | |||
459 | enum sst_ssp_fs_frequency { | ||
460 | SSP_FS_8_KHZ = 0, | ||
461 | SSP_FS_16_KHZ = 1, | ||
462 | SSP_FS_44_1_KHZ = 2, | ||
463 | SSP_FS_48_KHZ = 3, | ||
464 | }; | ||
465 | |||
466 | enum sst_ssp_fs_polarity { | ||
467 | SSP_FS_ACTIVE_LOW = 0, | ||
468 | SSP_FS_ACTIVE_HIGH = 1, | ||
469 | }; | ||
470 | |||
471 | enum sst_ssp_protocol { | ||
472 | SSP_MODE_PCM = 0, | ||
473 | SSP_MODE_I2S = 1, | ||
474 | }; | ||
475 | |||
476 | enum sst_ssp_port_id { | ||
477 | SSP_MODEM = 0, | ||
478 | SSP_BT = 1, | ||
479 | SSP_FM = 2, | ||
480 | SSP_CODEC = 3, | ||
481 | }; | ||
482 | |||
483 | struct sst_cmd_sba_hw_set_ssp { | ||
484 | struct sst_dsp_header header; | ||
485 | u16 selection; /* 0:SSP0(def), 1:SSP1, 2:SSP2 */ | ||
486 | |||
487 | u16 switch_state; | ||
488 | |||
489 | u16 nb_bits_per_slots:6; /* 0-32 bits, 24 (def) */ | ||
490 | u16 nb_slots:4; /* 0-8: slots per frame */ | ||
491 | u16 mode:3; /* 0:Master, 1: Slave */ | ||
492 | u16 duplex:3; | ||
493 | |||
494 | u16 active_tx_slot_map:8; /* Bit map, 0:off, 1:on */ | ||
495 | u16 reserved1:8; | ||
496 | |||
497 | u16 active_rx_slot_map:8; /* Bit map 0: Off, 1:On */ | ||
498 | u16 reserved2:8; | ||
499 | |||
500 | u16 frame_sync_frequency; | ||
501 | |||
502 | u16 frame_sync_polarity:8; | ||
503 | u16 data_polarity:8; | ||
504 | |||
505 | u16 frame_sync_width; /* 1 to N clocks */ | ||
506 | u16 ssp_protocol:8; | ||
507 | u16 start_delay:8; /* Start delay in terms of clock ticks */ | ||
508 | } __packed; | ||
509 | |||
510 | #define SST_MAX_TDM_SLOTS 8 | ||
511 | |||
512 | struct sst_param_sba_ssp_slot_map { | ||
513 | struct sst_dsp_header header; | ||
514 | |||
515 | u16 param_id; | ||
516 | u16 param_len; | ||
517 | u16 ssp_index; | ||
518 | |||
519 | u8 rx_slot_map[SST_MAX_TDM_SLOTS]; | ||
520 | u8 tx_slot_map[SST_MAX_TDM_SLOTS]; | ||
521 | } __packed; | ||
522 | |||
523 | enum { | ||
524 | SST_PROBE_EXTRACTOR = 0, | ||
525 | SST_PROBE_INJECTOR = 1, | ||
526 | }; | ||
527 | |||
528 | /**** widget defines *****/ | ||
529 | |||
530 | #define SST_MODULE_GAIN 1 | ||
531 | #define SST_MODULE_ALGO 2 | ||
532 | |||
533 | #define SST_FMT_MONO 0 | ||
534 | #define SST_FMT_STEREO 3 | ||
535 | |||
536 | /* physical SSP numbers */ | ||
537 | enum { | ||
538 | SST_SSP0 = 0, | ||
539 | SST_SSP1, | ||
540 | SST_SSP2, | ||
541 | SST_SSP_LAST = SST_SSP2, | ||
542 | }; | ||
543 | |||
544 | #define SST_NUM_SSPS (SST_SSP_LAST + 1) /* physical SSPs */ | ||
545 | #define SST_MAX_SSP_MUX 2 /* single SSP muxed between pipes */ | ||
546 | #define SST_MAX_SSP_DOMAINS 2 /* domains present in each pipe */ | ||
547 | |||
548 | struct sst_module { | ||
549 | struct snd_kcontrol *kctl; | ||
550 | struct list_head node; | ||
551 | }; | ||
552 | |||
553 | struct sst_ssp_config { | ||
554 | u8 ssp_id; | ||
555 | u8 bits_per_slot; | ||
556 | u8 slots; | ||
557 | u8 ssp_mode; | ||
558 | u8 pcm_mode; | ||
559 | u8 duplex; | ||
560 | u8 ssp_protocol; | ||
561 | u8 fs_frequency; | ||
562 | u8 active_slot_map; | ||
563 | u8 start_delay; | ||
564 | u16 fs_width; | ||
565 | }; | ||
566 | |||
567 | struct sst_ssp_cfg { | ||
568 | const u8 ssp_number; | ||
569 | const int *mux_shift; | ||
570 | const int (*domain_shift)[SST_MAX_SSP_MUX]; | ||
571 | const struct sst_ssp_config (*ssp_config)[SST_MAX_SSP_MUX][SST_MAX_SSP_DOMAINS]; | ||
572 | }; | ||
573 | |||
574 | struct sst_ids { | ||
575 | u16 location_id; | ||
576 | u16 module_id; | ||
577 | u8 task_id; | ||
578 | u8 format; | ||
579 | u8 reg; | ||
580 | const char *parent_wname; | ||
581 | struct snd_soc_dapm_widget *parent_w; | ||
582 | struct list_head algo_list; | ||
583 | struct list_head gain_list; | ||
584 | const struct sst_pcm_format *pcm_fmt; | ||
585 | }; | ||
586 | |||
587 | |||
588 | #define SST_AIF_IN(wname, wevent) \ | ||
589 | { .id = snd_soc_dapm_aif_in, .name = wname, .sname = NULL, \ | ||
590 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
591 | .on_val = 1, .off_val = 0, \ | ||
592 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
593 | .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \ | ||
594 | } | ||
595 | |||
596 | #define SST_AIF_OUT(wname, wevent) \ | ||
597 | { .id = snd_soc_dapm_aif_out, .name = wname, .sname = NULL, \ | ||
598 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
599 | .on_val = 1, .off_val = 0, \ | ||
600 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
601 | .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \ | ||
602 | } | ||
603 | |||
604 | #define SST_INPUT(wname, wevent) \ | ||
605 | { .id = snd_soc_dapm_input, .name = wname, .sname = NULL, \ | ||
606 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
607 | .on_val = 1, .off_val = 0, \ | ||
608 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
609 | .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \ | ||
610 | } | ||
611 | |||
612 | #define SST_OUTPUT(wname, wevent) \ | ||
613 | { .id = snd_soc_dapm_output, .name = wname, .sname = NULL, \ | ||
614 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
615 | .on_val = 1, .off_val = 0, \ | ||
616 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
617 | .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \ | ||
618 | } | ||
619 | |||
620 | #define SST_DAPM_OUTPUT(wname, wloc_id, wtask_id, wformat, wevent) \ | ||
621 | { .id = snd_soc_dapm_output, .name = wname, .sname = NULL, \ | ||
622 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
623 | .on_val = 1, .off_val = 0, \ | ||
624 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
625 | .priv = (void *)&(struct sst_ids) { .location_id = wloc_id, .task_id = wtask_id,\ | ||
626 | .pcm_fmt = wformat, } \ | ||
627 | } | ||
628 | |||
629 | #define SST_PATH(wname, wtask, wloc_id, wevent, wflags) \ | ||
630 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \ | ||
631 | .kcontrol_news = NULL, .num_kcontrols = 0, \ | ||
632 | .on_val = 1, .off_val = 0, \ | ||
633 | .event = wevent, .event_flags = wflags, \ | ||
634 | .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, } \ | ||
635 | } | ||
636 | |||
637 | #define SST_LINKED_PATH(wname, wtask, wloc_id, linked_wname, wevent, wflags) \ | ||
638 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \ | ||
639 | .kcontrol_news = NULL, .num_kcontrols = 0, \ | ||
640 | .on_val = 1, .off_val = 0, \ | ||
641 | .event = wevent, .event_flags = wflags, \ | ||
642 | .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \ | ||
643 | .parent_wname = linked_wname} \ | ||
644 | } | ||
645 | |||
646 | #define SST_PATH_MEDIA_LOOP(wname, wtask, wloc_id, wformat, wevent, wflags) \ | ||
647 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \ | ||
648 | .kcontrol_news = NULL, .num_kcontrols = 0, \ | ||
649 | .event = wevent, .event_flags = wflags, \ | ||
650 | .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \ | ||
651 | .format = wformat,} \ | ||
652 | } | ||
653 | |||
654 | /* output is triggered before input */ | ||
655 | #define SST_PATH_INPUT(name, task_id, loc_id, event) \ | ||
656 | SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) | ||
657 | |||
658 | #define SST_PATH_LINKED_INPUT(name, task_id, loc_id, linked_wname, event) \ | ||
659 | SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event, \ | ||
660 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) | ||
661 | |||
662 | #define SST_PATH_OUTPUT(name, task_id, loc_id, event) \ | ||
663 | SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD) | ||
664 | |||
665 | #define SST_PATH_LINKED_OUTPUT(name, task_id, loc_id, linked_wname, event) \ | ||
666 | SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event, \ | ||
667 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD) | ||
668 | |||
669 | #define SST_PATH_MEDIA_LOOP_OUTPUT(name, task_id, loc_id, format, event) \ | ||
670 | SST_PATH_MEDIA_LOOP(name, task_id, loc_id, format, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD) | ||
671 | |||
672 | |||
673 | #define SST_SWM_MIXER(wname, wreg, wtask, wloc_id, wcontrols, wevent) \ | ||
674 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \ | ||
675 | .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols),\ | ||
676 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD | \ | ||
677 | SND_SOC_DAPM_POST_REG, \ | ||
678 | .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \ | ||
679 | .reg = wreg } \ | ||
680 | } | ||
681 | |||
682 | enum sst_gain_kcontrol_type { | ||
683 | SST_GAIN_TLV, | ||
684 | SST_GAIN_MUTE, | ||
685 | SST_GAIN_RAMP_DURATION, | ||
686 | }; | ||
687 | |||
688 | struct sst_gain_mixer_control { | ||
689 | bool stereo; | ||
690 | enum sst_gain_kcontrol_type type; | ||
691 | struct sst_gain_value *gain_val; | ||
692 | int max; | ||
693 | int min; | ||
694 | u16 instance_id; | ||
695 | u16 module_id; | ||
696 | u16 pipe_id; | ||
697 | u16 task_id; | ||
698 | char pname[44]; | ||
699 | struct snd_soc_dapm_widget *w; | ||
700 | }; | ||
701 | |||
702 | struct sst_gain_value { | ||
703 | u16 ramp_duration; | ||
704 | s16 l_gain; | ||
705 | s16 r_gain; | ||
706 | bool mute; | ||
707 | }; | ||
708 | #define SST_GAIN_VOLUME_DEFAULT (-1440) | ||
709 | #define SST_GAIN_RAMP_DURATION_DEFAULT 5 /* timeconstant */ | ||
710 | #define SST_GAIN_MUTE_DEFAULT true | ||
711 | |||
712 | #define SST_GAIN_KCONTROL_TLV(xname, xhandler_get, xhandler_put, \ | ||
713 | xmod, xpipe, xinstance, xtask, tlv_array, xgain_val, \ | ||
714 | xmin, xmax, xpname) \ | ||
715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
716 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
717 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
718 | .tlv.p = (tlv_array), \ | ||
719 | .info = sst_gain_ctl_info,\ | ||
720 | .get = xhandler_get, .put = xhandler_put, \ | ||
721 | .private_value = (unsigned long)&(struct sst_gain_mixer_control) \ | ||
722 | { .stereo = true, .max = xmax, .min = xmin, .type = SST_GAIN_TLV, \ | ||
723 | .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\ | ||
724 | .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname} | ||
725 | |||
726 | #define SST_GAIN_KCONTROL_INT(xname, xhandler_get, xhandler_put, \ | ||
727 | xmod, xpipe, xinstance, xtask, xtype, xgain_val, \ | ||
728 | xmin, xmax, xpname) \ | ||
729 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
730 | .info = sst_gain_ctl_info, \ | ||
731 | .get = xhandler_get, .put = xhandler_put, \ | ||
732 | .private_value = (unsigned long)&(struct sst_gain_mixer_control) \ | ||
733 | { .stereo = false, .max = xmax, .min = xmin, .type = xtype, \ | ||
734 | .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\ | ||
735 | .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname} | ||
736 | |||
737 | #define SST_GAIN_KCONTROL_BOOL(xname, xhandler_get, xhandler_put,\ | ||
738 | xmod, xpipe, xinstance, xtask, xgain_val, xpname) \ | ||
739 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
740 | .info = snd_soc_info_bool_ext, \ | ||
741 | .get = xhandler_get, .put = xhandler_put, \ | ||
742 | .private_value = (unsigned long)&(struct sst_gain_mixer_control) \ | ||
743 | { .stereo = false, .type = SST_GAIN_MUTE, \ | ||
744 | .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\ | ||
745 | .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname} | ||
368 | #define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \ | 746 | #define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \ |
369 | xpname " " xmname " " #xinstance " " xtype | 747 | xpname " " xmname " " #xinstance " " xtype |
370 | 748 | ||
371 | #define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \ | 749 | #define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \ |
372 | xpname " " xmname " " #xinstance " " xtype " " xsubmodule | 750 | xpname " " xmname " " #xinstance " " xtype " " xsubmodule |
751 | |||
752 | /* | ||
753 | * 3 Controls for each Gain module | ||
754 | * e.g. - pcm0_in Gain 0 Volume | ||
755 | * - pcm0_in Gain 0 Ramp Delay | ||
756 | * - pcm0_in Gain 0 Switch | ||
757 | */ | ||
758 | #define SST_GAIN_KCONTROLS(xpname, xmname, xmin_gain, xmax_gain, xmin_tc, xmax_tc, \ | ||
759 | xhandler_get, xhandler_put, \ | ||
760 | xmod, xpipe, xinstance, xtask, tlv_array, xgain_val) \ | ||
761 | { SST_GAIN_KCONTROL_INT(SST_CONTROL_NAME(xpname, xmname, xinstance, "Ramp Delay"), \ | ||
762 | xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, SST_GAIN_RAMP_DURATION, \ | ||
763 | xgain_val, xmin_tc, xmax_tc, xpname) }, \ | ||
764 | { SST_GAIN_KCONTROL_BOOL(SST_CONTROL_NAME(xpname, xmname, xinstance, "Switch"), \ | ||
765 | xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, \ | ||
766 | xgain_val, xpname) } ,\ | ||
767 | { SST_GAIN_KCONTROL_TLV(SST_CONTROL_NAME(xpname, xmname, xinstance, "Volume"), \ | ||
768 | xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, tlv_array, \ | ||
769 | xgain_val, xmin_gain, xmax_gain, xpname) } | ||
770 | |||
771 | #define SST_GAIN_TC_MIN 5 | ||
772 | #define SST_GAIN_TC_MAX 5000 | ||
773 | #define SST_GAIN_MIN_VALUE -1440 /* in 0.1 DB units */ | ||
774 | #define SST_GAIN_MAX_VALUE 360 | ||
775 | |||
373 | enum sst_algo_kcontrol_type { | 776 | enum sst_algo_kcontrol_type { |
374 | SST_ALGO_PARAMS, | 777 | SST_ALGO_PARAMS, |
375 | SST_ALGO_BYPASS, | 778 | SST_ALGO_BYPASS, |
@@ -439,4 +842,29 @@ struct sst_enum { | |||
439 | struct snd_soc_dapm_widget *w; | 842 | struct snd_soc_dapm_widget *w; |
440 | }; | 843 | }; |
441 | 844 | ||
845 | /* only 4 slots/channels supported atm */ | ||
846 | #define SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts) \ | ||
847 | (struct sst_enum){ .reg = s_ch_no, .tx = is_tx, .max = 4+1, .texts = xtexts, } | ||
848 | |||
849 | #define SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name) \ | ||
850 | xpname " " xmname " " s_ch_name | ||
851 | |||
852 | #define SST_SSP_SLOT_CTL(xpname, xmname, s_ch_name, s_ch_no, is_tx, xtexts, xget, xput) \ | ||
853 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
854 | .name = SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name), \ | ||
855 | .info = sst_slot_enum_info, \ | ||
856 | .get = xget, .put = xput, \ | ||
857 | .private_value = (unsigned long)&SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts), \ | ||
858 | } | ||
859 | |||
860 | #define SST_MUX_CTL_NAME(xpname, xinstance) \ | ||
861 | xpname " " #xinstance | ||
862 | |||
863 | #define SST_SSP_MUX_ENUM(xreg, xshift, xtexts) \ | ||
864 | (struct soc_enum) SOC_ENUM_DOUBLE(xreg, xshift, xshift, ARRAY_SIZE(xtexts), xtexts) | ||
865 | |||
866 | #define SST_SSP_MUX_CTL(xpname, xinstance, xreg, xshift, xtexts) \ | ||
867 | SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \ | ||
868 | SST_SSP_MUX_ENUM(xreg, xshift, xtexts)) | ||
869 | |||
442 | #endif | 870 | #endif |
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c index fc588764ffa3..5a9e56700f31 100644 --- a/sound/soc/intel/sst-baytrail-dsp.c +++ b/sound/soc/intel/sst-baytrail-dsp.c | |||
@@ -67,17 +67,12 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
67 | { | 67 | { |
68 | struct dma_block_info *block; | 68 | struct dma_block_info *block; |
69 | struct sst_module *mod; | 69 | struct sst_module *mod; |
70 | struct sst_module_data block_data; | ||
71 | struct sst_module_template template; | 70 | struct sst_module_template template; |
72 | int count; | 71 | int count; |
73 | 72 | ||
74 | memset(&template, 0, sizeof(template)); | 73 | memset(&template, 0, sizeof(template)); |
75 | template.id = module->type; | 74 | template.id = module->type; |
76 | template.entry = module->entry_point; | 75 | template.entry = module->entry_point; |
77 | template.p.type = SST_MEM_DRAM; | ||
78 | template.p.data_type = SST_DATA_P; | ||
79 | template.s.type = SST_MEM_DRAM; | ||
80 | template.s.data_type = SST_DATA_S; | ||
81 | 76 | ||
82 | mod = sst_module_new(fw, &template, NULL); | 77 | mod = sst_module_new(fw, &template, NULL); |
83 | if (mod == NULL) | 78 | if (mod == NULL) |
@@ -94,19 +89,19 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
94 | 89 | ||
95 | switch (block->type) { | 90 | switch (block->type) { |
96 | case SST_BYT_IRAM: | 91 | case SST_BYT_IRAM: |
97 | block_data.offset = block->ram_offset + | 92 | mod->offset = block->ram_offset + |
98 | dsp->addr.iram_offset; | 93 | dsp->addr.iram_offset; |
99 | block_data.type = SST_MEM_IRAM; | 94 | mod->type = SST_MEM_IRAM; |
100 | break; | 95 | break; |
101 | case SST_BYT_DRAM: | 96 | case SST_BYT_DRAM: |
102 | block_data.offset = block->ram_offset + | 97 | mod->offset = block->ram_offset + |
103 | dsp->addr.dram_offset; | 98 | dsp->addr.dram_offset; |
104 | block_data.type = SST_MEM_DRAM; | 99 | mod->type = SST_MEM_DRAM; |
105 | break; | 100 | break; |
106 | case SST_BYT_CACHE: | 101 | case SST_BYT_CACHE: |
107 | block_data.offset = block->ram_offset + | 102 | mod->offset = block->ram_offset + |
108 | (dsp->addr.fw_ext - dsp->addr.lpe); | 103 | (dsp->addr.fw_ext - dsp->addr.lpe); |
109 | block_data.type = SST_MEM_CACHE; | 104 | mod->type = SST_MEM_CACHE; |
110 | break; | 105 | break; |
111 | default: | 106 | default: |
112 | dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n", | 107 | dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n", |
@@ -114,11 +109,10 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
114 | return -EINVAL; | 109 | return -EINVAL; |
115 | } | 110 | } |
116 | 111 | ||
117 | block_data.size = block->size; | 112 | mod->size = block->size; |
118 | block_data.data_type = SST_DATA_M; | 113 | mod->data = (void *)block + sizeof(*block); |
119 | block_data.data = (void *)block + sizeof(*block); | ||
120 | 114 | ||
121 | sst_module_insert_fixed_block(mod, &block_data); | 115 | sst_module_alloc_blocks(mod); |
122 | 116 | ||
123 | block = (void *)block + sizeof(*block) + block->size; | 117 | block = (void *)block + sizeof(*block) + block->size; |
124 | } | 118 | } |
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h index ffb308bd81ce..b9da030e312d 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/sst-dsp-priv.h | |||
@@ -26,6 +26,9 @@ struct sst_mem_block; | |||
26 | struct sst_module; | 26 | struct sst_module; |
27 | struct sst_fw; | 27 | struct sst_fw; |
28 | 28 | ||
29 | /* do we need to remove or keep */ | ||
30 | #define DSP_DRAM_ADDR_OFFSET 0x400000 | ||
31 | |||
29 | /* | 32 | /* |
30 | * DSP Operations exported by platform Audio DSP driver. | 33 | * DSP Operations exported by platform Audio DSP driver. |
31 | */ | 34 | */ |
@@ -33,6 +36,9 @@ struct sst_ops { | |||
33 | /* DSP core boot / reset */ | 36 | /* DSP core boot / reset */ |
34 | void (*boot)(struct sst_dsp *); | 37 | void (*boot)(struct sst_dsp *); |
35 | void (*reset)(struct sst_dsp *); | 38 | void (*reset)(struct sst_dsp *); |
39 | int (*wake)(struct sst_dsp *); | ||
40 | void (*sleep)(struct sst_dsp *); | ||
41 | void (*stall)(struct sst_dsp *); | ||
36 | 42 | ||
37 | /* Shim IO */ | 43 | /* Shim IO */ |
38 | void (*write)(void __iomem *addr, u32 offset, u32 value); | 44 | void (*write)(void __iomem *addr, u32 offset, u32 value); |
@@ -67,6 +73,8 @@ struct sst_addr { | |||
67 | u32 shim_offset; | 73 | u32 shim_offset; |
68 | u32 iram_offset; | 74 | u32 iram_offset; |
69 | u32 dram_offset; | 75 | u32 dram_offset; |
76 | u32 dsp_iram_offset; | ||
77 | u32 dsp_dram_offset; | ||
70 | void __iomem *lpe; | 78 | void __iomem *lpe; |
71 | void __iomem *shim; | 79 | void __iomem *shim; |
72 | void __iomem *pci_cfg; | 80 | void __iomem *pci_cfg; |
@@ -84,15 +92,6 @@ struct sst_mailbox { | |||
84 | }; | 92 | }; |
85 | 93 | ||
86 | /* | 94 | /* |
87 | * Audio DSP Firmware data types. | ||
88 | */ | ||
89 | enum sst_data_type { | ||
90 | SST_DATA_M = 0, /* module block data */ | ||
91 | SST_DATA_P = 1, /* peristant data (text, data) */ | ||
92 | SST_DATA_S = 2, /* scratch data (usually buffers) */ | ||
93 | }; | ||
94 | |||
95 | /* | ||
96 | * Audio DSP memory block types. | 95 | * Audio DSP memory block types. |
97 | */ | 96 | */ |
98 | enum sst_mem_type { | 97 | enum sst_mem_type { |
@@ -125,23 +124,6 @@ struct sst_fw { | |||
125 | }; | 124 | }; |
126 | 125 | ||
127 | /* | 126 | /* |
128 | * Audio DSP Generic Module data. | ||
129 | * | ||
130 | * This is used to dsecribe any sections of persistent (text and data) and | ||
131 | * scratch (buffers) of module data in ADSP memory space. | ||
132 | */ | ||
133 | struct sst_module_data { | ||
134 | |||
135 | enum sst_mem_type type; /* destination memory type */ | ||
136 | enum sst_data_type data_type; /* type of module data */ | ||
137 | |||
138 | u32 size; /* size in bytes */ | ||
139 | int32_t offset; /* offset in FW file */ | ||
140 | u32 data_offset; /* offset in ADSP memory space */ | ||
141 | void *data; /* module data */ | ||
142 | }; | ||
143 | |||
144 | /* | ||
145 | * Audio DSP Generic Module Template. | 127 | * Audio DSP Generic Module Template. |
146 | * | 128 | * |
147 | * Used to define and register a new FW module. This data is extracted from | 129 | * Used to define and register a new FW module. This data is extracted from |
@@ -150,15 +132,52 @@ struct sst_module_data { | |||
150 | struct sst_module_template { | 132 | struct sst_module_template { |
151 | u32 id; | 133 | u32 id; |
152 | u32 entry; /* entry point */ | 134 | u32 entry; /* entry point */ |
153 | struct sst_module_data s; /* scratch data */ | 135 | u32 scratch_size; |
154 | struct sst_module_data p; /* peristant data */ | 136 | u32 persistent_size; |
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Block Allocator - Used to allocate blocks of DSP memory. | ||
141 | */ | ||
142 | struct sst_block_allocator { | ||
143 | u32 id; | ||
144 | u32 offset; | ||
145 | int size; | ||
146 | enum sst_mem_type type; | ||
147 | }; | ||
148 | |||
149 | /* | ||
150 | * Runtime Module Instance - A module object can be instanciated multiple | ||
151 | * times within the DSP FW. | ||
152 | */ | ||
153 | struct sst_module_runtime { | ||
154 | struct sst_dsp *dsp; | ||
155 | int id; | ||
156 | struct sst_module *module; /* parent module we belong too */ | ||
157 | |||
158 | u32 persistent_offset; /* private memory offset */ | ||
159 | void *private; | ||
160 | |||
161 | struct list_head list; | ||
162 | struct list_head block_list; /* list of blocks used */ | ||
163 | }; | ||
164 | |||
165 | /* | ||
166 | * Runtime Module Context - The runtime context must be manually stored by the | ||
167 | * driver prior to enter S3 and restored after leaving S3. This should really be | ||
168 | * part of the memory context saved by the enter D3 message IPC ??? | ||
169 | */ | ||
170 | struct sst_module_runtime_context { | ||
171 | dma_addr_t dma_buffer; | ||
172 | u32 *buffer; | ||
155 | }; | 173 | }; |
156 | 174 | ||
157 | /* | 175 | /* |
158 | * Audio DSP Generic Module. | 176 | * Audio DSP Generic Module. |
159 | * | 177 | * |
160 | * Each Firmware file can consist of 1..N modules. A module can span multiple | 178 | * Each Firmware file can consist of 1..N modules. A module can span multiple |
161 | * ADSP memory blocks. The simplest FW will be a file with 1 module. | 179 | * ADSP memory blocks. The simplest FW will be a file with 1 module. A module |
180 | * can be instanciated multiple times in the DSP. | ||
162 | */ | 181 | */ |
163 | struct sst_module { | 182 | struct sst_module { |
164 | struct sst_dsp *dsp; | 183 | struct sst_dsp *dsp; |
@@ -167,10 +186,13 @@ struct sst_module { | |||
167 | /* module configuration */ | 186 | /* module configuration */ |
168 | u32 id; | 187 | u32 id; |
169 | u32 entry; /* module entry point */ | 188 | u32 entry; /* module entry point */ |
170 | u32 offset; /* module offset in firmware file */ | 189 | s32 offset; /* module offset in firmware file */ |
171 | u32 size; /* module size */ | 190 | u32 size; /* module size */ |
172 | struct sst_module_data s; /* scratch data */ | 191 | u32 scratch_size; /* global scratch memory required */ |
173 | struct sst_module_data p; /* peristant data */ | 192 | u32 persistent_size; /* private memory required */ |
193 | enum sst_mem_type type; /* destination memory type */ | ||
194 | u32 data_offset; /* offset in ADSP memory space */ | ||
195 | void *data; /* module data */ | ||
174 | 196 | ||
175 | /* runtime */ | 197 | /* runtime */ |
176 | u32 usage_count; /* can be unloaded if count == 0 */ | 198 | u32 usage_count; /* can be unloaded if count == 0 */ |
@@ -180,6 +202,7 @@ struct sst_module { | |||
180 | struct list_head block_list; /* Module list of blocks in use */ | 202 | struct list_head block_list; /* Module list of blocks in use */ |
181 | struct list_head list; /* DSP list of modules */ | 203 | struct list_head list; /* DSP list of modules */ |
182 | struct list_head list_fw; /* FW list of modules */ | 204 | struct list_head list_fw; /* FW list of modules */ |
205 | struct list_head runtime_list; /* list of runtime module objects*/ | ||
183 | }; | 206 | }; |
184 | 207 | ||
185 | /* | 208 | /* |
@@ -208,7 +231,6 @@ struct sst_mem_block { | |||
208 | struct sst_block_ops *ops; /* block operations, if any */ | 231 | struct sst_block_ops *ops; /* block operations, if any */ |
209 | 232 | ||
210 | /* block status */ | 233 | /* block status */ |
211 | enum sst_data_type data_type; /* data type held in this block */ | ||
212 | u32 bytes_used; /* bytes in use by modules */ | 234 | u32 bytes_used; /* bytes in use by modules */ |
213 | void *private; /* generic core does not touch this */ | 235 | void *private; /* generic core does not touch this */ |
214 | int users; /* number of modules using this block */ | 236 | int users; /* number of modules using this block */ |
@@ -253,6 +275,11 @@ struct sst_dsp { | |||
253 | struct list_head module_list; | 275 | struct list_head module_list; |
254 | struct list_head fw_list; | 276 | struct list_head fw_list; |
255 | 277 | ||
278 | /* scratch buffer */ | ||
279 | struct list_head scratch_block_list; | ||
280 | u32 scratch_offset; | ||
281 | u32 scratch_size; | ||
282 | |||
256 | /* platform data */ | 283 | /* platform data */ |
257 | struct sst_pdata *pdata; | 284 | struct sst_pdata *pdata; |
258 | 285 | ||
@@ -290,18 +317,33 @@ void sst_fw_unload(struct sst_fw *sst_fw); | |||
290 | /* Create/Free firmware modules */ | 317 | /* Create/Free firmware modules */ |
291 | struct sst_module *sst_module_new(struct sst_fw *sst_fw, | 318 | struct sst_module *sst_module_new(struct sst_fw *sst_fw, |
292 | struct sst_module_template *template, void *private); | 319 | struct sst_module_template *template, void *private); |
293 | void sst_module_free(struct sst_module *sst_module); | 320 | void sst_module_free(struct sst_module *module); |
294 | int sst_module_insert(struct sst_module *sst_module); | ||
295 | int sst_module_remove(struct sst_module *sst_module); | ||
296 | int sst_module_insert_fixed_block(struct sst_module *module, | ||
297 | struct sst_module_data *data); | ||
298 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id); | 321 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id); |
299 | 322 | int sst_module_alloc_blocks(struct sst_module *module); | |
300 | /* allocate/free pesistent/scratch memory regions managed by drv */ | 323 | int sst_module_free_blocks(struct sst_module *module); |
301 | struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp); | 324 | |
302 | void sst_mem_block_free_scratch(struct sst_dsp *dsp, | 325 | /* Create/Free firmware module runtime instances */ |
303 | struct sst_module *scratch); | 326 | struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module, |
304 | int sst_block_module_remove(struct sst_module *module); | 327 | int id, void *private); |
328 | void sst_module_runtime_free(struct sst_module_runtime *runtime); | ||
329 | struct sst_module_runtime *sst_module_runtime_get_from_id( | ||
330 | struct sst_module *module, u32 id); | ||
331 | int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime, | ||
332 | int offset); | ||
333 | int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime); | ||
334 | int sst_module_runtime_save(struct sst_module_runtime *runtime, | ||
335 | struct sst_module_runtime_context *context); | ||
336 | int sst_module_runtime_restore(struct sst_module_runtime *runtime, | ||
337 | struct sst_module_runtime_context *context); | ||
338 | |||
339 | /* generic block allocation */ | ||
340 | int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba, | ||
341 | struct list_head *block_list); | ||
342 | int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list); | ||
343 | |||
344 | /* scratch allocation */ | ||
345 | int sst_block_alloc_scratch(struct sst_dsp *dsp); | ||
346 | void sst_block_free_scratch(struct sst_dsp *dsp); | ||
305 | 347 | ||
306 | /* Register the DSPs memory blocks - would be nice to read from ACPI */ | 348 | /* Register the DSPs memory blocks - would be nice to read from ACPI */ |
307 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | 349 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, |
@@ -309,4 +351,10 @@ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | |||
309 | void *private); | 351 | void *private); |
310 | void sst_mem_block_unregister_all(struct sst_dsp *dsp); | 352 | void sst_mem_block_unregister_all(struct sst_dsp *dsp); |
311 | 353 | ||
354 | /* Create/Free DMA resources */ | ||
355 | int sst_dma_new(struct sst_dsp *sst); | ||
356 | void sst_dma_free(struct sst_dma *dma); | ||
357 | |||
358 | u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset, | ||
359 | enum sst_mem_type type); | ||
312 | #endif | 360 | #endif |
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index cd23060a0d86..86e410845670 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c | |||
@@ -245,6 +245,29 @@ int sst_dsp_boot(struct sst_dsp *sst) | |||
245 | } | 245 | } |
246 | EXPORT_SYMBOL_GPL(sst_dsp_boot); | 246 | EXPORT_SYMBOL_GPL(sst_dsp_boot); |
247 | 247 | ||
248 | int sst_dsp_wake(struct sst_dsp *sst) | ||
249 | { | ||
250 | if (sst->ops->wake) | ||
251 | return sst->ops->wake(sst); | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | EXPORT_SYMBOL_GPL(sst_dsp_wake); | ||
256 | |||
257 | void sst_dsp_sleep(struct sst_dsp *sst) | ||
258 | { | ||
259 | if (sst->ops->sleep) | ||
260 | sst->ops->sleep(sst); | ||
261 | } | ||
262 | EXPORT_SYMBOL_GPL(sst_dsp_sleep); | ||
263 | |||
264 | void sst_dsp_stall(struct sst_dsp *sst) | ||
265 | { | ||
266 | if (sst->ops->stall) | ||
267 | sst->ops->stall(sst); | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(sst_dsp_stall); | ||
270 | |||
248 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg) | 271 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg) |
249 | { | 272 | { |
250 | sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY); | 273 | sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY); |
@@ -352,6 +375,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev, | |||
352 | INIT_LIST_HEAD(&sst->free_block_list); | 375 | INIT_LIST_HEAD(&sst->free_block_list); |
353 | INIT_LIST_HEAD(&sst->module_list); | 376 | INIT_LIST_HEAD(&sst->module_list); |
354 | INIT_LIST_HEAD(&sst->fw_list); | 377 | INIT_LIST_HEAD(&sst->fw_list); |
378 | INIT_LIST_HEAD(&sst->scratch_block_list); | ||
355 | 379 | ||
356 | /* Initialise SST Audio DSP */ | 380 | /* Initialise SST Audio DSP */ |
357 | if (sst->ops->init) { | 381 | if (sst->ops->init) { |
@@ -366,6 +390,10 @@ struct sst_dsp *sst_dsp_new(struct device *dev, | |||
366 | if (err) | 390 | if (err) |
367 | goto irq_err; | 391 | goto irq_err; |
368 | 392 | ||
393 | err = sst_dma_new(sst); | ||
394 | if (err) | ||
395 | dev_warn(dev, "sst_dma_new failed %d\n", err); | ||
396 | |||
369 | return sst; | 397 | return sst; |
370 | 398 | ||
371 | irq_err: | 399 | irq_err: |
@@ -381,6 +409,9 @@ void sst_dsp_free(struct sst_dsp *sst) | |||
381 | free_irq(sst->irq, sst); | 409 | free_irq(sst->irq, sst); |
382 | if (sst->ops->free) | 410 | if (sst->ops->free) |
383 | sst->ops->free(sst); | 411 | sst->ops->free(sst); |
412 | |||
413 | if (sst->dma) | ||
414 | sst_dma_free(sst->dma); | ||
384 | } | 415 | } |
385 | EXPORT_SYMBOL_GPL(sst_dsp_free); | 416 | EXPORT_SYMBOL_GPL(sst_dsp_free); |
386 | 417 | ||
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index 3165dfa97408..f291e32f0077 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h | |||
@@ -30,6 +30,9 @@ | |||
30 | #define SST_DMA_TYPE_DW 1 | 30 | #define SST_DMA_TYPE_DW 1 |
31 | #define SST_DMA_TYPE_MID 2 | 31 | #define SST_DMA_TYPE_MID 2 |
32 | 32 | ||
33 | /* autosuspend delay 5s*/ | ||
34 | #define SST_RUNTIME_SUSPEND_DELAY (5 * 1000) | ||
35 | |||
33 | /* SST Shim register map | 36 | /* SST Shim register map |
34 | * The register naming can differ between products. Some products also | 37 | * The register naming can differ between products. Some products also |
35 | * contain extra functionality. | 38 | * contain extra functionality. |
@@ -156,12 +159,18 @@ | |||
156 | #define SST_VDRTCTL3 0xaC | 159 | #define SST_VDRTCTL3 0xaC |
157 | 160 | ||
158 | /* VDRTCTL0 */ | 161 | /* VDRTCTL0 */ |
159 | #define SST_VDRTCL0_APLLSE_MASK 1 | 162 | #define SST_VDRTCL0_D3PGD (1 << 0) |
160 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 16 | 163 | #define SST_VDRTCL0_D3SRAMPGD (1 << 1) |
161 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) | 164 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 12 |
162 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 6 | 165 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xfffff << SST_VDRTCL0_DSRAMPGE_SHIFT) |
166 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 2 | ||
163 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) | 167 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) |
164 | 168 | ||
169 | /* VDRTCTL2 */ | ||
170 | #define SST_VDRTCL2_DCLCGE (1 << 1) | ||
171 | #define SST_VDRTCL2_DTCGE (1 << 10) | ||
172 | #define SST_VDRTCL2_APLLSE_MASK (1 << 31) | ||
173 | |||
165 | /* PMCS */ | 174 | /* PMCS */ |
166 | #define SST_PMCS 0x84 | 175 | #define SST_PMCS 0x84 |
167 | #define SST_PMCS_PS_MASK 0x3 | 176 | #define SST_PMCS_PS_MASK 0x3 |
@@ -245,6 +254,17 @@ void sst_memcpy_fromio_32(struct sst_dsp *sst, | |||
245 | /* DSP reset & boot */ | 254 | /* DSP reset & boot */ |
246 | void sst_dsp_reset(struct sst_dsp *sst); | 255 | void sst_dsp_reset(struct sst_dsp *sst); |
247 | int sst_dsp_boot(struct sst_dsp *sst); | 256 | int sst_dsp_boot(struct sst_dsp *sst); |
257 | int sst_dsp_wake(struct sst_dsp *sst); | ||
258 | void sst_dsp_sleep(struct sst_dsp *sst); | ||
259 | void sst_dsp_stall(struct sst_dsp *sst); | ||
260 | |||
261 | /* DMA */ | ||
262 | int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id); | ||
263 | void sst_dsp_dma_put_channel(struct sst_dsp *dsp); | ||
264 | int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
265 | dma_addr_t src_addr, size_t size); | ||
266 | int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
267 | dma_addr_t src_addr, size_t size); | ||
248 | 268 | ||
249 | /* Msg IO */ | 269 | /* Msg IO */ |
250 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg); | 270 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg); |
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 3bb43dac892d..4a5bde9c686b 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c | |||
@@ -23,6 +23,11 @@ | |||
23 | #include <linux/dma-mapping.h> | 23 | #include <linux/dma-mapping.h> |
24 | #include <linux/dmaengine.h> | 24 | #include <linux/dmaengine.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/acpi.h> | ||
27 | |||
28 | /* supported DMA engine drivers */ | ||
29 | #include <linux/platform_data/dma-dw.h> | ||
30 | #include <linux/dma/dw.h> | ||
26 | 31 | ||
27 | #include <asm/page.h> | 32 | #include <asm/page.h> |
28 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
@@ -30,16 +35,301 @@ | |||
30 | #include "sst-dsp.h" | 35 | #include "sst-dsp.h" |
31 | #include "sst-dsp-priv.h" | 36 | #include "sst-dsp-priv.h" |
32 | 37 | ||
33 | static void block_module_remove(struct sst_module *module); | 38 | #define SST_DMA_RESOURCES 2 |
39 | #define SST_DSP_DMA_MAX_BURST 0x3 | ||
40 | #define SST_HSW_BLOCK_ANY 0xffffffff | ||
41 | |||
42 | #define SST_HSW_MASK_DMA_ADDR_DSP 0xfff00000 | ||
43 | |||
44 | struct sst_dma { | ||
45 | struct sst_dsp *sst; | ||
46 | |||
47 | struct dw_dma_chip *chip; | ||
48 | |||
49 | struct dma_async_tx_descriptor *desc; | ||
50 | struct dma_chan *ch; | ||
51 | }; | ||
52 | |||
53 | static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes) | ||
54 | { | ||
55 | /* __iowrite32_copy use 32bit size values so divide by 4 */ | ||
56 | __iowrite32_copy((void *)dest, src, bytes/4); | ||
57 | } | ||
58 | |||
59 | static void sst_dma_transfer_complete(void *arg) | ||
60 | { | ||
61 | struct sst_dsp *sst = (struct sst_dsp *)arg; | ||
62 | |||
63 | dev_dbg(sst->dev, "DMA: callback\n"); | ||
64 | } | ||
65 | |||
66 | static int sst_dsp_dma_copy(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
67 | dma_addr_t src_addr, size_t size) | ||
68 | { | ||
69 | struct dma_async_tx_descriptor *desc; | ||
70 | struct sst_dma *dma = sst->dma; | ||
71 | |||
72 | if (dma->ch == NULL) { | ||
73 | dev_err(sst->dev, "error: no DMA channel\n"); | ||
74 | return -ENODEV; | ||
75 | } | ||
76 | |||
77 | dev_dbg(sst->dev, "DMA: src: 0x%lx dest 0x%lx size %zu\n", | ||
78 | (unsigned long)src_addr, (unsigned long)dest_addr, size); | ||
79 | |||
80 | desc = dma->ch->device->device_prep_dma_memcpy(dma->ch, dest_addr, | ||
81 | src_addr, size, DMA_CTRL_ACK); | ||
82 | if (!desc){ | ||
83 | dev_err(sst->dev, "error: dma prep memcpy failed\n"); | ||
84 | return -EINVAL; | ||
85 | } | ||
86 | |||
87 | desc->callback = sst_dma_transfer_complete; | ||
88 | desc->callback_param = sst; | ||
89 | |||
90 | desc->tx_submit(desc); | ||
91 | dma_wait_for_async_tx(desc); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | /* copy to DSP */ | ||
97 | int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
98 | dma_addr_t src_addr, size_t size) | ||
99 | { | ||
100 | return sst_dsp_dma_copy(sst, dest_addr | SST_HSW_MASK_DMA_ADDR_DSP, | ||
101 | src_addr, size); | ||
102 | } | ||
103 | EXPORT_SYMBOL_GPL(sst_dsp_dma_copyto); | ||
104 | |||
105 | /* copy from DSP */ | ||
106 | int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
107 | dma_addr_t src_addr, size_t size) | ||
108 | { | ||
109 | return sst_dsp_dma_copy(sst, dest_addr, | ||
110 | src_addr | SST_HSW_MASK_DMA_ADDR_DSP, size); | ||
111 | } | ||
112 | EXPORT_SYMBOL_GPL(sst_dsp_dma_copyfrom); | ||
113 | |||
114 | /* remove module from memory - callers hold locks */ | ||
115 | static void block_list_remove(struct sst_dsp *dsp, | ||
116 | struct list_head *block_list) | ||
117 | { | ||
118 | struct sst_mem_block *block, *tmp; | ||
119 | int err; | ||
120 | |||
121 | /* disable each block */ | ||
122 | list_for_each_entry(block, block_list, module_list) { | ||
123 | |||
124 | if (block->ops && block->ops->disable) { | ||
125 | err = block->ops->disable(block); | ||
126 | if (err < 0) | ||
127 | dev_err(dsp->dev, | ||
128 | "error: cant disable block %d:%d\n", | ||
129 | block->type, block->index); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | /* mark each block as free */ | ||
134 | list_for_each_entry_safe(block, tmp, block_list, module_list) { | ||
135 | list_del(&block->module_list); | ||
136 | list_move(&block->list, &dsp->free_block_list); | ||
137 | dev_dbg(dsp->dev, "block freed %d:%d at offset 0x%x\n", | ||
138 | block->type, block->index, block->offset); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | /* prepare the memory block to receive data from host - callers hold locks */ | ||
143 | static int block_list_prepare(struct sst_dsp *dsp, | ||
144 | struct list_head *block_list) | ||
145 | { | ||
146 | struct sst_mem_block *block; | ||
147 | int ret = 0; | ||
148 | |||
149 | /* enable each block so that's it'e ready for data */ | ||
150 | list_for_each_entry(block, block_list, module_list) { | ||
151 | |||
152 | if (block->ops && block->ops->enable && !block->users) { | ||
153 | ret = block->ops->enable(block); | ||
154 | if (ret < 0) { | ||
155 | dev_err(dsp->dev, | ||
156 | "error: cant disable block %d:%d\n", | ||
157 | block->type, block->index); | ||
158 | goto err; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | return ret; | ||
163 | |||
164 | err: | ||
165 | list_for_each_entry(block, block_list, module_list) { | ||
166 | if (block->ops && block->ops->disable) | ||
167 | block->ops->disable(block); | ||
168 | } | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static struct dw_dma_platform_data dw_pdata = { | ||
173 | .is_private = 1, | ||
174 | .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, | ||
175 | .chan_priority = CHAN_PRIORITY_ASCENDING, | ||
176 | }; | ||
177 | |||
178 | static struct dw_dma_chip *dw_probe(struct device *dev, struct resource *mem, | ||
179 | int irq) | ||
180 | { | ||
181 | struct dw_dma_chip *chip; | ||
182 | int err; | ||
183 | |||
184 | chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); | ||
185 | if (!chip) | ||
186 | return ERR_PTR(-ENOMEM); | ||
187 | |||
188 | chip->irq = irq; | ||
189 | chip->regs = devm_ioremap_resource(dev, mem); | ||
190 | if (IS_ERR(chip->regs)) | ||
191 | return ERR_CAST(chip->regs); | ||
192 | |||
193 | err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31)); | ||
194 | if (err) | ||
195 | return ERR_PTR(err); | ||
196 | |||
197 | chip->dev = dev; | ||
198 | err = dw_dma_probe(chip, &dw_pdata); | ||
199 | if (err) | ||
200 | return ERR_PTR(err); | ||
201 | |||
202 | return chip; | ||
203 | } | ||
204 | |||
205 | static void dw_remove(struct dw_dma_chip *chip) | ||
206 | { | ||
207 | dw_dma_remove(chip); | ||
208 | } | ||
209 | |||
210 | static bool dma_chan_filter(struct dma_chan *chan, void *param) | ||
211 | { | ||
212 | struct sst_dsp *dsp = (struct sst_dsp *)param; | ||
213 | |||
214 | return chan->device->dev == dsp->dma_dev; | ||
215 | } | ||
34 | 216 | ||
35 | static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes) | 217 | int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id) |
36 | { | 218 | { |
37 | u32 i; | 219 | struct sst_dma *dma = dsp->dma; |
220 | struct dma_slave_config slave; | ||
221 | dma_cap_mask_t mask; | ||
222 | int ret; | ||
223 | |||
224 | /* The Intel MID DMA engine driver needs the slave config set but | ||
225 | * Synopsis DMA engine driver safely ignores the slave config */ | ||
226 | dma_cap_zero(mask); | ||
227 | dma_cap_set(DMA_SLAVE, mask); | ||
228 | dma_cap_set(DMA_MEMCPY, mask); | ||
229 | |||
230 | dma->ch = dma_request_channel(mask, dma_chan_filter, dsp); | ||
231 | if (dma->ch == NULL) { | ||
232 | dev_err(dsp->dev, "error: DMA request channel failed\n"); | ||
233 | return -EIO; | ||
234 | } | ||
235 | |||
236 | memset(&slave, 0, sizeof(slave)); | ||
237 | slave.direction = DMA_MEM_TO_DEV; | ||
238 | slave.src_addr_width = | ||
239 | slave.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
240 | slave.src_maxburst = slave.dst_maxburst = SST_DSP_DMA_MAX_BURST; | ||
241 | |||
242 | ret = dmaengine_slave_config(dma->ch, &slave); | ||
243 | if (ret) { | ||
244 | dev_err(dsp->dev, "error: unable to set DMA slave config %d\n", | ||
245 | ret); | ||
246 | dma_release_channel(dma->ch); | ||
247 | dma->ch = NULL; | ||
248 | } | ||
38 | 249 | ||
39 | /* copy one 32 bit word at a time as 64 bit access is not supported */ | 250 | return ret; |
40 | for (i = 0; i < bytes; i += 4) | ||
41 | memcpy_toio(dest + i, src + i, 4); | ||
42 | } | 251 | } |
252 | EXPORT_SYMBOL_GPL(sst_dsp_dma_get_channel); | ||
253 | |||
254 | void sst_dsp_dma_put_channel(struct sst_dsp *dsp) | ||
255 | { | ||
256 | struct sst_dma *dma = dsp->dma; | ||
257 | |||
258 | if (!dma->ch) | ||
259 | return; | ||
260 | |||
261 | dma_release_channel(dma->ch); | ||
262 | dma->ch = NULL; | ||
263 | } | ||
264 | EXPORT_SYMBOL_GPL(sst_dsp_dma_put_channel); | ||
265 | |||
266 | int sst_dma_new(struct sst_dsp *sst) | ||
267 | { | ||
268 | struct sst_pdata *sst_pdata = sst->pdata; | ||
269 | struct sst_dma *dma; | ||
270 | struct resource mem; | ||
271 | const char *dma_dev_name; | ||
272 | int ret = 0; | ||
273 | |||
274 | /* configure the correct platform data for whatever DMA engine | ||
275 | * is attached to the ADSP IP. */ | ||
276 | switch (sst->pdata->dma_engine) { | ||
277 | case SST_DMA_TYPE_DW: | ||
278 | dma_dev_name = "dw_dmac"; | ||
279 | break; | ||
280 | case SST_DMA_TYPE_MID: | ||
281 | dma_dev_name = "Intel MID DMA"; | ||
282 | break; | ||
283 | default: | ||
284 | dev_err(sst->dev, "error: invalid DMA engine %d\n", | ||
285 | sst->pdata->dma_engine); | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | dma = devm_kzalloc(sst->dev, sizeof(struct sst_dma), GFP_KERNEL); | ||
290 | if (!dma) | ||
291 | return -ENOMEM; | ||
292 | |||
293 | dma->sst = sst; | ||
294 | |||
295 | memset(&mem, 0, sizeof(mem)); | ||
296 | |||
297 | mem.start = sst->addr.lpe_base + sst_pdata->dma_base; | ||
298 | mem.end = sst->addr.lpe_base + sst_pdata->dma_base + sst_pdata->dma_size - 1; | ||
299 | mem.flags = IORESOURCE_MEM; | ||
300 | |||
301 | /* now register DMA engine device */ | ||
302 | dma->chip = dw_probe(sst->dma_dev, &mem, sst_pdata->irq); | ||
303 | if (IS_ERR(dma->chip)) { | ||
304 | dev_err(sst->dev, "error: DMA device register failed\n"); | ||
305 | ret = PTR_ERR(dma->chip); | ||
306 | goto err_dma_dev; | ||
307 | } | ||
308 | |||
309 | sst->dma = dma; | ||
310 | sst->fw_use_dma = true; | ||
311 | return 0; | ||
312 | |||
313 | err_dma_dev: | ||
314 | devm_kfree(sst->dev, dma); | ||
315 | return ret; | ||
316 | } | ||
317 | EXPORT_SYMBOL(sst_dma_new); | ||
318 | |||
319 | void sst_dma_free(struct sst_dma *dma) | ||
320 | { | ||
321 | |||
322 | if (dma == NULL) | ||
323 | return; | ||
324 | |||
325 | if (dma->ch) | ||
326 | dma_release_channel(dma->ch); | ||
327 | |||
328 | if (dma->chip) | ||
329 | dw_remove(dma->chip); | ||
330 | |||
331 | } | ||
332 | EXPORT_SYMBOL(sst_dma_free); | ||
43 | 333 | ||
44 | /* create new generic firmware object */ | 334 | /* create new generic firmware object */ |
45 | struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | 335 | struct sst_fw *sst_fw_new(struct sst_dsp *dsp, |
@@ -71,6 +361,12 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | |||
71 | /* copy FW data to DMA-able memory */ | 361 | /* copy FW data to DMA-able memory */ |
72 | memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size); | 362 | memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size); |
73 | 363 | ||
364 | if (dsp->fw_use_dma) { | ||
365 | err = sst_dsp_dma_get_channel(dsp, 0); | ||
366 | if (err < 0) | ||
367 | goto chan_err; | ||
368 | } | ||
369 | |||
74 | /* call core specific FW paser to load FW data into DSP */ | 370 | /* call core specific FW paser to load FW data into DSP */ |
75 | err = dsp->ops->parse_fw(sst_fw); | 371 | err = dsp->ops->parse_fw(sst_fw); |
76 | if (err < 0) { | 372 | if (err < 0) { |
@@ -78,6 +374,9 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | |||
78 | goto parse_err; | 374 | goto parse_err; |
79 | } | 375 | } |
80 | 376 | ||
377 | if (dsp->fw_use_dma) | ||
378 | sst_dsp_dma_put_channel(dsp); | ||
379 | |||
81 | mutex_lock(&dsp->mutex); | 380 | mutex_lock(&dsp->mutex); |
82 | list_add(&sst_fw->list, &dsp->fw_list); | 381 | list_add(&sst_fw->list, &dsp->fw_list); |
83 | mutex_unlock(&dsp->mutex); | 382 | mutex_unlock(&dsp->mutex); |
@@ -85,9 +384,13 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | |||
85 | return sst_fw; | 384 | return sst_fw; |
86 | 385 | ||
87 | parse_err: | 386 | parse_err: |
88 | dma_free_coherent(dsp->dev, sst_fw->size, | 387 | if (dsp->fw_use_dma) |
388 | sst_dsp_dma_put_channel(dsp); | ||
389 | chan_err: | ||
390 | dma_free_coherent(dsp->dma_dev, sst_fw->size, | ||
89 | sst_fw->dma_buf, | 391 | sst_fw->dma_buf, |
90 | sst_fw->dmable_fw_paddr); | 392 | sst_fw->dmable_fw_paddr); |
393 | sst_fw->dma_buf = NULL; | ||
91 | kfree(sst_fw); | 394 | kfree(sst_fw); |
92 | return NULL; | 395 | return NULL; |
93 | } | 396 | } |
@@ -111,21 +414,37 @@ EXPORT_SYMBOL_GPL(sst_fw_reload); | |||
111 | 414 | ||
112 | void sst_fw_unload(struct sst_fw *sst_fw) | 415 | void sst_fw_unload(struct sst_fw *sst_fw) |
113 | { | 416 | { |
114 | struct sst_dsp *dsp = sst_fw->dsp; | 417 | struct sst_dsp *dsp = sst_fw->dsp; |
115 | struct sst_module *module, *tmp; | 418 | struct sst_module *module, *mtmp; |
419 | struct sst_module_runtime *runtime, *rtmp; | ||
420 | |||
421 | dev_dbg(dsp->dev, "unloading firmware\n"); | ||
422 | |||
423 | mutex_lock(&dsp->mutex); | ||
424 | |||
425 | /* check module by module */ | ||
426 | list_for_each_entry_safe(module, mtmp, &dsp->module_list, list) { | ||
427 | if (module->sst_fw == sst_fw) { | ||
428 | |||
429 | /* remove runtime modules */ | ||
430 | list_for_each_entry_safe(runtime, rtmp, &module->runtime_list, list) { | ||
116 | 431 | ||
117 | dev_dbg(dsp->dev, "unloading firmware\n"); | 432 | block_list_remove(dsp, &runtime->block_list); |
433 | list_del(&runtime->list); | ||
434 | kfree(runtime); | ||
435 | } | ||
436 | |||
437 | /* now remove the module */ | ||
438 | block_list_remove(dsp, &module->block_list); | ||
439 | list_del(&module->list); | ||
440 | kfree(module); | ||
441 | } | ||
442 | } | ||
118 | 443 | ||
119 | mutex_lock(&dsp->mutex); | 444 | /* remove all scratch blocks */ |
120 | list_for_each_entry_safe(module, tmp, &dsp->module_list, list) { | 445 | block_list_remove(dsp, &dsp->scratch_block_list); |
121 | if (module->sst_fw == sst_fw) { | ||
122 | block_module_remove(module); | ||
123 | list_del(&module->list); | ||
124 | kfree(module); | ||
125 | } | ||
126 | } | ||
127 | 446 | ||
128 | mutex_unlock(&dsp->mutex); | 447 | mutex_unlock(&dsp->mutex); |
129 | } | 448 | } |
130 | EXPORT_SYMBOL_GPL(sst_fw_unload); | 449 | EXPORT_SYMBOL_GPL(sst_fw_unload); |
131 | 450 | ||
@@ -138,7 +457,8 @@ void sst_fw_free(struct sst_fw *sst_fw) | |||
138 | list_del(&sst_fw->list); | 457 | list_del(&sst_fw->list); |
139 | mutex_unlock(&dsp->mutex); | 458 | mutex_unlock(&dsp->mutex); |
140 | 459 | ||
141 | dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf, | 460 | if (sst_fw->dma_buf) |
461 | dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf, | ||
142 | sst_fw->dmable_fw_paddr); | 462 | sst_fw->dmable_fw_paddr); |
143 | kfree(sst_fw); | 463 | kfree(sst_fw); |
144 | } | 464 | } |
@@ -175,11 +495,11 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw, | |||
175 | sst_module->id = template->id; | 495 | sst_module->id = template->id; |
176 | sst_module->dsp = dsp; | 496 | sst_module->dsp = dsp; |
177 | sst_module->sst_fw = sst_fw; | 497 | sst_module->sst_fw = sst_fw; |
178 | 498 | sst_module->scratch_size = template->scratch_size; | |
179 | memcpy(&sst_module->s, &template->s, sizeof(struct sst_module_data)); | 499 | sst_module->persistent_size = template->persistent_size; |
180 | memcpy(&sst_module->p, &template->p, sizeof(struct sst_module_data)); | ||
181 | 500 | ||
182 | INIT_LIST_HEAD(&sst_module->block_list); | 501 | INIT_LIST_HEAD(&sst_module->block_list); |
502 | INIT_LIST_HEAD(&sst_module->runtime_list); | ||
183 | 503 | ||
184 | mutex_lock(&dsp->mutex); | 504 | mutex_lock(&dsp->mutex); |
185 | list_add(&sst_module->list, &dsp->module_list); | 505 | list_add(&sst_module->list, &dsp->module_list); |
@@ -202,73 +522,122 @@ void sst_module_free(struct sst_module *sst_module) | |||
202 | } | 522 | } |
203 | EXPORT_SYMBOL_GPL(sst_module_free); | 523 | EXPORT_SYMBOL_GPL(sst_module_free); |
204 | 524 | ||
205 | static struct sst_mem_block *find_block(struct sst_dsp *dsp, int type, | 525 | struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module, |
206 | u32 offset) | 526 | int id, void *private) |
527 | { | ||
528 | struct sst_dsp *dsp = module->dsp; | ||
529 | struct sst_module_runtime *runtime; | ||
530 | |||
531 | runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); | ||
532 | if (runtime == NULL) | ||
533 | return NULL; | ||
534 | |||
535 | runtime->id = id; | ||
536 | runtime->dsp = dsp; | ||
537 | runtime->module = module; | ||
538 | INIT_LIST_HEAD(&runtime->block_list); | ||
539 | |||
540 | mutex_lock(&dsp->mutex); | ||
541 | list_add(&runtime->list, &module->runtime_list); | ||
542 | mutex_unlock(&dsp->mutex); | ||
543 | |||
544 | return runtime; | ||
545 | } | ||
546 | EXPORT_SYMBOL_GPL(sst_module_runtime_new); | ||
547 | |||
548 | void sst_module_runtime_free(struct sst_module_runtime *runtime) | ||
549 | { | ||
550 | struct sst_dsp *dsp = runtime->dsp; | ||
551 | |||
552 | mutex_lock(&dsp->mutex); | ||
553 | list_del(&runtime->list); | ||
554 | mutex_unlock(&dsp->mutex); | ||
555 | |||
556 | kfree(runtime); | ||
557 | } | ||
558 | EXPORT_SYMBOL_GPL(sst_module_runtime_free); | ||
559 | |||
560 | static struct sst_mem_block *find_block(struct sst_dsp *dsp, | ||
561 | struct sst_block_allocator *ba) | ||
207 | { | 562 | { |
208 | struct sst_mem_block *block; | 563 | struct sst_mem_block *block; |
209 | 564 | ||
210 | list_for_each_entry(block, &dsp->free_block_list, list) { | 565 | list_for_each_entry(block, &dsp->free_block_list, list) { |
211 | if (block->type == type && block->offset == offset) | 566 | if (block->type == ba->type && block->offset == ba->offset) |
212 | return block; | 567 | return block; |
213 | } | 568 | } |
214 | 569 | ||
215 | return NULL; | 570 | return NULL; |
216 | } | 571 | } |
217 | 572 | ||
218 | static int block_alloc_contiguous(struct sst_module *module, | 573 | /* Block allocator must be on block boundary */ |
219 | struct sst_module_data *data, u32 offset, int size) | 574 | static int block_alloc_contiguous(struct sst_dsp *dsp, |
575 | struct sst_block_allocator *ba, struct list_head *block_list) | ||
220 | { | 576 | { |
221 | struct list_head tmp = LIST_HEAD_INIT(tmp); | 577 | struct list_head tmp = LIST_HEAD_INIT(tmp); |
222 | struct sst_dsp *dsp = module->dsp; | ||
223 | struct sst_mem_block *block; | 578 | struct sst_mem_block *block; |
579 | u32 block_start = SST_HSW_BLOCK_ANY; | ||
580 | int size = ba->size, offset = ba->offset; | ||
581 | |||
582 | while (ba->size > 0) { | ||
224 | 583 | ||
225 | while (size > 0) { | 584 | block = find_block(dsp, ba); |
226 | block = find_block(dsp, data->type, offset); | ||
227 | if (!block) { | 585 | if (!block) { |
228 | list_splice(&tmp, &dsp->free_block_list); | 586 | list_splice(&tmp, &dsp->free_block_list); |
587 | |||
588 | ba->size = size; | ||
589 | ba->offset = offset; | ||
229 | return -ENOMEM; | 590 | return -ENOMEM; |
230 | } | 591 | } |
231 | 592 | ||
232 | list_move_tail(&block->list, &tmp); | 593 | list_move_tail(&block->list, &tmp); |
233 | offset += block->size; | 594 | ba->offset += block->size; |
234 | size -= block->size; | 595 | ba->size -= block->size; |
235 | } | 596 | } |
597 | ba->size = size; | ||
598 | ba->offset = offset; | ||
599 | |||
600 | list_for_each_entry(block, &tmp, list) { | ||
601 | |||
602 | if (block->offset < block_start) | ||
603 | block_start = block->offset; | ||
236 | 604 | ||
237 | list_for_each_entry(block, &tmp, list) | 605 | list_add(&block->module_list, block_list); |
238 | list_add(&block->module_list, &module->block_list); | 606 | |
607 | dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n", | ||
608 | block->type, block->index, block->offset); | ||
609 | } | ||
239 | 610 | ||
240 | list_splice(&tmp, &dsp->used_block_list); | 611 | list_splice(&tmp, &dsp->used_block_list); |
241 | return 0; | 612 | return 0; |
242 | } | 613 | } |
243 | 614 | ||
244 | /* allocate free DSP blocks for module data - callers hold locks */ | 615 | /* allocate first free DSP blocks for data - callers hold locks */ |
245 | static int block_alloc(struct sst_module *module, | 616 | static int block_alloc(struct sst_dsp *dsp, struct sst_block_allocator *ba, |
246 | struct sst_module_data *data) | 617 | struct list_head *block_list) |
247 | { | 618 | { |
248 | struct sst_dsp *dsp = module->dsp; | ||
249 | struct sst_mem_block *block, *tmp; | 619 | struct sst_mem_block *block, *tmp; |
250 | int ret = 0; | 620 | int ret = 0; |
251 | 621 | ||
252 | if (data->size == 0) | 622 | if (ba->size == 0) |
253 | return 0; | 623 | return 0; |
254 | 624 | ||
255 | /* find first free whole blocks that can hold module */ | 625 | /* find first free whole blocks that can hold module */ |
256 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | 626 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { |
257 | 627 | ||
258 | /* ignore blocks with wrong type */ | 628 | /* ignore blocks with wrong type */ |
259 | if (block->type != data->type) | 629 | if (block->type != ba->type) |
260 | continue; | 630 | continue; |
261 | 631 | ||
262 | if (data->size > block->size) | 632 | if (ba->size > block->size) |
263 | continue; | 633 | continue; |
264 | 634 | ||
265 | data->offset = block->offset; | 635 | ba->offset = block->offset; |
266 | block->data_type = data->data_type; | 636 | block->bytes_used = ba->size % block->size; |
267 | block->bytes_used = data->size % block->size; | 637 | list_add(&block->module_list, block_list); |
268 | list_add(&block->module_list, &module->block_list); | ||
269 | list_move(&block->list, &dsp->used_block_list); | 638 | list_move(&block->list, &dsp->used_block_list); |
270 | dev_dbg(dsp->dev, " *module %d added block %d:%d\n", | 639 | dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n", |
271 | module->id, block->type, block->index); | 640 | block->type, block->index, block->offset); |
272 | return 0; | 641 | return 0; |
273 | } | 642 | } |
274 | 643 | ||
@@ -276,15 +645,19 @@ static int block_alloc(struct sst_module *module, | |||
276 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | 645 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { |
277 | 646 | ||
278 | /* ignore blocks with wrong type */ | 647 | /* ignore blocks with wrong type */ |
279 | if (block->type != data->type) | 648 | if (block->type != ba->type) |
280 | continue; | 649 | continue; |
281 | 650 | ||
282 | /* do we span > 1 blocks */ | 651 | /* do we span > 1 blocks */ |
283 | if (data->size > block->size) { | 652 | if (ba->size > block->size) { |
284 | ret = block_alloc_contiguous(module, data, | 653 | |
285 | block->offset, data->size); | 654 | /* align ba to block boundary */ |
655 | ba->offset = block->offset; | ||
656 | |||
657 | ret = block_alloc_contiguous(dsp, ba, block_list); | ||
286 | if (ret == 0) | 658 | if (ret == 0) |
287 | return ret; | 659 | return ret; |
660 | |||
288 | } | 661 | } |
289 | } | 662 | } |
290 | 663 | ||
@@ -292,93 +665,74 @@ static int block_alloc(struct sst_module *module, | |||
292 | return -ENOMEM; | 665 | return -ENOMEM; |
293 | } | 666 | } |
294 | 667 | ||
295 | /* remove module from memory - callers hold locks */ | 668 | int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba, |
296 | static void block_module_remove(struct sst_module *module) | 669 | struct list_head *block_list) |
297 | { | 670 | { |
298 | struct sst_mem_block *block, *tmp; | 671 | int ret; |
299 | struct sst_dsp *dsp = module->dsp; | ||
300 | int err; | ||
301 | 672 | ||
302 | /* disable each block */ | 673 | dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n", |
303 | list_for_each_entry(block, &module->block_list, module_list) { | 674 | ba->size, ba->offset, ba->type); |
304 | 675 | ||
305 | if (block->ops && block->ops->disable) { | 676 | mutex_lock(&dsp->mutex); |
306 | err = block->ops->disable(block); | ||
307 | if (err < 0) | ||
308 | dev_err(dsp->dev, | ||
309 | "error: cant disable block %d:%d\n", | ||
310 | block->type, block->index); | ||
311 | } | ||
312 | } | ||
313 | 677 | ||
314 | /* mark each block as free */ | 678 | ret = block_alloc(dsp, ba, block_list); |
315 | list_for_each_entry_safe(block, tmp, &module->block_list, module_list) { | 679 | if (ret < 0) { |
316 | list_del(&block->module_list); | 680 | dev_err(dsp->dev, "error: can't alloc blocks %d\n", ret); |
317 | list_move(&block->list, &dsp->free_block_list); | 681 | goto out; |
318 | } | 682 | } |
319 | } | ||
320 | |||
321 | /* prepare the memory block to receive data from host - callers hold locks */ | ||
322 | static int block_module_prepare(struct sst_module *module) | ||
323 | { | ||
324 | struct sst_mem_block *block; | ||
325 | int ret = 0; | ||
326 | 683 | ||
327 | /* enable each block so that's it'e ready for module P/S data */ | 684 | /* prepare DSP blocks for module usage */ |
328 | list_for_each_entry(block, &module->block_list, module_list) { | 685 | ret = block_list_prepare(dsp, block_list); |
686 | if (ret < 0) | ||
687 | dev_err(dsp->dev, "error: prepare failed\n"); | ||
329 | 688 | ||
330 | if (block->ops && block->ops->enable) { | 689 | out: |
331 | ret = block->ops->enable(block); | 690 | mutex_unlock(&dsp->mutex); |
332 | if (ret < 0) { | ||
333 | dev_err(module->dsp->dev, | ||
334 | "error: cant disable block %d:%d\n", | ||
335 | block->type, block->index); | ||
336 | goto err; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | return ret; | 691 | return ret; |
692 | } | ||
693 | EXPORT_SYMBOL_GPL(sst_alloc_blocks); | ||
341 | 694 | ||
342 | err: | 695 | int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list) |
343 | list_for_each_entry(block, &module->block_list, module_list) { | 696 | { |
344 | if (block->ops && block->ops->disable) | 697 | mutex_lock(&dsp->mutex); |
345 | block->ops->disable(block); | 698 | block_list_remove(dsp, block_list); |
346 | } | 699 | mutex_unlock(&dsp->mutex); |
347 | return ret; | 700 | return 0; |
348 | } | 701 | } |
702 | EXPORT_SYMBOL_GPL(sst_free_blocks); | ||
349 | 703 | ||
350 | /* allocate memory blocks for static module addresses - callers hold locks */ | 704 | /* allocate memory blocks for static module addresses - callers hold locks */ |
351 | static int block_alloc_fixed(struct sst_module *module, | 705 | static int block_alloc_fixed(struct sst_dsp *dsp, struct sst_block_allocator *ba, |
352 | struct sst_module_data *data) | 706 | struct list_head *block_list) |
353 | { | 707 | { |
354 | struct sst_dsp *dsp = module->dsp; | ||
355 | struct sst_mem_block *block, *tmp; | 708 | struct sst_mem_block *block, *tmp; |
356 | u32 end = data->offset + data->size, block_end; | 709 | u32 end = ba->offset + ba->size, block_end; |
357 | int err; | 710 | int err; |
358 | 711 | ||
359 | /* only IRAM/DRAM blocks are managed */ | 712 | /* only IRAM/DRAM blocks are managed */ |
360 | if (data->type != SST_MEM_IRAM && data->type != SST_MEM_DRAM) | 713 | if (ba->type != SST_MEM_IRAM && ba->type != SST_MEM_DRAM) |
361 | return 0; | 714 | return 0; |
362 | 715 | ||
363 | /* are blocks already attached to this module */ | 716 | /* are blocks already attached to this module */ |
364 | list_for_each_entry_safe(block, tmp, &module->block_list, module_list) { | 717 | list_for_each_entry_safe(block, tmp, block_list, module_list) { |
365 | 718 | ||
366 | /* force compacting mem blocks of the same data_type */ | 719 | /* ignore blocks with wrong type */ |
367 | if (block->data_type != data->data_type) | 720 | if (block->type != ba->type) |
368 | continue; | 721 | continue; |
369 | 722 | ||
370 | block_end = block->offset + block->size; | 723 | block_end = block->offset + block->size; |
371 | 724 | ||
372 | /* find block that holds section */ | 725 | /* find block that holds section */ |
373 | if (data->offset >= block->offset && end < block_end) | 726 | if (ba->offset >= block->offset && end <= block_end) |
374 | return 0; | 727 | return 0; |
375 | 728 | ||
376 | /* does block span more than 1 section */ | 729 | /* does block span more than 1 section */ |
377 | if (data->offset >= block->offset && data->offset < block_end) { | 730 | if (ba->offset >= block->offset && ba->offset < block_end) { |
378 | 731 | ||
379 | err = block_alloc_contiguous(module, data, | 732 | /* align ba to block boundary */ |
380 | block->offset + block->size, | 733 | ba->size -= block_end - ba->offset; |
381 | data->size - block->size); | 734 | ba->offset = block_end; |
735 | err = block_alloc_contiguous(dsp, ba, block_list); | ||
382 | if (err < 0) | 736 | if (err < 0) |
383 | return -ENOMEM; | 737 | return -ENOMEM; |
384 | 738 | ||
@@ -391,82 +745,270 @@ static int block_alloc_fixed(struct sst_module *module, | |||
391 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | 745 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { |
392 | block_end = block->offset + block->size; | 746 | block_end = block->offset + block->size; |
393 | 747 | ||
748 | /* ignore blocks with wrong type */ | ||
749 | if (block->type != ba->type) | ||
750 | continue; | ||
751 | |||
394 | /* find block that holds section */ | 752 | /* find block that holds section */ |
395 | if (data->offset >= block->offset && end < block_end) { | 753 | if (ba->offset >= block->offset && end <= block_end) { |
396 | 754 | ||
397 | /* add block */ | 755 | /* add block */ |
398 | block->data_type = data->data_type; | ||
399 | list_move(&block->list, &dsp->used_block_list); | 756 | list_move(&block->list, &dsp->used_block_list); |
400 | list_add(&block->module_list, &module->block_list); | 757 | list_add(&block->module_list, block_list); |
758 | dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n", | ||
759 | block->type, block->index, block->offset); | ||
401 | return 0; | 760 | return 0; |
402 | } | 761 | } |
403 | 762 | ||
404 | /* does block span more than 1 section */ | 763 | /* does block span more than 1 section */ |
405 | if (data->offset >= block->offset && data->offset < block_end) { | 764 | if (ba->offset >= block->offset && ba->offset < block_end) { |
406 | 765 | ||
407 | err = block_alloc_contiguous(module, data, | 766 | /* align ba to block boundary */ |
408 | block->offset, data->size); | 767 | ba->offset = block->offset; |
768 | |||
769 | err = block_alloc_contiguous(dsp, ba, block_list); | ||
409 | if (err < 0) | 770 | if (err < 0) |
410 | return -ENOMEM; | 771 | return -ENOMEM; |
411 | 772 | ||
412 | return 0; | 773 | return 0; |
413 | } | 774 | } |
414 | |||
415 | } | 775 | } |
416 | 776 | ||
417 | return -ENOMEM; | 777 | return -ENOMEM; |
418 | } | 778 | } |
419 | 779 | ||
420 | /* Load fixed module data into DSP memory blocks */ | 780 | /* Load fixed module data into DSP memory blocks */ |
421 | int sst_module_insert_fixed_block(struct sst_module *module, | 781 | int sst_module_alloc_blocks(struct sst_module *module) |
422 | struct sst_module_data *data) | ||
423 | { | 782 | { |
424 | struct sst_dsp *dsp = module->dsp; | 783 | struct sst_dsp *dsp = module->dsp; |
784 | struct sst_fw *sst_fw = module->sst_fw; | ||
785 | struct sst_block_allocator ba; | ||
425 | int ret; | 786 | int ret; |
426 | 787 | ||
788 | ba.size = module->size; | ||
789 | ba.type = module->type; | ||
790 | ba.offset = module->offset; | ||
791 | |||
792 | dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n", | ||
793 | ba.size, ba.offset, ba.type); | ||
794 | |||
427 | mutex_lock(&dsp->mutex); | 795 | mutex_lock(&dsp->mutex); |
428 | 796 | ||
429 | /* alloc blocks that includes this section */ | 797 | /* alloc blocks that includes this section */ |
430 | ret = block_alloc_fixed(module, data); | 798 | ret = block_alloc_fixed(dsp, &ba, &module->block_list); |
431 | if (ret < 0) { | 799 | if (ret < 0) { |
432 | dev_err(dsp->dev, | 800 | dev_err(dsp->dev, |
433 | "error: no free blocks for section at offset 0x%x size 0x%x\n", | 801 | "error: no free blocks for section at offset 0x%x size 0x%x\n", |
434 | data->offset, data->size); | 802 | module->offset, module->size); |
435 | mutex_unlock(&dsp->mutex); | 803 | mutex_unlock(&dsp->mutex); |
436 | return -ENOMEM; | 804 | return -ENOMEM; |
437 | } | 805 | } |
438 | 806 | ||
439 | /* prepare DSP blocks for module copy */ | 807 | /* prepare DSP blocks for module copy */ |
440 | ret = block_module_prepare(module); | 808 | ret = block_list_prepare(dsp, &module->block_list); |
441 | if (ret < 0) { | 809 | if (ret < 0) { |
442 | dev_err(dsp->dev, "error: fw module prepare failed\n"); | 810 | dev_err(dsp->dev, "error: fw module prepare failed\n"); |
443 | goto err; | 811 | goto err; |
444 | } | 812 | } |
445 | 813 | ||
446 | /* copy partial module data to blocks */ | 814 | /* copy partial module data to blocks */ |
447 | sst_memcpy32(dsp->addr.lpe + data->offset, data->data, data->size); | 815 | if (dsp->fw_use_dma) { |
816 | ret = sst_dsp_dma_copyto(dsp, | ||
817 | dsp->addr.lpe_base + module->offset, | ||
818 | sst_fw->dmable_fw_paddr + module->data_offset, | ||
819 | module->size); | ||
820 | if (ret < 0) { | ||
821 | dev_err(dsp->dev, "error: module copy failed\n"); | ||
822 | goto err; | ||
823 | } | ||
824 | } else | ||
825 | sst_memcpy32(dsp->addr.lpe + module->offset, module->data, | ||
826 | module->size); | ||
448 | 827 | ||
449 | mutex_unlock(&dsp->mutex); | 828 | mutex_unlock(&dsp->mutex); |
450 | return ret; | 829 | return ret; |
451 | 830 | ||
452 | err: | 831 | err: |
453 | block_module_remove(module); | 832 | block_list_remove(dsp, &module->block_list); |
454 | mutex_unlock(&dsp->mutex); | 833 | mutex_unlock(&dsp->mutex); |
455 | return ret; | 834 | return ret; |
456 | } | 835 | } |
457 | EXPORT_SYMBOL_GPL(sst_module_insert_fixed_block); | 836 | EXPORT_SYMBOL_GPL(sst_module_alloc_blocks); |
458 | 837 | ||
459 | /* Unload entire module from DSP memory */ | 838 | /* Unload entire module from DSP memory */ |
460 | int sst_block_module_remove(struct sst_module *module) | 839 | int sst_module_free_blocks(struct sst_module *module) |
461 | { | 840 | { |
462 | struct sst_dsp *dsp = module->dsp; | 841 | struct sst_dsp *dsp = module->dsp; |
463 | 842 | ||
464 | mutex_lock(&dsp->mutex); | 843 | mutex_lock(&dsp->mutex); |
465 | block_module_remove(module); | 844 | block_list_remove(dsp, &module->block_list); |
466 | mutex_unlock(&dsp->mutex); | 845 | mutex_unlock(&dsp->mutex); |
467 | return 0; | 846 | return 0; |
468 | } | 847 | } |
469 | EXPORT_SYMBOL_GPL(sst_block_module_remove); | 848 | EXPORT_SYMBOL_GPL(sst_module_free_blocks); |
849 | |||
850 | int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime, | ||
851 | int offset) | ||
852 | { | ||
853 | struct sst_dsp *dsp = runtime->dsp; | ||
854 | struct sst_module *module = runtime->module; | ||
855 | struct sst_block_allocator ba; | ||
856 | int ret; | ||
857 | |||
858 | if (module->persistent_size == 0) | ||
859 | return 0; | ||
860 | |||
861 | ba.size = module->persistent_size; | ||
862 | ba.type = SST_MEM_DRAM; | ||
863 | |||
864 | mutex_lock(&dsp->mutex); | ||
865 | |||
866 | /* do we need to allocate at a fixed address ? */ | ||
867 | if (offset != 0) { | ||
868 | |||
869 | ba.offset = offset; | ||
870 | |||
871 | dev_dbg(dsp->dev, "persistent fixed block request 0x%x bytes type %d offset 0x%x\n", | ||
872 | ba.size, ba.type, ba.offset); | ||
873 | |||
874 | /* alloc blocks that includes this section */ | ||
875 | ret = block_alloc_fixed(dsp, &ba, &runtime->block_list); | ||
876 | |||
877 | } else { | ||
878 | dev_dbg(dsp->dev, "persistent block request 0x%x bytes type %d\n", | ||
879 | ba.size, ba.type); | ||
880 | |||
881 | /* alloc blocks that includes this section */ | ||
882 | ret = block_alloc(dsp, &ba, &runtime->block_list); | ||
883 | } | ||
884 | if (ret < 0) { | ||
885 | dev_err(dsp->dev, | ||
886 | "error: no free blocks for runtime module size 0x%x\n", | ||
887 | module->persistent_size); | ||
888 | mutex_unlock(&dsp->mutex); | ||
889 | return -ENOMEM; | ||
890 | } | ||
891 | runtime->persistent_offset = ba.offset; | ||
892 | |||
893 | /* prepare DSP blocks for module copy */ | ||
894 | ret = block_list_prepare(dsp, &runtime->block_list); | ||
895 | if (ret < 0) { | ||
896 | dev_err(dsp->dev, "error: runtime block prepare failed\n"); | ||
897 | goto err; | ||
898 | } | ||
899 | |||
900 | mutex_unlock(&dsp->mutex); | ||
901 | return ret; | ||
902 | |||
903 | err: | ||
904 | block_list_remove(dsp, &module->block_list); | ||
905 | mutex_unlock(&dsp->mutex); | ||
906 | return ret; | ||
907 | } | ||
908 | EXPORT_SYMBOL_GPL(sst_module_runtime_alloc_blocks); | ||
909 | |||
910 | int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime) | ||
911 | { | ||
912 | struct sst_dsp *dsp = runtime->dsp; | ||
913 | |||
914 | mutex_lock(&dsp->mutex); | ||
915 | block_list_remove(dsp, &runtime->block_list); | ||
916 | mutex_unlock(&dsp->mutex); | ||
917 | return 0; | ||
918 | } | ||
919 | EXPORT_SYMBOL_GPL(sst_module_runtime_free_blocks); | ||
920 | |||
921 | int sst_module_runtime_save(struct sst_module_runtime *runtime, | ||
922 | struct sst_module_runtime_context *context) | ||
923 | { | ||
924 | struct sst_dsp *dsp = runtime->dsp; | ||
925 | struct sst_module *module = runtime->module; | ||
926 | int ret = 0; | ||
927 | |||
928 | dev_dbg(dsp->dev, "saving runtime %d memory at 0x%x size 0x%x\n", | ||
929 | runtime->id, runtime->persistent_offset, | ||
930 | module->persistent_size); | ||
931 | |||
932 | context->buffer = dma_alloc_coherent(dsp->dma_dev, | ||
933 | module->persistent_size, | ||
934 | &context->dma_buffer, GFP_DMA | GFP_KERNEL); | ||
935 | if (!context->buffer) { | ||
936 | dev_err(dsp->dev, "error: DMA context alloc failed\n"); | ||
937 | return -ENOMEM; | ||
938 | } | ||
939 | |||
940 | mutex_lock(&dsp->mutex); | ||
941 | |||
942 | if (dsp->fw_use_dma) { | ||
943 | |||
944 | ret = sst_dsp_dma_get_channel(dsp, 0); | ||
945 | if (ret < 0) | ||
946 | goto err; | ||
947 | |||
948 | ret = sst_dsp_dma_copyfrom(dsp, context->dma_buffer, | ||
949 | dsp->addr.lpe_base + runtime->persistent_offset, | ||
950 | module->persistent_size); | ||
951 | sst_dsp_dma_put_channel(dsp); | ||
952 | if (ret < 0) { | ||
953 | dev_err(dsp->dev, "error: context copy failed\n"); | ||
954 | goto err; | ||
955 | } | ||
956 | } else | ||
957 | sst_memcpy32(context->buffer, dsp->addr.lpe + | ||
958 | runtime->persistent_offset, | ||
959 | module->persistent_size); | ||
960 | |||
961 | err: | ||
962 | mutex_unlock(&dsp->mutex); | ||
963 | return ret; | ||
964 | } | ||
965 | EXPORT_SYMBOL_GPL(sst_module_runtime_save); | ||
966 | |||
967 | int sst_module_runtime_restore(struct sst_module_runtime *runtime, | ||
968 | struct sst_module_runtime_context *context) | ||
969 | { | ||
970 | struct sst_dsp *dsp = runtime->dsp; | ||
971 | struct sst_module *module = runtime->module; | ||
972 | int ret = 0; | ||
973 | |||
974 | dev_dbg(dsp->dev, "restoring runtime %d memory at 0x%x size 0x%x\n", | ||
975 | runtime->id, runtime->persistent_offset, | ||
976 | module->persistent_size); | ||
977 | |||
978 | mutex_lock(&dsp->mutex); | ||
979 | |||
980 | if (!context->buffer) { | ||
981 | dev_info(dsp->dev, "no context buffer need to restore!\n"); | ||
982 | goto err; | ||
983 | } | ||
984 | |||
985 | if (dsp->fw_use_dma) { | ||
986 | |||
987 | ret = sst_dsp_dma_get_channel(dsp, 0); | ||
988 | if (ret < 0) | ||
989 | goto err; | ||
990 | |||
991 | ret = sst_dsp_dma_copyto(dsp, | ||
992 | dsp->addr.lpe_base + runtime->persistent_offset, | ||
993 | context->dma_buffer, module->persistent_size); | ||
994 | sst_dsp_dma_put_channel(dsp); | ||
995 | if (ret < 0) { | ||
996 | dev_err(dsp->dev, "error: module copy failed\n"); | ||
997 | goto err; | ||
998 | } | ||
999 | } else | ||
1000 | sst_memcpy32(dsp->addr.lpe + runtime->persistent_offset, | ||
1001 | context->buffer, module->persistent_size); | ||
1002 | |||
1003 | dma_free_coherent(dsp->dma_dev, module->persistent_size, | ||
1004 | context->buffer, context->dma_buffer); | ||
1005 | context->buffer = NULL; | ||
1006 | |||
1007 | err: | ||
1008 | mutex_unlock(&dsp->mutex); | ||
1009 | return ret; | ||
1010 | } | ||
1011 | EXPORT_SYMBOL_GPL(sst_module_runtime_restore); | ||
470 | 1012 | ||
471 | /* register a DSP memory block for use with FW based modules */ | 1013 | /* register a DSP memory block for use with FW based modules */ |
472 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | 1014 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, |
@@ -519,80 +1061,84 @@ void sst_mem_block_unregister_all(struct sst_dsp *dsp) | |||
519 | EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all); | 1061 | EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all); |
520 | 1062 | ||
521 | /* allocate scratch buffer blocks */ | 1063 | /* allocate scratch buffer blocks */ |
522 | struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp) | 1064 | int sst_block_alloc_scratch(struct sst_dsp *dsp) |
523 | { | 1065 | { |
524 | struct sst_module *sst_module, *scratch; | 1066 | struct sst_module *module; |
525 | struct sst_mem_block *block, *tmp; | 1067 | struct sst_block_allocator ba; |
526 | u32 block_size; | 1068 | int ret; |
527 | int ret = 0; | ||
528 | |||
529 | scratch = kzalloc(sizeof(struct sst_module), GFP_KERNEL); | ||
530 | if (scratch == NULL) | ||
531 | return NULL; | ||
532 | 1069 | ||
533 | mutex_lock(&dsp->mutex); | 1070 | mutex_lock(&dsp->mutex); |
534 | 1071 | ||
535 | /* calculate required scratch size */ | 1072 | /* calculate required scratch size */ |
536 | list_for_each_entry(sst_module, &dsp->module_list, list) { | 1073 | dsp->scratch_size = 0; |
537 | if (scratch->s.size < sst_module->s.size) | 1074 | list_for_each_entry(module, &dsp->module_list, list) { |
538 | scratch->s.size = sst_module->s.size; | 1075 | dev_dbg(dsp->dev, "module %d scratch req 0x%x bytes\n", |
1076 | module->id, module->scratch_size); | ||
1077 | if (dsp->scratch_size < module->scratch_size) | ||
1078 | dsp->scratch_size = module->scratch_size; | ||
539 | } | 1079 | } |
540 | 1080 | ||
541 | dev_dbg(dsp->dev, "scratch buffer required is %d bytes\n", | 1081 | dev_dbg(dsp->dev, "scratch buffer required is 0x%x bytes\n", |
542 | scratch->s.size); | 1082 | dsp->scratch_size); |
543 | |||
544 | /* init scratch module */ | ||
545 | scratch->dsp = dsp; | ||
546 | scratch->s.type = SST_MEM_DRAM; | ||
547 | scratch->s.data_type = SST_DATA_S; | ||
548 | INIT_LIST_HEAD(&scratch->block_list); | ||
549 | 1083 | ||
550 | /* check free blocks before looking at used blocks for space */ | 1084 | if (dsp->scratch_size == 0) { |
551 | if (!list_empty(&dsp->free_block_list)) | 1085 | dev_info(dsp->dev, "no modules need scratch buffer\n"); |
552 | block = list_first_entry(&dsp->free_block_list, | 1086 | mutex_unlock(&dsp->mutex); |
553 | struct sst_mem_block, list); | 1087 | return 0; |
554 | else | 1088 | } |
555 | block = list_first_entry(&dsp->used_block_list, | ||
556 | struct sst_mem_block, list); | ||
557 | block_size = block->size; | ||
558 | 1089 | ||
559 | /* allocate blocks for module scratch buffers */ | 1090 | /* allocate blocks for module scratch buffers */ |
560 | dev_dbg(dsp->dev, "allocating scratch blocks\n"); | 1091 | dev_dbg(dsp->dev, "allocating scratch blocks\n"); |
561 | ret = block_alloc(scratch, &scratch->s); | 1092 | |
1093 | ba.size = dsp->scratch_size; | ||
1094 | ba.type = SST_MEM_DRAM; | ||
1095 | |||
1096 | /* do we need to allocate at fixed offset */ | ||
1097 | if (dsp->scratch_offset != 0) { | ||
1098 | |||
1099 | dev_dbg(dsp->dev, "block request 0x%x bytes type %d at 0x%x\n", | ||
1100 | ba.size, ba.type, ba.offset); | ||
1101 | |||
1102 | ba.offset = dsp->scratch_offset; | ||
1103 | |||
1104 | /* alloc blocks that includes this section */ | ||
1105 | ret = block_alloc_fixed(dsp, &ba, &dsp->scratch_block_list); | ||
1106 | |||
1107 | } else { | ||
1108 | dev_dbg(dsp->dev, "block request 0x%x bytes type %d\n", | ||
1109 | ba.size, ba.type); | ||
1110 | |||
1111 | ba.offset = 0; | ||
1112 | ret = block_alloc(dsp, &ba, &dsp->scratch_block_list); | ||
1113 | } | ||
562 | if (ret < 0) { | 1114 | if (ret < 0) { |
563 | dev_err(dsp->dev, "error: can't alloc scratch blocks\n"); | 1115 | dev_err(dsp->dev, "error: can't alloc scratch blocks\n"); |
564 | goto err; | 1116 | mutex_unlock(&dsp->mutex); |
1117 | return ret; | ||
565 | } | 1118 | } |
566 | 1119 | ||
567 | /* assign the same offset of scratch to each module */ | 1120 | ret = block_list_prepare(dsp, &dsp->scratch_block_list); |
568 | list_for_each_entry(sst_module, &dsp->module_list, list) | 1121 | if (ret < 0) { |
569 | sst_module->s.offset = scratch->s.offset; | 1122 | dev_err(dsp->dev, "error: scratch block prepare failed\n"); |
570 | 1123 | mutex_unlock(&dsp->mutex); | |
571 | mutex_unlock(&dsp->mutex); | 1124 | return ret; |
572 | return scratch; | 1125 | } |
573 | 1126 | ||
574 | err: | 1127 | /* assign the same offset of scratch to each module */ |
575 | list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list) | 1128 | dsp->scratch_offset = ba.offset; |
576 | list_del(&block->module_list); | ||
577 | mutex_unlock(&dsp->mutex); | 1129 | mutex_unlock(&dsp->mutex); |
578 | return NULL; | 1130 | return dsp->scratch_size; |
579 | } | 1131 | } |
580 | EXPORT_SYMBOL_GPL(sst_mem_block_alloc_scratch); | 1132 | EXPORT_SYMBOL_GPL(sst_block_alloc_scratch); |
581 | 1133 | ||
582 | /* free all scratch blocks */ | 1134 | /* free all scratch blocks */ |
583 | void sst_mem_block_free_scratch(struct sst_dsp *dsp, | 1135 | void sst_block_free_scratch(struct sst_dsp *dsp) |
584 | struct sst_module *scratch) | ||
585 | { | 1136 | { |
586 | struct sst_mem_block *block, *tmp; | ||
587 | |||
588 | mutex_lock(&dsp->mutex); | 1137 | mutex_lock(&dsp->mutex); |
589 | 1138 | block_list_remove(dsp, &dsp->scratch_block_list); | |
590 | list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list) | ||
591 | list_del(&block->module_list); | ||
592 | |||
593 | mutex_unlock(&dsp->mutex); | 1139 | mutex_unlock(&dsp->mutex); |
594 | } | 1140 | } |
595 | EXPORT_SYMBOL_GPL(sst_mem_block_free_scratch); | 1141 | EXPORT_SYMBOL_GPL(sst_block_free_scratch); |
596 | 1142 | ||
597 | /* get a module from it's unique ID */ | 1143 | /* get a module from it's unique ID */ |
598 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id) | 1144 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id) |
@@ -612,3 +1158,40 @@ struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id) | |||
612 | return NULL; | 1158 | return NULL; |
613 | } | 1159 | } |
614 | EXPORT_SYMBOL_GPL(sst_module_get_from_id); | 1160 | EXPORT_SYMBOL_GPL(sst_module_get_from_id); |
1161 | |||
1162 | struct sst_module_runtime *sst_module_runtime_get_from_id( | ||
1163 | struct sst_module *module, u32 id) | ||
1164 | { | ||
1165 | struct sst_module_runtime *runtime; | ||
1166 | struct sst_dsp *dsp = module->dsp; | ||
1167 | |||
1168 | mutex_lock(&dsp->mutex); | ||
1169 | |||
1170 | list_for_each_entry(runtime, &module->runtime_list, list) { | ||
1171 | if (runtime->id == id) { | ||
1172 | mutex_unlock(&dsp->mutex); | ||
1173 | return runtime; | ||
1174 | } | ||
1175 | } | ||
1176 | |||
1177 | mutex_unlock(&dsp->mutex); | ||
1178 | return NULL; | ||
1179 | } | ||
1180 | EXPORT_SYMBOL_GPL(sst_module_runtime_get_from_id); | ||
1181 | |||
1182 | /* returns block address in DSP address space */ | ||
1183 | u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset, | ||
1184 | enum sst_mem_type type) | ||
1185 | { | ||
1186 | switch (type) { | ||
1187 | case SST_MEM_IRAM: | ||
1188 | return offset - dsp->addr.iram_offset + | ||
1189 | dsp->addr.dsp_iram_offset; | ||
1190 | case SST_MEM_DRAM: | ||
1191 | return offset - dsp->addr.dram_offset + | ||
1192 | dsp->addr.dsp_dram_offset; | ||
1193 | default: | ||
1194 | return 0; | ||
1195 | } | ||
1196 | } | ||
1197 | EXPORT_SYMBOL_GPL(sst_dsp_get_offset); | ||
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 4b6c163c10ff..57039b00efc2 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c | |||
@@ -42,6 +42,10 @@ | |||
42 | #define SST_LP_SHIM_OFFSET 0xE7000 | 42 | #define SST_LP_SHIM_OFFSET 0xE7000 |
43 | #define SST_WPT_IRAM_OFFSET 0xA0000 | 43 | #define SST_WPT_IRAM_OFFSET 0xA0000 |
44 | #define SST_LP_IRAM_OFFSET 0x80000 | 44 | #define SST_LP_IRAM_OFFSET 0x80000 |
45 | #define SST_WPT_DSP_DRAM_OFFSET 0x400000 | ||
46 | #define SST_WPT_DSP_IRAM_OFFSET 0x00000 | ||
47 | #define SST_LPT_DSP_DRAM_OFFSET 0x400000 | ||
48 | #define SST_LPT_DSP_IRAM_OFFSET 0x00000 | ||
45 | 49 | ||
46 | #define SST_SHIM_PM_REG 0x84 | 50 | #define SST_SHIM_PM_REG 0x84 |
47 | 51 | ||
@@ -86,9 +90,8 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
86 | { | 90 | { |
87 | struct dma_block_info *block; | 91 | struct dma_block_info *block; |
88 | struct sst_module *mod; | 92 | struct sst_module *mod; |
89 | struct sst_module_data block_data; | ||
90 | struct sst_module_template template; | 93 | struct sst_module_template template; |
91 | int count; | 94 | int count, ret; |
92 | void __iomem *ram; | 95 | void __iomem *ram; |
93 | 96 | ||
94 | /* TODO: allowed module types need to be configurable */ | 97 | /* TODO: allowed module types need to be configurable */ |
@@ -109,13 +112,9 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
109 | 112 | ||
110 | memset(&template, 0, sizeof(template)); | 113 | memset(&template, 0, sizeof(template)); |
111 | template.id = module->type; | 114 | template.id = module->type; |
112 | template.entry = module->entry_point; | 115 | template.entry = module->entry_point - 4; |
113 | template.p.size = module->info.persistent_size; | 116 | template.persistent_size = module->info.persistent_size; |
114 | template.p.type = SST_MEM_DRAM; | 117 | template.scratch_size = module->info.scratch_size; |
115 | template.p.data_type = SST_DATA_P; | ||
116 | template.s.size = module->info.scratch_size; | ||
117 | template.s.type = SST_MEM_DRAM; | ||
118 | template.s.data_type = SST_DATA_S; | ||
119 | 118 | ||
120 | mod = sst_module_new(fw, &template, NULL); | 119 | mod = sst_module_new(fw, &template, NULL); |
121 | if (mod == NULL) | 120 | if (mod == NULL) |
@@ -135,14 +134,14 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
135 | switch (block->type) { | 134 | switch (block->type) { |
136 | case SST_HSW_IRAM: | 135 | case SST_HSW_IRAM: |
137 | ram = dsp->addr.lpe; | 136 | ram = dsp->addr.lpe; |
138 | block_data.offset = | 137 | mod->offset = |
139 | block->ram_offset + dsp->addr.iram_offset; | 138 | block->ram_offset + dsp->addr.iram_offset; |
140 | block_data.type = SST_MEM_IRAM; | 139 | mod->type = SST_MEM_IRAM; |
141 | break; | 140 | break; |
142 | case SST_HSW_DRAM: | 141 | case SST_HSW_DRAM: |
143 | ram = dsp->addr.lpe; | 142 | ram = dsp->addr.lpe; |
144 | block_data.offset = block->ram_offset; | 143 | mod->offset = block->ram_offset; |
145 | block_data.type = SST_MEM_DRAM; | 144 | mod->type = SST_MEM_DRAM; |
146 | break; | 145 | break; |
147 | default: | 146 | default: |
148 | dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n", | 147 | dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n", |
@@ -151,30 +150,34 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
151 | return -EINVAL; | 150 | return -EINVAL; |
152 | } | 151 | } |
153 | 152 | ||
154 | block_data.size = block->size; | 153 | mod->size = block->size; |
155 | block_data.data_type = SST_DATA_M; | 154 | mod->data = (void *)block + sizeof(*block); |
156 | block_data.data = (void *)block + sizeof(*block); | 155 | mod->data_offset = mod->data - fw->dma_buf; |
157 | block_data.data_offset = block_data.data - fw->dma_buf; | ||
158 | 156 | ||
159 | dev_dbg(dsp->dev, "copy firmware block %d type 0x%x " | 157 | dev_dbg(dsp->dev, "module block %d type 0x%x " |
160 | "size 0x%x ==> ram %p offset 0x%x\n", | 158 | "size 0x%x ==> ram %p offset 0x%x\n", |
161 | count, block->type, block->size, ram, | 159 | count, mod->type, block->size, ram, |
162 | block->ram_offset); | 160 | block->ram_offset); |
163 | 161 | ||
164 | sst_module_insert_fixed_block(mod, &block_data); | 162 | ret = sst_module_alloc_blocks(mod); |
163 | if (ret < 0) { | ||
164 | dev_err(dsp->dev, "error: could not allocate blocks for module %d\n", | ||
165 | count); | ||
166 | sst_module_free(mod); | ||
167 | return ret; | ||
168 | } | ||
165 | 169 | ||
166 | block = (void *)block + sizeof(*block) + block->size; | 170 | block = (void *)block + sizeof(*block) + block->size; |
167 | } | 171 | } |
172 | |||
168 | return 0; | 173 | return 0; |
169 | } | 174 | } |
170 | 175 | ||
171 | static int hsw_parse_fw_image(struct sst_fw *sst_fw) | 176 | static int hsw_parse_fw_image(struct sst_fw *sst_fw) |
172 | { | 177 | { |
173 | struct fw_header *header; | 178 | struct fw_header *header; |
174 | struct sst_module *scratch; | ||
175 | struct fw_module_header *module; | 179 | struct fw_module_header *module; |
176 | struct sst_dsp *dsp = sst_fw->dsp; | 180 | struct sst_dsp *dsp = sst_fw->dsp; |
177 | struct sst_hsw *hsw = sst_fw->private; | ||
178 | int ret, count; | 181 | int ret, count; |
179 | 182 | ||
180 | /* Read the header information from the data pointer */ | 183 | /* Read the header information from the data pointer */ |
@@ -204,12 +207,8 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw) | |||
204 | module = (void *)module + sizeof(*module) + module->mod_size; | 207 | module = (void *)module + sizeof(*module) + module->mod_size; |
205 | } | 208 | } |
206 | 209 | ||
207 | /* allocate persistent/scratch mem regions */ | 210 | /* allocate scratch mem regions */ |
208 | scratch = sst_mem_block_alloc_scratch(dsp); | 211 | sst_block_alloc_scratch(dsp); |
209 | if (scratch == NULL) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | sst_hsw_set_scratch_module(hsw, scratch); | ||
213 | 212 | ||
214 | return 0; | 213 | return 0; |
215 | } | 214 | } |
@@ -248,8 +247,94 @@ static irqreturn_t hsw_irq(int irq, void *context) | |||
248 | return ret; | 247 | return ret; |
249 | } | 248 | } |
250 | 249 | ||
251 | static void hsw_boot(struct sst_dsp *sst) | 250 | static void hsw_set_dsp_D3(struct sst_dsp *sst) |
251 | { | ||
252 | u32 val; | ||
253 | u32 reg; | ||
254 | |||
255 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ | ||
256 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
257 | reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE); | ||
258 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
259 | |||
260 | /* enable power gating and switch off DRAM & IRAM blocks */ | ||
261 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
262 | val |= SST_VDRTCL0_DSRAMPGE_MASK | | ||
263 | SST_VDRTCL0_ISRAMPGE_MASK; | ||
264 | val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD); | ||
265 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
266 | |||
267 | /* switch off audio PLL */ | ||
268 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
269 | val |= SST_VDRTCL2_APLLSE_MASK; | ||
270 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
271 | |||
272 | /* disable MCLK(clkctl.smos = 0) */ | ||
273 | sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL, | ||
274 | SST_CLKCTL_MASK, 0); | ||
275 | |||
276 | /* Set D3 state, delay 50 us */ | ||
277 | val = readl(sst->addr.pci_cfg + SST_PMCS); | ||
278 | val |= SST_PMCS_PS_MASK; | ||
279 | writel(val, sst->addr.pci_cfg + SST_PMCS); | ||
280 | udelay(50); | ||
281 | |||
282 | /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ | ||
283 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
284 | reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE; | ||
285 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
286 | |||
287 | udelay(50); | ||
288 | |||
289 | } | ||
290 | |||
291 | static void hsw_reset(struct sst_dsp *sst) | ||
252 | { | 292 | { |
293 | /* put DSP into reset and stall */ | ||
294 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
295 | SST_CSR_RST | SST_CSR_STALL, | ||
296 | SST_CSR_RST | SST_CSR_STALL); | ||
297 | |||
298 | /* keep in reset for 10ms */ | ||
299 | mdelay(10); | ||
300 | |||
301 | /* take DSP out of reset and keep stalled for FW loading */ | ||
302 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
303 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL); | ||
304 | } | ||
305 | |||
306 | static int hsw_set_dsp_D0(struct sst_dsp *sst) | ||
307 | { | ||
308 | int tries = 10; | ||
309 | u32 reg; | ||
310 | |||
311 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ | ||
312 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
313 | reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE); | ||
314 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
315 | |||
316 | /* Disable D3PG (VDRTCTL0.D3PGD = 1) */ | ||
317 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
318 | reg |= SST_VDRTCL0_D3PGD; | ||
319 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
320 | |||
321 | /* Set D0 state */ | ||
322 | reg = readl(sst->addr.pci_cfg + SST_PMCS); | ||
323 | reg &= ~SST_PMCS_PS_MASK; | ||
324 | writel(reg, sst->addr.pci_cfg + SST_PMCS); | ||
325 | |||
326 | /* check that ADSP shim is enabled */ | ||
327 | while (tries--) { | ||
328 | reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK; | ||
329 | if (reg == 0) | ||
330 | goto finish; | ||
331 | |||
332 | msleep(1); | ||
333 | } | ||
334 | |||
335 | return -ENODEV; | ||
336 | |||
337 | finish: | ||
253 | /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */ | 338 | /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */ |
254 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | 339 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, |
255 | SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0); | 340 | SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0); |
@@ -264,34 +349,96 @@ static void hsw_boot(struct sst_dsp *sst) | |||
264 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0, | 349 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0, |
265 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0); | 350 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0); |
266 | 351 | ||
352 | /* Stall and reset core, set CSR */ | ||
353 | hsw_reset(sst); | ||
354 | |||
355 | /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ | ||
356 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
357 | reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE; | ||
358 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
359 | |||
360 | udelay(50); | ||
361 | |||
362 | /* switch on audio PLL */ | ||
363 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
364 | reg &= ~SST_VDRTCL2_APLLSE_MASK; | ||
365 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
366 | |||
367 | /* set default power gating control, enable power gating control for all blocks. that is, | ||
368 | can't be accessed, please enable each block before accessing. */ | ||
369 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
370 | reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK; | ||
371 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
372 | |||
373 | |||
267 | /* disable DMA finish function for SSP0 & SSP1 */ | 374 | /* disable DMA finish function for SSP0 & SSP1 */ |
268 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1, | 375 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1, |
269 | SST_CSR2_SDFD_SSP1); | 376 | SST_CSR2_SDFD_SSP1); |
270 | 377 | ||
271 | /* enable DMA engine 0,1 all channels to access host memory */ | 378 | /* set on-demond mode on engine 0,1 for all channels */ |
272 | sst_dsp_shim_update_bits_unlocked(sst, SST_HMDC, | 379 | sst_dsp_shim_update_bits(sst, SST_HMDC, |
273 | SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff), | 380 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, |
274 | SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff)); | 381 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH); |
382 | |||
383 | /* Enable Interrupt from both sides */ | ||
384 | sst_dsp_shim_update_bits(sst, SST_IMRX, (SST_IMRX_BUSY | SST_IMRX_DONE), | ||
385 | 0x0); | ||
386 | sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY | | ||
387 | SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0); | ||
388 | |||
389 | /* clear IPC registers */ | ||
390 | sst_dsp_shim_write(sst, SST_IPCX, 0x0); | ||
391 | sst_dsp_shim_write(sst, SST_IPCD, 0x0); | ||
392 | sst_dsp_shim_write(sst, 0x80, 0x6); | ||
393 | sst_dsp_shim_write(sst, 0xe0, 0x300a); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
275 | 397 | ||
276 | /* disable all clock gating */ | 398 | static void hsw_boot(struct sst_dsp *sst) |
277 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2); | 399 | { |
400 | /* set oportunistic mode on engine 0,1 for all channels */ | ||
401 | sst_dsp_shim_update_bits(sst, SST_HMDC, | ||
402 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, 0); | ||
278 | 403 | ||
279 | /* set DSP to RUN */ | 404 | /* set DSP to RUN */ |
280 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0); | 405 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0); |
281 | } | 406 | } |
282 | 407 | ||
283 | static void hsw_reset(struct sst_dsp *sst) | 408 | static void hsw_stall(struct sst_dsp *sst) |
409 | { | ||
410 | /* stall DSP */ | ||
411 | sst_dsp_shim_update_bits(sst, SST_CSR, | ||
412 | SST_CSR_24MHZ_LPCS | SST_CSR_STALL, | ||
413 | SST_CSR_STALL | SST_CSR_24MHZ_LPCS); | ||
414 | } | ||
415 | |||
416 | static void hsw_sleep(struct sst_dsp *sst) | ||
284 | { | 417 | { |
418 | dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n"); | ||
419 | |||
285 | /* put DSP into reset and stall */ | 420 | /* put DSP into reset and stall */ |
286 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | 421 | sst_dsp_shim_update_bits(sst, SST_CSR, |
287 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL); | 422 | SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL, |
423 | SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS); | ||
288 | 424 | ||
289 | /* keep in reset for 10ms */ | 425 | hsw_set_dsp_D3(sst); |
290 | mdelay(10); | 426 | dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n"); |
427 | } | ||
291 | 428 | ||
292 | /* take DSP out of reset and keep stalled for FW loading */ | 429 | static int hsw_wake(struct sst_dsp *sst) |
293 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | 430 | { |
294 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL); | 431 | int ret; |
432 | |||
433 | dev_dbg(sst->dev, "HSW_PM dsp runtime resume\n"); | ||
434 | |||
435 | ret = hsw_set_dsp_D0(sst); | ||
436 | if (ret < 0) | ||
437 | return ret; | ||
438 | |||
439 | dev_dbg(sst->dev, "HSW_PM dsp runtime resume exit\n"); | ||
440 | |||
441 | return 0; | ||
295 | } | 442 | } |
296 | 443 | ||
297 | struct sst_adsp_memregion { | 444 | struct sst_adsp_memregion { |
@@ -396,6 +543,11 @@ static int hsw_block_enable(struct sst_mem_block *block) | |||
396 | dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n", | 543 | dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n", |
397 | block->type, block->index, block->offset); | 544 | block->type, block->index, block->offset); |
398 | 545 | ||
546 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ | ||
547 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
548 | val &= ~SST_VDRTCL2_DCLCGE; | ||
549 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
550 | |||
399 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | 551 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); |
400 | bit = hsw_block_get_bit(block); | 552 | bit = hsw_block_get_bit(block); |
401 | writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0); | 553 | writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0); |
@@ -403,6 +555,13 @@ static int hsw_block_enable(struct sst_mem_block *block) | |||
403 | /* wait 18 DSP clock ticks */ | 555 | /* wait 18 DSP clock ticks */ |
404 | udelay(10); | 556 | udelay(10); |
405 | 557 | ||
558 | /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ | ||
559 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
560 | val |= SST_VDRTCL2_DCLCGE; | ||
561 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
562 | |||
563 | udelay(50); | ||
564 | |||
406 | /*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/ | 565 | /*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/ |
407 | sst_mem_block_dummy_read(block); | 566 | sst_mem_block_dummy_read(block); |
408 | return 0; | 567 | return 0; |
@@ -420,10 +579,26 @@ static int hsw_block_disable(struct sst_mem_block *block) | |||
420 | dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n", | 579 | dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n", |
421 | block->type, block->index, block->offset); | 580 | block->type, block->index, block->offset); |
422 | 581 | ||
582 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ | ||
583 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
584 | val &= ~SST_VDRTCL2_DCLCGE; | ||
585 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
586 | |||
587 | |||
423 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | 588 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); |
424 | bit = hsw_block_get_bit(block); | 589 | bit = hsw_block_get_bit(block); |
425 | writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); | 590 | writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); |
426 | 591 | ||
592 | /* wait 18 DSP clock ticks */ | ||
593 | udelay(10); | ||
594 | |||
595 | /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ | ||
596 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
597 | val |= SST_VDRTCL2_DCLCGE; | ||
598 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
599 | |||
600 | udelay(50); | ||
601 | |||
427 | return 0; | 602 | return 0; |
428 | } | 603 | } |
429 | 604 | ||
@@ -432,27 +607,6 @@ static struct sst_block_ops sst_hsw_ops = { | |||
432 | .disable = hsw_block_disable, | 607 | .disable = hsw_block_disable, |
433 | }; | 608 | }; |
434 | 609 | ||
435 | static int hsw_enable_shim(struct sst_dsp *sst) | ||
436 | { | ||
437 | int tries = 10; | ||
438 | u32 reg; | ||
439 | |||
440 | /* enable shim */ | ||
441 | reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG); | ||
442 | writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG); | ||
443 | |||
444 | /* check that ADSP shim is enabled */ | ||
445 | while (tries--) { | ||
446 | reg = sst_dsp_shim_read_unlocked(sst, SST_CSR); | ||
447 | if (reg != 0xffffffff) | ||
448 | return 0; | ||
449 | |||
450 | msleep(1); | ||
451 | } | ||
452 | |||
453 | return -ENODEV; | ||
454 | } | ||
455 | |||
456 | static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | 610 | static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) |
457 | { | 611 | { |
458 | const struct sst_adsp_memregion *region; | 612 | const struct sst_adsp_memregion *region; |
@@ -467,12 +621,16 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
467 | region = lp_region; | 621 | region = lp_region; |
468 | region_count = ARRAY_SIZE(lp_region); | 622 | region_count = ARRAY_SIZE(lp_region); |
469 | sst->addr.iram_offset = SST_LP_IRAM_OFFSET; | 623 | sst->addr.iram_offset = SST_LP_IRAM_OFFSET; |
624 | sst->addr.dsp_iram_offset = SST_LPT_DSP_IRAM_OFFSET; | ||
625 | sst->addr.dsp_dram_offset = SST_LPT_DSP_DRAM_OFFSET; | ||
470 | sst->addr.shim_offset = SST_LP_SHIM_OFFSET; | 626 | sst->addr.shim_offset = SST_LP_SHIM_OFFSET; |
471 | break; | 627 | break; |
472 | case SST_DEV_ID_WILDCAT_POINT: | 628 | case SST_DEV_ID_WILDCAT_POINT: |
473 | region = wpt_region; | 629 | region = wpt_region; |
474 | region_count = ARRAY_SIZE(wpt_region); | 630 | region_count = ARRAY_SIZE(wpt_region); |
475 | sst->addr.iram_offset = SST_WPT_IRAM_OFFSET; | 631 | sst->addr.iram_offset = SST_WPT_IRAM_OFFSET; |
632 | sst->addr.dsp_iram_offset = SST_WPT_DSP_IRAM_OFFSET; | ||
633 | sst->addr.dsp_dram_offset = SST_WPT_DSP_DRAM_OFFSET; | ||
476 | sst->addr.shim_offset = SST_WPT_SHIM_OFFSET; | 634 | sst->addr.shim_offset = SST_WPT_SHIM_OFFSET; |
477 | break; | 635 | break; |
478 | default: | 636 | default: |
@@ -487,7 +645,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
487 | } | 645 | } |
488 | 646 | ||
489 | /* enable the DSP SHIM */ | 647 | /* enable the DSP SHIM */ |
490 | ret = hsw_enable_shim(sst); | 648 | ret = hsw_set_dsp_D0(sst); |
491 | if (ret < 0) { | 649 | if (ret < 0) { |
492 | dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n"); | 650 | dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n"); |
493 | return ret; | 651 | return ret; |
@@ -497,10 +655,6 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
497 | if (ret) | 655 | if (ret) |
498 | return ret; | 656 | return ret; |
499 | 657 | ||
500 | /* Enable Interrupt from both sides */ | ||
501 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0); | ||
502 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD, | ||
503 | (0x3 | 0x1 << 16 | 0x3 << 21), 0x0); | ||
504 | 658 | ||
505 | /* register DSP memory blocks - ideally we should get this from ACPI */ | 659 | /* register DSP memory blocks - ideally we should get this from ACPI */ |
506 | for (i = 0; i < region_count; i++) { | 660 | for (i = 0; i < region_count; i++) { |
@@ -532,6 +686,9 @@ static void hsw_free(struct sst_dsp *sst) | |||
532 | struct sst_ops haswell_ops = { | 686 | struct sst_ops haswell_ops = { |
533 | .reset = hsw_reset, | 687 | .reset = hsw_reset, |
534 | .boot = hsw_boot, | 688 | .boot = hsw_boot, |
689 | .stall = hsw_stall, | ||
690 | .wake = hsw_wake, | ||
691 | .sleep = hsw_sleep, | ||
535 | .write = sst_shim32_write, | 692 | .write = sst_shim32_write, |
536 | .read = sst_shim32_read, | 693 | .read = sst_shim32_read, |
537 | .write64 = sst_shim32_write64, | 694 | .write64 = sst_shim32_write64, |
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index b6291516dbbf..3f8c48231364 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/firmware.h> | 30 | #include <linux/firmware.h> |
31 | #include <linux/dma-mapping.h> | 31 | #include <linux/dma-mapping.h> |
32 | #include <linux/debugfs.h> | 32 | #include <linux/debugfs.h> |
33 | #include <linux/pm_runtime.h> | ||
33 | 34 | ||
34 | #include "sst-haswell-ipc.h" | 35 | #include "sst-haswell-ipc.h" |
35 | #include "sst-dsp.h" | 36 | #include "sst-dsp.h" |
@@ -276,6 +277,7 @@ struct sst_hsw { | |||
276 | struct sst_hsw_ipc_fw_version version; | 277 | struct sst_hsw_ipc_fw_version version; |
277 | struct sst_module *scratch; | 278 | struct sst_module *scratch; |
278 | bool fw_done; | 279 | bool fw_done; |
280 | struct sst_fw *sst_fw; | ||
279 | 281 | ||
280 | /* stream */ | 282 | /* stream */ |
281 | struct list_head stream_list; | 283 | struct list_head stream_list; |
@@ -289,6 +291,8 @@ struct sst_hsw { | |||
289 | 291 | ||
290 | /* DX */ | 292 | /* DX */ |
291 | struct sst_hsw_ipc_dx_reply dx; | 293 | struct sst_hsw_ipc_dx_reply dx; |
294 | void *dx_context; | ||
295 | dma_addr_t dx_context_paddr; | ||
292 | 296 | ||
293 | /* boot */ | 297 | /* boot */ |
294 | wait_queue_head_t boot_wait; | 298 | wait_queue_head_t boot_wait; |
@@ -1038,14 +1042,9 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | |||
1038 | 1042 | ||
1039 | trace_ipc_request("set stream volume", stream->reply.stream_hw_id); | 1043 | trace_ipc_request("set stream volume", stream->reply.stream_hw_id); |
1040 | 1044 | ||
1041 | if (channel > 1) | 1045 | if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL) |
1042 | return -EINVAL; | 1046 | return -EINVAL; |
1043 | 1047 | ||
1044 | if (stream->mute[channel]) { | ||
1045 | stream->mute_volume[channel] = volume; | ||
1046 | return 0; | ||
1047 | } | ||
1048 | |||
1049 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | | 1048 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | |
1050 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); | 1049 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); |
1051 | header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); | 1050 | header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); |
@@ -1053,9 +1052,28 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | |||
1053 | header |= (stage_id << IPC_STG_ID_SHIFT); | 1052 | header |= (stage_id << IPC_STG_ID_SHIFT); |
1054 | 1053 | ||
1055 | req = &stream->vol_req; | 1054 | req = &stream->vol_req; |
1056 | req->channel = channel; | ||
1057 | req->target_volume = volume; | 1055 | req->target_volume = volume; |
1058 | 1056 | ||
1057 | /* set both at same time ? */ | ||
1058 | if (channel == SST_HSW_CHANNELS_ALL) { | ||
1059 | if (hsw->mute[0] && hsw->mute[1]) { | ||
1060 | hsw->mute_volume[0] = hsw->mute_volume[1] = volume; | ||
1061 | return 0; | ||
1062 | } else if (hsw->mute[0]) | ||
1063 | req->channel = 1; | ||
1064 | else if (hsw->mute[1]) | ||
1065 | req->channel = 0; | ||
1066 | else | ||
1067 | req->channel = SST_HSW_CHANNELS_ALL; | ||
1068 | } else { | ||
1069 | /* set only 1 channel */ | ||
1070 | if (hsw->mute[channel]) { | ||
1071 | hsw->mute_volume[channel] = volume; | ||
1072 | return 0; | ||
1073 | } | ||
1074 | req->channel = channel; | ||
1075 | } | ||
1076 | |||
1059 | ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0); | 1077 | ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0); |
1060 | if (ret < 0) { | 1078 | if (ret < 0) { |
1061 | dev_err(hsw->dev, "error: set stream volume failed\n"); | 1079 | dev_err(hsw->dev, "error: set stream volume failed\n"); |
@@ -1134,8 +1152,11 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | |||
1134 | 1152 | ||
1135 | trace_ipc_request("set mixer volume", volume); | 1153 | trace_ipc_request("set mixer volume", volume); |
1136 | 1154 | ||
1155 | if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL) | ||
1156 | return -EINVAL; | ||
1157 | |||
1137 | /* set both at same time ? */ | 1158 | /* set both at same time ? */ |
1138 | if (channel == 2) { | 1159 | if (channel == SST_HSW_CHANNELS_ALL) { |
1139 | if (hsw->mute[0] && hsw->mute[1]) { | 1160 | if (hsw->mute[0] && hsw->mute[1]) { |
1140 | hsw->mute_volume[0] = hsw->mute_volume[1] = volume; | 1161 | hsw->mute_volume[0] = hsw->mute_volume[1] = volume; |
1141 | return 0; | 1162 | return 0; |
@@ -1144,7 +1165,7 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | |||
1144 | else if (hsw->mute[1]) | 1165 | else if (hsw->mute[1]) |
1145 | req.channel = 0; | 1166 | req.channel = 0; |
1146 | else | 1167 | else |
1147 | req.channel = 0xffffffff; | 1168 | req.channel = SST_HSW_CHANNELS_ALL; |
1148 | } else { | 1169 | } else { |
1149 | /* set only 1 channel */ | 1170 | /* set only 1 channel */ |
1150 | if (hsw->mute[channel]) { | 1171 | if (hsw->mute[channel]) { |
@@ -1256,10 +1277,6 @@ int sst_hsw_stream_set_channels(struct sst_hsw *hsw, | |||
1256 | return -EINVAL; | 1277 | return -EINVAL; |
1257 | } | 1278 | } |
1258 | 1279 | ||
1259 | /* stereo is only supported atm */ | ||
1260 | if (channels != 2) | ||
1261 | return -EINVAL; | ||
1262 | |||
1263 | stream->request.format.ch_num = channels; | 1280 | stream->request.format.ch_num = channels; |
1264 | return 0; | 1281 | return 0; |
1265 | } | 1282 | } |
@@ -1355,10 +1372,11 @@ int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | |||
1355 | } | 1372 | } |
1356 | 1373 | ||
1357 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | 1374 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, |
1358 | struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id, | 1375 | struct sst_hsw_stream *stream, struct sst_module_runtime *runtime) |
1359 | u32 entry_point) | ||
1360 | { | 1376 | { |
1361 | struct sst_hsw_module_map *map = &stream->request.map; | 1377 | struct sst_hsw_module_map *map = &stream->request.map; |
1378 | struct sst_dsp *dsp = sst_hsw_get_dsp(hsw); | ||
1379 | struct sst_module *module = runtime->module; | ||
1362 | 1380 | ||
1363 | if (stream->commited) { | 1381 | if (stream->commited) { |
1364 | dev_err(hsw->dev, "error: stream committed for set module\n"); | 1382 | dev_err(hsw->dev, "error: stream committed for set module\n"); |
@@ -1367,36 +1385,25 @@ int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | |||
1367 | 1385 | ||
1368 | /* only support initial module atm */ | 1386 | /* only support initial module atm */ |
1369 | map->module_entries_count = 1; | 1387 | map->module_entries_count = 1; |
1370 | map->module_entries[0].module_id = module_id; | 1388 | map->module_entries[0].module_id = module->id; |
1371 | map->module_entries[0].entry_point = entry_point; | 1389 | map->module_entries[0].entry_point = module->entry; |
1372 | 1390 | ||
1373 | return 0; | 1391 | stream->request.persistent_mem.offset = |
1374 | } | 1392 | sst_dsp_get_offset(dsp, runtime->persistent_offset, SST_MEM_DRAM); |
1375 | 1393 | stream->request.persistent_mem.size = module->persistent_size; | |
1376 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, | 1394 | |
1377 | struct sst_hsw_stream *stream, u32 offset, u32 size) | 1395 | stream->request.scratch_mem.offset = |
1378 | { | 1396 | sst_dsp_get_offset(dsp, dsp->scratch_offset, SST_MEM_DRAM); |
1379 | if (stream->commited) { | 1397 | stream->request.scratch_mem.size = dsp->scratch_size; |
1380 | dev_err(hsw->dev, "error: stream committed for set pmem\n"); | 1398 | |
1381 | return -EINVAL; | 1399 | dev_dbg(hsw->dev, "module %d runtime %d using:\n", module->id, |
1382 | } | 1400 | runtime->id); |
1383 | 1401 | dev_dbg(hsw->dev, " persistent offset 0x%x bytes 0x%x\n", | |
1384 | stream->request.persistent_mem.offset = offset; | 1402 | stream->request.persistent_mem.offset, |
1385 | stream->request.persistent_mem.size = size; | 1403 | stream->request.persistent_mem.size); |
1386 | 1404 | dev_dbg(hsw->dev, " scratch offset 0x%x bytes 0x%x\n", | |
1387 | return 0; | 1405 | stream->request.scratch_mem.offset, |
1388 | } | 1406 | stream->request.scratch_mem.size); |
1389 | |||
1390 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, | ||
1391 | struct sst_hsw_stream *stream, u32 offset, u32 size) | ||
1392 | { | ||
1393 | if (stream->commited) { | ||
1394 | dev_err(hsw->dev, "error: stream committed for set smem\n"); | ||
1395 | return -EINVAL; | ||
1396 | } | ||
1397 | |||
1398 | stream->request.scratch_mem.offset = offset; | ||
1399 | stream->request.scratch_mem.size = size; | ||
1400 | 1407 | ||
1401 | return 0; | 1408 | return 0; |
1402 | } | 1409 | } |
@@ -1630,6 +1637,10 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, | |||
1630 | config.clock_frequency = mclk; | 1637 | config.clock_frequency = mclk; |
1631 | config.mode = mode; | 1638 | config.mode = mode; |
1632 | config.clock_divider = clock_divider; | 1639 | config.clock_divider = clock_divider; |
1640 | if (mode == SST_HSW_DEVICE_TDM_CLOCK_MASTER) | ||
1641 | config.channels = 4; | ||
1642 | else | ||
1643 | config.channels = 2; | ||
1633 | 1644 | ||
1634 | trace_hsw_device_config_req(&config); | 1645 | trace_hsw_device_config_req(&config); |
1635 | 1646 | ||
@@ -1673,34 +1684,283 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
1673 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", | 1684 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", |
1674 | dx->entries_no, state); | 1685 | dx->entries_no, state); |
1675 | 1686 | ||
1676 | memcpy(&hsw->dx, dx, sizeof(*dx)); | 1687 | return ret; |
1677 | return 0; | ||
1678 | } | 1688 | } |
1679 | 1689 | ||
1680 | /* Used to save state into hsw->dx_reply */ | 1690 | struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, |
1681 | int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, | 1691 | int mod_id, int offset) |
1682 | u32 *offset, u32 *size, u32 *source) | ||
1683 | { | 1692 | { |
1684 | struct sst_hsw_ipc_dx_memory_item *dx_mem; | 1693 | struct sst_dsp *dsp = hsw->dsp; |
1685 | struct sst_hsw_ipc_dx_reply *dx_reply; | 1694 | struct sst_module *module; |
1686 | int entry_no; | 1695 | struct sst_module_runtime *runtime; |
1696 | int err; | ||
1687 | 1697 | ||
1688 | dx_reply = &hsw->dx; | 1698 | module = sst_module_get_from_id(dsp, mod_id); |
1689 | entry_no = dx_reply->entries_no; | 1699 | if (module == NULL) { |
1700 | dev_err(dsp->dev, "error: failed to get module %d for pcm\n", | ||
1701 | mod_id); | ||
1702 | return NULL; | ||
1703 | } | ||
1704 | |||
1705 | runtime = sst_module_runtime_new(module, mod_id, NULL); | ||
1706 | if (runtime == NULL) { | ||
1707 | dev_err(dsp->dev, "error: failed to create module %d runtime\n", | ||
1708 | mod_id); | ||
1709 | return NULL; | ||
1710 | } | ||
1711 | |||
1712 | err = sst_module_runtime_alloc_blocks(runtime, offset); | ||
1713 | if (err < 0) { | ||
1714 | dev_err(dsp->dev, "error: failed to alloc blocks for module %d runtime\n", | ||
1715 | mod_id); | ||
1716 | sst_module_runtime_free(runtime); | ||
1717 | return NULL; | ||
1718 | } | ||
1719 | |||
1720 | dev_dbg(dsp->dev, "runtime id %d created for module %d\n", runtime->id, | ||
1721 | mod_id); | ||
1722 | return runtime; | ||
1723 | } | ||
1724 | |||
1725 | void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime) | ||
1726 | { | ||
1727 | sst_module_runtime_free_blocks(runtime); | ||
1728 | sst_module_runtime_free(runtime); | ||
1729 | } | ||
1730 | |||
1731 | #ifdef CONFIG_PM | ||
1732 | static int sst_hsw_dx_state_dump(struct sst_hsw *hsw) | ||
1733 | { | ||
1734 | struct sst_dsp *sst = hsw->dsp; | ||
1735 | u32 item, offset, size; | ||
1736 | int ret = 0; | ||
1690 | 1737 | ||
1691 | trace_ipc_request("PM get Dx state", entry_no); | 1738 | trace_ipc_request("PM state dump. Items #", SST_HSW_MAX_DX_REGIONS); |
1692 | 1739 | ||
1693 | if (item >= entry_no) | 1740 | if (hsw->dx.entries_no > SST_HSW_MAX_DX_REGIONS) { |
1741 | dev_err(hsw->dev, | ||
1742 | "error: number of FW context regions greater than %d\n", | ||
1743 | SST_HSW_MAX_DX_REGIONS); | ||
1744 | memset(&hsw->dx, 0, sizeof(hsw->dx)); | ||
1694 | return -EINVAL; | 1745 | return -EINVAL; |
1746 | } | ||
1747 | |||
1748 | ret = sst_dsp_dma_get_channel(sst, 0); | ||
1749 | if (ret < 0) { | ||
1750 | dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret); | ||
1751 | return ret; | ||
1752 | } | ||
1753 | |||
1754 | /* set on-demond mode on engine 0 channel 3 */ | ||
1755 | sst_dsp_shim_update_bits(sst, SST_HMDC, | ||
1756 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, | ||
1757 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH); | ||
1758 | |||
1759 | for (item = 0; item < hsw->dx.entries_no; item++) { | ||
1760 | if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP | ||
1761 | && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET | ||
1762 | && hsw->dx.mem_info[item].offset < | ||
1763 | DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) { | ||
1764 | |||
1765 | offset = hsw->dx.mem_info[item].offset | ||
1766 | - DSP_DRAM_ADDR_OFFSET; | ||
1767 | size = (hsw->dx.mem_info[item].size + 3) & (~3); | ||
1768 | |||
1769 | ret = sst_dsp_dma_copyfrom(sst, hsw->dx_context_paddr + offset, | ||
1770 | sst->addr.lpe_base + offset, size); | ||
1771 | if (ret < 0) { | ||
1772 | dev_err(hsw->dev, | ||
1773 | "error: FW context dump failed\n"); | ||
1774 | memset(&hsw->dx, 0, sizeof(hsw->dx)); | ||
1775 | goto out; | ||
1776 | } | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | out: | ||
1781 | sst_dsp_dma_put_channel(sst); | ||
1782 | return ret; | ||
1783 | } | ||
1784 | |||
1785 | static int sst_hsw_dx_state_restore(struct sst_hsw *hsw) | ||
1786 | { | ||
1787 | struct sst_dsp *sst = hsw->dsp; | ||
1788 | u32 item, offset, size; | ||
1789 | int ret; | ||
1790 | |||
1791 | for (item = 0; item < hsw->dx.entries_no; item++) { | ||
1792 | if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP | ||
1793 | && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET | ||
1794 | && hsw->dx.mem_info[item].offset < | ||
1795 | DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) { | ||
1796 | |||
1797 | offset = hsw->dx.mem_info[item].offset | ||
1798 | - DSP_DRAM_ADDR_OFFSET; | ||
1799 | size = (hsw->dx.mem_info[item].size + 3) & (~3); | ||
1800 | |||
1801 | ret = sst_dsp_dma_copyto(sst, sst->addr.lpe_base + offset, | ||
1802 | hsw->dx_context_paddr + offset, size); | ||
1803 | if (ret < 0) { | ||
1804 | dev_err(hsw->dev, | ||
1805 | "error: FW context restore failed\n"); | ||
1806 | return ret; | ||
1807 | } | ||
1808 | } | ||
1809 | } | ||
1810 | |||
1811 | return 0; | ||
1812 | } | ||
1813 | |||
1814 | static void sst_hsw_drop_all(struct sst_hsw *hsw) | ||
1815 | { | ||
1816 | struct ipc_message *msg, *tmp; | ||
1817 | unsigned long flags; | ||
1818 | int tx_drop_cnt = 0, rx_drop_cnt = 0; | ||
1695 | 1819 | ||
1696 | dx_mem = &dx_reply->mem_info[item]; | 1820 | /* drop all TX and Rx messages before we stall + reset DSP */ |
1697 | *offset = dx_mem->offset; | 1821 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); |
1698 | *size = dx_mem->size; | 1822 | |
1699 | *source = dx_mem->source; | 1823 | list_for_each_entry_safe(msg, tmp, &hsw->tx_list, list) { |
1824 | list_move(&msg->list, &hsw->empty_list); | ||
1825 | tx_drop_cnt++; | ||
1826 | } | ||
1827 | |||
1828 | list_for_each_entry_safe(msg, tmp, &hsw->rx_list, list) { | ||
1829 | list_move(&msg->list, &hsw->empty_list); | ||
1830 | rx_drop_cnt++; | ||
1831 | } | ||
1832 | |||
1833 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
1834 | |||
1835 | if (tx_drop_cnt || rx_drop_cnt) | ||
1836 | dev_err(hsw->dev, "dropped IPC msg RX=%d, TX=%d\n", | ||
1837 | tx_drop_cnt, rx_drop_cnt); | ||
1838 | } | ||
1839 | |||
1840 | int sst_hsw_dsp_load(struct sst_hsw *hsw) | ||
1841 | { | ||
1842 | struct sst_dsp *dsp = hsw->dsp; | ||
1843 | int ret; | ||
1844 | |||
1845 | dev_dbg(hsw->dev, "loading audio DSP...."); | ||
1846 | |||
1847 | ret = sst_dsp_wake(dsp); | ||
1848 | if (ret < 0) { | ||
1849 | dev_err(hsw->dev, "error: failed to wake audio DSP\n"); | ||
1850 | return -ENODEV; | ||
1851 | } | ||
1852 | |||
1853 | ret = sst_dsp_dma_get_channel(dsp, 0); | ||
1854 | if (ret < 0) { | ||
1855 | dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret); | ||
1856 | return ret; | ||
1857 | } | ||
1858 | |||
1859 | ret = sst_fw_reload(hsw->sst_fw); | ||
1860 | if (ret < 0) { | ||
1861 | dev_err(hsw->dev, "error: SST FW reload failed\n"); | ||
1862 | sst_dsp_dma_put_channel(dsp); | ||
1863 | return -ENOMEM; | ||
1864 | } | ||
1700 | 1865 | ||
1866 | sst_dsp_dma_put_channel(dsp); | ||
1701 | return 0; | 1867 | return 0; |
1702 | } | 1868 | } |
1703 | 1869 | ||
1870 | static int sst_hsw_dsp_restore(struct sst_hsw *hsw) | ||
1871 | { | ||
1872 | struct sst_dsp *dsp = hsw->dsp; | ||
1873 | int ret; | ||
1874 | |||
1875 | dev_dbg(hsw->dev, "restoring audio DSP...."); | ||
1876 | |||
1877 | ret = sst_dsp_dma_get_channel(dsp, 0); | ||
1878 | if (ret < 0) { | ||
1879 | dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret); | ||
1880 | return ret; | ||
1881 | } | ||
1882 | |||
1883 | ret = sst_hsw_dx_state_restore(hsw); | ||
1884 | if (ret < 0) { | ||
1885 | dev_err(hsw->dev, "error: SST FW context restore failed\n"); | ||
1886 | sst_dsp_dma_put_channel(dsp); | ||
1887 | return -ENOMEM; | ||
1888 | } | ||
1889 | sst_dsp_dma_put_channel(dsp); | ||
1890 | |||
1891 | /* wait for DSP boot completion */ | ||
1892 | sst_dsp_boot(dsp); | ||
1893 | |||
1894 | return ret; | ||
1895 | } | ||
1896 | |||
1897 | int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw) | ||
1898 | { | ||
1899 | int ret; | ||
1900 | |||
1901 | dev_dbg(hsw->dev, "audio dsp runtime suspend\n"); | ||
1902 | |||
1903 | ret = sst_hsw_dx_set_state(hsw, SST_HSW_DX_STATE_D3, &hsw->dx); | ||
1904 | if (ret < 0) | ||
1905 | return ret; | ||
1906 | |||
1907 | sst_dsp_stall(hsw->dsp); | ||
1908 | |||
1909 | ret = sst_hsw_dx_state_dump(hsw); | ||
1910 | if (ret < 0) | ||
1911 | return ret; | ||
1912 | |||
1913 | sst_hsw_drop_all(hsw); | ||
1914 | |||
1915 | return 0; | ||
1916 | } | ||
1917 | |||
1918 | int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw) | ||
1919 | { | ||
1920 | sst_fw_unload(hsw->sst_fw); | ||
1921 | sst_block_free_scratch(hsw->dsp); | ||
1922 | |||
1923 | hsw->boot_complete = false; | ||
1924 | |||
1925 | sst_dsp_sleep(hsw->dsp); | ||
1926 | |||
1927 | return 0; | ||
1928 | } | ||
1929 | |||
1930 | int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw) | ||
1931 | { | ||
1932 | struct device *dev = hsw->dev; | ||
1933 | int ret; | ||
1934 | |||
1935 | dev_dbg(dev, "audio dsp runtime resume\n"); | ||
1936 | |||
1937 | if (hsw->boot_complete) | ||
1938 | return 1; /* tell caller no action is required */ | ||
1939 | |||
1940 | ret = sst_hsw_dsp_restore(hsw); | ||
1941 | if (ret < 0) | ||
1942 | dev_err(dev, "error: audio DSP boot failure\n"); | ||
1943 | |||
1944 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, | ||
1945 | msecs_to_jiffies(IPC_BOOT_MSECS)); | ||
1946 | if (ret == 0) { | ||
1947 | dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n", | ||
1948 | sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD), | ||
1949 | sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX)); | ||
1950 | return -EIO; | ||
1951 | } | ||
1952 | |||
1953 | /* Set ADSP SSP port settings */ | ||
1954 | ret = sst_hsw_device_set_config(hsw, SST_HSW_DEVICE_SSP_0, | ||
1955 | SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, | ||
1956 | SST_HSW_DEVICE_CLOCK_MASTER, 9); | ||
1957 | if (ret < 0) | ||
1958 | dev_err(dev, "error: SSP re-initialization failed\n"); | ||
1959 | |||
1960 | return ret; | ||
1961 | } | ||
1962 | #endif | ||
1963 | |||
1704 | static int msg_empty_list_init(struct sst_hsw *hsw) | 1964 | static int msg_empty_list_init(struct sst_hsw *hsw) |
1705 | { | 1965 | { |
1706 | int i; | 1966 | int i; |
@@ -1718,12 +1978,6 @@ static int msg_empty_list_init(struct sst_hsw *hsw) | |||
1718 | return 0; | 1978 | return 0; |
1719 | } | 1979 | } |
1720 | 1980 | ||
1721 | void sst_hsw_set_scratch_module(struct sst_hsw *hsw, | ||
1722 | struct sst_module *scratch) | ||
1723 | { | ||
1724 | hsw->scratch = scratch; | ||
1725 | } | ||
1726 | |||
1727 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) | 1981 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) |
1728 | { | 1982 | { |
1729 | return hsw->dsp; | 1983 | return hsw->dsp; |
@@ -1738,7 +1992,6 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1738 | { | 1992 | { |
1739 | struct sst_hsw_ipc_fw_version version; | 1993 | struct sst_hsw_ipc_fw_version version; |
1740 | struct sst_hsw *hsw; | 1994 | struct sst_hsw *hsw; |
1741 | struct sst_fw *hsw_sst_fw; | ||
1742 | int ret; | 1995 | int ret; |
1743 | 1996 | ||
1744 | dev_dbg(dev, "initialising Audio DSP IPC\n"); | 1997 | dev_dbg(dev, "initialising Audio DSP IPC\n"); |
@@ -1780,12 +2033,19 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1780 | goto dsp_err; | 2033 | goto dsp_err; |
1781 | } | 2034 | } |
1782 | 2035 | ||
2036 | /* allocate DMA buffer for context storage */ | ||
2037 | hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev, | ||
2038 | SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL); | ||
2039 | if (hsw->dx_context == NULL) { | ||
2040 | ret = -ENOMEM; | ||
2041 | goto dma_err; | ||
2042 | } | ||
2043 | |||
1783 | /* keep the DSP in reset state for base FW loading */ | 2044 | /* keep the DSP in reset state for base FW loading */ |
1784 | sst_dsp_reset(hsw->dsp); | 2045 | sst_dsp_reset(hsw->dsp); |
1785 | 2046 | ||
1786 | hsw_sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); | 2047 | hsw->sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); |
1787 | 2048 | if (hsw->sst_fw == NULL) { | |
1788 | if (hsw_sst_fw == NULL) { | ||
1789 | ret = -ENODEV; | 2049 | ret = -ENODEV; |
1790 | dev_err(dev, "error: failed to load firmware\n"); | 2050 | dev_err(dev, "error: failed to load firmware\n"); |
1791 | goto fw_err; | 2051 | goto fw_err; |
@@ -1797,7 +2057,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1797 | msecs_to_jiffies(IPC_BOOT_MSECS)); | 2057 | msecs_to_jiffies(IPC_BOOT_MSECS)); |
1798 | if (ret == 0) { | 2058 | if (ret == 0) { |
1799 | ret = -EIO; | 2059 | ret = -EIO; |
1800 | dev_err(hsw->dev, "error: ADSP boot timeout\n"); | 2060 | dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n", |
2061 | sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD), | ||
2062 | sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX)); | ||
1801 | goto boot_err; | 2063 | goto boot_err; |
1802 | } | 2064 | } |
1803 | 2065 | ||
@@ -1816,8 +2078,11 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1816 | 2078 | ||
1817 | boot_err: | 2079 | boot_err: |
1818 | sst_dsp_reset(hsw->dsp); | 2080 | sst_dsp_reset(hsw->dsp); |
1819 | sst_fw_free(hsw_sst_fw); | 2081 | sst_fw_free(hsw->sst_fw); |
1820 | fw_err: | 2082 | fw_err: |
2083 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, | ||
2084 | hsw->dx_context, hsw->dx_context_paddr); | ||
2085 | dma_err: | ||
1821 | sst_dsp_free(hsw->dsp); | 2086 | sst_dsp_free(hsw->dsp); |
1822 | dsp_err: | 2087 | dsp_err: |
1823 | kthread_stop(hsw->tx_thread); | 2088 | kthread_stop(hsw->tx_thread); |
@@ -1834,6 +2099,8 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) | |||
1834 | 2099 | ||
1835 | sst_dsp_reset(hsw->dsp); | 2100 | sst_dsp_reset(hsw->dsp); |
1836 | sst_fw_free_all(hsw->dsp); | 2101 | sst_fw_free_all(hsw->dsp); |
2102 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, | ||
2103 | hsw->dx_context, hsw->dx_context_paddr); | ||
1837 | sst_dsp_free(hsw->dsp); | 2104 | sst_dsp_free(hsw->dsp); |
1838 | kfree(hsw->scratch); | 2105 | kfree(hsw->scratch); |
1839 | kthread_stop(hsw->tx_thread); | 2106 | kthread_stop(hsw->tx_thread); |
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 2ac194a6d04b..138e894ab413 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h | |||
@@ -21,8 +21,10 @@ | |||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | 23 | ||
24 | #define SST_HSW_NO_CHANNELS 2 | 24 | #define SST_HSW_NO_CHANNELS 4 |
25 | #define SST_HSW_MAX_DX_REGIONS 14 | 25 | #define SST_HSW_MAX_DX_REGIONS 14 |
26 | #define SST_HSW_DX_CONTEXT_SIZE (640 * 1024) | ||
27 | #define SST_HSW_CHANNELS_ALL 0xffffffff | ||
26 | 28 | ||
27 | #define SST_HSW_FW_LOG_CONFIG_DWORDS 12 | 29 | #define SST_HSW_FW_LOG_CONFIG_DWORDS 12 |
28 | #define SST_HSW_GLOBAL_LOG 15 | 30 | #define SST_HSW_GLOBAL_LOG 15 |
@@ -40,6 +42,7 @@ struct sst_hsw_stream; | |||
40 | struct sst_hsw_log_stream; | 42 | struct sst_hsw_log_stream; |
41 | struct sst_pdata; | 43 | struct sst_pdata; |
42 | struct sst_module; | 44 | struct sst_module; |
45 | struct sst_module_runtime; | ||
43 | extern struct sst_ops haswell_ops; | 46 | extern struct sst_ops haswell_ops; |
44 | 47 | ||
45 | /* Stream Allocate Path ID */ | 48 | /* Stream Allocate Path ID */ |
@@ -84,6 +87,7 @@ enum sst_hsw_device_mclk { | |||
84 | enum sst_hsw_device_mode { | 87 | enum sst_hsw_device_mode { |
85 | SST_HSW_DEVICE_CLOCK_SLAVE = 0, | 88 | SST_HSW_DEVICE_CLOCK_SLAVE = 0, |
86 | SST_HSW_DEVICE_CLOCK_MASTER = 1, | 89 | SST_HSW_DEVICE_CLOCK_MASTER = 1, |
90 | SST_HSW_DEVICE_TDM_CLOCK_MASTER = 2, | ||
87 | }; | 91 | }; |
88 | 92 | ||
89 | /* DX Power State */ | 93 | /* DX Power State */ |
@@ -295,7 +299,8 @@ struct sst_hsw_ipc_device_config_req { | |||
295 | u32 clock_frequency; | 299 | u32 clock_frequency; |
296 | u32 mode; | 300 | u32 mode; |
297 | u16 clock_divider; | 301 | u16 clock_divider; |
298 | u16 reserved; | 302 | u8 channels; |
303 | u8 reserved; | ||
299 | } __attribute__((packed)); | 304 | } __attribute__((packed)); |
300 | 305 | ||
301 | /* Audio Data formats */ | 306 | /* Audio Data formats */ |
@@ -430,8 +435,7 @@ int sst_hsw_stream_set_map_config(struct sst_hsw *hsw, | |||
430 | int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | 435 | int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream, |
431 | enum sst_hsw_interleaving style); | 436 | enum sst_hsw_interleaving style); |
432 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | 437 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, |
433 | struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id, | 438 | struct sst_hsw_stream *stream, struct sst_module_runtime *runtime); |
434 | u32 entry_point); | ||
435 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, | 439 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, |
436 | struct sst_hsw_stream *stream, u32 offset, u32 size); | 440 | struct sst_hsw_stream *stream, u32 offset, u32 size); |
437 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, | 441 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, |
@@ -484,7 +488,16 @@ int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, | |||
484 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); | 488 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); |
485 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); | 489 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); |
486 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); | 490 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); |
487 | void sst_hsw_set_scratch_module(struct sst_hsw *hsw, | 491 | |
488 | struct sst_module *scratch); | 492 | /* runtime module management */ |
493 | struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, | ||
494 | int mod_id, int offset); | ||
495 | void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime); | ||
496 | |||
497 | /* PM */ | ||
498 | int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw); | ||
499 | int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw); | ||
500 | int sst_hsw_dsp_load(struct sst_hsw *hsw); | ||
501 | int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw); | ||
489 | 502 | ||
490 | #endif | 503 | #endif |
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 4df867cbb92a..0180b386c421 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/pm_runtime.h> | ||
21 | #include <asm/page.h> | 22 | #include <asm/page.h> |
22 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
@@ -73,6 +74,13 @@ static const u32 volume_map[] = { | |||
73 | #define HSW_PCM_PERIODS_MAX 64 | 74 | #define HSW_PCM_PERIODS_MAX 64 |
74 | #define HSW_PCM_PERIODS_MIN 2 | 75 | #define HSW_PCM_PERIODS_MIN 2 |
75 | 76 | ||
77 | #define HSW_PCM_DAI_ID_SYSTEM 0 | ||
78 | #define HSW_PCM_DAI_ID_OFFLOAD0 1 | ||
79 | #define HSW_PCM_DAI_ID_OFFLOAD1 2 | ||
80 | #define HSW_PCM_DAI_ID_LOOPBACK 3 | ||
81 | #define HSW_PCM_DAI_ID_CAPTURE 4 | ||
82 | |||
83 | |||
76 | static const struct snd_pcm_hardware hsw_pcm_hardware = { | 84 | static const struct snd_pcm_hardware hsw_pcm_hardware = { |
77 | .info = SNDRV_PCM_INFO_MMAP | | 85 | .info = SNDRV_PCM_INFO_MMAP | |
78 | SNDRV_PCM_INFO_MMAP_VALID | | 86 | SNDRV_PCM_INFO_MMAP_VALID | |
@@ -89,22 +97,39 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = { | |||
89 | .buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE, | 97 | .buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE, |
90 | }; | 98 | }; |
91 | 99 | ||
100 | struct hsw_pcm_module_map { | ||
101 | int dai_id; | ||
102 | enum sst_hsw_module_id mod_id; | ||
103 | }; | ||
104 | |||
92 | /* private data for each PCM DSP stream */ | 105 | /* private data for each PCM DSP stream */ |
93 | struct hsw_pcm_data { | 106 | struct hsw_pcm_data { |
94 | int dai_id; | 107 | int dai_id; |
95 | struct sst_hsw_stream *stream; | 108 | struct sst_hsw_stream *stream; |
109 | struct sst_module_runtime *runtime; | ||
110 | struct sst_module_runtime_context context; | ||
111 | struct snd_pcm *hsw_pcm; | ||
96 | u32 volume[2]; | 112 | u32 volume[2]; |
97 | struct snd_pcm_substream *substream; | 113 | struct snd_pcm_substream *substream; |
98 | struct snd_compr_stream *cstream; | 114 | struct snd_compr_stream *cstream; |
99 | unsigned int wpos; | 115 | unsigned int wpos; |
100 | struct mutex mutex; | 116 | struct mutex mutex; |
101 | bool allocated; | 117 | bool allocated; |
118 | int persistent_offset; | ||
119 | }; | ||
120 | |||
121 | enum hsw_pm_state { | ||
122 | HSW_PM_STATE_D3 = 0, | ||
123 | HSW_PM_STATE_D0 = 1, | ||
102 | }; | 124 | }; |
103 | 125 | ||
104 | /* private data for the driver */ | 126 | /* private data for the driver */ |
105 | struct hsw_priv_data { | 127 | struct hsw_priv_data { |
106 | /* runtime DSP */ | 128 | /* runtime DSP */ |
107 | struct sst_hsw *hsw; | 129 | struct sst_hsw *hsw; |
130 | struct device *dev; | ||
131 | enum hsw_pm_state pm_state; | ||
132 | struct snd_soc_card *soc_card; | ||
108 | 133 | ||
109 | /* page tables */ | 134 | /* page tables */ |
110 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; | 135 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; |
@@ -138,21 +163,25 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value) | |||
138 | static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | 163 | static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, |
139 | struct snd_ctl_elem_value *ucontrol) | 164 | struct snd_ctl_elem_value *ucontrol) |
140 | { | 165 | { |
141 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | 166 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); |
142 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | ||
143 | struct soc_mixer_control *mc = | 167 | struct soc_mixer_control *mc = |
144 | (struct soc_mixer_control *)kcontrol->private_value; | 168 | (struct soc_mixer_control *)kcontrol->private_value; |
169 | struct hsw_priv_data *pdata = | ||
170 | snd_soc_platform_get_drvdata(platform); | ||
145 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | 171 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; |
146 | struct sst_hsw *hsw = pdata->hsw; | 172 | struct sst_hsw *hsw = pdata->hsw; |
147 | u32 volume; | 173 | u32 volume; |
148 | 174 | ||
149 | mutex_lock(&pcm_data->mutex); | 175 | mutex_lock(&pcm_data->mutex); |
176 | pm_runtime_get_sync(pdata->dev); | ||
150 | 177 | ||
151 | if (!pcm_data->stream) { | 178 | if (!pcm_data->stream) { |
152 | pcm_data->volume[0] = | 179 | pcm_data->volume[0] = |
153 | hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 180 | hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
154 | pcm_data->volume[1] = | 181 | pcm_data->volume[1] = |
155 | hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); | 182 | hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); |
183 | pm_runtime_mark_last_busy(pdata->dev); | ||
184 | pm_runtime_put_autosuspend(pdata->dev); | ||
156 | mutex_unlock(&pcm_data->mutex); | 185 | mutex_unlock(&pcm_data->mutex); |
157 | return 0; | 186 | return 0; |
158 | } | 187 | } |
@@ -160,7 +189,8 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | |||
160 | if (ucontrol->value.integer.value[0] == | 189 | if (ucontrol->value.integer.value[0] == |
161 | ucontrol->value.integer.value[1]) { | 190 | ucontrol->value.integer.value[1]) { |
162 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 191 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
163 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 2, volume); | 192 | /* apply volume value to all channels */ |
193 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, SST_HSW_CHANNELS_ALL, volume); | ||
164 | } else { | 194 | } else { |
165 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 195 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
166 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume); | 196 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume); |
@@ -168,6 +198,8 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | |||
168 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume); | 198 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume); |
169 | } | 199 | } |
170 | 200 | ||
201 | pm_runtime_mark_last_busy(pdata->dev); | ||
202 | pm_runtime_put_autosuspend(pdata->dev); | ||
171 | mutex_unlock(&pcm_data->mutex); | 203 | mutex_unlock(&pcm_data->mutex); |
172 | return 0; | 204 | return 0; |
173 | } | 205 | } |
@@ -175,21 +207,25 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | |||
175 | static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | 207 | static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, |
176 | struct snd_ctl_elem_value *ucontrol) | 208 | struct snd_ctl_elem_value *ucontrol) |
177 | { | 209 | { |
178 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | 210 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); |
179 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | ||
180 | struct soc_mixer_control *mc = | 211 | struct soc_mixer_control *mc = |
181 | (struct soc_mixer_control *)kcontrol->private_value; | 212 | (struct soc_mixer_control *)kcontrol->private_value; |
213 | struct hsw_priv_data *pdata = | ||
214 | snd_soc_platform_get_drvdata(platform); | ||
182 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | 215 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; |
183 | struct sst_hsw *hsw = pdata->hsw; | 216 | struct sst_hsw *hsw = pdata->hsw; |
184 | u32 volume; | 217 | u32 volume; |
185 | 218 | ||
186 | mutex_lock(&pcm_data->mutex); | 219 | mutex_lock(&pcm_data->mutex); |
220 | pm_runtime_get_sync(pdata->dev); | ||
187 | 221 | ||
188 | if (!pcm_data->stream) { | 222 | if (!pcm_data->stream) { |
189 | ucontrol->value.integer.value[0] = | 223 | ucontrol->value.integer.value[0] = |
190 | hsw_ipc_to_mixer(pcm_data->volume[0]); | 224 | hsw_ipc_to_mixer(pcm_data->volume[0]); |
191 | ucontrol->value.integer.value[1] = | 225 | ucontrol->value.integer.value[1] = |
192 | hsw_ipc_to_mixer(pcm_data->volume[1]); | 226 | hsw_ipc_to_mixer(pcm_data->volume[1]); |
227 | pm_runtime_mark_last_busy(pdata->dev); | ||
228 | pm_runtime_put_autosuspend(pdata->dev); | ||
193 | mutex_unlock(&pcm_data->mutex); | 229 | mutex_unlock(&pcm_data->mutex); |
194 | return 0; | 230 | return 0; |
195 | } | 231 | } |
@@ -198,6 +234,9 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | |||
198 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); | 234 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); |
199 | sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume); | 235 | sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume); |
200 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); | 236 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); |
237 | |||
238 | pm_runtime_mark_last_busy(pdata->dev); | ||
239 | pm_runtime_put_autosuspend(pdata->dev); | ||
201 | mutex_unlock(&pcm_data->mutex); | 240 | mutex_unlock(&pcm_data->mutex); |
202 | 241 | ||
203 | return 0; | 242 | return 0; |
@@ -206,16 +245,18 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | |||
206 | static int hsw_volume_put(struct snd_kcontrol *kcontrol, | 245 | static int hsw_volume_put(struct snd_kcontrol *kcontrol, |
207 | struct snd_ctl_elem_value *ucontrol) | 246 | struct snd_ctl_elem_value *ucontrol) |
208 | { | 247 | { |
209 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | 248 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); |
210 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | 249 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); |
211 | struct sst_hsw *hsw = pdata->hsw; | 250 | struct sst_hsw *hsw = pdata->hsw; |
212 | u32 volume; | 251 | u32 volume; |
213 | 252 | ||
253 | pm_runtime_get_sync(pdata->dev); | ||
254 | |||
214 | if (ucontrol->value.integer.value[0] == | 255 | if (ucontrol->value.integer.value[0] == |
215 | ucontrol->value.integer.value[1]) { | 256 | ucontrol->value.integer.value[1]) { |
216 | 257 | ||
217 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 258 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
218 | sst_hsw_mixer_set_volume(hsw, 0, 2, volume); | 259 | sst_hsw_mixer_set_volume(hsw, 0, SST_HSW_CHANNELS_ALL, volume); |
219 | 260 | ||
220 | } else { | 261 | } else { |
221 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 262 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
@@ -225,23 +266,28 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol, | |||
225 | sst_hsw_mixer_set_volume(hsw, 0, 1, volume); | 266 | sst_hsw_mixer_set_volume(hsw, 0, 1, volume); |
226 | } | 267 | } |
227 | 268 | ||
269 | pm_runtime_mark_last_busy(pdata->dev); | ||
270 | pm_runtime_put_autosuspend(pdata->dev); | ||
228 | return 0; | 271 | return 0; |
229 | } | 272 | } |
230 | 273 | ||
231 | static int hsw_volume_get(struct snd_kcontrol *kcontrol, | 274 | static int hsw_volume_get(struct snd_kcontrol *kcontrol, |
232 | struct snd_ctl_elem_value *ucontrol) | 275 | struct snd_ctl_elem_value *ucontrol) |
233 | { | 276 | { |
234 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | 277 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); |
235 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | 278 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); |
236 | struct sst_hsw *hsw = pdata->hsw; | 279 | struct sst_hsw *hsw = pdata->hsw; |
237 | unsigned int volume = 0; | 280 | unsigned int volume = 0; |
238 | 281 | ||
282 | pm_runtime_get_sync(pdata->dev); | ||
239 | sst_hsw_mixer_get_volume(hsw, 0, 0, &volume); | 283 | sst_hsw_mixer_get_volume(hsw, 0, 0, &volume); |
240 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); | 284 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); |
241 | 285 | ||
242 | sst_hsw_mixer_get_volume(hsw, 0, 1, &volume); | 286 | sst_hsw_mixer_get_volume(hsw, 0, 1, &volume); |
243 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); | 287 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); |
244 | 288 | ||
289 | pm_runtime_mark_last_busy(pdata->dev); | ||
290 | pm_runtime_put_autosuspend(pdata->dev); | ||
245 | return 0; | 291 | return 0; |
246 | } | 292 | } |
247 | 293 | ||
@@ -252,23 +298,19 @@ static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); | |||
252 | static const struct snd_kcontrol_new hsw_volume_controls[] = { | 298 | static const struct snd_kcontrol_new hsw_volume_controls[] = { |
253 | /* Global DSP volume */ | 299 | /* Global DSP volume */ |
254 | SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8, | 300 | SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8, |
255 | ARRAY_SIZE(volume_map) -1, 0, | 301 | ARRAY_SIZE(volume_map) - 1, 0, |
256 | hsw_volume_get, hsw_volume_put, hsw_vol_tlv), | 302 | hsw_volume_get, hsw_volume_put, hsw_vol_tlv), |
257 | /* Offload 0 volume */ | 303 | /* Offload 0 volume */ |
258 | SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8, | 304 | SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8, |
259 | ARRAY_SIZE(volume_map), 0, | 305 | ARRAY_SIZE(volume_map) - 1, 0, |
260 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | 306 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
261 | /* Offload 1 volume */ | 307 | /* Offload 1 volume */ |
262 | SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8, | 308 | SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8, |
263 | ARRAY_SIZE(volume_map), 0, | 309 | ARRAY_SIZE(volume_map) - 1, 0, |
264 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | ||
265 | /* Loopback volume */ | ||
266 | SOC_DOUBLE_EXT_TLV("Loopback Capture Volume", 3, 0, 8, | ||
267 | ARRAY_SIZE(volume_map), 0, | ||
268 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | 310 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
269 | /* Mic Capture volume */ | 311 | /* Mic Capture volume */ |
270 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, | 312 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 0, 0, 8, |
271 | ARRAY_SIZE(volume_map), 0, | 313 | ARRAY_SIZE(volume_map) - 1, 0, |
272 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | 314 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
273 | }; | 315 | }; |
274 | 316 | ||
@@ -354,8 +396,14 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
354 | /* DSP stream type depends on DAI ID */ | 396 | /* DSP stream type depends on DAI ID */ |
355 | switch (rtd->cpu_dai->id) { | 397 | switch (rtd->cpu_dai->id) { |
356 | case 0: | 398 | case 0: |
357 | stream_type = SST_HSW_STREAM_TYPE_SYSTEM; | 399 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
358 | module_id = SST_HSW_MODULE_PCM_SYSTEM; | 400 | stream_type = SST_HSW_STREAM_TYPE_SYSTEM; |
401 | module_id = SST_HSW_MODULE_PCM_SYSTEM; | ||
402 | } | ||
403 | else { | ||
404 | stream_type = SST_HSW_STREAM_TYPE_CAPTURE; | ||
405 | module_id = SST_HSW_MODULE_PCM_CAPTURE; | ||
406 | } | ||
359 | break; | 407 | break; |
360 | case 1: | 408 | case 1: |
361 | case 2: | 409 | case 2: |
@@ -368,10 +416,6 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
368 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; | 416 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; |
369 | module_id = SST_HSW_MODULE_PCM_REFERENCE; | 417 | module_id = SST_HSW_MODULE_PCM_REFERENCE; |
370 | break; | 418 | break; |
371 | case 4: | ||
372 | stream_type = SST_HSW_STREAM_TYPE_CAPTURE; | ||
373 | module_id = SST_HSW_MODULE_PCM_CAPTURE; | ||
374 | break; | ||
375 | default: | 419 | default: |
376 | dev_err(rtd->dev, "error: invalid DAI ID %d\n", | 420 | dev_err(rtd->dev, "error: invalid DAI ID %d\n", |
377 | rtd->cpu_dai->id); | 421 | rtd->cpu_dai->id); |
@@ -421,13 +465,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
421 | return ret; | 465 | return ret; |
422 | } | 466 | } |
423 | 467 | ||
424 | /* we only support stereo atm */ | ||
425 | channels = params_channels(params); | 468 | channels = params_channels(params); |
426 | if (channels != 2) { | ||
427 | dev_err(rtd->dev, "error: invalid channels %d\n", channels); | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO); | 469 | map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO); |
432 | sst_hsw_stream_set_map_config(hsw, pcm_data->stream, | 470 | sst_hsw_stream_set_map_config(hsw, pcm_data->stream, |
433 | map, SST_HSW_CHANNEL_CONFIG_STEREO); | 471 | map, SST_HSW_CHANNEL_CONFIG_STEREO); |
@@ -478,35 +516,23 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
478 | return -EINVAL; | 516 | return -EINVAL; |
479 | } | 517 | } |
480 | 518 | ||
481 | /* we use hardcoded memory offsets atm, will be updated for new FW */ | 519 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, |
482 | if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) { | 520 | pcm_data->runtime); |
483 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, | ||
484 | SST_HSW_MODULE_PCM_CAPTURE, module_data->entry); | ||
485 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
486 | 0x449400, 0x4000); | ||
487 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
488 | 0x400000, 0); | ||
489 | } else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */ | ||
490 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, | ||
491 | SST_HSW_MODULE_PCM_SYSTEM, module_data->entry); | ||
492 | |||
493 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
494 | module_data->offset, module_data->size); | ||
495 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
496 | 0x44d400, 0x3800); | ||
497 | |||
498 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
499 | module_data->offset, module_data->size); | ||
500 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
501 | 0x400000, 0); | ||
502 | } | ||
503 | 521 | ||
504 | ret = sst_hsw_stream_commit(hsw, pcm_data->stream); | 522 | ret = sst_hsw_stream_commit(hsw, pcm_data->stream); |
505 | if (ret < 0) { | 523 | if (ret < 0) { |
506 | dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); | 524 | dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); |
507 | return ret; | 525 | return ret; |
508 | } | 526 | } |
509 | pcm_data->allocated = true; | 527 | |
528 | if (!pcm_data->allocated) { | ||
529 | /* Set previous saved volume */ | ||
530 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
531 | 0, pcm_data->volume[0]); | ||
532 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
533 | 1, pcm_data->volume[1]); | ||
534 | pcm_data->allocated = true; | ||
535 | } | ||
510 | 536 | ||
511 | ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); | 537 | ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); |
512 | if (ret < 0) | 538 | if (ret < 0) |
@@ -558,7 +584,7 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data) | |||
558 | pos = frames_to_bytes(runtime, | 584 | pos = frames_to_bytes(runtime, |
559 | (runtime->control->appl_ptr % runtime->buffer_size)); | 585 | (runtime->control->appl_ptr % runtime->buffer_size)); |
560 | 586 | ||
561 | dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); | 587 | dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); |
562 | 588 | ||
563 | /* let alsa know we have play a period */ | 589 | /* let alsa know we have play a period */ |
564 | snd_pcm_period_elapsed(substream); | 590 | snd_pcm_period_elapsed(substream); |
@@ -580,7 +606,7 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) | |||
580 | offset = bytes_to_frames(runtime, position); | 606 | offset = bytes_to_frames(runtime, position); |
581 | ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); | 607 | ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); |
582 | 608 | ||
583 | dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n", | 609 | dev_vdbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n", |
584 | position, ppos); | 610 | position, ppos); |
585 | return offset; | 611 | return offset; |
586 | } | 612 | } |
@@ -596,6 +622,7 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) | |||
596 | pcm_data = &pdata->pcm[rtd->cpu_dai->id]; | 622 | pcm_data = &pdata->pcm[rtd->cpu_dai->id]; |
597 | 623 | ||
598 | mutex_lock(&pcm_data->mutex); | 624 | mutex_lock(&pcm_data->mutex); |
625 | pm_runtime_get_sync(pdata->dev); | ||
599 | 626 | ||
600 | snd_soc_pcm_set_drvdata(rtd, pcm_data); | 627 | snd_soc_pcm_set_drvdata(rtd, pcm_data); |
601 | pcm_data->substream = substream; | 628 | pcm_data->substream = substream; |
@@ -606,16 +633,12 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) | |||
606 | hsw_notify_pointer, pcm_data); | 633 | hsw_notify_pointer, pcm_data); |
607 | if (pcm_data->stream == NULL) { | 634 | if (pcm_data->stream == NULL) { |
608 | dev_err(rtd->dev, "error: failed to create stream\n"); | 635 | dev_err(rtd->dev, "error: failed to create stream\n"); |
636 | pm_runtime_mark_last_busy(pdata->dev); | ||
637 | pm_runtime_put_autosuspend(pdata->dev); | ||
609 | mutex_unlock(&pcm_data->mutex); | 638 | mutex_unlock(&pcm_data->mutex); |
610 | return -EINVAL; | 639 | return -EINVAL; |
611 | } | 640 | } |
612 | 641 | ||
613 | /* Set previous saved volume */ | ||
614 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
615 | 0, pcm_data->volume[0]); | ||
616 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
617 | 1, pcm_data->volume[1]); | ||
618 | |||
619 | mutex_unlock(&pcm_data->mutex); | 642 | mutex_unlock(&pcm_data->mutex); |
620 | return 0; | 643 | return 0; |
621 | } | 644 | } |
@@ -645,6 +668,8 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) | |||
645 | pcm_data->stream = NULL; | 668 | pcm_data->stream = NULL; |
646 | 669 | ||
647 | out: | 670 | out: |
671 | pm_runtime_mark_last_busy(pdata->dev); | ||
672 | pm_runtime_put_autosuspend(pdata->dev); | ||
648 | mutex_unlock(&pcm_data->mutex); | 673 | mutex_unlock(&pcm_data->mutex); |
649 | return ret; | 674 | return ret; |
650 | } | 675 | } |
@@ -660,6 +685,56 @@ static struct snd_pcm_ops hsw_pcm_ops = { | |||
660 | .page = snd_pcm_sgbuf_ops_page, | 685 | .page = snd_pcm_sgbuf_ops_page, |
661 | }; | 686 | }; |
662 | 687 | ||
688 | /* static mappings between PCMs and modules - may be dynamic in future */ | ||
689 | static struct hsw_pcm_module_map mod_map[] = { | ||
690 | {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM}, | ||
691 | {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM}, | ||
692 | {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM}, | ||
693 | {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE}, | ||
694 | {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE}, | ||
695 | }; | ||
696 | |||
697 | static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) | ||
698 | { | ||
699 | struct sst_hsw *hsw = pdata->hsw; | ||
700 | struct hsw_pcm_data *pcm_data; | ||
701 | int i; | ||
702 | |||
703 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { | ||
704 | pcm_data = &pdata->pcm[i]; | ||
705 | |||
706 | /* create new runtime module, use same offset if recreated */ | ||
707 | pcm_data->runtime = sst_hsw_runtime_module_create(hsw, | ||
708 | mod_map[i].mod_id, pcm_data->persistent_offset); | ||
709 | if (pcm_data->runtime == NULL) | ||
710 | goto err; | ||
711 | pcm_data->persistent_offset = | ||
712 | pcm_data->runtime->persistent_offset; | ||
713 | } | ||
714 | |||
715 | return 0; | ||
716 | |||
717 | err: | ||
718 | for (--i; i >= 0; i--) { | ||
719 | pcm_data = &pdata->pcm[i]; | ||
720 | sst_hsw_runtime_module_free(pcm_data->runtime); | ||
721 | } | ||
722 | |||
723 | return -ENODEV; | ||
724 | } | ||
725 | |||
726 | static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) | ||
727 | { | ||
728 | struct hsw_pcm_data *pcm_data; | ||
729 | int i; | ||
730 | |||
731 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { | ||
732 | pcm_data = &pdata->pcm[i]; | ||
733 | |||
734 | sst_hsw_runtime_module_free(pcm_data->runtime); | ||
735 | } | ||
736 | } | ||
737 | |||
663 | static void hsw_pcm_free(struct snd_pcm *pcm) | 738 | static void hsw_pcm_free(struct snd_pcm *pcm) |
664 | { | 739 | { |
665 | snd_pcm_lib_preallocate_free_for_all(pcm); | 740 | snd_pcm_lib_preallocate_free_for_all(pcm); |
@@ -670,6 +745,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
670 | struct snd_pcm *pcm = rtd->pcm; | 745 | struct snd_pcm *pcm = rtd->pcm; |
671 | struct snd_soc_platform *platform = rtd->platform; | 746 | struct snd_soc_platform *platform = rtd->platform; |
672 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | 747 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); |
748 | struct hsw_priv_data *priv_data = dev_get_drvdata(platform->dev); | ||
673 | struct device *dev = pdata->dma_dev; | 749 | struct device *dev = pdata->dma_dev; |
674 | int ret = 0; | 750 | int ret = 0; |
675 | 751 | ||
@@ -686,6 +762,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
686 | return ret; | 762 | return ret; |
687 | } | 763 | } |
688 | } | 764 | } |
765 | priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm; | ||
689 | 766 | ||
690 | return ret; | 767 | return ret; |
691 | } | 768 | } |
@@ -696,6 +773,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
696 | static struct snd_soc_dai_driver hsw_dais[] = { | 773 | static struct snd_soc_dai_driver hsw_dais[] = { |
697 | { | 774 | { |
698 | .name = "System Pin", | 775 | .name = "System Pin", |
776 | .id = HSW_PCM_DAI_ID_SYSTEM, | ||
699 | .playback = { | 777 | .playback = { |
700 | .stream_name = "System Playback", | 778 | .stream_name = "System Playback", |
701 | .channels_min = 2, | 779 | .channels_min = 2, |
@@ -703,10 +781,18 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
703 | .rates = SNDRV_PCM_RATE_48000, | 781 | .rates = SNDRV_PCM_RATE_48000, |
704 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, | 782 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, |
705 | }, | 783 | }, |
784 | .capture = { | ||
785 | .stream_name = "Analog Capture", | ||
786 | .channels_min = 2, | ||
787 | .channels_max = 4, | ||
788 | .rates = SNDRV_PCM_RATE_48000, | ||
789 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, | ||
790 | }, | ||
706 | }, | 791 | }, |
707 | { | 792 | { |
708 | /* PCM */ | 793 | /* PCM */ |
709 | .name = "Offload0 Pin", | 794 | .name = "Offload0 Pin", |
795 | .id = HSW_PCM_DAI_ID_OFFLOAD0, | ||
710 | .playback = { | 796 | .playback = { |
711 | .stream_name = "Offload0 Playback", | 797 | .stream_name = "Offload0 Playback", |
712 | .channels_min = 2, | 798 | .channels_min = 2, |
@@ -718,6 +804,7 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
718 | { | 804 | { |
719 | /* PCM */ | 805 | /* PCM */ |
720 | .name = "Offload1 Pin", | 806 | .name = "Offload1 Pin", |
807 | .id = HSW_PCM_DAI_ID_OFFLOAD1, | ||
721 | .playback = { | 808 | .playback = { |
722 | .stream_name = "Offload1 Playback", | 809 | .stream_name = "Offload1 Playback", |
723 | .channels_min = 2, | 810 | .channels_min = 2, |
@@ -728,6 +815,7 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
728 | }, | 815 | }, |
729 | { | 816 | { |
730 | .name = "Loopback Pin", | 817 | .name = "Loopback Pin", |
818 | .id = HSW_PCM_DAI_ID_LOOPBACK, | ||
731 | .capture = { | 819 | .capture = { |
732 | .stream_name = "Loopback Capture", | 820 | .stream_name = "Loopback Capture", |
733 | .channels_min = 2, | 821 | .channels_min = 2, |
@@ -736,16 +824,6 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
736 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, | 824 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, |
737 | }, | 825 | }, |
738 | }, | 826 | }, |
739 | { | ||
740 | .name = "Capture Pin", | ||
741 | .capture = { | ||
742 | .stream_name = "Analog Capture", | ||
743 | .channels_min = 2, | ||
744 | .channels_max = 2, | ||
745 | .rates = SNDRV_PCM_RATE_48000, | ||
746 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, | ||
747 | }, | ||
748 | }, | ||
749 | }; | 827 | }; |
750 | 828 | ||
751 | static const struct snd_soc_dapm_widget widgets[] = { | 829 | static const struct snd_soc_dapm_widget widgets[] = { |
@@ -776,9 +854,20 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
776 | { | 854 | { |
777 | struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform); | 855 | struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform); |
778 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | 856 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); |
779 | struct device *dma_dev = pdata->dma_dev; | 857 | struct device *dma_dev, *dev; |
780 | int i, ret = 0; | 858 | int i, ret = 0; |
781 | 859 | ||
860 | if (!pdata) | ||
861 | return -ENODEV; | ||
862 | |||
863 | dev = platform->dev; | ||
864 | dma_dev = pdata->dma_dev; | ||
865 | |||
866 | priv_data->hsw = pdata->dsp; | ||
867 | priv_data->dev = platform->dev; | ||
868 | priv_data->pm_state = HSW_PM_STATE_D0; | ||
869 | priv_data->soc_card = platform->component.card; | ||
870 | |||
782 | /* allocate DSP buffer page tables */ | 871 | /* allocate DSP buffer page tables */ |
783 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | 872 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { |
784 | 873 | ||
@@ -801,6 +890,16 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
801 | } | 890 | } |
802 | } | 891 | } |
803 | 892 | ||
893 | /* allocate runtime modules */ | ||
894 | hsw_pcm_create_modules(priv_data); | ||
895 | |||
896 | /* enable runtime PM with auto suspend */ | ||
897 | pm_runtime_set_autosuspend_delay(platform->dev, | ||
898 | SST_RUNTIME_SUSPEND_DELAY); | ||
899 | pm_runtime_use_autosuspend(platform->dev); | ||
900 | pm_runtime_enable(platform->dev); | ||
901 | pm_runtime_idle(platform->dev); | ||
902 | |||
804 | return 0; | 903 | return 0; |
805 | 904 | ||
806 | err: | 905 | err: |
@@ -819,6 +918,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform) | |||
819 | snd_soc_platform_get_drvdata(platform); | 918 | snd_soc_platform_get_drvdata(platform); |
820 | int i; | 919 | int i; |
821 | 920 | ||
921 | pm_runtime_disable(platform->dev); | ||
922 | hsw_pcm_free_modules(priv_data); | ||
923 | |||
822 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | 924 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { |
823 | if (hsw_dais[i].playback.channels_min) | 925 | if (hsw_dais[i].playback.channels_min) |
824 | snd_dma_free_pages(&priv_data->dmab[i][0]); | 926 | snd_dma_free_pages(&priv_data->dmab[i][0]); |
@@ -896,10 +998,181 @@ static int hsw_pcm_dev_remove(struct platform_device *pdev) | |||
896 | return 0; | 998 | return 0; |
897 | } | 999 | } |
898 | 1000 | ||
1001 | #ifdef CONFIG_PM_RUNTIME | ||
1002 | |||
1003 | static int hsw_pcm_runtime_idle(struct device *dev) | ||
1004 | { | ||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | static int hsw_pcm_runtime_suspend(struct device *dev) | ||
1009 | { | ||
1010 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | ||
1011 | struct sst_hsw *hsw = pdata->hsw; | ||
1012 | |||
1013 | if (pdata->pm_state == HSW_PM_STATE_D3) | ||
1014 | return 0; | ||
1015 | |||
1016 | sst_hsw_dsp_runtime_suspend(hsw); | ||
1017 | sst_hsw_dsp_runtime_sleep(hsw); | ||
1018 | pdata->pm_state = HSW_PM_STATE_D3; | ||
1019 | |||
1020 | return 0; | ||
1021 | } | ||
1022 | |||
1023 | static int hsw_pcm_runtime_resume(struct device *dev) | ||
1024 | { | ||
1025 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | ||
1026 | struct sst_hsw *hsw = pdata->hsw; | ||
1027 | int ret; | ||
1028 | |||
1029 | if (pdata->pm_state == HSW_PM_STATE_D0) | ||
1030 | return 0; | ||
1031 | |||
1032 | ret = sst_hsw_dsp_load(hsw); | ||
1033 | if (ret < 0) { | ||
1034 | dev_err(dev, "failed to reload %d\n", ret); | ||
1035 | return ret; | ||
1036 | } | ||
1037 | |||
1038 | ret = hsw_pcm_create_modules(pdata); | ||
1039 | if (ret < 0) { | ||
1040 | dev_err(dev, "failed to create modules %d\n", ret); | ||
1041 | return ret; | ||
1042 | } | ||
1043 | |||
1044 | ret = sst_hsw_dsp_runtime_resume(hsw); | ||
1045 | if (ret < 0) | ||
1046 | return ret; | ||
1047 | else if (ret == 1) /* no action required */ | ||
1048 | return 0; | ||
1049 | |||
1050 | pdata->pm_state = HSW_PM_STATE_D0; | ||
1051 | return ret; | ||
1052 | } | ||
1053 | |||
1054 | #else | ||
1055 | #define hsw_pcm_runtime_idle NULL | ||
1056 | #define hsw_pcm_runtime_suspend NULL | ||
1057 | #define hsw_pcm_runtime_resume NULL | ||
1058 | #endif | ||
1059 | |||
1060 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_RUNTIME) | ||
1061 | |||
1062 | static void hsw_pcm_complete(struct device *dev) | ||
1063 | { | ||
1064 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | ||
1065 | struct sst_hsw *hsw = pdata->hsw; | ||
1066 | struct hsw_pcm_data *pcm_data; | ||
1067 | int i, err; | ||
1068 | |||
1069 | if (pdata->pm_state == HSW_PM_STATE_D0) | ||
1070 | return; | ||
1071 | |||
1072 | err = sst_hsw_dsp_load(hsw); | ||
1073 | if (err < 0) { | ||
1074 | dev_err(dev, "failed to reload %d\n", err); | ||
1075 | return; | ||
1076 | } | ||
1077 | |||
1078 | err = hsw_pcm_create_modules(pdata); | ||
1079 | if (err < 0) { | ||
1080 | dev_err(dev, "failed to create modules %d\n", err); | ||
1081 | return; | ||
1082 | } | ||
1083 | |||
1084 | for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { | ||
1085 | pcm_data = &pdata->pcm[i]; | ||
1086 | |||
1087 | if (!pcm_data->substream) | ||
1088 | continue; | ||
1089 | |||
1090 | err = sst_module_runtime_restore(pcm_data->runtime, | ||
1091 | &pcm_data->context); | ||
1092 | if (err < 0) | ||
1093 | dev_err(dev, "failed to restore context for PCM %d\n", i); | ||
1094 | } | ||
1095 | |||
1096 | snd_soc_resume(pdata->soc_card->dev); | ||
1097 | |||
1098 | err = sst_hsw_dsp_runtime_resume(hsw); | ||
1099 | if (err < 0) | ||
1100 | return; | ||
1101 | else if (err == 1) /* no action required */ | ||
1102 | return; | ||
1103 | |||
1104 | pdata->pm_state = HSW_PM_STATE_D0; | ||
1105 | return; | ||
1106 | } | ||
1107 | |||
1108 | static int hsw_pcm_prepare(struct device *dev) | ||
1109 | { | ||
1110 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | ||
1111 | struct sst_hsw *hsw = pdata->hsw; | ||
1112 | struct hsw_pcm_data *pcm_data; | ||
1113 | int i, err; | ||
1114 | |||
1115 | if (pdata->pm_state == HSW_PM_STATE_D3) | ||
1116 | return 0; | ||
1117 | /* suspend all active streams */ | ||
1118 | for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { | ||
1119 | pcm_data = &pdata->pcm[i]; | ||
1120 | |||
1121 | if (!pcm_data->substream) | ||
1122 | continue; | ||
1123 | dev_dbg(dev, "suspending pcm %d\n", i); | ||
1124 | snd_pcm_suspend_all(pcm_data->hsw_pcm); | ||
1125 | |||
1126 | /* We need to wait until the DSP FW stops the streams */ | ||
1127 | msleep(2); | ||
1128 | } | ||
1129 | |||
1130 | snd_soc_suspend(pdata->soc_card->dev); | ||
1131 | snd_soc_poweroff(pdata->soc_card->dev); | ||
1132 | |||
1133 | /* enter D3 state and stall */ | ||
1134 | sst_hsw_dsp_runtime_suspend(hsw); | ||
1135 | |||
1136 | /* preserve persistent memory */ | ||
1137 | for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { | ||
1138 | pcm_data = &pdata->pcm[i]; | ||
1139 | |||
1140 | if (!pcm_data->substream) | ||
1141 | continue; | ||
1142 | |||
1143 | dev_dbg(dev, "saving context pcm %d\n", i); | ||
1144 | err = sst_module_runtime_save(pcm_data->runtime, | ||
1145 | &pcm_data->context); | ||
1146 | if (err < 0) | ||
1147 | dev_err(dev, "failed to save context for PCM %d\n", i); | ||
1148 | } | ||
1149 | |||
1150 | /* put the DSP to sleep */ | ||
1151 | sst_hsw_dsp_runtime_sleep(hsw); | ||
1152 | pdata->pm_state = HSW_PM_STATE_D3; | ||
1153 | |||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | #else | ||
1158 | #define hsw_pcm_prepare NULL | ||
1159 | #define hsw_pcm_complete NULL | ||
1160 | #endif | ||
1161 | |||
1162 | static const struct dev_pm_ops hsw_pcm_pm = { | ||
1163 | .runtime_idle = hsw_pcm_runtime_idle, | ||
1164 | .runtime_suspend = hsw_pcm_runtime_suspend, | ||
1165 | .runtime_resume = hsw_pcm_runtime_resume, | ||
1166 | .prepare = hsw_pcm_prepare, | ||
1167 | .complete = hsw_pcm_complete, | ||
1168 | }; | ||
1169 | |||
899 | static struct platform_driver hsw_pcm_driver = { | 1170 | static struct platform_driver hsw_pcm_driver = { |
900 | .driver = { | 1171 | .driver = { |
901 | .name = "haswell-pcm-audio", | 1172 | .name = "haswell-pcm-audio", |
902 | .owner = THIS_MODULE, | 1173 | .owner = THIS_MODULE, |
1174 | .pm = &hsw_pcm_pm, | ||
1175 | |||
903 | }, | 1176 | }, |
904 | 1177 | ||
905 | .probe = hsw_pcm_dev_probe, | 1178 | .probe = hsw_pcm_dev_probe, |
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c index 59467775c9b8..395168986462 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/sst-mfld-platform-compress.c | |||
@@ -67,8 +67,11 @@ static int sst_platform_compr_open(struct snd_compr_stream *cstream) | |||
67 | goto out_ops; | 67 | goto out_ops; |
68 | } | 68 | } |
69 | stream->compr_ops = sst->compr_ops; | 69 | stream->compr_ops = sst->compr_ops; |
70 | |||
71 | stream->id = 0; | 70 | stream->id = 0; |
71 | |||
72 | /* Turn on LPE */ | ||
73 | sst->compr_ops->power(sst->dev, true); | ||
74 | |||
72 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | 75 | sst_set_stream_status(stream, SST_PLATFORM_INIT); |
73 | runtime->private_data = stream; | 76 | runtime->private_data = stream; |
74 | return 0; | 77 | return 0; |
@@ -83,6 +86,9 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream) | |||
83 | int ret_val = 0, str_id; | 86 | int ret_val = 0, str_id; |
84 | 87 | ||
85 | stream = cstream->runtime->private_data; | 88 | stream = cstream->runtime->private_data; |
89 | /* Turn off LPE */ | ||
90 | sst->compr_ops->power(sst->dev, false); | ||
91 | |||
86 | /*need to check*/ | 92 | /*need to check*/ |
87 | str_id = stream->id; | 93 | str_id = stream->id; |
88 | if (str_id) | 94 | if (str_id) |
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index aa9b600dfc9b..6032f18693be 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c | |||
@@ -101,35 +101,11 @@ static struct sst_dev_stream_map dpcm_strm_map[] = { | |||
101 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0}, | 101 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0}, |
102 | }; | 102 | }; |
103 | 103 | ||
104 | /* MFLD - MSIC */ | 104 | static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream) |
105 | static struct snd_soc_dai_driver sst_platform_dai[] = { | ||
106 | { | 105 | { |
107 | .name = "Headset-cpu-dai", | 106 | |
108 | .id = 0, | 107 | return sst_send_pipe_gains(dai, stream, mute); |
109 | .playback = { | 108 | } |
110 | .channels_min = SST_STEREO, | ||
111 | .channels_max = SST_STEREO, | ||
112 | .rates = SNDRV_PCM_RATE_48000, | ||
113 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
114 | }, | ||
115 | .capture = { | ||
116 | .channels_min = 1, | ||
117 | .channels_max = 5, | ||
118 | .rates = SNDRV_PCM_RATE_48000, | ||
119 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
120 | }, | ||
121 | }, | ||
122 | { | ||
123 | .name = "Compress-cpu-dai", | ||
124 | .compress_dai = 1, | ||
125 | .playback = { | ||
126 | .channels_min = SST_STEREO, | ||
127 | .channels_max = SST_STEREO, | ||
128 | .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, | ||
129 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
130 | }, | ||
131 | }, | ||
132 | }; | ||
133 | 109 | ||
134 | /* helper functions */ | 110 | /* helper functions */ |
135 | void sst_set_stream_status(struct sst_runtime_stream *stream, | 111 | void sst_set_stream_status(struct sst_runtime_stream *stream, |
@@ -451,12 +427,133 @@ static int sst_media_hw_free(struct snd_pcm_substream *substream, | |||
451 | return snd_pcm_lib_free_pages(substream); | 427 | return snd_pcm_lib_free_pages(substream); |
452 | } | 428 | } |
453 | 429 | ||
430 | static int sst_enable_ssp(struct snd_pcm_substream *substream, | ||
431 | struct snd_soc_dai *dai) | ||
432 | { | ||
433 | int ret = 0; | ||
434 | |||
435 | if (!dai->active) { | ||
436 | ret = sst_handle_vb_timer(dai, true); | ||
437 | if (ret) | ||
438 | return ret; | ||
439 | ret = send_ssp_cmd(dai, dai->name, 1); | ||
440 | } | ||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | static void sst_disable_ssp(struct snd_pcm_substream *substream, | ||
445 | struct snd_soc_dai *dai) | ||
446 | { | ||
447 | if (!dai->active) { | ||
448 | send_ssp_cmd(dai, dai->name, 0); | ||
449 | sst_handle_vb_timer(dai, false); | ||
450 | } | ||
451 | } | ||
452 | |||
454 | static struct snd_soc_dai_ops sst_media_dai_ops = { | 453 | static struct snd_soc_dai_ops sst_media_dai_ops = { |
455 | .startup = sst_media_open, | 454 | .startup = sst_media_open, |
456 | .shutdown = sst_media_close, | 455 | .shutdown = sst_media_close, |
457 | .prepare = sst_media_prepare, | 456 | .prepare = sst_media_prepare, |
458 | .hw_params = sst_media_hw_params, | 457 | .hw_params = sst_media_hw_params, |
459 | .hw_free = sst_media_hw_free, | 458 | .hw_free = sst_media_hw_free, |
459 | .mute_stream = sst_media_digital_mute, | ||
460 | }; | ||
461 | |||
462 | static struct snd_soc_dai_ops sst_compr_dai_ops = { | ||
463 | .mute_stream = sst_media_digital_mute, | ||
464 | }; | ||
465 | |||
466 | static struct snd_soc_dai_ops sst_be_dai_ops = { | ||
467 | .startup = sst_enable_ssp, | ||
468 | .shutdown = sst_disable_ssp, | ||
469 | }; | ||
470 | |||
471 | static struct snd_soc_dai_driver sst_platform_dai[] = { | ||
472 | { | ||
473 | .name = "media-cpu-dai", | ||
474 | .ops = &sst_media_dai_ops, | ||
475 | .playback = { | ||
476 | .stream_name = "Headset Playback", | ||
477 | .channels_min = SST_STEREO, | ||
478 | .channels_max = SST_STEREO, | ||
479 | .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, | ||
480 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
481 | }, | ||
482 | .capture = { | ||
483 | .stream_name = "Headset Capture", | ||
484 | .channels_min = 1, | ||
485 | .channels_max = 2, | ||
486 | .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, | ||
487 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
488 | }, | ||
489 | }, | ||
490 | { | ||
491 | .name = "compress-cpu-dai", | ||
492 | .compress_dai = 1, | ||
493 | .ops = &sst_compr_dai_ops, | ||
494 | .playback = { | ||
495 | .stream_name = "Compress Playback", | ||
496 | .channels_min = SST_STEREO, | ||
497 | .channels_max = SST_STEREO, | ||
498 | .rates = SNDRV_PCM_RATE_48000, | ||
499 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
500 | }, | ||
501 | }, | ||
502 | /* BE CPU Dais */ | ||
503 | { | ||
504 | .name = "ssp0-port", | ||
505 | .ops = &sst_be_dai_ops, | ||
506 | .playback = { | ||
507 | .stream_name = "ssp0 Tx", | ||
508 | .channels_min = SST_STEREO, | ||
509 | .channels_max = SST_STEREO, | ||
510 | .rates = SNDRV_PCM_RATE_48000, | ||
511 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
512 | }, | ||
513 | .capture = { | ||
514 | .stream_name = "ssp0 Rx", | ||
515 | .channels_min = SST_STEREO, | ||
516 | .channels_max = SST_STEREO, | ||
517 | .rates = SNDRV_PCM_RATE_48000, | ||
518 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
519 | }, | ||
520 | }, | ||
521 | { | ||
522 | .name = "ssp1-port", | ||
523 | .ops = &sst_be_dai_ops, | ||
524 | .playback = { | ||
525 | .stream_name = "ssp1 Tx", | ||
526 | .channels_min = SST_STEREO, | ||
527 | .channels_max = SST_STEREO, | ||
528 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, | ||
529 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
530 | }, | ||
531 | .capture = { | ||
532 | .stream_name = "ssp1 Rx", | ||
533 | .channels_min = SST_STEREO, | ||
534 | .channels_max = SST_STEREO, | ||
535 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, | ||
536 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
537 | }, | ||
538 | }, | ||
539 | { | ||
540 | .name = "ssp2-port", | ||
541 | .ops = &sst_be_dai_ops, | ||
542 | .playback = { | ||
543 | .stream_name = "ssp2 Tx", | ||
544 | .channels_min = SST_STEREO, | ||
545 | .channels_max = SST_STEREO, | ||
546 | .rates = SNDRV_PCM_RATE_48000, | ||
547 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
548 | }, | ||
549 | .capture = { | ||
550 | .stream_name = "ssp2 Rx", | ||
551 | .channels_min = SST_STEREO, | ||
552 | .channels_max = SST_STEREO, | ||
553 | .rates = SNDRV_PCM_RATE_48000, | ||
554 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
555 | }, | ||
556 | }, | ||
460 | }; | 557 | }; |
461 | 558 | ||
462 | static int sst_platform_open(struct snd_pcm_substream *substream) | 559 | static int sst_platform_open(struct snd_pcm_substream *substream) |
@@ -609,6 +706,7 @@ static int sst_platform_probe(struct platform_device *pdev) | |||
609 | pdata->pdev_strm_map = dpcm_strm_map; | 706 | pdata->pdev_strm_map = dpcm_strm_map; |
610 | pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map); | 707 | pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map); |
611 | drv->pdata = pdata; | 708 | drv->pdata = pdata; |
709 | drv->pdev = pdev; | ||
612 | mutex_init(&drv->lock); | 710 | mutex_init(&drv->lock); |
613 | dev_set_drvdata(&pdev->dev, drv); | 711 | dev_set_drvdata(&pdev->dev, drv); |
614 | 712 | ||
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 19f83ec51613..79c8d1246a8f 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h | |||
@@ -117,6 +117,7 @@ struct compress_sst_ops { | |||
117 | int (*get_codec_caps)(struct snd_compr_codec_caps *codec); | 117 | int (*get_codec_caps)(struct snd_compr_codec_caps *codec); |
118 | int (*set_metadata)(struct device *dev, unsigned int str_id, | 118 | int (*set_metadata)(struct device *dev, unsigned int str_id, |
119 | struct snd_compr_metadata *mdata); | 119 | struct snd_compr_metadata *mdata); |
120 | int (*power)(struct device *dev, bool state); | ||
120 | }; | 121 | }; |
121 | 122 | ||
122 | struct sst_ops { | 123 | struct sst_ops { |
@@ -153,6 +154,10 @@ struct sst_device { | |||
153 | struct sst_data; | 154 | struct sst_data; |
154 | 155 | ||
155 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); | 156 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); |
157 | int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute); | ||
158 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable); | ||
159 | int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable); | ||
160 | |||
156 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); | 161 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); |
157 | int sst_fill_stream_params(void *substream, const struct sst_data *ctx, | 162 | int sst_fill_stream_params(void *substream, const struct sst_data *ctx, |
158 | struct snd_sst_params *str_params, bool is_compress); | 163 | struct snd_sst_params *str_params, bool is_compress); |
diff --git a/sound/soc/intel/sst/Makefile b/sound/soc/intel/sst/Makefile new file mode 100644 index 000000000000..fd21726361b5 --- /dev/null +++ b/sound/soc/intel/sst/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | snd-intel-sst-core-objs := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o | ||
2 | snd-intel-sst-pci-objs += sst_pci.o | ||
3 | snd-intel-sst-acpi-objs += sst_acpi.o | ||
4 | |||
5 | obj-$(CONFIG_SND_SST_IPC) += snd-intel-sst-core.o | ||
6 | obj-$(CONFIG_SND_SST_IPC_PCI) += snd-intel-sst-pci.o | ||
7 | obj-$(CONFIG_SND_SST_IPC_ACPI) += snd-intel-sst-acpi.o | ||
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c new file mode 100644 index 000000000000..8a8d56a146e7 --- /dev/null +++ b/sound/soc/intel/sst/sst.c | |||
@@ -0,0 +1,437 @@ | |||
1 | /* | ||
2 | * sst.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/pm_qos.h> | ||
28 | #include <linux/async.h> | ||
29 | #include <linux/acpi.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <asm/platform_sst_audio.h> | ||
33 | #include "../sst-mfld-platform.h" | ||
34 | #include "sst.h" | ||
35 | #include "../sst-dsp.h" | ||
36 | |||
37 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | ||
38 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | ||
39 | MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine Driver"); | ||
40 | MODULE_LICENSE("GPL v2"); | ||
41 | |||
42 | static inline bool sst_is_process_reply(u32 msg_id) | ||
43 | { | ||
44 | return ((msg_id & PROCESS_MSG) ? true : false); | ||
45 | } | ||
46 | |||
47 | static inline bool sst_validate_mailbox_size(unsigned int size) | ||
48 | { | ||
49 | return ((size <= SST_MAILBOX_SIZE) ? true : false); | ||
50 | } | ||
51 | |||
52 | static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context) | ||
53 | { | ||
54 | union interrupt_reg_mrfld isr; | ||
55 | union ipc_header_mrfld header; | ||
56 | union sst_imr_reg_mrfld imr; | ||
57 | struct ipc_post *msg = NULL; | ||
58 | unsigned int size = 0; | ||
59 | struct intel_sst_drv *drv = (struct intel_sst_drv *) context; | ||
60 | irqreturn_t retval = IRQ_HANDLED; | ||
61 | |||
62 | /* Interrupt arrived, check src */ | ||
63 | isr.full = sst_shim_read64(drv->shim, SST_ISRX); | ||
64 | |||
65 | if (isr.part.done_interrupt) { | ||
66 | /* Clear done bit */ | ||
67 | spin_lock(&drv->ipc_spin_lock); | ||
68 | header.full = sst_shim_read64(drv->shim, | ||
69 | drv->ipc_reg.ipcx); | ||
70 | header.p.header_high.part.done = 0; | ||
71 | sst_shim_write64(drv->shim, drv->ipc_reg.ipcx, header.full); | ||
72 | |||
73 | /* write 1 to clear status register */; | ||
74 | isr.part.done_interrupt = 1; | ||
75 | sst_shim_write64(drv->shim, SST_ISRX, isr.full); | ||
76 | spin_unlock(&drv->ipc_spin_lock); | ||
77 | |||
78 | /* we can send more messages to DSP so trigger work */ | ||
79 | queue_work(drv->post_msg_wq, &drv->ipc_post_msg_wq); | ||
80 | retval = IRQ_HANDLED; | ||
81 | } | ||
82 | |||
83 | if (isr.part.busy_interrupt) { | ||
84 | /* message from dsp so copy that */ | ||
85 | spin_lock(&drv->ipc_spin_lock); | ||
86 | imr.full = sst_shim_read64(drv->shim, SST_IMRX); | ||
87 | imr.part.busy_interrupt = 1; | ||
88 | sst_shim_write64(drv->shim, SST_IMRX, imr.full); | ||
89 | spin_unlock(&drv->ipc_spin_lock); | ||
90 | header.full = sst_shim_read64(drv->shim, drv->ipc_reg.ipcd); | ||
91 | |||
92 | if (sst_create_ipc_msg(&msg, header.p.header_high.part.large)) { | ||
93 | drv->ops->clear_interrupt(drv); | ||
94 | return IRQ_HANDLED; | ||
95 | } | ||
96 | |||
97 | if (header.p.header_high.part.large) { | ||
98 | size = header.p.header_low_payload; | ||
99 | if (sst_validate_mailbox_size(size)) { | ||
100 | memcpy_fromio(msg->mailbox_data, | ||
101 | drv->mailbox + drv->mailbox_recv_offset, size); | ||
102 | } else { | ||
103 | dev_err(drv->dev, | ||
104 | "Mailbox not copied, payload size is: %u\n", size); | ||
105 | header.p.header_low_payload = 0; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | msg->mrfld_header = header; | ||
110 | msg->is_process_reply = | ||
111 | sst_is_process_reply(header.p.header_high.part.msg_id); | ||
112 | spin_lock(&drv->rx_msg_lock); | ||
113 | list_add_tail(&msg->node, &drv->rx_list); | ||
114 | spin_unlock(&drv->rx_msg_lock); | ||
115 | drv->ops->clear_interrupt(drv); | ||
116 | retval = IRQ_WAKE_THREAD; | ||
117 | } | ||
118 | return retval; | ||
119 | } | ||
120 | |||
121 | static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context) | ||
122 | { | ||
123 | struct intel_sst_drv *drv = (struct intel_sst_drv *) context; | ||
124 | struct ipc_post *__msg, *msg = NULL; | ||
125 | unsigned long irq_flags; | ||
126 | |||
127 | spin_lock_irqsave(&drv->rx_msg_lock, irq_flags); | ||
128 | if (list_empty(&drv->rx_list)) { | ||
129 | spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags); | ||
130 | return IRQ_HANDLED; | ||
131 | } | ||
132 | |||
133 | list_for_each_entry_safe(msg, __msg, &drv->rx_list, node) { | ||
134 | list_del(&msg->node); | ||
135 | spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags); | ||
136 | if (msg->is_process_reply) | ||
137 | drv->ops->process_message(msg); | ||
138 | else | ||
139 | drv->ops->process_reply(drv, msg); | ||
140 | |||
141 | if (msg->is_large) | ||
142 | kfree(msg->mailbox_data); | ||
143 | kfree(msg); | ||
144 | spin_lock_irqsave(&drv->rx_msg_lock, irq_flags); | ||
145 | } | ||
146 | spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags); | ||
147 | return IRQ_HANDLED; | ||
148 | } | ||
149 | |||
150 | static int sst_save_dsp_context_v2(struct intel_sst_drv *sst) | ||
151 | { | ||
152 | int ret = 0; | ||
153 | |||
154 | ret = sst_prepare_and_post_msg(sst, SST_TASK_ID_MEDIA, IPC_CMD, | ||
155 | IPC_PREP_D3, PIPE_RSVD, 0, NULL, NULL, | ||
156 | true, true, false, true); | ||
157 | |||
158 | if (ret < 0) { | ||
159 | dev_err(sst->dev, "not suspending FW!!, Err: %d\n", ret); | ||
160 | return -EIO; | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | |||
167 | static struct intel_sst_ops mrfld_ops = { | ||
168 | .interrupt = intel_sst_interrupt_mrfld, | ||
169 | .irq_thread = intel_sst_irq_thread_mrfld, | ||
170 | .clear_interrupt = intel_sst_clear_intr_mrfld, | ||
171 | .start = sst_start_mrfld, | ||
172 | .reset = intel_sst_reset_dsp_mrfld, | ||
173 | .post_message = sst_post_message_mrfld, | ||
174 | .process_reply = sst_process_reply_mrfld, | ||
175 | .save_dsp_context = sst_save_dsp_context_v2, | ||
176 | .alloc_stream = sst_alloc_stream_mrfld, | ||
177 | .post_download = sst_post_download_mrfld, | ||
178 | }; | ||
179 | |||
180 | int sst_driver_ops(struct intel_sst_drv *sst) | ||
181 | { | ||
182 | |||
183 | switch (sst->dev_id) { | ||
184 | case SST_MRFLD_PCI_ID: | ||
185 | case SST_BYT_ACPI_ID: | ||
186 | case SST_CHV_ACPI_ID: | ||
187 | sst->tstamp = SST_TIME_STAMP_MRFLD; | ||
188 | sst->ops = &mrfld_ops; | ||
189 | return 0; | ||
190 | |||
191 | default: | ||
192 | dev_err(sst->dev, | ||
193 | "SST Driver capablities missing for dev_id: %x", sst->dev_id); | ||
194 | return -EINVAL; | ||
195 | }; | ||
196 | } | ||
197 | |||
198 | void sst_process_pending_msg(struct work_struct *work) | ||
199 | { | ||
200 | struct intel_sst_drv *ctx = container_of(work, | ||
201 | struct intel_sst_drv, ipc_post_msg_wq); | ||
202 | |||
203 | ctx->ops->post_message(ctx, NULL, false); | ||
204 | } | ||
205 | |||
206 | static int sst_workqueue_init(struct intel_sst_drv *ctx) | ||
207 | { | ||
208 | INIT_LIST_HEAD(&ctx->memcpy_list); | ||
209 | INIT_LIST_HEAD(&ctx->rx_list); | ||
210 | INIT_LIST_HEAD(&ctx->ipc_dispatch_list); | ||
211 | INIT_LIST_HEAD(&ctx->block_list); | ||
212 | INIT_WORK(&ctx->ipc_post_msg_wq, sst_process_pending_msg); | ||
213 | init_waitqueue_head(&ctx->wait_queue); | ||
214 | |||
215 | ctx->post_msg_wq = | ||
216 | create_singlethread_workqueue("sst_post_msg_wq"); | ||
217 | if (!ctx->post_msg_wq) | ||
218 | return -EBUSY; | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static void sst_init_locks(struct intel_sst_drv *ctx) | ||
223 | { | ||
224 | mutex_init(&ctx->sst_lock); | ||
225 | spin_lock_init(&ctx->rx_msg_lock); | ||
226 | spin_lock_init(&ctx->ipc_spin_lock); | ||
227 | spin_lock_init(&ctx->block_lock); | ||
228 | } | ||
229 | |||
230 | int sst_alloc_drv_context(struct intel_sst_drv **ctx, | ||
231 | struct device *dev, unsigned int dev_id) | ||
232 | { | ||
233 | *ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL); | ||
234 | if (!(*ctx)) | ||
235 | return -ENOMEM; | ||
236 | |||
237 | (*ctx)->dev = dev; | ||
238 | (*ctx)->dev_id = dev_id; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | EXPORT_SYMBOL_GPL(sst_alloc_drv_context); | ||
243 | |||
244 | int sst_context_init(struct intel_sst_drv *ctx) | ||
245 | { | ||
246 | int ret = 0, i; | ||
247 | |||
248 | if (!ctx->pdata) | ||
249 | return -EINVAL; | ||
250 | |||
251 | if (!ctx->pdata->probe_data) | ||
252 | return -EINVAL; | ||
253 | |||
254 | memcpy(&ctx->info, ctx->pdata->probe_data, sizeof(ctx->info)); | ||
255 | |||
256 | ret = sst_driver_ops(ctx); | ||
257 | if (ret != 0) | ||
258 | return -EINVAL; | ||
259 | |||
260 | sst_init_locks(ctx); | ||
261 | sst_set_fw_state_locked(ctx, SST_RESET); | ||
262 | |||
263 | /* pvt_id 0 reserved for async messages */ | ||
264 | ctx->pvt_id = 1; | ||
265 | ctx->stream_cnt = 0; | ||
266 | ctx->fw_in_mem = NULL; | ||
267 | /* we use memcpy, so set to 0 */ | ||
268 | ctx->use_dma = 0; | ||
269 | ctx->use_lli = 0; | ||
270 | |||
271 | if (sst_workqueue_init(ctx)) | ||
272 | return -EINVAL; | ||
273 | |||
274 | ctx->mailbox_recv_offset = ctx->pdata->ipc_info->mbox_recv_off; | ||
275 | ctx->ipc_reg.ipcx = SST_IPCX + ctx->pdata->ipc_info->ipc_offset; | ||
276 | ctx->ipc_reg.ipcd = SST_IPCD + ctx->pdata->ipc_info->ipc_offset; | ||
277 | |||
278 | dev_info(ctx->dev, "Got drv data max stream %d\n", | ||
279 | ctx->info.max_streams); | ||
280 | |||
281 | for (i = 1; i <= ctx->info.max_streams; i++) { | ||
282 | struct stream_info *stream = &ctx->streams[i]; | ||
283 | |||
284 | memset(stream, 0, sizeof(*stream)); | ||
285 | stream->pipe_id = PIPE_RSVD; | ||
286 | mutex_init(&stream->lock); | ||
287 | } | ||
288 | |||
289 | /* Register the ISR */ | ||
290 | ret = devm_request_threaded_irq(ctx->dev, ctx->irq_num, ctx->ops->interrupt, | ||
291 | ctx->ops->irq_thread, 0, SST_DRV_NAME, | ||
292 | ctx); | ||
293 | if (ret) | ||
294 | goto do_free_mem; | ||
295 | |||
296 | dev_dbg(ctx->dev, "Registered IRQ %#x\n", ctx->irq_num); | ||
297 | |||
298 | /* default intr are unmasked so set this as masked */ | ||
299 | sst_shim_write64(ctx->shim, SST_IMRX, 0xFFFF0038); | ||
300 | |||
301 | ctx->qos = devm_kzalloc(ctx->dev, | ||
302 | sizeof(struct pm_qos_request), GFP_KERNEL); | ||
303 | if (!ctx->qos) { | ||
304 | ret = -ENOMEM; | ||
305 | goto do_free_mem; | ||
306 | } | ||
307 | pm_qos_add_request(ctx->qos, PM_QOS_CPU_DMA_LATENCY, | ||
308 | PM_QOS_DEFAULT_VALUE); | ||
309 | |||
310 | dev_dbg(ctx->dev, "Requesting FW %s now...\n", ctx->firmware_name); | ||
311 | ret = request_firmware_nowait(THIS_MODULE, true, ctx->firmware_name, | ||
312 | ctx->dev, GFP_KERNEL, ctx, sst_firmware_load_cb); | ||
313 | if (ret) { | ||
314 | dev_err(ctx->dev, "Firmware download failed:%d\n", ret); | ||
315 | goto do_free_mem; | ||
316 | } | ||
317 | sst_register(ctx->dev); | ||
318 | return 0; | ||
319 | |||
320 | do_free_mem: | ||
321 | destroy_workqueue(ctx->post_msg_wq); | ||
322 | return ret; | ||
323 | } | ||
324 | EXPORT_SYMBOL_GPL(sst_context_init); | ||
325 | |||
326 | void sst_context_cleanup(struct intel_sst_drv *ctx) | ||
327 | { | ||
328 | pm_runtime_get_noresume(ctx->dev); | ||
329 | pm_runtime_disable(ctx->dev); | ||
330 | sst_unregister(ctx->dev); | ||
331 | sst_set_fw_state_locked(ctx, SST_SHUTDOWN); | ||
332 | flush_scheduled_work(); | ||
333 | destroy_workqueue(ctx->post_msg_wq); | ||
334 | pm_qos_remove_request(ctx->qos); | ||
335 | kfree(ctx->fw_sg_list.src); | ||
336 | kfree(ctx->fw_sg_list.dst); | ||
337 | ctx->fw_sg_list.list_len = 0; | ||
338 | kfree(ctx->fw_in_mem); | ||
339 | ctx->fw_in_mem = NULL; | ||
340 | sst_memcpy_free_resources(ctx); | ||
341 | ctx = NULL; | ||
342 | } | ||
343 | EXPORT_SYMBOL_GPL(sst_context_cleanup); | ||
344 | |||
345 | static inline void sst_save_shim64(struct intel_sst_drv *ctx, | ||
346 | void __iomem *shim, | ||
347 | struct sst_shim_regs64 *shim_regs) | ||
348 | { | ||
349 | unsigned long irq_flags; | ||
350 | |||
351 | spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); | ||
352 | |||
353 | shim_regs->imrx = sst_shim_read64(shim, SST_IMRX), | ||
354 | |||
355 | spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); | ||
356 | } | ||
357 | |||
358 | static inline void sst_restore_shim64(struct intel_sst_drv *ctx, | ||
359 | void __iomem *shim, | ||
360 | struct sst_shim_regs64 *shim_regs) | ||
361 | { | ||
362 | unsigned long irq_flags; | ||
363 | |||
364 | /* | ||
365 | * we only need to restore IMRX for this case, rest will be | ||
366 | * initialize by FW or driver when firmware is loaded | ||
367 | */ | ||
368 | spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); | ||
369 | sst_shim_write64(shim, SST_IMRX, shim_regs->imrx), | ||
370 | spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); | ||
371 | } | ||
372 | |||
373 | void sst_configure_runtime_pm(struct intel_sst_drv *ctx) | ||
374 | { | ||
375 | pm_runtime_set_autosuspend_delay(ctx->dev, SST_SUSPEND_DELAY); | ||
376 | pm_runtime_use_autosuspend(ctx->dev); | ||
377 | /* | ||
378 | * For acpi devices, the actual physical device state is | ||
379 | * initially active. So change the state to active before | ||
380 | * enabling the pm | ||
381 | */ | ||
382 | pm_runtime_enable(ctx->dev); | ||
383 | |||
384 | if (acpi_disabled) | ||
385 | pm_runtime_set_active(ctx->dev); | ||
386 | else | ||
387 | pm_runtime_put_noidle(ctx->dev); | ||
388 | |||
389 | sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); | ||
390 | } | ||
391 | EXPORT_SYMBOL_GPL(sst_configure_runtime_pm); | ||
392 | |||
393 | static int intel_sst_runtime_suspend(struct device *dev) | ||
394 | { | ||
395 | int ret = 0; | ||
396 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
397 | |||
398 | if (ctx->sst_state == SST_RESET) { | ||
399 | dev_dbg(dev, "LPE is already in RESET state, No action\n"); | ||
400 | return 0; | ||
401 | } | ||
402 | /* save fw context */ | ||
403 | if (ctx->ops->save_dsp_context(ctx)) | ||
404 | return -EBUSY; | ||
405 | |||
406 | /* Move the SST state to Reset */ | ||
407 | sst_set_fw_state_locked(ctx, SST_RESET); | ||
408 | |||
409 | synchronize_irq(ctx->irq_num); | ||
410 | flush_workqueue(ctx->post_msg_wq); | ||
411 | |||
412 | /* save the shim registers because PMC doesn't save state */ | ||
413 | sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); | ||
414 | |||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | static int intel_sst_runtime_resume(struct device *dev) | ||
419 | { | ||
420 | int ret = 0; | ||
421 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
422 | |||
423 | if (ctx->sst_state == SST_RESET) { | ||
424 | ret = sst_load_fw(ctx); | ||
425 | if (ret) { | ||
426 | dev_err(dev, "FW download fail %d\n", ret); | ||
427 | sst_set_fw_state_locked(ctx, SST_RESET); | ||
428 | } | ||
429 | } | ||
430 | return ret; | ||
431 | } | ||
432 | |||
433 | const struct dev_pm_ops intel_sst_pm = { | ||
434 | .runtime_suspend = intel_sst_runtime_suspend, | ||
435 | .runtime_resume = intel_sst_runtime_resume, | ||
436 | }; | ||
437 | EXPORT_SYMBOL_GPL(intel_sst_pm); | ||
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h new file mode 100644 index 000000000000..7f4bbfcbc6f5 --- /dev/null +++ b/sound/soc/intel/sst/sst.h | |||
@@ -0,0 +1,546 @@ | |||
1 | /* | ||
2 | * sst.h - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corporation | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | * | ||
22 | * Common private declarations for SST | ||
23 | */ | ||
24 | #ifndef __SST_H__ | ||
25 | #define __SST_H__ | ||
26 | |||
27 | #include <linux/firmware.h> | ||
28 | |||
29 | /* driver names */ | ||
30 | #define SST_DRV_NAME "intel_sst_driver" | ||
31 | #define SST_MRFLD_PCI_ID 0x119A | ||
32 | #define SST_BYT_ACPI_ID 0x80860F28 | ||
33 | #define SST_CHV_ACPI_ID 0x808622A8 | ||
34 | |||
35 | #define SST_SUSPEND_DELAY 2000 | ||
36 | #define FW_CONTEXT_MEM (64*1024) | ||
37 | #define SST_ICCM_BOUNDARY 4 | ||
38 | #define SST_CONFIG_SSP_SIGN 0x7ffe8001 | ||
39 | |||
40 | #define MRFLD_FW_VIRTUAL_BASE 0xC0000000 | ||
41 | #define MRFLD_FW_DDR_BASE_OFFSET 0x0 | ||
42 | #define MRFLD_FW_FEATURE_BASE_OFFSET 0x4 | ||
43 | #define MRFLD_FW_BSS_RESET_BIT 0 | ||
44 | |||
45 | extern const struct dev_pm_ops intel_sst_pm; | ||
46 | enum sst_states { | ||
47 | SST_FW_LOADING = 1, | ||
48 | SST_FW_RUNNING, | ||
49 | SST_RESET, | ||
50 | SST_SHUTDOWN, | ||
51 | }; | ||
52 | |||
53 | enum sst_algo_ops { | ||
54 | SST_SET_ALGO = 0, | ||
55 | SST_GET_ALGO = 1, | ||
56 | }; | ||
57 | |||
58 | #define SST_BLOCK_TIMEOUT 1000 | ||
59 | |||
60 | #define FW_SIGNATURE_SIZE 4 | ||
61 | |||
62 | /* stream states */ | ||
63 | enum sst_stream_states { | ||
64 | STREAM_UN_INIT = 0, /* Freed/Not used stream */ | ||
65 | STREAM_RUNNING = 1, /* Running */ | ||
66 | STREAM_PAUSED = 2, /* Paused stream */ | ||
67 | STREAM_DECODE = 3, /* stream is in decoding only state */ | ||
68 | STREAM_INIT = 4, /* stream init, waiting for data */ | ||
69 | STREAM_RESET = 5, /* force reset on recovery */ | ||
70 | }; | ||
71 | |||
72 | enum sst_ram_type { | ||
73 | SST_IRAM = 1, | ||
74 | SST_DRAM = 2, | ||
75 | SST_DDR = 5, | ||
76 | SST_CUSTOM_INFO = 7, /* consists of FW binary information */ | ||
77 | }; | ||
78 | |||
79 | /* SST shim registers to structure mapping */ | ||
80 | union interrupt_reg { | ||
81 | struct { | ||
82 | u64 done_interrupt:1; | ||
83 | u64 busy_interrupt:1; | ||
84 | u64 rsvd:62; | ||
85 | } part; | ||
86 | u64 full; | ||
87 | }; | ||
88 | |||
89 | union sst_pisr_reg { | ||
90 | struct { | ||
91 | u32 pssp0:1; | ||
92 | u32 pssp1:1; | ||
93 | u32 rsvd0:3; | ||
94 | u32 dmac:1; | ||
95 | u32 rsvd1:26; | ||
96 | } part; | ||
97 | u32 full; | ||
98 | }; | ||
99 | |||
100 | union sst_pimr_reg { | ||
101 | struct { | ||
102 | u32 ssp0:1; | ||
103 | u32 ssp1:1; | ||
104 | u32 rsvd0:3; | ||
105 | u32 dmac:1; | ||
106 | u32 rsvd1:10; | ||
107 | u32 ssp0_sc:1; | ||
108 | u32 ssp1_sc:1; | ||
109 | u32 rsvd2:3; | ||
110 | u32 dmac_sc:1; | ||
111 | u32 rsvd3:10; | ||
112 | } part; | ||
113 | u32 full; | ||
114 | }; | ||
115 | |||
116 | union config_status_reg_mrfld { | ||
117 | struct { | ||
118 | u64 lpe_reset:1; | ||
119 | u64 lpe_reset_vector:1; | ||
120 | u64 runstall:1; | ||
121 | u64 pwaitmode:1; | ||
122 | u64 clk_sel:3; | ||
123 | u64 rsvd2:1; | ||
124 | u64 sst_clk:3; | ||
125 | u64 xt_snoop:1; | ||
126 | u64 rsvd3:4; | ||
127 | u64 clk_sel1:6; | ||
128 | u64 clk_enable:3; | ||
129 | u64 rsvd4:6; | ||
130 | u64 slim0baseclk:1; | ||
131 | u64 rsvd:32; | ||
132 | } part; | ||
133 | u64 full; | ||
134 | }; | ||
135 | |||
136 | union interrupt_reg_mrfld { | ||
137 | struct { | ||
138 | u64 done_interrupt:1; | ||
139 | u64 busy_interrupt:1; | ||
140 | u64 rsvd:62; | ||
141 | } part; | ||
142 | u64 full; | ||
143 | }; | ||
144 | |||
145 | union sst_imr_reg_mrfld { | ||
146 | struct { | ||
147 | u64 done_interrupt:1; | ||
148 | u64 busy_interrupt:1; | ||
149 | u64 rsvd:62; | ||
150 | } part; | ||
151 | u64 full; | ||
152 | }; | ||
153 | |||
154 | /** | ||
155 | * struct sst_block - This structure is used to block a user/fw data call to another | ||
156 | * fw/user call | ||
157 | * | ||
158 | * @condition: condition for blocking check | ||
159 | * @ret_code: ret code when block is released | ||
160 | * @data: data ptr | ||
161 | * @size: size of data | ||
162 | * @on: block condition | ||
163 | * @msg_id: msg_id = msgid in mfld/ctp, mrfld = NULL | ||
164 | * @drv_id: str_id in mfld/ctp, = drv_id in mrfld | ||
165 | * @node: list head node | ||
166 | */ | ||
167 | struct sst_block { | ||
168 | bool condition; | ||
169 | int ret_code; | ||
170 | void *data; | ||
171 | u32 size; | ||
172 | bool on; | ||
173 | u32 msg_id; | ||
174 | u32 drv_id; | ||
175 | struct list_head node; | ||
176 | }; | ||
177 | |||
178 | /** | ||
179 | * struct stream_info - structure that holds the stream information | ||
180 | * | ||
181 | * @status : stream current state | ||
182 | * @prev : stream prev state | ||
183 | * @ops : stream operation pb/cp/drm... | ||
184 | * @bufs: stream buffer list | ||
185 | * @lock : stream mutex for protecting state | ||
186 | * @pcm_substream : PCM substream | ||
187 | * @period_elapsed : PCM period elapsed callback | ||
188 | * @sfreq : stream sampling freq | ||
189 | * @str_type : stream type | ||
190 | * @cumm_bytes : cummulative bytes decoded | ||
191 | * @str_type : stream type | ||
192 | * @src : stream source | ||
193 | */ | ||
194 | struct stream_info { | ||
195 | unsigned int status; | ||
196 | unsigned int prev; | ||
197 | unsigned int ops; | ||
198 | struct mutex lock; | ||
199 | |||
200 | void *pcm_substream; | ||
201 | void (*period_elapsed)(void *pcm_substream); | ||
202 | |||
203 | unsigned int sfreq; | ||
204 | u32 cumm_bytes; | ||
205 | |||
206 | void *compr_cb_param; | ||
207 | void (*compr_cb)(void *compr_cb_param); | ||
208 | |||
209 | void *drain_cb_param; | ||
210 | void (*drain_notify)(void *drain_cb_param); | ||
211 | |||
212 | unsigned int num_ch; | ||
213 | unsigned int pipe_id; | ||
214 | unsigned int str_id; | ||
215 | unsigned int task_id; | ||
216 | }; | ||
217 | |||
218 | #define SST_FW_SIGN "$SST" | ||
219 | #define SST_FW_LIB_SIGN "$LIB" | ||
220 | |||
221 | /** | ||
222 | * struct sst_fw_header - FW file headers | ||
223 | * | ||
224 | * @signature : FW signature | ||
225 | * @file_size: size of fw image | ||
226 | * @modules : # of modules | ||
227 | * @file_format : version of header format | ||
228 | * @reserved : reserved fields | ||
229 | */ | ||
230 | struct sst_fw_header { | ||
231 | unsigned char signature[FW_SIGNATURE_SIZE]; | ||
232 | u32 file_size; | ||
233 | u32 modules; | ||
234 | u32 file_format; | ||
235 | u32 reserved[4]; | ||
236 | }; | ||
237 | |||
238 | /** | ||
239 | * struct fw_module_header - module header in FW | ||
240 | * | ||
241 | * @signature: module signature | ||
242 | * @mod_size: size of module | ||
243 | * @blocks: block count | ||
244 | * @type: block type | ||
245 | * @entry_point: module netry point | ||
246 | */ | ||
247 | struct fw_module_header { | ||
248 | unsigned char signature[FW_SIGNATURE_SIZE]; | ||
249 | u32 mod_size; | ||
250 | u32 blocks; | ||
251 | u32 type; | ||
252 | u32 entry_point; | ||
253 | }; | ||
254 | |||
255 | /** | ||
256 | * struct fw_block_info - block header for FW | ||
257 | * | ||
258 | * @type: block ram type I/D | ||
259 | * @size: size of block | ||
260 | * @ram_offset: offset in ram | ||
261 | */ | ||
262 | struct fw_block_info { | ||
263 | enum sst_ram_type type; | ||
264 | u32 size; | ||
265 | u32 ram_offset; | ||
266 | u32 rsvd; | ||
267 | }; | ||
268 | |||
269 | struct sst_runtime_param { | ||
270 | struct snd_sst_runtime_params param; | ||
271 | }; | ||
272 | |||
273 | struct sst_sg_list { | ||
274 | struct scatterlist *src; | ||
275 | struct scatterlist *dst; | ||
276 | int list_len; | ||
277 | unsigned int sg_idx; | ||
278 | }; | ||
279 | |||
280 | struct sst_memcpy_list { | ||
281 | struct list_head memcpylist; | ||
282 | void *dstn; | ||
283 | const void *src; | ||
284 | u32 size; | ||
285 | bool is_io; | ||
286 | }; | ||
287 | |||
288 | /*Firmware Module Information*/ | ||
289 | enum sst_lib_dwnld_status { | ||
290 | SST_LIB_NOT_FOUND = 0, | ||
291 | SST_LIB_FOUND, | ||
292 | SST_LIB_DOWNLOADED, | ||
293 | }; | ||
294 | |||
295 | struct sst_module_info { | ||
296 | const char *name; /*Library name*/ | ||
297 | u32 id; /*Module ID*/ | ||
298 | u32 entry_pt; /*Module entry point*/ | ||
299 | u8 status; /*module status*/ | ||
300 | u8 rsvd1; | ||
301 | u16 rsvd2; | ||
302 | }; | ||
303 | |||
304 | /* | ||
305 | * Structure for managing the Library Region(1.5MB) | ||
306 | * in DDR in Merrifield | ||
307 | */ | ||
308 | struct sst_mem_mgr { | ||
309 | phys_addr_t current_base; | ||
310 | int avail; | ||
311 | unsigned int count; | ||
312 | }; | ||
313 | |||
314 | struct sst_ipc_reg { | ||
315 | int ipcx; | ||
316 | int ipcd; | ||
317 | }; | ||
318 | |||
319 | struct sst_shim_regs64 { | ||
320 | u64 csr; | ||
321 | u64 pisr; | ||
322 | u64 pimr; | ||
323 | u64 isrx; | ||
324 | u64 isrd; | ||
325 | u64 imrx; | ||
326 | u64 imrd; | ||
327 | u64 ipcx; | ||
328 | u64 ipcd; | ||
329 | u64 isrsc; | ||
330 | u64 isrlpesc; | ||
331 | u64 imrsc; | ||
332 | u64 imrlpesc; | ||
333 | u64 ipcsc; | ||
334 | u64 ipclpesc; | ||
335 | u64 clkctl; | ||
336 | u64 csr2; | ||
337 | }; | ||
338 | |||
339 | /** | ||
340 | * struct intel_sst_drv - driver ops | ||
341 | * | ||
342 | * @sst_state : current sst device state | ||
343 | * @dev_id : device identifier, pci_id for pci devices and acpi_id for acpi | ||
344 | * devices | ||
345 | * @shim : SST shim pointer | ||
346 | * @mailbox : SST mailbox pointer | ||
347 | * @iram : SST IRAM pointer | ||
348 | * @dram : SST DRAM pointer | ||
349 | * @pdata : SST info passed as a part of pci platform data | ||
350 | * @shim_phy_add : SST shim phy addr | ||
351 | * @shim_regs64: Struct to save shim registers | ||
352 | * @ipc_dispatch_list : ipc messages dispatched | ||
353 | * @rx_list : to copy the process_reply/process_msg from DSP | ||
354 | * @ipc_post_msg_wq : wq to post IPC messages context | ||
355 | * @mad_ops : MAD driver operations registered | ||
356 | * @mad_wq : MAD driver wq | ||
357 | * @post_msg_wq : wq to post IPC messages | ||
358 | * @streams : sst stream contexts | ||
359 | * @list_lock : sst driver list lock (deprecated) | ||
360 | * @ipc_spin_lock : spin lock to handle audio shim access and ipc queue | ||
361 | * @block_lock : spin lock to add block to block_list and assign pvt_id | ||
362 | * @rx_msg_lock : spin lock to handle the rx messages from the DSP | ||
363 | * @scard_ops : sst card ops | ||
364 | * @pci : sst pci device struture | ||
365 | * @dev : pointer to current device struct | ||
366 | * @sst_lock : sst device lock | ||
367 | * @pvt_id : sst private id | ||
368 | * @stream_cnt : total sst active stream count | ||
369 | * @pb_streams : total active pb streams | ||
370 | * @cp_streams : total active cp streams | ||
371 | * @audio_start : audio status | ||
372 | * @qos : PM Qos struct | ||
373 | * firmware_name : Firmware / Library name | ||
374 | */ | ||
375 | struct intel_sst_drv { | ||
376 | int sst_state; | ||
377 | int irq_num; | ||
378 | unsigned int dev_id; | ||
379 | void __iomem *ddr; | ||
380 | void __iomem *shim; | ||
381 | void __iomem *mailbox; | ||
382 | void __iomem *iram; | ||
383 | void __iomem *dram; | ||
384 | unsigned int mailbox_add; | ||
385 | unsigned int iram_base; | ||
386 | unsigned int dram_base; | ||
387 | unsigned int shim_phy_add; | ||
388 | unsigned int iram_end; | ||
389 | unsigned int dram_end; | ||
390 | unsigned int ddr_end; | ||
391 | unsigned int ddr_base; | ||
392 | unsigned int mailbox_recv_offset; | ||
393 | struct sst_shim_regs64 *shim_regs64; | ||
394 | struct list_head block_list; | ||
395 | struct list_head ipc_dispatch_list; | ||
396 | struct sst_platform_info *pdata; | ||
397 | struct list_head rx_list; | ||
398 | struct work_struct ipc_post_msg_wq; | ||
399 | wait_queue_head_t wait_queue; | ||
400 | struct workqueue_struct *post_msg_wq; | ||
401 | unsigned int tstamp; | ||
402 | /* str_id 0 is not used */ | ||
403 | struct stream_info streams[MAX_NUM_STREAMS+1]; | ||
404 | spinlock_t ipc_spin_lock; | ||
405 | spinlock_t block_lock; | ||
406 | spinlock_t rx_msg_lock; | ||
407 | struct pci_dev *pci; | ||
408 | struct device *dev; | ||
409 | volatile long unsigned pvt_id; | ||
410 | struct mutex sst_lock; | ||
411 | unsigned int stream_cnt; | ||
412 | unsigned int csr_value; | ||
413 | void *fw_in_mem; | ||
414 | struct sst_sg_list fw_sg_list, library_list; | ||
415 | struct intel_sst_ops *ops; | ||
416 | struct sst_info info; | ||
417 | struct pm_qos_request *qos; | ||
418 | unsigned int use_dma; | ||
419 | unsigned int use_lli; | ||
420 | atomic_t fw_clear_context; | ||
421 | bool lib_dwnld_reqd; | ||
422 | struct list_head memcpy_list; | ||
423 | struct sst_ipc_reg ipc_reg; | ||
424 | struct sst_mem_mgr lib_mem_mgr; | ||
425 | /* | ||
426 | * Holder for firmware name. Due to async call it needs to be | ||
427 | * persistent till worker thread gets called | ||
428 | */ | ||
429 | char firmware_name[20]; | ||
430 | }; | ||
431 | |||
432 | /* misc definitions */ | ||
433 | #define FW_DWNL_ID 0x01 | ||
434 | |||
435 | struct intel_sst_ops { | ||
436 | irqreturn_t (*interrupt)(int, void *); | ||
437 | irqreturn_t (*irq_thread)(int, void *); | ||
438 | void (*clear_interrupt)(struct intel_sst_drv *ctx); | ||
439 | int (*start)(struct intel_sst_drv *ctx); | ||
440 | int (*reset)(struct intel_sst_drv *ctx); | ||
441 | void (*process_reply)(struct intel_sst_drv *ctx, struct ipc_post *msg); | ||
442 | int (*post_message)(struct intel_sst_drv *ctx, | ||
443 | struct ipc_post *msg, bool sync); | ||
444 | void (*process_message)(struct ipc_post *msg); | ||
445 | void (*set_bypass)(bool set); | ||
446 | int (*save_dsp_context)(struct intel_sst_drv *sst); | ||
447 | void (*restore_dsp_context)(void); | ||
448 | int (*alloc_stream)(struct intel_sst_drv *ctx, void *params); | ||
449 | void (*post_download)(struct intel_sst_drv *sst); | ||
450 | }; | ||
451 | |||
452 | int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int id); | ||
453 | int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int id); | ||
454 | int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int id); | ||
455 | int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int id); | ||
456 | int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id); | ||
457 | int sst_send_byte_stream_mrfld(struct intel_sst_drv *ctx, | ||
458 | struct snd_sst_bytes_v2 *sbytes); | ||
459 | int sst_set_stream_param(int str_id, struct snd_sst_params *str_param); | ||
460 | int sst_set_metadata(int str_id, char *params); | ||
461 | int sst_get_stream(struct intel_sst_drv *sst_drv_ctx, | ||
462 | struct snd_sst_params *str_param); | ||
463 | int sst_get_stream_allocated(struct intel_sst_drv *ctx, | ||
464 | struct snd_sst_params *str_param, | ||
465 | struct snd_sst_lib_download **lib_dnld); | ||
466 | int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, | ||
467 | int str_id, bool partial_drain); | ||
468 | int sst_post_message_mrfld(struct intel_sst_drv *ctx, | ||
469 | struct ipc_post *msg, bool sync); | ||
470 | void sst_process_reply_mrfld(struct intel_sst_drv *ctx, struct ipc_post *msg); | ||
471 | int sst_start_mrfld(struct intel_sst_drv *ctx); | ||
472 | int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *ctx); | ||
473 | void intel_sst_clear_intr_mrfld(struct intel_sst_drv *ctx); | ||
474 | |||
475 | int sst_load_fw(struct intel_sst_drv *ctx); | ||
476 | int sst_load_library(struct snd_sst_lib_download *lib, u8 ops); | ||
477 | void sst_post_download_mrfld(struct intel_sst_drv *ctx); | ||
478 | int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx); | ||
479 | void sst_memcpy_free_resources(struct intel_sst_drv *ctx); | ||
480 | |||
481 | int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, | ||
482 | struct sst_block *block); | ||
483 | int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, | ||
484 | struct sst_block *block); | ||
485 | int sst_create_ipc_msg(struct ipc_post **arg, bool large); | ||
486 | int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id); | ||
487 | void sst_clean_stream(struct stream_info *stream); | ||
488 | int intel_sst_register_compress(struct intel_sst_drv *sst); | ||
489 | int intel_sst_remove_compress(struct intel_sst_drv *sst); | ||
490 | void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id); | ||
491 | int sst_send_sync_msg(int ipc, int str_id); | ||
492 | int sst_get_num_channel(struct snd_sst_params *str_param); | ||
493 | int sst_get_sfreq(struct snd_sst_params *str_param); | ||
494 | int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params); | ||
495 | void sst_restore_fw_context(void); | ||
496 | struct sst_block *sst_create_block(struct intel_sst_drv *ctx, | ||
497 | u32 msg_id, u32 drv_id); | ||
498 | int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large, | ||
499 | struct intel_sst_drv *sst_drv_ctx, struct sst_block **block, | ||
500 | u32 msg_id, u32 drv_id); | ||
501 | int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed); | ||
502 | int sst_wake_up_block(struct intel_sst_drv *ctx, int result, | ||
503 | u32 drv_id, u32 ipc, void *data, u32 size); | ||
504 | int sst_request_firmware_async(struct intel_sst_drv *ctx); | ||
505 | int sst_driver_ops(struct intel_sst_drv *sst); | ||
506 | struct sst_platform_info *sst_get_acpi_driver_data(const char *hid); | ||
507 | void sst_firmware_load_cb(const struct firmware *fw, void *context); | ||
508 | int sst_prepare_and_post_msg(struct intel_sst_drv *sst, | ||
509 | int task_id, int ipc_msg, int cmd_id, int pipe_id, | ||
510 | size_t mbox_data_len, const void *mbox_data, void **data, | ||
511 | bool large, bool fill_dsp, bool sync, bool response); | ||
512 | |||
513 | void sst_process_pending_msg(struct work_struct *work); | ||
514 | int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx); | ||
515 | void sst_init_stream(struct stream_info *stream, | ||
516 | int codec, int sst_id, int ops, u8 slot); | ||
517 | int sst_validate_strid(struct intel_sst_drv *sst_drv_ctx, int str_id); | ||
518 | struct stream_info *get_stream_info(struct intel_sst_drv *sst_drv_ctx, | ||
519 | int str_id); | ||
520 | int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
521 | u32 pipe_id); | ||
522 | u32 relocate_imr_addr_mrfld(u32 base_addr); | ||
523 | void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst, | ||
524 | struct ipc_post *msg); | ||
525 | int sst_pm_runtime_put(struct intel_sst_drv *sst_drv); | ||
526 | int sst_shim_write(void __iomem *addr, int offset, int value); | ||
527 | u32 sst_shim_read(void __iomem *addr, int offset); | ||
528 | u64 sst_reg_read64(void __iomem *addr, int offset); | ||
529 | int sst_shim_write64(void __iomem *addr, int offset, u64 value); | ||
530 | u64 sst_shim_read64(void __iomem *addr, int offset); | ||
531 | void sst_set_fw_state_locked( | ||
532 | struct intel_sst_drv *sst_drv_ctx, int sst_state); | ||
533 | void sst_fill_header_mrfld(union ipc_header_mrfld *header, | ||
534 | int msg, int task_id, int large, int drv_id); | ||
535 | void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg, | ||
536 | int pipe_id, int len); | ||
537 | |||
538 | int sst_register(struct device *); | ||
539 | int sst_unregister(struct device *); | ||
540 | |||
541 | int sst_alloc_drv_context(struct intel_sst_drv **ctx, | ||
542 | struct device *dev, unsigned int dev_id); | ||
543 | int sst_context_init(struct intel_sst_drv *ctx); | ||
544 | void sst_context_cleanup(struct intel_sst_drv *ctx); | ||
545 | void sst_configure_runtime_pm(struct intel_sst_drv *ctx); | ||
546 | #endif | ||
diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c new file mode 100644 index 000000000000..31124aa4434e --- /dev/null +++ b/sound/soc/intel/sst/sst_acpi.c | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | * sst_acpi.c - SST (LPE) driver init file for ACPI enumeration. | ||
3 | * | ||
4 | * Copyright (c) 2013, Intel Corporation. | ||
5 | * | ||
6 | * Authors: Ramesh Babu K V <Ramesh.Babu@intel.com> | ||
7 | * Authors: Omair Mohammed Abdullah <omair.m.abdullah@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/miscdevice.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/firmware.h> | ||
29 | #include <linux/pm_runtime.h> | ||
30 | #include <linux/pm_qos.h> | ||
31 | #include <linux/acpi.h> | ||
32 | #include <asm/platform_sst_audio.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/soc.h> | ||
35 | #include <sound/compress_driver.h> | ||
36 | #include <acpi/acbuffer.h> | ||
37 | #include <acpi/platform/acenv.h> | ||
38 | #include <acpi/platform/aclinux.h> | ||
39 | #include <acpi/actypes.h> | ||
40 | #include <acpi/acpi_bus.h> | ||
41 | #include "../sst-mfld-platform.h" | ||
42 | #include "../sst-dsp.h" | ||
43 | #include "sst.h" | ||
44 | |||
45 | struct sst_machines { | ||
46 | char codec_id[32]; | ||
47 | char board[32]; | ||
48 | char machine[32]; | ||
49 | void (*machine_quirk)(void); | ||
50 | char firmware[32]; | ||
51 | struct sst_platform_info *pdata; | ||
52 | |||
53 | }; | ||
54 | |||
55 | /* LPE viewpoint addresses */ | ||
56 | #define SST_BYT_IRAM_PHY_START 0xff2c0000 | ||
57 | #define SST_BYT_IRAM_PHY_END 0xff2d4000 | ||
58 | #define SST_BYT_DRAM_PHY_START 0xff300000 | ||
59 | #define SST_BYT_DRAM_PHY_END 0xff320000 | ||
60 | #define SST_BYT_IMR_VIRT_START 0xc0000000 /* virtual addr in LPE */ | ||
61 | #define SST_BYT_IMR_VIRT_END 0xc01fffff | ||
62 | #define SST_BYT_SHIM_PHY_ADDR 0xff340000 | ||
63 | #define SST_BYT_MBOX_PHY_ADDR 0xff344000 | ||
64 | #define SST_BYT_DMA0_PHY_ADDR 0xff298000 | ||
65 | #define SST_BYT_DMA1_PHY_ADDR 0xff29c000 | ||
66 | #define SST_BYT_SSP0_PHY_ADDR 0xff2a0000 | ||
67 | #define SST_BYT_SSP2_PHY_ADDR 0xff2a2000 | ||
68 | |||
69 | #define BYT_FW_MOD_TABLE_OFFSET 0x80000 | ||
70 | #define BYT_FW_MOD_TABLE_SIZE 0x100 | ||
71 | #define BYT_FW_MOD_OFFSET (BYT_FW_MOD_TABLE_OFFSET + BYT_FW_MOD_TABLE_SIZE) | ||
72 | |||
73 | static const struct sst_info byt_fwparse_info = { | ||
74 | .use_elf = false, | ||
75 | .max_streams = 25, | ||
76 | .iram_start = SST_BYT_IRAM_PHY_START, | ||
77 | .iram_end = SST_BYT_IRAM_PHY_END, | ||
78 | .iram_use = true, | ||
79 | .dram_start = SST_BYT_DRAM_PHY_START, | ||
80 | .dram_end = SST_BYT_DRAM_PHY_END, | ||
81 | .dram_use = true, | ||
82 | .imr_start = SST_BYT_IMR_VIRT_START, | ||
83 | .imr_end = SST_BYT_IMR_VIRT_END, | ||
84 | .imr_use = true, | ||
85 | .mailbox_start = SST_BYT_MBOX_PHY_ADDR, | ||
86 | .num_probes = 0, | ||
87 | .lpe_viewpt_rqd = true, | ||
88 | }; | ||
89 | |||
90 | static const struct sst_ipc_info byt_ipc_info = { | ||
91 | .ipc_offset = 0, | ||
92 | .mbox_recv_off = 0x400, | ||
93 | }; | ||
94 | |||
95 | static const struct sst_lib_dnld_info byt_lib_dnld_info = { | ||
96 | .mod_base = SST_BYT_IMR_VIRT_START, | ||
97 | .mod_end = SST_BYT_IMR_VIRT_END, | ||
98 | .mod_table_offset = BYT_FW_MOD_TABLE_OFFSET, | ||
99 | .mod_table_size = BYT_FW_MOD_TABLE_SIZE, | ||
100 | .mod_ddr_dnld = false, | ||
101 | }; | ||
102 | |||
103 | static const struct sst_res_info byt_rvp_res_info = { | ||
104 | .shim_offset = 0x140000, | ||
105 | .shim_size = 0x000100, | ||
106 | .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR, | ||
107 | .ssp0_offset = 0xa0000, | ||
108 | .ssp0_size = 0x1000, | ||
109 | .dma0_offset = 0x98000, | ||
110 | .dma0_size = 0x4000, | ||
111 | .dma1_offset = 0x9c000, | ||
112 | .dma1_size = 0x4000, | ||
113 | .iram_offset = 0x0c0000, | ||
114 | .iram_size = 0x14000, | ||
115 | .dram_offset = 0x100000, | ||
116 | .dram_size = 0x28000, | ||
117 | .mbox_offset = 0x144000, | ||
118 | .mbox_size = 0x1000, | ||
119 | .acpi_lpe_res_index = 0, | ||
120 | .acpi_ddr_index = 2, | ||
121 | .acpi_ipc_irq_index = 5, | ||
122 | }; | ||
123 | |||
124 | static struct sst_platform_info byt_rvp_platform_data = { | ||
125 | .probe_data = &byt_fwparse_info, | ||
126 | .ipc_info = &byt_ipc_info, | ||
127 | .lib_info = &byt_lib_dnld_info, | ||
128 | .res_info = &byt_rvp_res_info, | ||
129 | .platform = "sst-mfld-platform", | ||
130 | }; | ||
131 | |||
132 | /* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail, | ||
133 | * so pdata is same as Baytrail. | ||
134 | */ | ||
135 | static struct sst_platform_info chv_platform_data = { | ||
136 | .probe_data = &byt_fwparse_info, | ||
137 | .ipc_info = &byt_ipc_info, | ||
138 | .lib_info = &byt_lib_dnld_info, | ||
139 | .res_info = &byt_rvp_res_info, | ||
140 | .platform = "sst-mfld-platform", | ||
141 | }; | ||
142 | |||
143 | static int sst_platform_get_resources(struct intel_sst_drv *ctx) | ||
144 | { | ||
145 | struct resource *rsrc; | ||
146 | struct platform_device *pdev = to_platform_device(ctx->dev); | ||
147 | |||
148 | /* All ACPI resource request here */ | ||
149 | /* Get Shim addr */ | ||
150 | rsrc = platform_get_resource(pdev, IORESOURCE_MEM, | ||
151 | ctx->pdata->res_info->acpi_lpe_res_index); | ||
152 | if (!rsrc) { | ||
153 | dev_err(ctx->dev, "Invalid SHIM base from IFWI"); | ||
154 | return -EIO; | ||
155 | } | ||
156 | dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start, | ||
157 | (unsigned int)resource_size(rsrc)); | ||
158 | |||
159 | ctx->iram_base = rsrc->start + ctx->pdata->res_info->iram_offset; | ||
160 | ctx->iram_end = ctx->iram_base + ctx->pdata->res_info->iram_size - 1; | ||
161 | dev_info(ctx->dev, "IRAM base: %#x", ctx->iram_base); | ||
162 | ctx->iram = devm_ioremap_nocache(ctx->dev, ctx->iram_base, | ||
163 | ctx->pdata->res_info->iram_size); | ||
164 | if (!ctx->iram) { | ||
165 | dev_err(ctx->dev, "unable to map IRAM"); | ||
166 | return -EIO; | ||
167 | } | ||
168 | |||
169 | ctx->dram_base = rsrc->start + ctx->pdata->res_info->dram_offset; | ||
170 | ctx->dram_end = ctx->dram_base + ctx->pdata->res_info->dram_size - 1; | ||
171 | dev_info(ctx->dev, "DRAM base: %#x", ctx->dram_base); | ||
172 | ctx->dram = devm_ioremap_nocache(ctx->dev, ctx->dram_base, | ||
173 | ctx->pdata->res_info->dram_size); | ||
174 | if (!ctx->dram) { | ||
175 | dev_err(ctx->dev, "unable to map DRAM"); | ||
176 | return -EIO; | ||
177 | } | ||
178 | |||
179 | ctx->shim_phy_add = rsrc->start + ctx->pdata->res_info->shim_offset; | ||
180 | dev_info(ctx->dev, "SHIM base: %#x", ctx->shim_phy_add); | ||
181 | ctx->shim = devm_ioremap_nocache(ctx->dev, ctx->shim_phy_add, | ||
182 | ctx->pdata->res_info->shim_size); | ||
183 | if (!ctx->shim) { | ||
184 | dev_err(ctx->dev, "unable to map SHIM"); | ||
185 | return -EIO; | ||
186 | } | ||
187 | |||
188 | /* reassign physical address to LPE viewpoint address */ | ||
189 | ctx->shim_phy_add = ctx->pdata->res_info->shim_phy_addr; | ||
190 | |||
191 | /* Get mailbox addr */ | ||
192 | ctx->mailbox_add = rsrc->start + ctx->pdata->res_info->mbox_offset; | ||
193 | dev_info(ctx->dev, "Mailbox base: %#x", ctx->mailbox_add); | ||
194 | ctx->mailbox = devm_ioremap_nocache(ctx->dev, ctx->mailbox_add, | ||
195 | ctx->pdata->res_info->mbox_size); | ||
196 | if (!ctx->mailbox) { | ||
197 | dev_err(ctx->dev, "unable to map mailbox"); | ||
198 | return -EIO; | ||
199 | } | ||
200 | |||
201 | /* reassign physical address to LPE viewpoint address */ | ||
202 | ctx->mailbox_add = ctx->info.mailbox_start; | ||
203 | |||
204 | rsrc = platform_get_resource(pdev, IORESOURCE_MEM, | ||
205 | ctx->pdata->res_info->acpi_ddr_index); | ||
206 | if (!rsrc) { | ||
207 | dev_err(ctx->dev, "Invalid DDR base from IFWI"); | ||
208 | return -EIO; | ||
209 | } | ||
210 | ctx->ddr_base = rsrc->start; | ||
211 | ctx->ddr_end = rsrc->end; | ||
212 | dev_info(ctx->dev, "DDR base: %#x", ctx->ddr_base); | ||
213 | ctx->ddr = devm_ioremap_nocache(ctx->dev, ctx->ddr_base, | ||
214 | resource_size(rsrc)); | ||
215 | if (!ctx->ddr) { | ||
216 | dev_err(ctx->dev, "unable to map DDR"); | ||
217 | return -EIO; | ||
218 | } | ||
219 | |||
220 | /* Find the IRQ */ | ||
221 | ctx->irq_num = platform_get_irq(pdev, | ||
222 | ctx->pdata->res_info->acpi_ipc_irq_index); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, | ||
227 | void *context, void **ret) | ||
228 | { | ||
229 | *(bool *)context = true; | ||
230 | return AE_OK; | ||
231 | } | ||
232 | |||
233 | static struct sst_machines *sst_acpi_find_machine( | ||
234 | struct sst_machines *machines) | ||
235 | { | ||
236 | struct sst_machines *mach; | ||
237 | bool found = false; | ||
238 | |||
239 | for (mach = machines; mach->codec_id; mach++) | ||
240 | if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id, | ||
241 | sst_acpi_mach_match, | ||
242 | &found, NULL)) && found) | ||
243 | return mach; | ||
244 | |||
245 | return NULL; | ||
246 | } | ||
247 | |||
248 | int sst_acpi_probe(struct platform_device *pdev) | ||
249 | { | ||
250 | struct device *dev = &pdev->dev; | ||
251 | int ret = 0; | ||
252 | struct intel_sst_drv *ctx; | ||
253 | const struct acpi_device_id *id; | ||
254 | struct sst_machines *mach; | ||
255 | struct platform_device *mdev; | ||
256 | struct platform_device *plat_dev; | ||
257 | unsigned int dev_id; | ||
258 | |||
259 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | ||
260 | if (!id) | ||
261 | return -ENODEV; | ||
262 | dev_dbg(dev, "for %s", id->id); | ||
263 | |||
264 | mach = (struct sst_machines *)id->driver_data; | ||
265 | mach = sst_acpi_find_machine(mach); | ||
266 | if (mach == NULL) { | ||
267 | dev_err(dev, "No matching machine driver found\n"); | ||
268 | return -ENODEV; | ||
269 | } | ||
270 | |||
271 | ret = kstrtouint(id->id, 16, &dev_id); | ||
272 | if (ret < 0) { | ||
273 | dev_err(dev, "Unique device id conversion error: %d\n", ret); | ||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | dev_dbg(dev, "ACPI device id: %x\n", dev_id); | ||
278 | |||
279 | plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0); | ||
280 | if (plat_dev == NULL) { | ||
281 | dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform); | ||
282 | return -ENODEV; | ||
283 | } | ||
284 | |||
285 | /* Create platform device for sst machine driver */ | ||
286 | mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0); | ||
287 | if (mdev == NULL) { | ||
288 | dev_err(dev, "Failed to create machine device: %s\n", mach->machine); | ||
289 | return -ENODEV; | ||
290 | } | ||
291 | |||
292 | ret = sst_alloc_drv_context(&ctx, dev, dev_id); | ||
293 | if (ret < 0) | ||
294 | return ret; | ||
295 | |||
296 | /* Fill sst platform data */ | ||
297 | ctx->pdata = mach->pdata; | ||
298 | strcpy(ctx->firmware_name, mach->firmware); | ||
299 | |||
300 | ret = sst_platform_get_resources(ctx); | ||
301 | if (ret) | ||
302 | return ret; | ||
303 | |||
304 | ret = sst_context_init(ctx); | ||
305 | if (ret < 0) | ||
306 | return ret; | ||
307 | |||
308 | /* need to save shim registers in BYT */ | ||
309 | ctx->shim_regs64 = devm_kzalloc(ctx->dev, sizeof(*ctx->shim_regs64), | ||
310 | GFP_KERNEL); | ||
311 | if (!ctx->shim_regs64) { | ||
312 | return -ENOMEM; | ||
313 | goto do_sst_cleanup; | ||
314 | } | ||
315 | |||
316 | sst_configure_runtime_pm(ctx); | ||
317 | platform_set_drvdata(pdev, ctx); | ||
318 | return ret; | ||
319 | |||
320 | do_sst_cleanup: | ||
321 | sst_context_cleanup(ctx); | ||
322 | platform_set_drvdata(pdev, NULL); | ||
323 | dev_err(ctx->dev, "failed with %d\n", ret); | ||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | /** | ||
328 | * intel_sst_remove - remove function | ||
329 | * | ||
330 | * @pdev: platform device structure | ||
331 | * | ||
332 | * This function is called by OS when a device is unloaded | ||
333 | * This frees the interrupt etc | ||
334 | */ | ||
335 | int sst_acpi_remove(struct platform_device *pdev) | ||
336 | { | ||
337 | struct intel_sst_drv *ctx; | ||
338 | |||
339 | ctx = platform_get_drvdata(pdev); | ||
340 | sst_context_cleanup(ctx); | ||
341 | platform_set_drvdata(pdev, NULL); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static struct sst_machines sst_acpi_bytcr[] = { | ||
346 | {"10EC5640", "T100", "bytt100_rt5640", NULL, "fw_sst_0f28.bin", | ||
347 | &byt_rvp_platform_data }, | ||
348 | {}, | ||
349 | }; | ||
350 | |||
351 | /* Cherryview-based platforms: CherryTrail and Braswell */ | ||
352 | static struct sst_machines sst_acpi_chv[] = { | ||
353 | {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "fw_sst_22a8.bin", | ||
354 | &chv_platform_data }, | ||
355 | {}, | ||
356 | }; | ||
357 | |||
358 | static const struct acpi_device_id sst_acpi_ids[] = { | ||
359 | { "80860F28", (unsigned long)&sst_acpi_bytcr}, | ||
360 | { "808622A8", (unsigned long) &sst_acpi_chv}, | ||
361 | { }, | ||
362 | }; | ||
363 | |||
364 | MODULE_DEVICE_TABLE(acpi, sst_acpi_ids); | ||
365 | |||
366 | static struct platform_driver sst_acpi_driver = { | ||
367 | .driver = { | ||
368 | .name = "intel_sst_acpi", | ||
369 | .owner = THIS_MODULE, | ||
370 | .acpi_match_table = ACPI_PTR(sst_acpi_ids), | ||
371 | .pm = &intel_sst_pm, | ||
372 | }, | ||
373 | .probe = sst_acpi_probe, | ||
374 | .remove = sst_acpi_remove, | ||
375 | }; | ||
376 | |||
377 | module_platform_driver(sst_acpi_driver); | ||
378 | |||
379 | MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine ACPI Driver"); | ||
380 | MODULE_AUTHOR("Ramesh Babu K V"); | ||
381 | MODULE_AUTHOR("Omair Mohammed Abdullah"); | ||
382 | MODULE_LICENSE("GPL v2"); | ||
383 | MODULE_ALIAS("sst"); | ||
diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c new file mode 100644 index 000000000000..5f75ef3cdd22 --- /dev/null +++ b/sound/soc/intel/sst/sst_drv_interface.c | |||
@@ -0,0 +1,686 @@ | |||
1 | /* | ||
2 | * sst_drv_interface.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com) | ||
8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
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 as published by | ||
12 | * the Free Software Foundation; version 2 of the License. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/firmware.h> | ||
25 | #include <linux/pm_runtime.h> | ||
26 | #include <linux/pm_qos.h> | ||
27 | #include <linux/math64.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/compress_driver.h> | ||
32 | #include <asm/platform_sst_audio.h> | ||
33 | #include "../sst-mfld-platform.h" | ||
34 | #include "sst.h" | ||
35 | #include "../sst-dsp.h" | ||
36 | |||
37 | |||
38 | |||
39 | #define NUM_CODEC 2 | ||
40 | #define MIN_FRAGMENT 2 | ||
41 | #define MAX_FRAGMENT 4 | ||
42 | #define MIN_FRAGMENT_SIZE (50 * 1024) | ||
43 | #define MAX_FRAGMENT_SIZE (1024 * 1024) | ||
44 | #define SST_GET_BYTES_PER_SAMPLE(pcm_wd_sz) (((pcm_wd_sz + 15) >> 4) << 1) | ||
45 | |||
46 | int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id) | ||
47 | { | ||
48 | struct stream_info *stream; | ||
49 | int ret = 0; | ||
50 | |||
51 | stream = get_stream_info(ctx, str_id); | ||
52 | if (stream) { | ||
53 | /* str_id is valid, so stream is alloacted */ | ||
54 | ret = sst_free_stream(ctx, str_id); | ||
55 | if (ret) | ||
56 | sst_clean_stream(&ctx->streams[str_id]); | ||
57 | return ret; | ||
58 | } else { | ||
59 | dev_err(ctx->dev, "we tried to free stream context %d which was freed!!!\n", str_id); | ||
60 | } | ||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | int sst_get_stream_allocated(struct intel_sst_drv *ctx, | ||
65 | struct snd_sst_params *str_param, | ||
66 | struct snd_sst_lib_download **lib_dnld) | ||
67 | { | ||
68 | int retval; | ||
69 | |||
70 | retval = ctx->ops->alloc_stream(ctx, str_param); | ||
71 | if (retval > 0) | ||
72 | dev_dbg(ctx->dev, "Stream allocated %d\n", retval); | ||
73 | return retval; | ||
74 | |||
75 | } | ||
76 | |||
77 | /* | ||
78 | * sst_get_sfreq - this function returns the frequency of the stream | ||
79 | * | ||
80 | * @str_param : stream params | ||
81 | */ | ||
82 | int sst_get_sfreq(struct snd_sst_params *str_param) | ||
83 | { | ||
84 | switch (str_param->codec) { | ||
85 | case SST_CODEC_TYPE_PCM: | ||
86 | return str_param->sparams.uc.pcm_params.sfreq; | ||
87 | case SST_CODEC_TYPE_AAC: | ||
88 | return str_param->sparams.uc.aac_params.externalsr; | ||
89 | case SST_CODEC_TYPE_MP3: | ||
90 | return 0; | ||
91 | default: | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * sst_get_num_channel - get number of channels for the stream | ||
98 | * | ||
99 | * @str_param : stream params | ||
100 | */ | ||
101 | int sst_get_num_channel(struct snd_sst_params *str_param) | ||
102 | { | ||
103 | switch (str_param->codec) { | ||
104 | case SST_CODEC_TYPE_PCM: | ||
105 | return str_param->sparams.uc.pcm_params.num_chan; | ||
106 | case SST_CODEC_TYPE_MP3: | ||
107 | return str_param->sparams.uc.mp3_params.num_chan; | ||
108 | case SST_CODEC_TYPE_AAC: | ||
109 | return str_param->sparams.uc.aac_params.num_chan; | ||
110 | default: | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * sst_get_stream - this function prepares for stream allocation | ||
117 | * | ||
118 | * @str_param : stream param | ||
119 | */ | ||
120 | int sst_get_stream(struct intel_sst_drv *ctx, | ||
121 | struct snd_sst_params *str_param) | ||
122 | { | ||
123 | int retval; | ||
124 | struct stream_info *str_info; | ||
125 | |||
126 | /* stream is not allocated, we are allocating */ | ||
127 | retval = ctx->ops->alloc_stream(ctx, str_param); | ||
128 | if (retval <= 0) { | ||
129 | return -EIO; | ||
130 | } | ||
131 | /* store sampling freq */ | ||
132 | str_info = &ctx->streams[retval]; | ||
133 | str_info->sfreq = sst_get_sfreq(str_param); | ||
134 | |||
135 | return retval; | ||
136 | } | ||
137 | |||
138 | static int sst_power_control(struct device *dev, bool state) | ||
139 | { | ||
140 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
141 | |||
142 | dev_dbg(ctx->dev, "state:%d", state); | ||
143 | if (state == true) | ||
144 | return pm_runtime_get_sync(dev); | ||
145 | else | ||
146 | return sst_pm_runtime_put(ctx); | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * sst_open_pcm_stream - Open PCM interface | ||
151 | * | ||
152 | * @str_param: parameters of pcm stream | ||
153 | * | ||
154 | * This function is called by MID sound card driver to open | ||
155 | * a new pcm interface | ||
156 | */ | ||
157 | static int sst_open_pcm_stream(struct device *dev, | ||
158 | struct snd_sst_params *str_param) | ||
159 | { | ||
160 | int retval; | ||
161 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
162 | |||
163 | if (!str_param) | ||
164 | return -EINVAL; | ||
165 | |||
166 | retval = sst_get_stream(ctx, str_param); | ||
167 | if (retval > 0) | ||
168 | ctx->stream_cnt++; | ||
169 | else | ||
170 | dev_err(ctx->dev, "sst_get_stream returned err %d\n", retval); | ||
171 | |||
172 | return retval; | ||
173 | } | ||
174 | |||
175 | static int sst_cdev_open(struct device *dev, | ||
176 | struct snd_sst_params *str_params, struct sst_compress_cb *cb) | ||
177 | { | ||
178 | int str_id, retval; | ||
179 | struct stream_info *stream; | ||
180 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
181 | |||
182 | retval = pm_runtime_get_sync(ctx->dev); | ||
183 | if (retval < 0) | ||
184 | return retval; | ||
185 | |||
186 | str_id = sst_get_stream(ctx, str_params); | ||
187 | if (str_id > 0) { | ||
188 | dev_dbg(dev, "stream allocated in sst_cdev_open %d\n", str_id); | ||
189 | stream = &ctx->streams[str_id]; | ||
190 | stream->compr_cb = cb->compr_cb; | ||
191 | stream->compr_cb_param = cb->param; | ||
192 | stream->drain_notify = cb->drain_notify; | ||
193 | stream->drain_cb_param = cb->drain_cb_param; | ||
194 | } else { | ||
195 | dev_err(dev, "stream encountered error during alloc %d\n", str_id); | ||
196 | str_id = -EINVAL; | ||
197 | sst_pm_runtime_put(ctx); | ||
198 | } | ||
199 | return str_id; | ||
200 | } | ||
201 | |||
202 | static int sst_cdev_close(struct device *dev, unsigned int str_id) | ||
203 | { | ||
204 | int retval; | ||
205 | struct stream_info *stream; | ||
206 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
207 | |||
208 | stream = get_stream_info(ctx, str_id); | ||
209 | if (!stream) { | ||
210 | dev_err(dev, "stream info is NULL for str %d!!!\n", str_id); | ||
211 | return -EINVAL; | ||
212 | } | ||
213 | |||
214 | if (stream->status == STREAM_RESET) { | ||
215 | dev_dbg(dev, "stream in reset state...\n"); | ||
216 | stream->status = STREAM_UN_INIT; | ||
217 | |||
218 | retval = 0; | ||
219 | goto put; | ||
220 | } | ||
221 | |||
222 | retval = sst_free_stream(ctx, str_id); | ||
223 | put: | ||
224 | stream->compr_cb_param = NULL; | ||
225 | stream->compr_cb = NULL; | ||
226 | |||
227 | if (retval) | ||
228 | dev_err(dev, "free stream returned err %d\n", retval); | ||
229 | |||
230 | dev_dbg(dev, "End\n"); | ||
231 | return retval; | ||
232 | |||
233 | } | ||
234 | |||
235 | static int sst_cdev_ack(struct device *dev, unsigned int str_id, | ||
236 | unsigned long bytes) | ||
237 | { | ||
238 | struct stream_info *stream; | ||
239 | struct snd_sst_tstamp fw_tstamp = {0,}; | ||
240 | int offset; | ||
241 | void __iomem *addr; | ||
242 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
243 | |||
244 | stream = get_stream_info(ctx, str_id); | ||
245 | if (!stream) | ||
246 | return -EINVAL; | ||
247 | |||
248 | /* update bytes sent */ | ||
249 | stream->cumm_bytes += bytes; | ||
250 | dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes); | ||
251 | |||
252 | memcpy_fromio(&fw_tstamp, | ||
253 | ((void *)(ctx->mailbox + ctx->tstamp) | ||
254 | +(str_id * sizeof(fw_tstamp))), | ||
255 | sizeof(fw_tstamp)); | ||
256 | |||
257 | fw_tstamp.bytes_copied = stream->cumm_bytes; | ||
258 | dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n", | ||
259 | fw_tstamp.bytes_copied, bytes); | ||
260 | |||
261 | addr = ((void *)(ctx->mailbox + ctx->tstamp)) + | ||
262 | (str_id * sizeof(fw_tstamp)); | ||
263 | offset = offsetof(struct snd_sst_tstamp, bytes_copied); | ||
264 | sst_shim_write(addr, offset, fw_tstamp.bytes_copied); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static int sst_cdev_set_metadata(struct device *dev, | ||
269 | unsigned int str_id, struct snd_compr_metadata *metadata) | ||
270 | { | ||
271 | int retval = 0; | ||
272 | struct stream_info *str_info; | ||
273 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
274 | |||
275 | dev_dbg(dev, "set metadata for stream %d\n", str_id); | ||
276 | |||
277 | str_info = get_stream_info(ctx, str_id); | ||
278 | if (!str_info) | ||
279 | return -EINVAL; | ||
280 | |||
281 | dev_dbg(dev, "pipe id = %d\n", str_info->pipe_id); | ||
282 | retval = sst_prepare_and_post_msg(ctx, str_info->task_id, IPC_CMD, | ||
283 | IPC_IA_SET_STREAM_PARAMS_MRFLD, str_info->pipe_id, | ||
284 | sizeof(*metadata), metadata, NULL, | ||
285 | true, true, true, false); | ||
286 | |||
287 | return retval; | ||
288 | } | ||
289 | |||
290 | static int sst_cdev_stream_pause(struct device *dev, unsigned int str_id) | ||
291 | { | ||
292 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
293 | |||
294 | return sst_pause_stream(ctx, str_id); | ||
295 | } | ||
296 | |||
297 | static int sst_cdev_stream_pause_release(struct device *dev, | ||
298 | unsigned int str_id) | ||
299 | { | ||
300 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
301 | |||
302 | return sst_resume_stream(ctx, str_id); | ||
303 | } | ||
304 | |||
305 | static int sst_cdev_stream_start(struct device *dev, unsigned int str_id) | ||
306 | { | ||
307 | struct stream_info *str_info; | ||
308 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
309 | |||
310 | str_info = get_stream_info(ctx, str_id); | ||
311 | if (!str_info) | ||
312 | return -EINVAL; | ||
313 | str_info->prev = str_info->status; | ||
314 | str_info->status = STREAM_RUNNING; | ||
315 | return sst_start_stream(ctx, str_id); | ||
316 | } | ||
317 | |||
318 | static int sst_cdev_stream_drop(struct device *dev, unsigned int str_id) | ||
319 | { | ||
320 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
321 | |||
322 | return sst_drop_stream(ctx, str_id); | ||
323 | } | ||
324 | |||
325 | static int sst_cdev_stream_drain(struct device *dev, unsigned int str_id) | ||
326 | { | ||
327 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
328 | |||
329 | return sst_drain_stream(ctx, str_id, false); | ||
330 | } | ||
331 | |||
332 | static int sst_cdev_stream_partial_drain(struct device *dev, | ||
333 | unsigned int str_id) | ||
334 | { | ||
335 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
336 | |||
337 | return sst_drain_stream(ctx, str_id, true); | ||
338 | } | ||
339 | |||
340 | static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, | ||
341 | struct snd_compr_tstamp *tstamp) | ||
342 | { | ||
343 | struct snd_sst_tstamp fw_tstamp = {0,}; | ||
344 | struct stream_info *stream; | ||
345 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
346 | |||
347 | memcpy_fromio(&fw_tstamp, | ||
348 | ((void *)(ctx->mailbox + ctx->tstamp) | ||
349 | +(str_id * sizeof(fw_tstamp))), | ||
350 | sizeof(fw_tstamp)); | ||
351 | |||
352 | stream = get_stream_info(ctx, str_id); | ||
353 | if (!stream) | ||
354 | return -EINVAL; | ||
355 | dev_dbg(dev, "rb_counter %llu in bytes\n", fw_tstamp.ring_buffer_counter); | ||
356 | |||
357 | tstamp->copied_total = fw_tstamp.ring_buffer_counter; | ||
358 | tstamp->pcm_frames = fw_tstamp.frames_decoded; | ||
359 | tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter, | ||
360 | (u64)((stream->num_ch) * SST_GET_BYTES_PER_SAMPLE(24))); | ||
361 | tstamp->sampling_rate = fw_tstamp.sampling_frequency; | ||
362 | |||
363 | dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames); | ||
364 | dev_dbg(dev, "Ptr Query on strid = %d copied_total %d, decodec %d\n", | ||
365 | str_id, tstamp->copied_total, tstamp->pcm_frames); | ||
366 | dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int sst_cdev_caps(struct snd_compr_caps *caps) | ||
372 | { | ||
373 | caps->num_codecs = NUM_CODEC; | ||
374 | caps->min_fragment_size = MIN_FRAGMENT_SIZE; /* 50KB */ | ||
375 | caps->max_fragment_size = MAX_FRAGMENT_SIZE; /* 1024KB */ | ||
376 | caps->min_fragments = MIN_FRAGMENT; | ||
377 | caps->max_fragments = MAX_FRAGMENT; | ||
378 | caps->codecs[0] = SND_AUDIOCODEC_MP3; | ||
379 | caps->codecs[1] = SND_AUDIOCODEC_AAC; | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static struct snd_compr_codec_caps caps_mp3 = { | ||
384 | .num_descriptors = 1, | ||
385 | .descriptor[0].max_ch = 2, | ||
386 | .descriptor[0].sample_rates[0] = 48000, | ||
387 | .descriptor[0].sample_rates[1] = 44100, | ||
388 | .descriptor[0].sample_rates[2] = 32000, | ||
389 | .descriptor[0].sample_rates[3] = 16000, | ||
390 | .descriptor[0].sample_rates[4] = 8000, | ||
391 | .descriptor[0].num_sample_rates = 5, | ||
392 | .descriptor[0].bit_rate[0] = 320, | ||
393 | .descriptor[0].bit_rate[1] = 192, | ||
394 | .descriptor[0].num_bitrates = 2, | ||
395 | .descriptor[0].profiles = 0, | ||
396 | .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO, | ||
397 | .descriptor[0].formats = 0, | ||
398 | }; | ||
399 | |||
400 | static struct snd_compr_codec_caps caps_aac = { | ||
401 | .num_descriptors = 2, | ||
402 | .descriptor[1].max_ch = 2, | ||
403 | .descriptor[0].sample_rates[0] = 48000, | ||
404 | .descriptor[0].sample_rates[1] = 44100, | ||
405 | .descriptor[0].sample_rates[2] = 32000, | ||
406 | .descriptor[0].sample_rates[3] = 16000, | ||
407 | .descriptor[0].sample_rates[4] = 8000, | ||
408 | .descriptor[0].num_sample_rates = 5, | ||
409 | .descriptor[1].bit_rate[0] = 320, | ||
410 | .descriptor[1].bit_rate[1] = 192, | ||
411 | .descriptor[1].num_bitrates = 2, | ||
412 | .descriptor[1].profiles = 0, | ||
413 | .descriptor[1].modes = 0, | ||
414 | .descriptor[1].formats = | ||
415 | (SND_AUDIOSTREAMFORMAT_MP4ADTS | | ||
416 | SND_AUDIOSTREAMFORMAT_RAW), | ||
417 | }; | ||
418 | |||
419 | static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec) | ||
420 | { | ||
421 | if (codec->codec == SND_AUDIOCODEC_MP3) | ||
422 | *codec = caps_mp3; | ||
423 | else if (codec->codec == SND_AUDIOCODEC_AAC) | ||
424 | *codec = caps_aac; | ||
425 | else | ||
426 | return -EINVAL; | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id) | ||
432 | { | ||
433 | struct stream_info *stream; | ||
434 | |||
435 | dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n", | ||
436 | str_id); | ||
437 | stream = &ctx->streams[str_id]; | ||
438 | if (stream->compr_cb) | ||
439 | stream->compr_cb(stream->compr_cb_param); | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | * sst_close_pcm_stream - Close PCM interface | ||
444 | * | ||
445 | * @str_id: stream id to be closed | ||
446 | * | ||
447 | * This function is called by MID sound card driver to close | ||
448 | * an existing pcm interface | ||
449 | */ | ||
450 | static int sst_close_pcm_stream(struct device *dev, unsigned int str_id) | ||
451 | { | ||
452 | struct stream_info *stream; | ||
453 | int retval = 0; | ||
454 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
455 | |||
456 | stream = get_stream_info(ctx, str_id); | ||
457 | if (!stream) { | ||
458 | dev_err(ctx->dev, "stream info is NULL for str %d!!!\n", str_id); | ||
459 | return -EINVAL; | ||
460 | } | ||
461 | |||
462 | if (stream->status == STREAM_RESET) { | ||
463 | /* silently fail here as we have cleaned the stream earlier */ | ||
464 | dev_dbg(ctx->dev, "stream in reset state...\n"); | ||
465 | |||
466 | retval = 0; | ||
467 | goto put; | ||
468 | } | ||
469 | |||
470 | retval = free_stream_context(ctx, str_id); | ||
471 | put: | ||
472 | stream->pcm_substream = NULL; | ||
473 | stream->status = STREAM_UN_INIT; | ||
474 | stream->period_elapsed = NULL; | ||
475 | ctx->stream_cnt--; | ||
476 | |||
477 | if (retval) | ||
478 | dev_err(ctx->dev, "free stream returned err %d\n", retval); | ||
479 | |||
480 | dev_dbg(ctx->dev, "Exit\n"); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static inline int sst_calc_tstamp(struct intel_sst_drv *ctx, | ||
485 | struct pcm_stream_info *info, | ||
486 | struct snd_pcm_substream *substream, | ||
487 | struct snd_sst_tstamp *fw_tstamp) | ||
488 | { | ||
489 | size_t delay_bytes, delay_frames; | ||
490 | size_t buffer_sz; | ||
491 | u32 pointer_bytes, pointer_samples; | ||
492 | |||
493 | dev_dbg(ctx->dev, "mrfld ring_buffer_counter %llu in bytes\n", | ||
494 | fw_tstamp->ring_buffer_counter); | ||
495 | dev_dbg(ctx->dev, "mrfld hardware_counter %llu in bytes\n", | ||
496 | fw_tstamp->hardware_counter); | ||
497 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
498 | delay_bytes = (size_t) (fw_tstamp->ring_buffer_counter - | ||
499 | fw_tstamp->hardware_counter); | ||
500 | else | ||
501 | delay_bytes = (size_t) (fw_tstamp->hardware_counter - | ||
502 | fw_tstamp->ring_buffer_counter); | ||
503 | delay_frames = bytes_to_frames(substream->runtime, delay_bytes); | ||
504 | buffer_sz = snd_pcm_lib_buffer_bytes(substream); | ||
505 | div_u64_rem(fw_tstamp->ring_buffer_counter, buffer_sz, &pointer_bytes); | ||
506 | pointer_samples = bytes_to_samples(substream->runtime, pointer_bytes); | ||
507 | |||
508 | dev_dbg(ctx->dev, "pcm delay %zu in bytes\n", delay_bytes); | ||
509 | |||
510 | info->buffer_ptr = pointer_samples / substream->runtime->channels; | ||
511 | |||
512 | info->pcm_delay = delay_frames / substream->runtime->channels; | ||
513 | dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n", | ||
514 | info->buffer_ptr, info->pcm_delay); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info) | ||
519 | { | ||
520 | struct stream_info *stream; | ||
521 | struct snd_pcm_substream *substream; | ||
522 | struct snd_sst_tstamp fw_tstamp; | ||
523 | unsigned int str_id; | ||
524 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
525 | |||
526 | str_id = info->str_id; | ||
527 | stream = get_stream_info(ctx, str_id); | ||
528 | if (!stream) | ||
529 | return -EINVAL; | ||
530 | |||
531 | if (!stream->pcm_substream) | ||
532 | return -EINVAL; | ||
533 | substream = stream->pcm_substream; | ||
534 | |||
535 | memcpy_fromio(&fw_tstamp, | ||
536 | ((void *)(ctx->mailbox + ctx->tstamp) | ||
537 | + (str_id * sizeof(fw_tstamp))), | ||
538 | sizeof(fw_tstamp)); | ||
539 | return sst_calc_tstamp(ctx, info, substream, &fw_tstamp); | ||
540 | } | ||
541 | |||
542 | static int sst_stream_start(struct device *dev, int str_id) | ||
543 | { | ||
544 | struct stream_info *str_info; | ||
545 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
546 | |||
547 | if (ctx->sst_state != SST_FW_RUNNING) | ||
548 | return 0; | ||
549 | str_info = get_stream_info(ctx, str_id); | ||
550 | if (!str_info) | ||
551 | return -EINVAL; | ||
552 | str_info->prev = str_info->status; | ||
553 | str_info->status = STREAM_RUNNING; | ||
554 | sst_start_stream(ctx, str_id); | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int sst_stream_drop(struct device *dev, int str_id) | ||
560 | { | ||
561 | struct stream_info *str_info; | ||
562 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
563 | |||
564 | if (ctx->sst_state != SST_FW_RUNNING) | ||
565 | return 0; | ||
566 | |||
567 | str_info = get_stream_info(ctx, str_id); | ||
568 | if (!str_info) | ||
569 | return -EINVAL; | ||
570 | str_info->prev = STREAM_UN_INIT; | ||
571 | str_info->status = STREAM_INIT; | ||
572 | return sst_drop_stream(ctx, str_id); | ||
573 | } | ||
574 | |||
575 | static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) | ||
576 | { | ||
577 | int str_id = 0; | ||
578 | struct stream_info *stream; | ||
579 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
580 | |||
581 | str_id = str_info->str_id; | ||
582 | |||
583 | if (ctx->sst_state != SST_FW_RUNNING) | ||
584 | return 0; | ||
585 | |||
586 | stream = get_stream_info(ctx, str_id); | ||
587 | if (!stream) | ||
588 | return -EINVAL; | ||
589 | |||
590 | dev_dbg(ctx->dev, "setting the period ptrs\n"); | ||
591 | stream->pcm_substream = str_info->arg; | ||
592 | stream->period_elapsed = str_info->period_elapsed; | ||
593 | stream->sfreq = str_info->sfreq; | ||
594 | stream->prev = stream->status; | ||
595 | stream->status = STREAM_INIT; | ||
596 | dev_dbg(ctx->dev, | ||
597 | "pcm_substream %p, period_elapsed %p, sfreq %d, status %d\n", | ||
598 | stream->pcm_substream, stream->period_elapsed, | ||
599 | stream->sfreq, stream->status); | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | /* | ||
605 | * sst_set_byte_stream - Set generic params | ||
606 | * | ||
607 | * @cmd: control cmd to be set | ||
608 | * @arg: command argument | ||
609 | * | ||
610 | * This function is called by MID sound card driver to configure | ||
611 | * SST runtime params. | ||
612 | */ | ||
613 | static int sst_send_byte_stream(struct device *dev, | ||
614 | struct snd_sst_bytes_v2 *bytes) | ||
615 | { | ||
616 | int ret_val = 0; | ||
617 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
618 | |||
619 | if (NULL == bytes) | ||
620 | return -EINVAL; | ||
621 | ret_val = pm_runtime_get_sync(ctx->dev); | ||
622 | if (ret_val < 0) | ||
623 | return ret_val; | ||
624 | |||
625 | ret_val = sst_send_byte_stream_mrfld(ctx, bytes); | ||
626 | sst_pm_runtime_put(ctx); | ||
627 | |||
628 | return ret_val; | ||
629 | } | ||
630 | |||
631 | static struct sst_ops pcm_ops = { | ||
632 | .open = sst_open_pcm_stream, | ||
633 | .stream_init = sst_stream_init, | ||
634 | .stream_start = sst_stream_start, | ||
635 | .stream_drop = sst_stream_drop, | ||
636 | .stream_read_tstamp = sst_read_timestamp, | ||
637 | .send_byte_stream = sst_send_byte_stream, | ||
638 | .close = sst_close_pcm_stream, | ||
639 | .power = sst_power_control, | ||
640 | }; | ||
641 | |||
642 | static struct compress_sst_ops compr_ops = { | ||
643 | .open = sst_cdev_open, | ||
644 | .close = sst_cdev_close, | ||
645 | .stream_pause = sst_cdev_stream_pause, | ||
646 | .stream_pause_release = sst_cdev_stream_pause_release, | ||
647 | .stream_start = sst_cdev_stream_start, | ||
648 | .stream_drop = sst_cdev_stream_drop, | ||
649 | .stream_drain = sst_cdev_stream_drain, | ||
650 | .stream_partial_drain = sst_cdev_stream_partial_drain, | ||
651 | .tstamp = sst_cdev_tstamp, | ||
652 | .ack = sst_cdev_ack, | ||
653 | .get_caps = sst_cdev_caps, | ||
654 | .get_codec_caps = sst_cdev_codec_caps, | ||
655 | .set_metadata = sst_cdev_set_metadata, | ||
656 | .power = sst_power_control, | ||
657 | }; | ||
658 | |||
659 | static struct sst_device sst_dsp_device = { | ||
660 | .name = "Intel(R) SST LPE", | ||
661 | .dev = NULL, | ||
662 | .ops = &pcm_ops, | ||
663 | .compr_ops = &compr_ops, | ||
664 | }; | ||
665 | |||
666 | /* | ||
667 | * sst_register - function to register DSP | ||
668 | * | ||
669 | * This functions registers DSP with the platform driver | ||
670 | */ | ||
671 | int sst_register(struct device *dev) | ||
672 | { | ||
673 | int ret_val; | ||
674 | |||
675 | sst_dsp_device.dev = dev; | ||
676 | ret_val = sst_register_dsp(&sst_dsp_device); | ||
677 | if (ret_val) | ||
678 | dev_err(dev, "Unable to register DSP with platform driver\n"); | ||
679 | |||
680 | return ret_val; | ||
681 | } | ||
682 | |||
683 | int sst_unregister(struct device *dev) | ||
684 | { | ||
685 | return sst_unregister_dsp(&sst_dsp_device); | ||
686 | } | ||
diff --git a/sound/soc/intel/sst/sst_ipc.c b/sound/soc/intel/sst/sst_ipc.c new file mode 100644 index 000000000000..484e60978477 --- /dev/null +++ b/sound/soc/intel/sst/sst_ipc.c | |||
@@ -0,0 +1,373 @@ | |||
1 | /* | ||
2 | * sst_ipc.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corporation | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/firmware.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/soc.h> | ||
30 | #include <sound/compress_driver.h> | ||
31 | #include <asm/intel-mid.h> | ||
32 | #include <asm/platform_sst_audio.h> | ||
33 | #include "../sst-mfld-platform.h" | ||
34 | #include "sst.h" | ||
35 | #include "../sst-dsp.h" | ||
36 | |||
37 | struct sst_block *sst_create_block(struct intel_sst_drv *ctx, | ||
38 | u32 msg_id, u32 drv_id) | ||
39 | { | ||
40 | struct sst_block *msg = NULL; | ||
41 | |||
42 | dev_dbg(ctx->dev, "Enter\n"); | ||
43 | msg = kzalloc(sizeof(*msg), GFP_KERNEL); | ||
44 | if (!msg) | ||
45 | return NULL; | ||
46 | msg->condition = false; | ||
47 | msg->on = true; | ||
48 | msg->msg_id = msg_id; | ||
49 | msg->drv_id = drv_id; | ||
50 | spin_lock_bh(&ctx->block_lock); | ||
51 | list_add_tail(&msg->node, &ctx->block_list); | ||
52 | spin_unlock_bh(&ctx->block_lock); | ||
53 | |||
54 | return msg; | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * while handling the interrupts, we need to check for message status and | ||
59 | * then if we are blocking for a message | ||
60 | * | ||
61 | * here we are unblocking the blocked ones, this is based on id we have | ||
62 | * passed and search that for block threads. | ||
63 | * We will not find block in two cases | ||
64 | * a) when its small message and block in not there, so silently ignore | ||
65 | * them | ||
66 | * b) when we are actually not able to find the block (bug perhaps) | ||
67 | * | ||
68 | * Since we have bit of small messages we can spam kernel log with err | ||
69 | * print on above so need to keep as debug prints which should be enabled | ||
70 | * via dynamic debug while debugging IPC issues | ||
71 | */ | ||
72 | int sst_wake_up_block(struct intel_sst_drv *ctx, int result, | ||
73 | u32 drv_id, u32 ipc, void *data, u32 size) | ||
74 | { | ||
75 | struct sst_block *block = NULL; | ||
76 | |||
77 | dev_dbg(ctx->dev, "Enter\n"); | ||
78 | |||
79 | spin_lock_bh(&ctx->block_lock); | ||
80 | list_for_each_entry(block, &ctx->block_list, node) { | ||
81 | dev_dbg(ctx->dev, "Block ipc %d, drv_id %d\n", block->msg_id, | ||
82 | block->drv_id); | ||
83 | if (block->msg_id == ipc && block->drv_id == drv_id) { | ||
84 | dev_dbg(ctx->dev, "free up the block\n"); | ||
85 | block->ret_code = result; | ||
86 | block->data = data; | ||
87 | block->size = size; | ||
88 | block->condition = true; | ||
89 | spin_unlock_bh(&ctx->block_lock); | ||
90 | wake_up(&ctx->wait_queue); | ||
91 | return 0; | ||
92 | } | ||
93 | } | ||
94 | spin_unlock_bh(&ctx->block_lock); | ||
95 | dev_dbg(ctx->dev, | ||
96 | "Block not found or a response received for a short msg for ipc %d, drv_id %d\n", | ||
97 | ipc, drv_id); | ||
98 | return -EINVAL; | ||
99 | } | ||
100 | |||
101 | int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed) | ||
102 | { | ||
103 | struct sst_block *block = NULL, *__block; | ||
104 | |||
105 | dev_dbg(ctx->dev, "Enter\n"); | ||
106 | spin_lock_bh(&ctx->block_lock); | ||
107 | list_for_each_entry_safe(block, __block, &ctx->block_list, node) { | ||
108 | if (block == freed) { | ||
109 | pr_debug("pvt_id freed --> %d\n", freed->drv_id); | ||
110 | /* toggle the index position of pvt_id */ | ||
111 | list_del(&freed->node); | ||
112 | spin_unlock_bh(&ctx->block_lock); | ||
113 | kfree(freed->data); | ||
114 | freed->data = NULL; | ||
115 | kfree(freed); | ||
116 | return 0; | ||
117 | } | ||
118 | } | ||
119 | spin_unlock_bh(&ctx->block_lock); | ||
120 | dev_err(ctx->dev, "block is already freed!!!\n"); | ||
121 | return -EINVAL; | ||
122 | } | ||
123 | |||
124 | int sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
125 | struct ipc_post *ipc_msg, bool sync) | ||
126 | { | ||
127 | struct ipc_post *msg = ipc_msg; | ||
128 | union ipc_header_mrfld header; | ||
129 | unsigned int loop_count = 0; | ||
130 | int retval = 0; | ||
131 | unsigned long irq_flags; | ||
132 | |||
133 | dev_dbg(sst_drv_ctx->dev, "Enter: sync: %d\n", sync); | ||
134 | spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
135 | header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX); | ||
136 | if (sync) { | ||
137 | while (header.p.header_high.part.busy) { | ||
138 | if (loop_count > 25) { | ||
139 | dev_err(sst_drv_ctx->dev, | ||
140 | "sst: Busy wait failed, cant send this msg\n"); | ||
141 | retval = -EBUSY; | ||
142 | goto out; | ||
143 | } | ||
144 | cpu_relax(); | ||
145 | loop_count++; | ||
146 | header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX); | ||
147 | } | ||
148 | } else { | ||
149 | if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) { | ||
150 | /* queue is empty, nothing to send */ | ||
151 | spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
152 | dev_dbg(sst_drv_ctx->dev, | ||
153 | "Empty msg queue... NO Action\n"); | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | if (header.p.header_high.part.busy) { | ||
158 | spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
159 | dev_dbg(sst_drv_ctx->dev, "Busy not free... post later\n"); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* copy msg from list */ | ||
164 | msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next, | ||
165 | struct ipc_post, node); | ||
166 | list_del(&msg->node); | ||
167 | } | ||
168 | dev_dbg(sst_drv_ctx->dev, "sst: Post message: header = %x\n", | ||
169 | msg->mrfld_header.p.header_high.full); | ||
170 | dev_dbg(sst_drv_ctx->dev, "sst: size = 0x%x\n", | ||
171 | msg->mrfld_header.p.header_low_payload); | ||
172 | |||
173 | if (msg->mrfld_header.p.header_high.part.large) | ||
174 | memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND, | ||
175 | msg->mailbox_data, | ||
176 | msg->mrfld_header.p.header_low_payload); | ||
177 | |||
178 | sst_shim_write64(sst_drv_ctx->shim, SST_IPCX, msg->mrfld_header.full); | ||
179 | |||
180 | out: | ||
181 | spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
182 | kfree(msg->mailbox_data); | ||
183 | kfree(msg); | ||
184 | return retval; | ||
185 | } | ||
186 | |||
187 | void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx) | ||
188 | { | ||
189 | union interrupt_reg_mrfld isr; | ||
190 | union interrupt_reg_mrfld imr; | ||
191 | union ipc_header_mrfld clear_ipc; | ||
192 | unsigned long irq_flags; | ||
193 | |||
194 | spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
195 | imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX); | ||
196 | isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX); | ||
197 | |||
198 | /* write 1 to clear*/ | ||
199 | isr.part.busy_interrupt = 1; | ||
200 | sst_shim_write64(sst_drv_ctx->shim, SST_ISRX, isr.full); | ||
201 | |||
202 | /* Set IA done bit */ | ||
203 | clear_ipc.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCD); | ||
204 | |||
205 | clear_ipc.p.header_high.part.busy = 0; | ||
206 | clear_ipc.p.header_high.part.done = 1; | ||
207 | clear_ipc.p.header_low_payload = IPC_ACK_SUCCESS; | ||
208 | sst_shim_write64(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full); | ||
209 | /* un mask busy interrupt */ | ||
210 | imr.part.busy_interrupt = 0; | ||
211 | sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full); | ||
212 | spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
213 | } | ||
214 | |||
215 | |||
216 | /* | ||
217 | * process_fw_init - process the FW init msg | ||
218 | * | ||
219 | * @msg: IPC message mailbox data from FW | ||
220 | * | ||
221 | * This function processes the FW init msg from FW | ||
222 | * marks FW state and prints debug info of loaded FW | ||
223 | */ | ||
224 | static void process_fw_init(struct intel_sst_drv *sst_drv_ctx, | ||
225 | void *msg) | ||
226 | { | ||
227 | struct ipc_header_fw_init *init = | ||
228 | (struct ipc_header_fw_init *)msg; | ||
229 | int retval = 0; | ||
230 | |||
231 | dev_dbg(sst_drv_ctx->dev, "*** FW Init msg came***\n"); | ||
232 | if (init->result) { | ||
233 | sst_set_fw_state_locked(sst_drv_ctx, SST_RESET); | ||
234 | dev_err(sst_drv_ctx->dev, "FW Init failed, Error %x\n", | ||
235 | init->result); | ||
236 | retval = init->result; | ||
237 | goto ret; | ||
238 | } | ||
239 | |||
240 | ret: | ||
241 | sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); | ||
242 | } | ||
243 | |||
244 | static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx, | ||
245 | struct ipc_post *msg) | ||
246 | { | ||
247 | u32 msg_id; | ||
248 | int str_id; | ||
249 | u32 data_size, i; | ||
250 | void *data_offset; | ||
251 | struct stream_info *stream; | ||
252 | union ipc_header_high msg_high; | ||
253 | u32 msg_low, pipe_id; | ||
254 | |||
255 | msg_high = msg->mrfld_header.p.header_high; | ||
256 | msg_low = msg->mrfld_header.p.header_low_payload; | ||
257 | msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id; | ||
258 | data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr)); | ||
259 | data_size = msg_low - (sizeof(struct ipc_dsp_hdr)); | ||
260 | |||
261 | switch (msg_id) { | ||
262 | case IPC_SST_PERIOD_ELAPSED_MRFLD: | ||
263 | pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; | ||
264 | str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); | ||
265 | if (str_id > 0) { | ||
266 | dev_dbg(sst_drv_ctx->dev, | ||
267 | "Period elapsed rcvd for pipe id 0x%x\n", | ||
268 | pipe_id); | ||
269 | stream = &sst_drv_ctx->streams[str_id]; | ||
270 | if (stream->period_elapsed) | ||
271 | stream->period_elapsed(stream->pcm_substream); | ||
272 | if (stream->compr_cb) | ||
273 | stream->compr_cb(stream->compr_cb_param); | ||
274 | } | ||
275 | break; | ||
276 | |||
277 | case IPC_IA_DRAIN_STREAM_MRFLD: | ||
278 | pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; | ||
279 | str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); | ||
280 | if (str_id > 0) { | ||
281 | stream = &sst_drv_ctx->streams[str_id]; | ||
282 | if (stream->drain_notify) | ||
283 | stream->drain_notify(stream->drain_cb_param); | ||
284 | } | ||
285 | break; | ||
286 | |||
287 | case IPC_IA_FW_ASYNC_ERR_MRFLD: | ||
288 | dev_err(sst_drv_ctx->dev, "FW sent async error msg:\n"); | ||
289 | for (i = 0; i < (data_size/4); i++) | ||
290 | print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, | ||
291 | 16, 4, data_offset, data_size, false); | ||
292 | break; | ||
293 | |||
294 | case IPC_IA_FW_INIT_CMPLT_MRFLD: | ||
295 | process_fw_init(sst_drv_ctx, data_offset); | ||
296 | break; | ||
297 | |||
298 | case IPC_IA_BUF_UNDER_RUN_MRFLD: | ||
299 | pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; | ||
300 | str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); | ||
301 | if (str_id > 0) | ||
302 | dev_err(sst_drv_ctx->dev, | ||
303 | "Buffer under-run for pipe:%#x str_id:%d\n", | ||
304 | pipe_id, str_id); | ||
305 | break; | ||
306 | |||
307 | default: | ||
308 | dev_err(sst_drv_ctx->dev, | ||
309 | "Unrecognized async msg from FW msg_id %#x\n", msg_id); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
314 | struct ipc_post *msg) | ||
315 | { | ||
316 | unsigned int drv_id; | ||
317 | void *data; | ||
318 | union ipc_header_high msg_high; | ||
319 | u32 msg_low; | ||
320 | struct ipc_dsp_hdr *dsp_hdr; | ||
321 | unsigned int cmd_id; | ||
322 | |||
323 | msg_high = msg->mrfld_header.p.header_high; | ||
324 | msg_low = msg->mrfld_header.p.header_low_payload; | ||
325 | |||
326 | dev_dbg(sst_drv_ctx->dev, "IPC process message header %x payload %x\n", | ||
327 | msg->mrfld_header.p.header_high.full, | ||
328 | msg->mrfld_header.p.header_low_payload); | ||
329 | |||
330 | drv_id = msg_high.part.drv_id; | ||
331 | |||
332 | /* Check for async messages first */ | ||
333 | if (drv_id == SST_ASYNC_DRV_ID) { | ||
334 | /*FW sent async large message*/ | ||
335 | process_fw_async_msg(sst_drv_ctx, msg); | ||
336 | return; | ||
337 | } | ||
338 | |||
339 | /* FW sent short error response for an IPC */ | ||
340 | if (msg_high.part.result && drv_id && !msg_high.part.large) { | ||
341 | /* 32-bit FW error code in msg_low */ | ||
342 | dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low); | ||
343 | sst_wake_up_block(sst_drv_ctx, msg_high.part.result, | ||
344 | msg_high.part.drv_id, | ||
345 | msg_high.part.msg_id, NULL, 0); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * Process all valid responses | ||
351 | * if it is a large message, the payload contains the size to | ||
352 | * copy from mailbox | ||
353 | **/ | ||
354 | if (msg_high.part.large) { | ||
355 | data = kzalloc(msg_low, GFP_KERNEL); | ||
356 | if (!data) | ||
357 | return; | ||
358 | memcpy(data, (void *) msg->mailbox_data, msg_low); | ||
359 | /* Copy command id so that we can use to put sst to reset */ | ||
360 | dsp_hdr = (struct ipc_dsp_hdr *)data; | ||
361 | cmd_id = dsp_hdr->cmd_id; | ||
362 | dev_dbg(sst_drv_ctx->dev, "cmd_id %d\n", dsp_hdr->cmd_id); | ||
363 | if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result, | ||
364 | msg_high.part.drv_id, | ||
365 | msg_high.part.msg_id, data, msg_low)) | ||
366 | kfree(data); | ||
367 | } else { | ||
368 | sst_wake_up_block(sst_drv_ctx, msg_high.part.result, | ||
369 | msg_high.part.drv_id, | ||
370 | msg_high.part.msg_id, NULL, 0); | ||
371 | } | ||
372 | |||
373 | } | ||
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c new file mode 100644 index 000000000000..b580f96e25e5 --- /dev/null +++ b/sound/soc/intel/sst/sst_loader.c | |||
@@ -0,0 +1,456 @@ | |||
1 | /* | ||
2 | * sst_dsp.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | * | ||
22 | * This file contains all dsp controlling functions like firmware download, | ||
23 | * setting/resetting dsp cores, etc | ||
24 | */ | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/sched.h> | ||
29 | #include <linux/firmware.h> | ||
30 | #include <linux/dmaengine.h> | ||
31 | #include <linux/pm_runtime.h> | ||
32 | #include <linux/pm_qos.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/soc.h> | ||
36 | #include <sound/compress_driver.h> | ||
37 | #include <asm/platform_sst_audio.h> | ||
38 | #include "../sst-mfld-platform.h" | ||
39 | #include "sst.h" | ||
40 | #include "../sst-dsp.h" | ||
41 | |||
42 | static inline void memcpy32_toio(void __iomem *dst, const void *src, int count) | ||
43 | { | ||
44 | /* __iowrite32_copy uses 32-bit count values so divide by 4 for | ||
45 | * right count in words | ||
46 | */ | ||
47 | __iowrite32_copy(dst, src, count/4); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * intel_sst_reset_dsp_mrfld - Resetting SST DSP | ||
52 | * | ||
53 | * This resets DSP in case of MRFLD platfroms | ||
54 | */ | ||
55 | int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx) | ||
56 | { | ||
57 | union config_status_reg_mrfld csr; | ||
58 | |||
59 | dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n"); | ||
60 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
61 | |||
62 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
63 | |||
64 | csr.full |= 0x7; | ||
65 | sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); | ||
66 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
67 | |||
68 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
69 | |||
70 | csr.full &= ~(0x1); | ||
71 | sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); | ||
72 | |||
73 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
74 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * sst_start_merrifield - Start the SST DSP processor | ||
80 | * | ||
81 | * This starts the DSP in MERRIFIELD platfroms | ||
82 | */ | ||
83 | int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx) | ||
84 | { | ||
85 | union config_status_reg_mrfld csr; | ||
86 | |||
87 | dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n"); | ||
88 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
89 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
90 | |||
91 | csr.full |= 0x7; | ||
92 | sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); | ||
93 | |||
94 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
95 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
96 | |||
97 | csr.part.xt_snoop = 1; | ||
98 | csr.full &= ~(0x5); | ||
99 | sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); | ||
100 | |||
101 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
102 | dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n", | ||
103 | csr.full); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size, | ||
108 | struct fw_module_header **module, u32 *num_modules) | ||
109 | { | ||
110 | struct sst_fw_header *header; | ||
111 | const void *sst_fw_in_mem = ctx->fw_in_mem; | ||
112 | |||
113 | dev_dbg(ctx->dev, "Enter\n"); | ||
114 | |||
115 | /* Read the header information from the data pointer */ | ||
116 | header = (struct sst_fw_header *)sst_fw_in_mem; | ||
117 | dev_dbg(ctx->dev, | ||
118 | "header sign=%s size=%x modules=%x fmt=%x size=%zx\n", | ||
119 | header->signature, header->file_size, header->modules, | ||
120 | header->file_format, sizeof(*header)); | ||
121 | |||
122 | /* verify FW */ | ||
123 | if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) || | ||
124 | (size != header->file_size + sizeof(*header))) { | ||
125 | /* Invalid FW signature */ | ||
126 | dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n"); | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | *num_modules = header->modules; | ||
130 | *module = (void *)sst_fw_in_mem + sizeof(*header); | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * sst_fill_memcpy_list - Fill the memcpy list | ||
137 | * | ||
138 | * @memcpy_list: List to be filled | ||
139 | * @destn: Destination addr to be filled in the list | ||
140 | * @src: Source addr to be filled in the list | ||
141 | * @size: Size to be filled in the list | ||
142 | * | ||
143 | * Adds the node to the list after required fields | ||
144 | * are populated in the node | ||
145 | */ | ||
146 | static int sst_fill_memcpy_list(struct list_head *memcpy_list, | ||
147 | void *destn, const void *src, u32 size, bool is_io) | ||
148 | { | ||
149 | struct sst_memcpy_list *listnode; | ||
150 | |||
151 | listnode = kzalloc(sizeof(*listnode), GFP_KERNEL); | ||
152 | if (listnode == NULL) | ||
153 | return -ENOMEM; | ||
154 | listnode->dstn = destn; | ||
155 | listnode->src = src; | ||
156 | listnode->size = size; | ||
157 | listnode->is_io = is_io; | ||
158 | list_add_tail(&listnode->memcpylist, memcpy_list); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * sst_parse_module_memcpy - Parse audio FW modules and populate the memcpy list | ||
165 | * | ||
166 | * @sst_drv_ctx : driver context | ||
167 | * @module : FW module header | ||
168 | * @memcpy_list : Pointer to the list to be populated | ||
169 | * Create the memcpy list as the number of block to be copied | ||
170 | * returns error or 0 if module sizes are proper | ||
171 | */ | ||
172 | static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx, | ||
173 | struct fw_module_header *module, struct list_head *memcpy_list) | ||
174 | { | ||
175 | struct fw_block_info *block; | ||
176 | u32 count; | ||
177 | int ret_val = 0; | ||
178 | void __iomem *ram_iomem; | ||
179 | |||
180 | dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n", | ||
181 | module->signature, module->mod_size, | ||
182 | module->blocks, module->type); | ||
183 | dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point); | ||
184 | |||
185 | block = (void *)module + sizeof(*module); | ||
186 | |||
187 | for (count = 0; count < module->blocks; count++) { | ||
188 | if (block->size <= 0) { | ||
189 | dev_err(sst_drv_ctx->dev, "block size invalid\n"); | ||
190 | return -EINVAL; | ||
191 | } | ||
192 | switch (block->type) { | ||
193 | case SST_IRAM: | ||
194 | ram_iomem = sst_drv_ctx->iram; | ||
195 | break; | ||
196 | case SST_DRAM: | ||
197 | ram_iomem = sst_drv_ctx->dram; | ||
198 | break; | ||
199 | case SST_DDR: | ||
200 | ram_iomem = sst_drv_ctx->ddr; | ||
201 | break; | ||
202 | case SST_CUSTOM_INFO: | ||
203 | block = (void *)block + sizeof(*block) + block->size; | ||
204 | continue; | ||
205 | default: | ||
206 | dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n", | ||
207 | block->type, count); | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | |||
211 | ret_val = sst_fill_memcpy_list(memcpy_list, | ||
212 | ram_iomem + block->ram_offset, | ||
213 | (void *)block + sizeof(*block), block->size, 1); | ||
214 | if (ret_val) | ||
215 | return ret_val; | ||
216 | |||
217 | block = (void *)block + sizeof(*block) + block->size; | ||
218 | } | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * sst_parse_fw_memcpy - parse the firmware image & populate the list for memcpy | ||
224 | * | ||
225 | * @ctx : pointer to drv context | ||
226 | * @size : size of the firmware | ||
227 | * @fw_list : pointer to list_head to be populated | ||
228 | * This function parses the FW image and saves the parsed image in the list | ||
229 | * for memcpy | ||
230 | */ | ||
231 | static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size, | ||
232 | struct list_head *fw_list) | ||
233 | { | ||
234 | struct fw_module_header *module; | ||
235 | u32 count, num_modules; | ||
236 | int ret_val; | ||
237 | |||
238 | ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules); | ||
239 | if (ret_val) | ||
240 | return ret_val; | ||
241 | |||
242 | for (count = 0; count < num_modules; count++) { | ||
243 | ret_val = sst_parse_module_memcpy(ctx, module, fw_list); | ||
244 | if (ret_val) | ||
245 | return ret_val; | ||
246 | module = (void *)module + sizeof(*module) + module->mod_size; | ||
247 | } | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * sst_do_memcpy - function initiates the memcpy | ||
254 | * | ||
255 | * @memcpy_list: Pter to memcpy list on which the memcpy needs to be initiated | ||
256 | * | ||
257 | * Triggers the memcpy | ||
258 | */ | ||
259 | static void sst_do_memcpy(struct list_head *memcpy_list) | ||
260 | { | ||
261 | struct sst_memcpy_list *listnode; | ||
262 | |||
263 | list_for_each_entry(listnode, memcpy_list, memcpylist) { | ||
264 | if (listnode->is_io == true) | ||
265 | memcpy32_toio((void __iomem *)listnode->dstn, | ||
266 | listnode->src, listnode->size); | ||
267 | else | ||
268 | memcpy(listnode->dstn, listnode->src, listnode->size); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx) | ||
273 | { | ||
274 | struct sst_memcpy_list *listnode, *tmplistnode; | ||
275 | |||
276 | /* Free the list */ | ||
277 | if (!list_empty(&sst_drv_ctx->memcpy_list)) { | ||
278 | list_for_each_entry_safe(listnode, tmplistnode, | ||
279 | &sst_drv_ctx->memcpy_list, memcpylist) { | ||
280 | list_del(&listnode->memcpylist); | ||
281 | kfree(listnode); | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | |||
286 | static int sst_cache_and_parse_fw(struct intel_sst_drv *sst, | ||
287 | const struct firmware *fw) | ||
288 | { | ||
289 | int retval = 0; | ||
290 | |||
291 | sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL); | ||
292 | if (!sst->fw_in_mem) { | ||
293 | retval = -ENOMEM; | ||
294 | goto end_release; | ||
295 | } | ||
296 | dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem); | ||
297 | dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem)); | ||
298 | memcpy(sst->fw_in_mem, fw->data, fw->size); | ||
299 | retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list); | ||
300 | if (retval) { | ||
301 | dev_err(sst->dev, "Failed to parse fw\n"); | ||
302 | kfree(sst->fw_in_mem); | ||
303 | sst->fw_in_mem = NULL; | ||
304 | } | ||
305 | |||
306 | end_release: | ||
307 | release_firmware(fw); | ||
308 | return retval; | ||
309 | |||
310 | } | ||
311 | |||
312 | void sst_firmware_load_cb(const struct firmware *fw, void *context) | ||
313 | { | ||
314 | struct intel_sst_drv *ctx = context; | ||
315 | |||
316 | dev_dbg(ctx->dev, "Enter\n"); | ||
317 | |||
318 | if (fw == NULL) { | ||
319 | dev_err(ctx->dev, "request fw failed\n"); | ||
320 | return; | ||
321 | } | ||
322 | |||
323 | mutex_lock(&ctx->sst_lock); | ||
324 | |||
325 | if (ctx->sst_state != SST_RESET || | ||
326 | ctx->fw_in_mem != NULL) { | ||
327 | if (fw != NULL) | ||
328 | release_firmware(fw); | ||
329 | mutex_unlock(&ctx->sst_lock); | ||
330 | return; | ||
331 | } | ||
332 | |||
333 | dev_dbg(ctx->dev, "Request Fw completed\n"); | ||
334 | sst_cache_and_parse_fw(ctx, fw); | ||
335 | mutex_unlock(&ctx->sst_lock); | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * sst_request_fw - requests audio fw from kernel and saves a copy | ||
340 | * | ||
341 | * This function requests the SST FW from the kernel, parses it and | ||
342 | * saves a copy in the driver context | ||
343 | */ | ||
344 | static int sst_request_fw(struct intel_sst_drv *sst) | ||
345 | { | ||
346 | int retval = 0; | ||
347 | const struct firmware *fw; | ||
348 | |||
349 | retval = request_firmware(&fw, sst->firmware_name, sst->dev); | ||
350 | if (fw == NULL) { | ||
351 | dev_err(sst->dev, "fw is returning as null\n"); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | if (retval) { | ||
355 | dev_err(sst->dev, "request fw failed %d\n", retval); | ||
356 | return retval; | ||
357 | } | ||
358 | mutex_lock(&sst->sst_lock); | ||
359 | retval = sst_cache_and_parse_fw(sst, fw); | ||
360 | mutex_unlock(&sst->sst_lock); | ||
361 | |||
362 | return retval; | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | * Writing the DDR physical base to DCCM offset | ||
367 | * so that FW can use it to setup TLB | ||
368 | */ | ||
369 | static void sst_dccm_config_write(void __iomem *dram_base, | ||
370 | unsigned int ddr_base) | ||
371 | { | ||
372 | void __iomem *addr; | ||
373 | u32 bss_reset = 0; | ||
374 | |||
375 | addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET); | ||
376 | memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32)); | ||
377 | bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT); | ||
378 | addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET); | ||
379 | memcpy32_toio(addr, &bss_reset, sizeof(u32)); | ||
380 | |||
381 | } | ||
382 | |||
383 | void sst_post_download_mrfld(struct intel_sst_drv *ctx) | ||
384 | { | ||
385 | sst_dccm_config_write(ctx->dram, ctx->ddr_base); | ||
386 | dev_dbg(ctx->dev, "config written to DCCM\n"); | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * sst_load_fw - function to load FW into DSP | ||
391 | * Transfers the FW to DSP using dma/memcpy | ||
392 | */ | ||
393 | int sst_load_fw(struct intel_sst_drv *sst_drv_ctx) | ||
394 | { | ||
395 | int ret_val = 0; | ||
396 | struct sst_block *block; | ||
397 | |||
398 | dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n"); | ||
399 | |||
400 | if (sst_drv_ctx->sst_state != SST_RESET || | ||
401 | sst_drv_ctx->sst_state == SST_SHUTDOWN) | ||
402 | return -EAGAIN; | ||
403 | |||
404 | if (!sst_drv_ctx->fw_in_mem) { | ||
405 | dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n"); | ||
406 | ret_val = sst_request_fw(sst_drv_ctx); | ||
407 | if (ret_val) | ||
408 | return ret_val; | ||
409 | } | ||
410 | |||
411 | BUG_ON(!sst_drv_ctx->fw_in_mem); | ||
412 | block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID); | ||
413 | if (block == NULL) | ||
414 | return -ENOMEM; | ||
415 | |||
416 | /* Prevent C-states beyond C6 */ | ||
417 | pm_qos_update_request(sst_drv_ctx->qos, 0); | ||
418 | |||
419 | sst_drv_ctx->sst_state = SST_FW_LOADING; | ||
420 | |||
421 | ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx); | ||
422 | if (ret_val) | ||
423 | goto restore; | ||
424 | |||
425 | sst_do_memcpy(&sst_drv_ctx->memcpy_list); | ||
426 | |||
427 | /* Write the DRAM/DCCM config before enabling FW */ | ||
428 | if (sst_drv_ctx->ops->post_download) | ||
429 | sst_drv_ctx->ops->post_download(sst_drv_ctx); | ||
430 | |||
431 | /* bring sst out of reset */ | ||
432 | ret_val = sst_drv_ctx->ops->start(sst_drv_ctx); | ||
433 | if (ret_val) | ||
434 | goto restore; | ||
435 | |||
436 | ret_val = sst_wait_timeout(sst_drv_ctx, block); | ||
437 | if (ret_val) { | ||
438 | dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val); | ||
439 | /* FW download failed due to timeout */ | ||
440 | ret_val = -EBUSY; | ||
441 | |||
442 | } | ||
443 | |||
444 | |||
445 | restore: | ||
446 | /* Re-enable Deeper C-states beyond C6 */ | ||
447 | pm_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE); | ||
448 | sst_free_block(sst_drv_ctx, block); | ||
449 | dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n"); | ||
450 | |||
451 | if (sst_drv_ctx->ops->restore_dsp_context) | ||
452 | sst_drv_ctx->ops->restore_dsp_context(); | ||
453 | sst_drv_ctx->sst_state = SST_FW_RUNNING; | ||
454 | return ret_val; | ||
455 | } | ||
456 | |||
diff --git a/sound/soc/intel/sst/sst_pci.c b/sound/soc/intel/sst/sst_pci.c new file mode 100644 index 000000000000..3a0b3bf0af97 --- /dev/null +++ b/sound/soc/intel/sst/sst_pci.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * sst_pci.c - SST (LPE) driver init file for pci enumeration. | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <asm/platform_sst_audio.h> | ||
30 | #include "../sst-mfld-platform.h" | ||
31 | #include "sst.h" | ||
32 | |||
33 | static int sst_platform_get_resources(struct intel_sst_drv *ctx) | ||
34 | { | ||
35 | int ddr_base, ret = 0; | ||
36 | struct pci_dev *pci = ctx->pci; | ||
37 | |||
38 | ret = pci_request_regions(pci, SST_DRV_NAME); | ||
39 | if (ret) | ||
40 | return ret; | ||
41 | |||
42 | /* map registers */ | ||
43 | /* DDR base */ | ||
44 | if (ctx->dev_id == SST_MRFLD_PCI_ID) { | ||
45 | ctx->ddr_base = pci_resource_start(pci, 0); | ||
46 | /* check that the relocated IMR base matches with FW Binary */ | ||
47 | ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base); | ||
48 | if (!ctx->pdata->lib_info) { | ||
49 | dev_err(ctx->dev, "lib_info pointer NULL\n"); | ||
50 | ret = -EINVAL; | ||
51 | goto do_release_regions; | ||
52 | } | ||
53 | if (ddr_base != ctx->pdata->lib_info->mod_base) { | ||
54 | dev_err(ctx->dev, | ||
55 | "FW LSP DDR BASE does not match with IFWI\n"); | ||
56 | ret = -EINVAL; | ||
57 | goto do_release_regions; | ||
58 | } | ||
59 | ctx->ddr_end = pci_resource_end(pci, 0); | ||
60 | |||
61 | ctx->ddr = pcim_iomap(pci, 0, | ||
62 | pci_resource_len(pci, 0)); | ||
63 | if (!ctx->ddr) { | ||
64 | ret = -EINVAL; | ||
65 | goto do_release_regions; | ||
66 | } | ||
67 | dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr); | ||
68 | } else { | ||
69 | ctx->ddr = NULL; | ||
70 | } | ||
71 | /* SHIM */ | ||
72 | ctx->shim_phy_add = pci_resource_start(pci, 1); | ||
73 | ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1)); | ||
74 | if (!ctx->shim) { | ||
75 | ret = -EINVAL; | ||
76 | goto do_release_regions; | ||
77 | } | ||
78 | dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim); | ||
79 | |||
80 | /* Shared SRAM */ | ||
81 | ctx->mailbox_add = pci_resource_start(pci, 2); | ||
82 | ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2)); | ||
83 | if (!ctx->mailbox) { | ||
84 | ret = -EINVAL; | ||
85 | goto do_release_regions; | ||
86 | } | ||
87 | dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox); | ||
88 | |||
89 | /* IRAM */ | ||
90 | ctx->iram_end = pci_resource_end(pci, 3); | ||
91 | ctx->iram_base = pci_resource_start(pci, 3); | ||
92 | ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3)); | ||
93 | if (!ctx->iram) { | ||
94 | ret = -EINVAL; | ||
95 | goto do_release_regions; | ||
96 | } | ||
97 | dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram); | ||
98 | |||
99 | /* DRAM */ | ||
100 | ctx->dram_end = pci_resource_end(pci, 4); | ||
101 | ctx->dram_base = pci_resource_start(pci, 4); | ||
102 | ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4)); | ||
103 | if (!ctx->dram) { | ||
104 | ret = -EINVAL; | ||
105 | goto do_release_regions; | ||
106 | } | ||
107 | dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram); | ||
108 | do_release_regions: | ||
109 | pci_release_regions(pci); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * intel_sst_probe - PCI probe function | ||
115 | * | ||
116 | * @pci: PCI device structure | ||
117 | * @pci_id: PCI device ID structure | ||
118 | * | ||
119 | */ | ||
120 | static int intel_sst_probe(struct pci_dev *pci, | ||
121 | const struct pci_device_id *pci_id) | ||
122 | { | ||
123 | int ret = 0; | ||
124 | struct intel_sst_drv *sst_drv_ctx; | ||
125 | struct sst_platform_info *sst_pdata = pci->dev.platform_data; | ||
126 | |||
127 | dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device); | ||
128 | ret = sst_alloc_drv_context(&sst_drv_ctx, &pci->dev, pci->device); | ||
129 | if (ret < 0) | ||
130 | return ret; | ||
131 | |||
132 | sst_drv_ctx->pdata = sst_pdata; | ||
133 | sst_drv_ctx->irq_num = pci->irq; | ||
134 | snprintf(sst_drv_ctx->firmware_name, sizeof(sst_drv_ctx->firmware_name), | ||
135 | "%s%04x%s", "fw_sst_", | ||
136 | sst_drv_ctx->dev_id, ".bin"); | ||
137 | |||
138 | ret = sst_context_init(sst_drv_ctx); | ||
139 | if (ret < 0) | ||
140 | return ret; | ||
141 | |||
142 | /* Init the device */ | ||
143 | ret = pcim_enable_device(pci); | ||
144 | if (ret) { | ||
145 | dev_err(sst_drv_ctx->dev, | ||
146 | "device can't be enabled. Returned err: %d\n", ret); | ||
147 | goto do_free_drv_ctx; | ||
148 | } | ||
149 | sst_drv_ctx->pci = pci_dev_get(pci); | ||
150 | ret = sst_platform_get_resources(sst_drv_ctx); | ||
151 | if (ret < 0) | ||
152 | goto do_free_drv_ctx; | ||
153 | |||
154 | pci_set_drvdata(pci, sst_drv_ctx); | ||
155 | sst_configure_runtime_pm(sst_drv_ctx); | ||
156 | |||
157 | return ret; | ||
158 | |||
159 | do_free_drv_ctx: | ||
160 | sst_context_cleanup(sst_drv_ctx); | ||
161 | dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret); | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * intel_sst_remove - PCI remove function | ||
167 | * | ||
168 | * @pci: PCI device structure | ||
169 | * | ||
170 | * This function is called by OS when a device is unloaded | ||
171 | * This frees the interrupt etc | ||
172 | */ | ||
173 | static void intel_sst_remove(struct pci_dev *pci) | ||
174 | { | ||
175 | struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci); | ||
176 | |||
177 | sst_context_cleanup(sst_drv_ctx); | ||
178 | pci_dev_put(sst_drv_ctx->pci); | ||
179 | pci_release_regions(pci); | ||
180 | pci_set_drvdata(pci, NULL); | ||
181 | } | ||
182 | |||
183 | /* PCI Routines */ | ||
184 | static struct pci_device_id intel_sst_ids[] = { | ||
185 | { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0}, | ||
186 | { 0, } | ||
187 | }; | ||
188 | |||
189 | static struct pci_driver sst_driver = { | ||
190 | .name = SST_DRV_NAME, | ||
191 | .id_table = intel_sst_ids, | ||
192 | .probe = intel_sst_probe, | ||
193 | .remove = intel_sst_remove, | ||
194 | #ifdef CONFIG_PM | ||
195 | .driver = { | ||
196 | .pm = &intel_sst_pm, | ||
197 | }, | ||
198 | #endif | ||
199 | }; | ||
200 | |||
201 | module_pci_driver(sst_driver); | ||
202 | |||
203 | MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver"); | ||
204 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | ||
205 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | ||
206 | MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>"); | ||
207 | MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>"); | ||
208 | MODULE_LICENSE("GPL v2"); | ||
209 | MODULE_ALIAS("sst"); | ||
diff --git a/sound/soc/intel/sst/sst_pvt.c b/sound/soc/intel/sst/sst_pvt.c new file mode 100644 index 000000000000..4b7720864492 --- /dev/null +++ b/sound/soc/intel/sst/sst_pvt.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * sst_pvt.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/kobject.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/sched.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <sound/asound.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/soc.h> | ||
33 | #include <sound/compress_driver.h> | ||
34 | #include <asm/platform_sst_audio.h> | ||
35 | #include "../sst-mfld-platform.h" | ||
36 | #include "sst.h" | ||
37 | #include "../sst-dsp.h" | ||
38 | |||
39 | int sst_shim_write(void __iomem *addr, int offset, int value) | ||
40 | { | ||
41 | writel(value, addr + offset); | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | u32 sst_shim_read(void __iomem *addr, int offset) | ||
46 | { | ||
47 | return readl(addr + offset); | ||
48 | } | ||
49 | |||
50 | u64 sst_reg_read64(void __iomem *addr, int offset) | ||
51 | { | ||
52 | u64 val = 0; | ||
53 | |||
54 | memcpy_fromio(&val, addr + offset, sizeof(val)); | ||
55 | |||
56 | return val; | ||
57 | } | ||
58 | |||
59 | int sst_shim_write64(void __iomem *addr, int offset, u64 value) | ||
60 | { | ||
61 | memcpy_toio(addr + offset, &value, sizeof(value)); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | u64 sst_shim_read64(void __iomem *addr, int offset) | ||
66 | { | ||
67 | u64 val = 0; | ||
68 | |||
69 | memcpy_fromio(&val, addr + offset, sizeof(val)); | ||
70 | return val; | ||
71 | } | ||
72 | |||
73 | void sst_set_fw_state_locked( | ||
74 | struct intel_sst_drv *sst_drv_ctx, int sst_state) | ||
75 | { | ||
76 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
77 | sst_drv_ctx->sst_state = sst_state; | ||
78 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * sst_wait_interruptible - wait on event | ||
83 | * | ||
84 | * @sst_drv_ctx: Driver context | ||
85 | * @block: Driver block to wait on | ||
86 | * | ||
87 | * This function waits without a timeout (and is interruptable) for a | ||
88 | * given block event | ||
89 | */ | ||
90 | int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, | ||
91 | struct sst_block *block) | ||
92 | { | ||
93 | int retval = 0; | ||
94 | |||
95 | if (!wait_event_interruptible(sst_drv_ctx->wait_queue, | ||
96 | block->condition)) { | ||
97 | /* event wake */ | ||
98 | if (block->ret_code < 0) { | ||
99 | dev_err(sst_drv_ctx->dev, | ||
100 | "stream failed %d\n", block->ret_code); | ||
101 | retval = -EBUSY; | ||
102 | } else { | ||
103 | dev_dbg(sst_drv_ctx->dev, "event up\n"); | ||
104 | retval = 0; | ||
105 | } | ||
106 | } else { | ||
107 | dev_err(sst_drv_ctx->dev, "signal interrupted\n"); | ||
108 | retval = -EINTR; | ||
109 | } | ||
110 | return retval; | ||
111 | |||
112 | } | ||
113 | |||
114 | unsigned long long read_shim_data(struct intel_sst_drv *sst, int addr) | ||
115 | { | ||
116 | unsigned long long val = 0; | ||
117 | |||
118 | switch (sst->dev_id) { | ||
119 | case SST_MRFLD_PCI_ID: | ||
120 | case SST_BYT_ACPI_ID: | ||
121 | val = sst_shim_read64(sst->shim, addr); | ||
122 | break; | ||
123 | } | ||
124 | return val; | ||
125 | } | ||
126 | |||
127 | void write_shim_data(struct intel_sst_drv *sst, int addr, | ||
128 | unsigned long long data) | ||
129 | { | ||
130 | switch (sst->dev_id) { | ||
131 | case SST_MRFLD_PCI_ID: | ||
132 | case SST_BYT_ACPI_ID: | ||
133 | sst_shim_write64(sst->shim, addr, (u64) data); | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * sst_wait_timeout - wait on event for timeout | ||
140 | * | ||
141 | * @sst_drv_ctx: Driver context | ||
142 | * @block: Driver block to wait on | ||
143 | * | ||
144 | * This function waits with a timeout value (and is not interruptible) on a | ||
145 | * given block event | ||
146 | */ | ||
147 | int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, struct sst_block *block) | ||
148 | { | ||
149 | int retval = 0; | ||
150 | |||
151 | /* | ||
152 | * NOTE: | ||
153 | * Observed that FW processes the alloc msg and replies even | ||
154 | * before the alloc thread has finished execution | ||
155 | */ | ||
156 | dev_dbg(sst_drv_ctx->dev, | ||
157 | "waiting for condition %x ipc %d drv_id %d\n", | ||
158 | block->condition, block->msg_id, block->drv_id); | ||
159 | if (wait_event_timeout(sst_drv_ctx->wait_queue, | ||
160 | block->condition, | ||
161 | msecs_to_jiffies(SST_BLOCK_TIMEOUT))) { | ||
162 | /* event wake */ | ||
163 | dev_dbg(sst_drv_ctx->dev, "Event wake %x\n", | ||
164 | block->condition); | ||
165 | dev_dbg(sst_drv_ctx->dev, "message ret: %d\n", | ||
166 | block->ret_code); | ||
167 | retval = -block->ret_code; | ||
168 | } else { | ||
169 | block->on = false; | ||
170 | dev_err(sst_drv_ctx->dev, | ||
171 | "Wait timed-out condition:%#x, msg_id:%#x fw_state %#x\n", | ||
172 | block->condition, block->msg_id, sst_drv_ctx->sst_state); | ||
173 | sst_drv_ctx->sst_state = SST_RESET; | ||
174 | |||
175 | retval = -EBUSY; | ||
176 | } | ||
177 | return retval; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * sst_create_ipc_msg - create a IPC message | ||
182 | * | ||
183 | * @arg: ipc message | ||
184 | * @large: large or short message | ||
185 | * | ||
186 | * this function allocates structures to send a large or short | ||
187 | * message to the firmware | ||
188 | */ | ||
189 | int sst_create_ipc_msg(struct ipc_post **arg, bool large) | ||
190 | { | ||
191 | struct ipc_post *msg; | ||
192 | |||
193 | msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC); | ||
194 | if (!msg) | ||
195 | return -ENOMEM; | ||
196 | if (large) { | ||
197 | msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC); | ||
198 | if (!msg->mailbox_data) { | ||
199 | kfree(msg); | ||
200 | return -ENOMEM; | ||
201 | } | ||
202 | } else { | ||
203 | msg->mailbox_data = NULL; | ||
204 | } | ||
205 | msg->is_large = large; | ||
206 | *arg = msg; | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * sst_create_block_and_ipc_msg - Creates IPC message and sst block | ||
212 | * @arg: passed to sst_create_ipc_message API | ||
213 | * @large: large or short message | ||
214 | * @sst_drv_ctx: sst driver context | ||
215 | * @block: return block allocated | ||
216 | * @msg_id: IPC | ||
217 | * @drv_id: stream id or private id | ||
218 | */ | ||
219 | int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large, | ||
220 | struct intel_sst_drv *sst_drv_ctx, struct sst_block **block, | ||
221 | u32 msg_id, u32 drv_id) | ||
222 | { | ||
223 | int retval = 0; | ||
224 | |||
225 | retval = sst_create_ipc_msg(arg, large); | ||
226 | if (retval) | ||
227 | return retval; | ||
228 | *block = sst_create_block(sst_drv_ctx, msg_id, drv_id); | ||
229 | if (*block == NULL) { | ||
230 | kfree(*arg); | ||
231 | return -ENOMEM; | ||
232 | } | ||
233 | return retval; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * sst_clean_stream - clean the stream context | ||
238 | * | ||
239 | * @stream: stream structure | ||
240 | * | ||
241 | * this function resets the stream contexts | ||
242 | * should be called in free | ||
243 | */ | ||
244 | void sst_clean_stream(struct stream_info *stream) | ||
245 | { | ||
246 | stream->status = STREAM_UN_INIT; | ||
247 | stream->prev = STREAM_UN_INIT; | ||
248 | mutex_lock(&stream->lock); | ||
249 | stream->cumm_bytes = 0; | ||
250 | mutex_unlock(&stream->lock); | ||
251 | } | ||
252 | |||
253 | int sst_prepare_and_post_msg(struct intel_sst_drv *sst, | ||
254 | int task_id, int ipc_msg, int cmd_id, int pipe_id, | ||
255 | size_t mbox_data_len, const void *mbox_data, void **data, | ||
256 | bool large, bool fill_dsp, bool sync, bool response) | ||
257 | { | ||
258 | struct ipc_post *msg = NULL; | ||
259 | struct ipc_dsp_hdr dsp_hdr; | ||
260 | struct sst_block *block; | ||
261 | int ret = 0, pvt_id; | ||
262 | |||
263 | pvt_id = sst_assign_pvt_id(sst); | ||
264 | if (pvt_id < 0) | ||
265 | return pvt_id; | ||
266 | |||
267 | if (response) | ||
268 | ret = sst_create_block_and_ipc_msg( | ||
269 | &msg, large, sst, &block, ipc_msg, pvt_id); | ||
270 | else | ||
271 | ret = sst_create_ipc_msg(&msg, large); | ||
272 | |||
273 | if (ret < 0) { | ||
274 | test_and_clear_bit(pvt_id, &sst->pvt_id); | ||
275 | return -ENOMEM; | ||
276 | } | ||
277 | |||
278 | dev_dbg(sst->dev, "pvt_id = %d, pipe id = %d, task = %d ipc_msg: %d\n", | ||
279 | pvt_id, pipe_id, task_id, ipc_msg); | ||
280 | sst_fill_header_mrfld(&msg->mrfld_header, ipc_msg, | ||
281 | task_id, large, pvt_id); | ||
282 | msg->mrfld_header.p.header_low_payload = sizeof(dsp_hdr) + mbox_data_len; | ||
283 | msg->mrfld_header.p.header_high.part.res_rqd = !sync; | ||
284 | dev_dbg(sst->dev, "header:%x\n", | ||
285 | msg->mrfld_header.p.header_high.full); | ||
286 | dev_dbg(sst->dev, "response rqd: %x", | ||
287 | msg->mrfld_header.p.header_high.part.res_rqd); | ||
288 | dev_dbg(sst->dev, "msg->mrfld_header.p.header_low_payload:%d", | ||
289 | msg->mrfld_header.p.header_low_payload); | ||
290 | if (fill_dsp) { | ||
291 | sst_fill_header_dsp(&dsp_hdr, cmd_id, pipe_id, mbox_data_len); | ||
292 | memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr)); | ||
293 | if (mbox_data_len) { | ||
294 | memcpy(msg->mailbox_data + sizeof(dsp_hdr), | ||
295 | mbox_data, mbox_data_len); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | if (sync) | ||
300 | sst->ops->post_message(sst, msg, true); | ||
301 | else | ||
302 | sst_add_to_dispatch_list_and_post(sst, msg); | ||
303 | |||
304 | if (response) { | ||
305 | ret = sst_wait_timeout(sst, block); | ||
306 | if (ret < 0) { | ||
307 | goto out; | ||
308 | } else if(block->data) { | ||
309 | if (!data) | ||
310 | goto out; | ||
311 | *data = kzalloc(block->size, GFP_KERNEL); | ||
312 | if (!(*data)) { | ||
313 | ret = -ENOMEM; | ||
314 | goto out; | ||
315 | } else | ||
316 | memcpy(data, (void *) block->data, block->size); | ||
317 | } | ||
318 | } | ||
319 | out: | ||
320 | if (response) | ||
321 | sst_free_block(sst, block); | ||
322 | test_and_clear_bit(pvt_id, &sst->pvt_id); | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | int sst_pm_runtime_put(struct intel_sst_drv *sst_drv) | ||
327 | { | ||
328 | int ret; | ||
329 | |||
330 | pm_runtime_mark_last_busy(sst_drv->dev); | ||
331 | ret = pm_runtime_put_autosuspend(sst_drv->dev); | ||
332 | if (ret < 0) | ||
333 | return ret; | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | void sst_fill_header_mrfld(union ipc_header_mrfld *header, | ||
338 | int msg, int task_id, int large, int drv_id) | ||
339 | { | ||
340 | header->full = 0; | ||
341 | header->p.header_high.part.msg_id = msg; | ||
342 | header->p.header_high.part.task_id = task_id; | ||
343 | header->p.header_high.part.large = large; | ||
344 | header->p.header_high.part.drv_id = drv_id; | ||
345 | header->p.header_high.part.done = 0; | ||
346 | header->p.header_high.part.busy = 1; | ||
347 | header->p.header_high.part.res_rqd = 1; | ||
348 | } | ||
349 | |||
350 | void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg, | ||
351 | int pipe_id, int len) | ||
352 | { | ||
353 | dsp->cmd_id = msg; | ||
354 | dsp->mod_index_id = 0xff; | ||
355 | dsp->pipe_id = pipe_id; | ||
356 | dsp->length = len; | ||
357 | dsp->mod_id = 0; | ||
358 | } | ||
359 | |||
360 | #define SST_MAX_BLOCKS 15 | ||
361 | /* | ||
362 | * sst_assign_pvt_id - assign a pvt id for stream | ||
363 | * | ||
364 | * @sst_drv_ctx : driver context | ||
365 | * | ||
366 | * this function assigns a private id for calls that dont have stream | ||
367 | * context yet, should be called with lock held | ||
368 | * uses bits for the id, and finds first free bits and assigns that | ||
369 | */ | ||
370 | int sst_assign_pvt_id(struct intel_sst_drv *drv) | ||
371 | { | ||
372 | int local; | ||
373 | |||
374 | spin_lock(&drv->block_lock); | ||
375 | /* find first zero index from lsb */ | ||
376 | local = ffz(drv->pvt_id); | ||
377 | dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local); | ||
378 | if (local >= SST_MAX_BLOCKS){ | ||
379 | spin_unlock(&drv->block_lock); | ||
380 | dev_err(drv->dev, "PVT _ID error: no free id blocks "); | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | /* toggle the index */ | ||
384 | change_bit(local, &drv->pvt_id); | ||
385 | spin_unlock(&drv->block_lock); | ||
386 | return local; | ||
387 | } | ||
388 | |||
389 | void sst_init_stream(struct stream_info *stream, | ||
390 | int codec, int sst_id, int ops, u8 slot) | ||
391 | { | ||
392 | stream->status = STREAM_INIT; | ||
393 | stream->prev = STREAM_UN_INIT; | ||
394 | stream->ops = ops; | ||
395 | } | ||
396 | |||
397 | int sst_validate_strid( | ||
398 | struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
399 | { | ||
400 | if (str_id <= 0 || str_id > sst_drv_ctx->info.max_streams) { | ||
401 | dev_err(sst_drv_ctx->dev, | ||
402 | "SST ERR: invalid stream id : %d, max %d\n", | ||
403 | str_id, sst_drv_ctx->info.max_streams); | ||
404 | return -EINVAL; | ||
405 | } | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | struct stream_info *get_stream_info( | ||
411 | struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
412 | { | ||
413 | if (sst_validate_strid(sst_drv_ctx, str_id)) | ||
414 | return NULL; | ||
415 | return &sst_drv_ctx->streams[str_id]; | ||
416 | } | ||
417 | |||
418 | int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
419 | u32 pipe_id) | ||
420 | { | ||
421 | int i; | ||
422 | |||
423 | for (i = 1; i <= sst_drv_ctx->info.max_streams; i++) | ||
424 | if (pipe_id == sst_drv_ctx->streams[i].pipe_id) | ||
425 | return i; | ||
426 | |||
427 | dev_dbg(sst_drv_ctx->dev, "no such pipe_id(%u)", pipe_id); | ||
428 | return -1; | ||
429 | } | ||
430 | |||
431 | u32 relocate_imr_addr_mrfld(u32 base_addr) | ||
432 | { | ||
433 | /* Get the difference from 512MB aligned base addr */ | ||
434 | /* relocate the base */ | ||
435 | base_addr = MRFLD_FW_VIRTUAL_BASE + (base_addr % (512 * 1024 * 1024)); | ||
436 | return base_addr; | ||
437 | } | ||
438 | EXPORT_SYMBOL_GPL(relocate_imr_addr_mrfld); | ||
439 | |||
440 | void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst, | ||
441 | struct ipc_post *msg) | ||
442 | { | ||
443 | unsigned long irq_flags; | ||
444 | |||
445 | spin_lock_irqsave(&sst->ipc_spin_lock, irq_flags); | ||
446 | list_add_tail(&msg->node, &sst->ipc_dispatch_list); | ||
447 | spin_unlock_irqrestore(&sst->ipc_spin_lock, irq_flags); | ||
448 | sst->ops->post_message(sst, NULL, false); | ||
449 | } | ||
diff --git a/sound/soc/intel/sst/sst_stream.c b/sound/soc/intel/sst/sst_stream.c new file mode 100644 index 000000000000..dae2a41997aa --- /dev/null +++ b/sound/soc/intel/sst/sst_stream.c | |||
@@ -0,0 +1,437 @@ | |||
1 | /* | ||
2 | * sst_stream.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/firmware.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/soc.h> | ||
30 | #include <sound/compress_driver.h> | ||
31 | #include <asm/platform_sst_audio.h> | ||
32 | #include "../sst-mfld-platform.h" | ||
33 | #include "sst.h" | ||
34 | #include "../sst-dsp.h" | ||
35 | |||
36 | int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) | ||
37 | { | ||
38 | struct snd_sst_alloc_mrfld alloc_param; | ||
39 | struct snd_sst_params *str_params; | ||
40 | struct snd_sst_tstamp fw_tstamp; | ||
41 | struct stream_info *str_info; | ||
42 | struct snd_sst_alloc_response *response; | ||
43 | unsigned int str_id, pipe_id, task_id; | ||
44 | int i, num_ch, ret = 0; | ||
45 | void *data = NULL; | ||
46 | |||
47 | dev_dbg(sst_drv_ctx->dev, "Enter\n"); | ||
48 | BUG_ON(!params); | ||
49 | |||
50 | str_params = (struct snd_sst_params *)params; | ||
51 | memset(&alloc_param, 0, sizeof(alloc_param)); | ||
52 | alloc_param.operation = str_params->ops; | ||
53 | alloc_param.codec_type = str_params->codec; | ||
54 | alloc_param.sg_count = str_params->aparams.sg_count; | ||
55 | alloc_param.ring_buf_info[0].addr = | ||
56 | str_params->aparams.ring_buf_info[0].addr; | ||
57 | alloc_param.ring_buf_info[0].size = | ||
58 | str_params->aparams.ring_buf_info[0].size; | ||
59 | alloc_param.frag_size = str_params->aparams.frag_size; | ||
60 | |||
61 | memcpy(&alloc_param.codec_params, &str_params->sparams, | ||
62 | sizeof(struct snd_sst_stream_params)); | ||
63 | |||
64 | /* | ||
65 | * fill channel map params for multichannel support. | ||
66 | * Ideally channel map should be received from upper layers | ||
67 | * for multichannel support. | ||
68 | * Currently hardcoding as per FW reqm. | ||
69 | */ | ||
70 | num_ch = sst_get_num_channel(str_params); | ||
71 | for (i = 0; i < 8; i++) { | ||
72 | if (i < num_ch) | ||
73 | alloc_param.codec_params.uc.pcm_params.channel_map[i] = i; | ||
74 | else | ||
75 | alloc_param.codec_params.uc.pcm_params.channel_map[i] = 0xFF; | ||
76 | } | ||
77 | |||
78 | str_id = str_params->stream_id; | ||
79 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
80 | if (str_info == NULL) { | ||
81 | dev_err(sst_drv_ctx->dev, "get stream info returned null\n"); | ||
82 | return -EINVAL; | ||
83 | } | ||
84 | |||
85 | pipe_id = str_params->device_type; | ||
86 | task_id = str_params->task; | ||
87 | sst_drv_ctx->streams[str_id].pipe_id = pipe_id; | ||
88 | sst_drv_ctx->streams[str_id].task_id = task_id; | ||
89 | sst_drv_ctx->streams[str_id].num_ch = num_ch; | ||
90 | |||
91 | if (sst_drv_ctx->info.lpe_viewpt_rqd) | ||
92 | alloc_param.ts = sst_drv_ctx->info.mailbox_start + | ||
93 | sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); | ||
94 | else | ||
95 | alloc_param.ts = sst_drv_ctx->mailbox_add + | ||
96 | sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); | ||
97 | |||
98 | dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n", | ||
99 | alloc_param.ts); | ||
100 | dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n", | ||
101 | pipe_id, task_id); | ||
102 | |||
103 | /* allocate device type context */ | ||
104 | sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type, | ||
105 | str_id, alloc_param.operation, 0); | ||
106 | |||
107 | dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", | ||
108 | str_id, pipe_id); | ||
109 | ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD, | ||
110 | IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), | ||
111 | &alloc_param, data, true, true, false, true); | ||
112 | |||
113 | if (ret < 0) { | ||
114 | dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); | ||
115 | /* alloc failed, so reset the state to uninit */ | ||
116 | str_info->status = STREAM_UN_INIT; | ||
117 | str_id = ret; | ||
118 | } else if (data) { | ||
119 | response = (struct snd_sst_alloc_response *)data; | ||
120 | ret = response->str_type.result; | ||
121 | if (!ret) | ||
122 | goto out; | ||
123 | dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); | ||
124 | if (ret == SST_ERR_STREAM_IN_USE) { | ||
125 | dev_err(sst_drv_ctx->dev, | ||
126 | "FW not in clean state, send free for:%d\n", str_id); | ||
127 | sst_free_stream(sst_drv_ctx, str_id); | ||
128 | } | ||
129 | str_id = -ret; | ||
130 | } | ||
131 | out: | ||
132 | kfree(data); | ||
133 | return str_id; | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * sst_start_stream - Send msg for a starting stream | ||
138 | * @str_id: stream ID | ||
139 | * | ||
140 | * This function is called by any function which wants to start | ||
141 | * a stream. | ||
142 | */ | ||
143 | int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
144 | { | ||
145 | int retval = 0; | ||
146 | struct stream_info *str_info; | ||
147 | u16 data = 0; | ||
148 | |||
149 | dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id); | ||
150 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
151 | if (!str_info) | ||
152 | return -EINVAL; | ||
153 | if (str_info->status != STREAM_RUNNING) | ||
154 | return -EBADRQC; | ||
155 | |||
156 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, | ||
157 | IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id, | ||
158 | sizeof(u16), &data, NULL, true, true, true, false); | ||
159 | |||
160 | return retval; | ||
161 | } | ||
162 | |||
163 | int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
164 | struct snd_sst_bytes_v2 *bytes) | ||
165 | { struct ipc_post *msg = NULL; | ||
166 | u32 length; | ||
167 | int pvt_id, ret = 0; | ||
168 | struct sst_block *block = NULL; | ||
169 | |||
170 | dev_dbg(sst_drv_ctx->dev, | ||
171 | "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n", | ||
172 | bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id, | ||
173 | bytes->pipe_id, bytes->len); | ||
174 | |||
175 | if (sst_create_ipc_msg(&msg, true)) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | pvt_id = sst_assign_pvt_id(sst_drv_ctx); | ||
179 | sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg, | ||
180 | bytes->task_id, 1, pvt_id); | ||
181 | msg->mrfld_header.p.header_high.part.res_rqd = bytes->block; | ||
182 | length = bytes->len; | ||
183 | msg->mrfld_header.p.header_low_payload = length; | ||
184 | dev_dbg(sst_drv_ctx->dev, "length is %d\n", length); | ||
185 | memcpy(msg->mailbox_data, &bytes->bytes, bytes->len); | ||
186 | if (bytes->block) { | ||
187 | block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id); | ||
188 | if (block == NULL) { | ||
189 | kfree(msg); | ||
190 | ret = -ENOMEM; | ||
191 | goto out; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg); | ||
196 | dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d", | ||
197 | msg->mrfld_header.p.header_low_payload); | ||
198 | |||
199 | if (bytes->block) { | ||
200 | ret = sst_wait_timeout(sst_drv_ctx, block); | ||
201 | if (ret) { | ||
202 | dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret); | ||
203 | sst_free_block(sst_drv_ctx, block); | ||
204 | goto out; | ||
205 | } | ||
206 | } | ||
207 | if (bytes->type == SND_SST_BYTES_GET) { | ||
208 | /* | ||
209 | * copy the reply and send back | ||
210 | * we need to update only sz and payload | ||
211 | */ | ||
212 | if (bytes->block) { | ||
213 | unsigned char *r = block->data; | ||
214 | |||
215 | dev_dbg(sst_drv_ctx->dev, "read back %d bytes", | ||
216 | bytes->len); | ||
217 | memcpy(bytes->bytes, r, bytes->len); | ||
218 | } | ||
219 | } | ||
220 | if (bytes->block) | ||
221 | sst_free_block(sst_drv_ctx, block); | ||
222 | out: | ||
223 | test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * sst_pause_stream - Send msg for a pausing stream | ||
229 | * @str_id: stream ID | ||
230 | * | ||
231 | * This function is called by any function which wants to pause | ||
232 | * an already running stream. | ||
233 | */ | ||
234 | int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
235 | { | ||
236 | int retval = 0; | ||
237 | struct stream_info *str_info; | ||
238 | |||
239 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id); | ||
240 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
241 | if (!str_info) | ||
242 | return -EINVAL; | ||
243 | if (str_info->status == STREAM_PAUSED) | ||
244 | return 0; | ||
245 | if (str_info->status == STREAM_RUNNING || | ||
246 | str_info->status == STREAM_INIT) { | ||
247 | if (str_info->prev == STREAM_UN_INIT) | ||
248 | return -EBADRQC; | ||
249 | |||
250 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, | ||
251 | IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id, | ||
252 | 0, NULL, NULL, true, true, false, true); | ||
253 | |||
254 | if (retval == 0) { | ||
255 | str_info->prev = str_info->status; | ||
256 | str_info->status = STREAM_PAUSED; | ||
257 | } else if (retval == SST_ERR_INVALID_STREAM_ID) { | ||
258 | retval = -EINVAL; | ||
259 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
260 | sst_clean_stream(str_info); | ||
261 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
262 | } | ||
263 | } else { | ||
264 | retval = -EBADRQC; | ||
265 | dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n "); | ||
266 | } | ||
267 | |||
268 | return retval; | ||
269 | } | ||
270 | |||
271 | /** | ||
272 | * sst_resume_stream - Send msg for resuming stream | ||
273 | * @str_id: stream ID | ||
274 | * | ||
275 | * This function is called by any function which wants to resume | ||
276 | * an already paused stream. | ||
277 | */ | ||
278 | int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
279 | { | ||
280 | int retval = 0; | ||
281 | struct stream_info *str_info; | ||
282 | |||
283 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id); | ||
284 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
285 | if (!str_info) | ||
286 | return -EINVAL; | ||
287 | if (str_info->status == STREAM_RUNNING) | ||
288 | return 0; | ||
289 | if (str_info->status == STREAM_PAUSED) { | ||
290 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, | ||
291 | IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD, | ||
292 | str_info->pipe_id, 0, NULL, NULL, | ||
293 | true, true, false, true); | ||
294 | |||
295 | if (!retval) { | ||
296 | if (str_info->prev == STREAM_RUNNING) | ||
297 | str_info->status = STREAM_RUNNING; | ||
298 | else | ||
299 | str_info->status = STREAM_INIT; | ||
300 | str_info->prev = STREAM_PAUSED; | ||
301 | } else if (retval == -SST_ERR_INVALID_STREAM_ID) { | ||
302 | retval = -EINVAL; | ||
303 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
304 | sst_clean_stream(str_info); | ||
305 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
306 | } | ||
307 | } else { | ||
308 | retval = -EBADRQC; | ||
309 | dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n"); | ||
310 | } | ||
311 | |||
312 | return retval; | ||
313 | } | ||
314 | |||
315 | |||
316 | /** | ||
317 | * sst_drop_stream - Send msg for stopping stream | ||
318 | * @str_id: stream ID | ||
319 | * | ||
320 | * This function is called by any function which wants to stop | ||
321 | * a stream. | ||
322 | */ | ||
323 | int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
324 | { | ||
325 | int retval = 0; | ||
326 | struct stream_info *str_info; | ||
327 | |||
328 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id); | ||
329 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
330 | if (!str_info) | ||
331 | return -EINVAL; | ||
332 | |||
333 | if (str_info->status != STREAM_UN_INIT) { | ||
334 | str_info->prev = STREAM_UN_INIT; | ||
335 | str_info->status = STREAM_INIT; | ||
336 | str_info->cumm_bytes = 0; | ||
337 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, | ||
338 | IPC_CMD, IPC_IA_DROP_STREAM_MRFLD, | ||
339 | str_info->pipe_id, 0, NULL, NULL, | ||
340 | true, true, true, false); | ||
341 | } else { | ||
342 | retval = -EBADRQC; | ||
343 | dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n", | ||
344 | str_info->status); | ||
345 | } | ||
346 | return retval; | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * sst_drain_stream - Send msg for draining stream | ||
351 | * @str_id: stream ID | ||
352 | * | ||
353 | * This function is called by any function which wants to drain | ||
354 | * a stream. | ||
355 | */ | ||
356 | int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, | ||
357 | int str_id, bool partial_drain) | ||
358 | { | ||
359 | int retval = 0; | ||
360 | struct stream_info *str_info; | ||
361 | |||
362 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id); | ||
363 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
364 | if (!str_info) | ||
365 | return -EINVAL; | ||
366 | if (str_info->status != STREAM_RUNNING && | ||
367 | str_info->status != STREAM_INIT && | ||
368 | str_info->status != STREAM_PAUSED) { | ||
369 | dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n", | ||
370 | str_info->status); | ||
371 | return -EBADRQC; | ||
372 | } | ||
373 | |||
374 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, | ||
375 | IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id, | ||
376 | sizeof(u8), &partial_drain, NULL, true, true, false, false); | ||
377 | /* | ||
378 | * with new non blocked drain implementation in core we dont need to | ||
379 | * wait for respsonse, and need to only invoke callback for drain | ||
380 | * complete | ||
381 | */ | ||
382 | |||
383 | return retval; | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * sst_free_stream - Frees a stream | ||
388 | * @str_id: stream ID | ||
389 | * | ||
390 | * This function is called by any function which wants to free | ||
391 | * a stream. | ||
392 | */ | ||
393 | int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
394 | { | ||
395 | int retval = 0; | ||
396 | struct stream_info *str_info; | ||
397 | struct intel_sst_ops *ops; | ||
398 | |||
399 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id); | ||
400 | |||
401 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
402 | if (sst_drv_ctx->sst_state == SST_RESET) { | ||
403 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
404 | return -ENODEV; | ||
405 | } | ||
406 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
407 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
408 | if (!str_info) | ||
409 | return -EINVAL; | ||
410 | ops = sst_drv_ctx->ops; | ||
411 | |||
412 | mutex_lock(&str_info->lock); | ||
413 | if (str_info->status != STREAM_UN_INIT) { | ||
414 | str_info->prev = str_info->status; | ||
415 | str_info->status = STREAM_UN_INIT; | ||
416 | mutex_unlock(&str_info->lock); | ||
417 | |||
418 | dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", | ||
419 | str_id, str_info->pipe_id); | ||
420 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, | ||
421 | IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, | ||
422 | NULL, NULL, true, true, false, true); | ||
423 | |||
424 | dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n", | ||
425 | retval); | ||
426 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
427 | sst_clean_stream(str_info); | ||
428 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
429 | dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n"); | ||
430 | } else { | ||
431 | mutex_unlock(&str_info->lock); | ||
432 | retval = -EBADRQC; | ||
433 | dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n"); | ||
434 | } | ||
435 | |||
436 | return retval; | ||
437 | } | ||
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c index 5cb91f9e8626..0fb7d2a91c3a 100644 --- a/sound/soc/jz4740/qi_lb60.c +++ b/sound/soc/jz4740/qi_lb60.c | |||
@@ -77,25 +77,18 @@ static int qi_lb60_probe(struct platform_device *pdev) | |||
77 | { | 77 | { |
78 | struct qi_lb60 *qi_lb60; | 78 | struct qi_lb60 *qi_lb60; |
79 | struct snd_soc_card *card = &qi_lb60_card; | 79 | struct snd_soc_card *card = &qi_lb60_card; |
80 | int ret; | ||
81 | 80 | ||
82 | qi_lb60 = devm_kzalloc(&pdev->dev, sizeof(*qi_lb60), GFP_KERNEL); | 81 | qi_lb60 = devm_kzalloc(&pdev->dev, sizeof(*qi_lb60), GFP_KERNEL); |
83 | if (!qi_lb60) | 82 | if (!qi_lb60) |
84 | return -ENOMEM; | 83 | return -ENOMEM; |
85 | 84 | ||
86 | qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd"); | 85 | qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd", GPIOD_OUT_LOW); |
87 | if (IS_ERR(qi_lb60->snd_gpio)) | 86 | if (IS_ERR(qi_lb60->snd_gpio)) |
88 | return PTR_ERR(qi_lb60->snd_gpio); | 87 | return PTR_ERR(qi_lb60->snd_gpio); |
89 | ret = gpiod_direction_output(qi_lb60->snd_gpio, 0); | ||
90 | if (ret) | ||
91 | return ret; | ||
92 | 88 | ||
93 | qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp"); | 89 | qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp", GPIOD_OUT_LOW); |
94 | if (IS_ERR(qi_lb60->amp_gpio)) | 90 | if (IS_ERR(qi_lb60->amp_gpio)) |
95 | return PTR_ERR(qi_lb60->amp_gpio); | 91 | return PTR_ERR(qi_lb60->amp_gpio); |
96 | ret = gpiod_direction_output(qi_lb60->amp_gpio, 0); | ||
97 | if (ret) | ||
98 | return ret; | ||
99 | 92 | ||
100 | card->dev = &pdev->dev; | 93 | card->dev = &pdev->dev; |
101 | 94 | ||
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 231d7e7b0711..83b2fea09219 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c | |||
@@ -773,7 +773,7 @@ static int mxs_saif_probe(struct platform_device *pdev) | |||
773 | 773 | ||
774 | saif->dev = &pdev->dev; | 774 | saif->dev = &pdev->dev; |
775 | ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0, | 775 | ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0, |
776 | "mxs-saif", saif); | 776 | dev_name(&pdev->dev), saif); |
777 | if (ret) { | 777 | if (ret) { |
778 | dev_err(&pdev->dev, "failed to request irq\n"); | 778 | dev_err(&pdev->dev, "failed to request irq\n"); |
779 | return ret; | 779 | return ret; |
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 61822cc53bd3..3bba6cfe4f29 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c | |||
@@ -49,13 +49,6 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream, | |||
49 | break; | 49 | break; |
50 | } | 50 | } |
51 | 51 | ||
52 | /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */ | ||
53 | if (mclk < 8000000 || mclk > 27000000) { | ||
54 | dev_err(codec_dai->dev, "Invalid mclk frequency: %u.%03uMHz\n", | ||
55 | mclk / 1000000, mclk / 1000 % 1000); | ||
56 | return -EINVAL; | ||
57 | } | ||
58 | |||
59 | /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */ | 52 | /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */ |
60 | ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0); | 53 | ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0); |
61 | if (ret) { | 54 | if (ret) { |
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index f2f67942b229..dff443e4b657 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c | |||
@@ -298,7 +298,7 @@ static const struct snd_soc_dai_ops nuc900_ac97_dai_ops = { | |||
298 | static struct snd_soc_dai_driver nuc900_ac97_dai = { | 298 | static struct snd_soc_dai_driver nuc900_ac97_dai = { |
299 | .probe = nuc900_ac97_probe, | 299 | .probe = nuc900_ac97_probe, |
300 | .remove = nuc900_ac97_remove, | 300 | .remove = nuc900_ac97_remove, |
301 | .ac97_control = 1, | 301 | .bus_control = true, |
302 | .playback = { | 302 | .playback = { |
303 | .rates = SNDRV_PCM_RATE_8000_48000, | 303 | .rates = SNDRV_PCM_RATE_8000_48000, |
304 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 304 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index d44463a7b0fa..2738b1984410 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -25,15 +25,15 @@ config SND_OMAP_SOC_N810 | |||
25 | Say Y if you want to add support for SoC audio on Nokia N810. | 25 | Say Y if you want to add support for SoC audio on Nokia 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 N900 (RX-51)" |
29 | depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) && I2C | 29 | depends on SND_OMAP_SOC && ARM && I2C |
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 |
33 | depends on GPIOLIB | 33 | depends on GPIOLIB |
34 | help | 34 | help |
35 | Say Y if you want to add support for SoC audio on Nokia RX-51 | 35 | Say Y if you want to add support for SoC audio on Nokia N900 |
36 | hardware. This is also known as Nokia N900 product. | 36 | cellphone. |
37 | 37 | ||
38 | config SND_OMAP_SOC_AMS_DELTA | 38 | config SND_OMAP_SOC_AMS_DELTA |
39 | tristate "SoC Audio support for Amstrad E3 (Delta) videophone" | 39 | tristate "SoC Audio support for Amstrad E3 (Delta) videophone" |
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index 86c75384c3c8..68a125205375 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c | |||
@@ -621,8 +621,7 @@ void omap_mcbsp_free(struct omap_mcbsp *mcbsp) | |||
621 | mcbsp->reg_cache = NULL; | 621 | mcbsp->reg_cache = NULL; |
622 | spin_unlock(&mcbsp->lock); | 622 | spin_unlock(&mcbsp->lock); |
623 | 623 | ||
624 | if (reg_cache) | 624 | kfree(reg_cache); |
625 | kfree(reg_cache); | ||
626 | } | 625 | } |
627 | 626 | ||
628 | /* | 627 | /* |
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 595eee341e90..a6b2be20cc0b 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c | |||
@@ -127,15 +127,12 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
127 | static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) | 127 | static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) |
128 | { | 128 | { |
129 | struct snd_soc_codec *codec = rtd->codec; | 129 | struct snd_soc_codec *codec = rtd->codec; |
130 | unsigned short reg; | ||
131 | 130 | ||
132 | /* Prepare GPIO8 for rear speaker amplifier */ | 131 | /* Prepare GPIO8 for rear speaker amplifier */ |
133 | reg = codec->driver->read(codec, AC97_GPIO_CFG); | 132 | snd_soc_update_bits(codec, AC97_GPIO_CFG, 0x100, 0x100); |
134 | codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100); | ||
135 | 133 | ||
136 | /* Prepare MIC input */ | 134 | /* Prepare MIC input */ |
137 | reg = codec->driver->read(codec, AC97_3D_CONTROL); | 135 | snd_soc_update_bits(codec, AC97_3D_CONTROL, 0xc000, 0xc000); |
138 | codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000); | ||
139 | 136 | ||
140 | return 0; | 137 | return 0; |
141 | } | 138 | } |
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index a8e097433074..cbba063a7210 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -97,7 +97,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, | |||
97 | int ret = 0; | 97 | int ret = 0; |
98 | 98 | ||
99 | if (!cpu_dai->active) { | 99 | if (!cpu_dai->active) { |
100 | clk_enable(ssp->clk); | 100 | clk_prepare_enable(ssp->clk); |
101 | pxa_ssp_disable(ssp); | 101 | pxa_ssp_disable(ssp); |
102 | } | 102 | } |
103 | 103 | ||
@@ -121,7 +121,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, | |||
121 | 121 | ||
122 | if (!cpu_dai->active) { | 122 | if (!cpu_dai->active) { |
123 | pxa_ssp_disable(ssp); | 123 | pxa_ssp_disable(ssp); |
124 | clk_disable(ssp->clk); | 124 | clk_disable_unprepare(ssp->clk); |
125 | } | 125 | } |
126 | 126 | ||
127 | kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); | 127 | kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); |
@@ -136,7 +136,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) | |||
136 | struct ssp_device *ssp = priv->ssp; | 136 | struct ssp_device *ssp = priv->ssp; |
137 | 137 | ||
138 | if (!cpu_dai->active) | 138 | if (!cpu_dai->active) |
139 | clk_enable(ssp->clk); | 139 | clk_prepare_enable(ssp->clk); |
140 | 140 | ||
141 | priv->cr0 = __raw_readl(ssp->mmio_base + SSCR0); | 141 | priv->cr0 = __raw_readl(ssp->mmio_base + SSCR0); |
142 | priv->cr1 = __raw_readl(ssp->mmio_base + SSCR1); | 142 | priv->cr1 = __raw_readl(ssp->mmio_base + SSCR1); |
@@ -144,7 +144,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) | |||
144 | priv->psp = __raw_readl(ssp->mmio_base + SSPSP); | 144 | priv->psp = __raw_readl(ssp->mmio_base + SSPSP); |
145 | 145 | ||
146 | pxa_ssp_disable(ssp); | 146 | pxa_ssp_disable(ssp); |
147 | clk_disable(ssp->clk); | 147 | clk_disable_unprepare(ssp->clk); |
148 | return 0; | 148 | return 0; |
149 | } | 149 | } |
150 | 150 | ||
@@ -154,7 +154,7 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) | |||
154 | struct ssp_device *ssp = priv->ssp; | 154 | struct ssp_device *ssp = priv->ssp; |
155 | uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE; | 155 | uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE; |
156 | 156 | ||
157 | clk_enable(ssp->clk); | 157 | clk_prepare_enable(ssp->clk); |
158 | 158 | ||
159 | __raw_writel(sssr, ssp->mmio_base + SSSR); | 159 | __raw_writel(sssr, ssp->mmio_base + SSSR); |
160 | __raw_writel(priv->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0); | 160 | __raw_writel(priv->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0); |
@@ -165,7 +165,7 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) | |||
165 | if (cpu_dai->active) | 165 | if (cpu_dai->active) |
166 | pxa_ssp_enable(ssp); | 166 | pxa_ssp_enable(ssp); |
167 | else | 167 | else |
168 | clk_disable(ssp->clk); | 168 | clk_disable_unprepare(ssp->clk); |
169 | 169 | ||
170 | return 0; | 170 | return 0; |
171 | } | 171 | } |
@@ -256,11 +256,11 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
256 | /* The SSP clock must be disabled when changing SSP clock mode | 256 | /* The SSP clock must be disabled when changing SSP clock mode |
257 | * on PXA2xx. On PXA3xx it must be enabled when doing so. */ | 257 | * on PXA2xx. On PXA3xx it must be enabled when doing so. */ |
258 | if (ssp->type != PXA3xx_SSP) | 258 | if (ssp->type != PXA3xx_SSP) |
259 | clk_disable(ssp->clk); | 259 | clk_disable_unprepare(ssp->clk); |
260 | val = pxa_ssp_read_reg(ssp, SSCR0) | sscr0; | 260 | val = pxa_ssp_read_reg(ssp, SSCR0) | sscr0; |
261 | pxa_ssp_write_reg(ssp, SSCR0, val); | 261 | pxa_ssp_write_reg(ssp, SSCR0, val); |
262 | if (ssp->type != PXA3xx_SSP) | 262 | if (ssp->type != PXA3xx_SSP) |
263 | clk_enable(ssp->clk); | 263 | clk_prepare_enable(ssp->clk); |
264 | 264 | ||
265 | return 0; | 265 | return 0; |
266 | } | 266 | } |
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index ae956e3f4b9d..73ca2820c08c 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -157,7 +157,7 @@ static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = { | |||
157 | static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { | 157 | static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { |
158 | { | 158 | { |
159 | .name = "pxa2xx-ac97", | 159 | .name = "pxa2xx-ac97", |
160 | .ac97_control = 1, | 160 | .bus_control = true, |
161 | .playback = { | 161 | .playback = { |
162 | .stream_name = "AC97 Playback", | 162 | .stream_name = "AC97 Playback", |
163 | .channels_min = 2, | 163 | .channels_min = 2, |
@@ -174,7 +174,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { | |||
174 | }, | 174 | }, |
175 | { | 175 | { |
176 | .name = "pxa2xx-ac97-aux", | 176 | .name = "pxa2xx-ac97-aux", |
177 | .ac97_control = 1, | 177 | .bus_control = true, |
178 | .playback = { | 178 | .playback = { |
179 | .stream_name = "AC97 Aux Playback", | 179 | .stream_name = "AC97 Aux Playback", |
180 | .channels_min = 1, | 180 | .channels_min = 1, |
@@ -191,7 +191,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { | |||
191 | }, | 191 | }, |
192 | { | 192 | { |
193 | .name = "pxa2xx-ac97-mic", | 193 | .name = "pxa2xx-ac97-mic", |
194 | .ac97_control = 1, | 194 | .bus_control = true, |
195 | .capture = { | 195 | .capture = { |
196 | .stream_name = "AC97 Mic Capture", | 196 | .stream_name = "AC97 Mic Capture", |
197 | .channels_min = 1, | 197 | .channels_min = 1, |
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 1373b017a951..d7d5fb20ea6f 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
@@ -305,19 +305,15 @@ static struct snd_soc_card snd_soc_spitz = { | |||
305 | .num_dapm_routes = ARRAY_SIZE(spitz_audio_map), | 305 | .num_dapm_routes = ARRAY_SIZE(spitz_audio_map), |
306 | }; | 306 | }; |
307 | 307 | ||
308 | static struct platform_device *spitz_snd_device; | 308 | static int spitz_probe(struct platform_device *pdev) |
309 | |||
310 | static int __init spitz_init(void) | ||
311 | { | 309 | { |
310 | struct snd_soc_card *card = &snd_soc_spitz; | ||
312 | int ret; | 311 | int ret; |
313 | 312 | ||
314 | if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita())) | 313 | if (machine_is_akita()) |
315 | return -ENODEV; | ||
316 | |||
317 | if (machine_is_borzoi() || machine_is_spitz()) | ||
318 | spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS; | ||
319 | else | ||
320 | spitz_mic_gpio = AKITA_GPIO_MIC_BIAS; | 314 | spitz_mic_gpio = AKITA_GPIO_MIC_BIAS; |
315 | else | ||
316 | spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS; | ||
321 | 317 | ||
322 | ret = gpio_request(spitz_mic_gpio, "MIC GPIO"); | 318 | ret = gpio_request(spitz_mic_gpio, "MIC GPIO"); |
323 | if (ret) | 319 | if (ret) |
@@ -327,37 +323,45 @@ static int __init spitz_init(void) | |||
327 | if (ret) | 323 | if (ret) |
328 | goto err2; | 324 | goto err2; |
329 | 325 | ||
330 | spitz_snd_device = platform_device_alloc("soc-audio", -1); | 326 | card->dev = &pdev->dev; |
331 | if (!spitz_snd_device) { | 327 | |
332 | ret = -ENOMEM; | 328 | ret = snd_soc_register_card(card); |
329 | if (ret) { | ||
330 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
331 | ret); | ||
333 | goto err2; | 332 | goto err2; |
334 | } | 333 | } |
335 | 334 | ||
336 | platform_set_drvdata(spitz_snd_device, &snd_soc_spitz); | ||
337 | |||
338 | ret = platform_device_add(spitz_snd_device); | ||
339 | if (ret) | ||
340 | goto err3; | ||
341 | |||
342 | return 0; | 335 | return 0; |
343 | 336 | ||
344 | err3: | ||
345 | platform_device_put(spitz_snd_device); | ||
346 | err2: | 337 | err2: |
347 | gpio_free(spitz_mic_gpio); | 338 | gpio_free(spitz_mic_gpio); |
348 | err1: | 339 | err1: |
349 | return ret; | 340 | return ret; |
350 | } | 341 | } |
351 | 342 | ||
352 | static void __exit spitz_exit(void) | 343 | static int spitz_remove(struct platform_device *pdev) |
353 | { | 344 | { |
354 | platform_device_unregister(spitz_snd_device); | 345 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
346 | |||
347 | snd_soc_unregister_card(card); | ||
355 | gpio_free(spitz_mic_gpio); | 348 | gpio_free(spitz_mic_gpio); |
349 | return 0; | ||
356 | } | 350 | } |
357 | 351 | ||
358 | module_init(spitz_init); | 352 | static struct platform_driver spitz_driver = { |
359 | module_exit(spitz_exit); | 353 | .driver = { |
354 | .name = "spitz-audio", | ||
355 | .owner = THIS_MODULE, | ||
356 | .pm = &snd_soc_pm_ops, | ||
357 | }, | ||
358 | .probe = spitz_probe, | ||
359 | .remove = spitz_remove, | ||
360 | }; | ||
361 | |||
362 | module_platform_driver(spitz_driver); | ||
360 | 363 | ||
361 | MODULE_AUTHOR("Richard Purdie"); | 364 | MODULE_AUTHOR("Richard Purdie"); |
362 | MODULE_DESCRIPTION("ALSA SoC Spitz"); | 365 | MODULE_DESCRIPTION("ALSA SoC Spitz"); |
363 | MODULE_LICENSE("GPL"); | 366 | MODULE_LICENSE("GPL"); |
367 | MODULE_ALIAS("platform:spitz-audio"); | ||
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index 78fc159559b0..e18182699d83 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig | |||
@@ -1,11 +1,16 @@ | |||
1 | config SND_SOC_ROCKCHIP | 1 | config SND_SOC_ROCKCHIP |
2 | tristate "ASoC support for Rockchip" | 2 | tristate "ASoC support for Rockchip" |
3 | depends on COMPILE_TEST || ARCH_ROCKCHIP | 3 | depends on COMPILE_TEST || ARCH_ROCKCHIP |
4 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
5 | help | 4 | help |
6 | 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 |
7 | the Rockchip SoCs' Audio interfaces. You will also need to | 6 | the Rockchip SoCs' Audio interfaces. You will also need to |
8 | select the audio interfaces to support below. | 7 | select the audio interfaces to support below. |
9 | 8 | ||
10 | config SND_SOC_ROCKCHIP_I2S | 9 | config SND_SOC_ROCKCHIP_I2S |
11 | tristate | 10 | tristate "Rockchip I2S Device Driver" |
11 | depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP | ||
12 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
13 | help | ||
14 | Say Y or M if you want to add support for I2S driver for | ||
15 | Rockchip I2S device. The device supports upto maximum of | ||
16 | 8 channels each for play and record. | ||
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 55a38697443d..fc67f97f19f6 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_SOC_SAMSUNG | 1 | config SND_SOC_SAMSUNG |
2 | tristate "ASoC support for Samsung" | 2 | tristate "ASoC support for Samsung" |
3 | depends on PLAT_SAMSUNG | 3 | depends on (PLAT_SAMSUNG || ARCH_EXYNOS) |
4 | depends on S3C64XX_PL080 || !ARCH_S3C64XX | 4 | depends on S3C64XX_PL080 || !ARCH_S3C64XX |
5 | depends on S3C24XX_DMAC || !ARCH_S3C24XX | 5 | depends on S3C24XX_DMAC || !ARCH_S3C24XX |
6 | select SND_SOC_GENERIC_DMAENGINE_PCM | 6 | select SND_SOC_GENERIC_DMAENGINE_PCM |
@@ -239,3 +239,9 @@ config SND_SOC_ODROIDX2 | |||
239 | select SND_SAMSUNG_I2S | 239 | select SND_SAMSUNG_I2S |
240 | help | 240 | help |
241 | Say Y here to enable audio support for the Odroid-X2/U3. | 241 | Say Y here to enable audio support for the Odroid-X2/U3. |
242 | |||
243 | config SND_SOC_ARNDALE_RT5631_ALC5631 | ||
244 | tristate "Audio support for RT5631(ALC5631) on Arndale Board" | ||
245 | depends on SND_SOC_SAMSUNG | ||
246 | select SND_SAMSUNG_I2S | ||
247 | select SND_SOC_RT5631 | ||
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 91505ddaaf95..31e3dba7e3b5 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile | |||
@@ -45,6 +45,7 @@ snd-soc-lowland-objs := lowland.o | |||
45 | snd-soc-littlemill-objs := littlemill.o | 45 | snd-soc-littlemill-objs := littlemill.o |
46 | snd-soc-bells-objs := bells.o | 46 | snd-soc-bells-objs := bells.o |
47 | snd-soc-odroidx2-max98090-objs := odroidx2_max98090.o | 47 | snd-soc-odroidx2-max98090-objs := odroidx2_max98090.o |
48 | snd-soc-arndale-rt5631-objs := arndale_rt5631.o | ||
48 | 49 | ||
49 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o | 50 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o |
50 | obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 51 | obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
@@ -71,3 +72,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o | |||
71 | obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o | 72 | obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o |
72 | obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o | 73 | obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o |
73 | obj-$(CONFIG_SND_SOC_ODROIDX2) += snd-soc-odroidx2-max98090.o | 74 | obj-$(CONFIG_SND_SOC_ODROIDX2) += snd-soc-odroidx2-max98090.o |
75 | obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o | ||
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index e1615113fd84..7952a625669d 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c | |||
@@ -288,7 +288,7 @@ static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai) | |||
288 | static struct snd_soc_dai_driver s3c_ac97_dai[] = { | 288 | static struct snd_soc_dai_driver s3c_ac97_dai[] = { |
289 | [S3C_AC97_DAI_PCM] = { | 289 | [S3C_AC97_DAI_PCM] = { |
290 | .name = "samsung-ac97", | 290 | .name = "samsung-ac97", |
291 | .ac97_control = 1, | 291 | .bus_control = true, |
292 | .playback = { | 292 | .playback = { |
293 | .stream_name = "AC97 Playback", | 293 | .stream_name = "AC97 Playback", |
294 | .channels_min = 2, | 294 | .channels_min = 2, |
@@ -306,7 +306,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = { | |||
306 | }, | 306 | }, |
307 | [S3C_AC97_DAI_MIC] = { | 307 | [S3C_AC97_DAI_MIC] = { |
308 | .name = "samsung-ac97-mic", | 308 | .name = "samsung-ac97-mic", |
309 | .ac97_control = 1, | 309 | .bus_control = true, |
310 | .capture = { | 310 | .capture = { |
311 | .stream_name = "AC97 Mic Capture", | 311 | .stream_name = "AC97 Mic Capture", |
312 | .channels_min = 1, | 312 | .channels_min = 1, |
diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c new file mode 100644 index 000000000000..1e2b61ca8db2 --- /dev/null +++ b/sound/soc/samsung/arndale_rt5631.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * arndale_rt5631.c | ||
3 | * | ||
4 | * Copyright (c) 2014, Insignal Co., Ltd. | ||
5 | * | ||
6 | * Author: Claude <claude@insginal.co.kr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/clk.h> | ||
17 | |||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | |||
23 | #include "i2s.h" | ||
24 | |||
25 | static int arndale_hw_params(struct snd_pcm_substream *substream, | ||
26 | struct snd_pcm_hw_params *params) | ||
27 | { | ||
28 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
29 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
30 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
31 | int rfs, ret; | ||
32 | unsigned long rclk; | ||
33 | |||
34 | rfs = 256; | ||
35 | |||
36 | rclk = params_rate(params) * rfs; | ||
37 | |||
38 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, | ||
39 | 0, SND_SOC_CLOCK_OUT); | ||
40 | if (ret < 0) | ||
41 | return ret; | ||
42 | |||
43 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, | ||
44 | 0, SND_SOC_CLOCK_OUT); | ||
45 | |||
46 | if (ret < 0) | ||
47 | return ret; | ||
48 | |||
49 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT); | ||
50 | if (ret < 0) | ||
51 | return ret; | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static struct snd_soc_ops arndale_ops = { | ||
57 | .hw_params = arndale_hw_params, | ||
58 | }; | ||
59 | |||
60 | static struct snd_soc_dai_link arndale_rt5631_dai[] = { | ||
61 | { | ||
62 | .name = "RT5631 HiFi", | ||
63 | .stream_name = "Primary", | ||
64 | .codec_dai_name = "rt5631-hifi", | ||
65 | .dai_fmt = SND_SOC_DAIFMT_I2S | ||
66 | | SND_SOC_DAIFMT_NB_NF | ||
67 | | SND_SOC_DAIFMT_CBS_CFS, | ||
68 | .ops = &arndale_ops, | ||
69 | }, | ||
70 | }; | ||
71 | |||
72 | static struct snd_soc_card arndale_rt5631 = { | ||
73 | .name = "Arndale RT5631", | ||
74 | .dai_link = arndale_rt5631_dai, | ||
75 | .num_links = ARRAY_SIZE(arndale_rt5631_dai), | ||
76 | }; | ||
77 | |||
78 | static int arndale_audio_probe(struct platform_device *pdev) | ||
79 | { | ||
80 | int n, ret; | ||
81 | struct device_node *np = pdev->dev.of_node; | ||
82 | struct snd_soc_card *card = &arndale_rt5631; | ||
83 | |||
84 | card->dev = &pdev->dev; | ||
85 | |||
86 | for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) { | ||
87 | if (!arndale_rt5631_dai[n].cpu_dai_name) { | ||
88 | arndale_rt5631_dai[n].cpu_of_node = of_parse_phandle(np, | ||
89 | "samsung,audio-cpu", n); | ||
90 | |||
91 | if (!arndale_rt5631_dai[n].cpu_of_node) { | ||
92 | dev_err(&pdev->dev, | ||
93 | "Property 'samsung,audio-cpu' missing or invalid\n"); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | } | ||
97 | if (!arndale_rt5631_dai[n].platform_name) | ||
98 | arndale_rt5631_dai[n].platform_of_node = | ||
99 | arndale_rt5631_dai[n].cpu_of_node; | ||
100 | |||
101 | arndale_rt5631_dai[n].codec_name = NULL; | ||
102 | arndale_rt5631_dai[n].codec_of_node = of_parse_phandle(np, | ||
103 | "samsung,audio-codec", n); | ||
104 | if (!arndale_rt5631_dai[0].codec_of_node) { | ||
105 | dev_err(&pdev->dev, | ||
106 | "Property 'samsung,audio-codec' missing or invalid\n"); | ||
107 | return -EINVAL; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | ret = devm_snd_soc_register_card(card->dev, card); | ||
112 | |||
113 | if (ret) | ||
114 | dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | static int arndale_audio_remove(struct platform_device *pdev) | ||
120 | { | ||
121 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
122 | |||
123 | snd_soc_unregister_card(card); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = { | ||
129 | { .compatible = "samsung,arndale-rt5631", }, | ||
130 | { .compatible = "samsung,arndale-alc5631", }, | ||
131 | {}, | ||
132 | }; | ||
133 | MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match); | ||
134 | |||
135 | static struct platform_driver arndale_audio_driver = { | ||
136 | .driver = { | ||
137 | .name = "arndale-audio", | ||
138 | .owner = THIS_MODULE, | ||
139 | .pm = &snd_soc_pm_ops, | ||
140 | .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), | ||
141 | }, | ||
142 | .probe = arndale_audio_probe, | ||
143 | .remove = arndale_audio_remove, | ||
144 | }; | ||
145 | |||
146 | module_platform_driver(arndale_audio_driver); | ||
147 | |||
148 | MODULE_AUTHOR("Claude <claude@insignal.co.kr>"); | ||
149 | MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board"); | ||
150 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h index 821a50231002..9170c311d66e 100644 --- a/sound/soc/samsung/i2s-regs.h +++ b/sound/soc/samsung/i2s-regs.h | |||
@@ -33,8 +33,9 @@ | |||
33 | #define I2SLVL3ADDR 0x3c | 33 | #define I2SLVL3ADDR 0x3c |
34 | #define I2SSTR1 0x40 | 34 | #define I2SSTR1 0x40 |
35 | #define I2SVER 0x44 | 35 | #define I2SVER 0x44 |
36 | #define I2SFIC2 0x48 | 36 | #define I2SFIC1 0x48 |
37 | #define I2STDM 0x4c | 37 | #define I2STDM 0x4c |
38 | #define I2SFSTA 0x50 | ||
38 | 39 | ||
39 | #define CON_RSTCLR (1 << 31) | 40 | #define CON_RSTCLR (1 << 31) |
40 | #define CON_FRXOFSTATUS (1 << 26) | 41 | #define CON_FRXOFSTATUS (1 << 26) |
@@ -93,8 +94,6 @@ | |||
93 | #define MOD_BLC_24BIT (2 << 13) | 94 | #define MOD_BLC_24BIT (2 << 13) |
94 | #define MOD_BLC_MASK (3 << 13) | 95 | #define MOD_BLC_MASK (3 << 13) |
95 | 96 | ||
96 | #define MOD_IMS_SYSMUX (1 << 10) | ||
97 | #define MOD_SLAVE (1 << 11) | ||
98 | #define MOD_TXONLY (0 << 8) | 97 | #define MOD_TXONLY (0 << 8) |
99 | #define MOD_RXONLY (1 << 8) | 98 | #define MOD_RXONLY (1 << 8) |
100 | #define MOD_TXRX (2 << 8) | 99 | #define MOD_TXRX (2 << 8) |
@@ -132,7 +131,10 @@ | |||
132 | #define EXYNOS5420_MOD_BCLK_256FS 8 | 131 | #define EXYNOS5420_MOD_BCLK_256FS 8 |
133 | #define EXYNOS5420_MOD_BCLK_MASK 0xf | 132 | #define EXYNOS5420_MOD_BCLK_MASK 0xf |
134 | 133 | ||
135 | #define MOD_CDCLKCON (1 << 12) | 134 | #define EXYNOS7_MOD_RCLK_64FS 4 |
135 | #define EXYNOS7_MOD_RCLK_128FS 5 | ||
136 | #define EXYNOS7_MOD_RCLK_96FS 6 | ||
137 | #define EXYNOS7_MOD_RCLK_192FS 7 | ||
136 | 138 | ||
137 | #define PSR_PSREN (1 << 15) | 139 | #define PSR_PSREN (1 << 15) |
138 | 140 | ||
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 9d513473b300..c7aafcd95de3 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -36,9 +36,24 @@ enum samsung_dai_type { | |||
36 | TYPE_SEC, | 36 | TYPE_SEC, |
37 | }; | 37 | }; |
38 | 38 | ||
39 | struct samsung_i2s_variant_regs { | ||
40 | unsigned int bfs_off; | ||
41 | unsigned int rfs_off; | ||
42 | unsigned int sdf_off; | ||
43 | unsigned int txr_off; | ||
44 | unsigned int rclksrc_off; | ||
45 | unsigned int mss_off; | ||
46 | unsigned int cdclkcon_off; | ||
47 | unsigned int lrp_off; | ||
48 | unsigned int bfs_mask; | ||
49 | unsigned int rfs_mask; | ||
50 | unsigned int ftx0cnt_off; | ||
51 | }; | ||
52 | |||
39 | struct samsung_i2s_dai_data { | 53 | struct samsung_i2s_dai_data { |
40 | int dai_type; | 54 | int dai_type; |
41 | u32 quirks; | 55 | u32 quirks; |
56 | const struct samsung_i2s_variant_regs *i2s_variant_regs; | ||
42 | }; | 57 | }; |
43 | 58 | ||
44 | struct i2s_dai { | 59 | struct i2s_dai { |
@@ -81,6 +96,7 @@ struct i2s_dai { | |||
81 | u32 suspend_i2scon; | 96 | u32 suspend_i2scon; |
82 | u32 suspend_i2spsr; | 97 | u32 suspend_i2spsr; |
83 | unsigned long gpios[7]; /* i2s gpio line numbers */ | 98 | unsigned long gpios[7]; /* i2s gpio line numbers */ |
99 | const struct samsung_i2s_variant_regs *variant_regs; | ||
84 | }; | 100 | }; |
85 | 101 | ||
86 | /* Lock for cross i/f checks */ | 102 | /* Lock for cross i/f checks */ |
@@ -95,7 +111,8 @@ static inline bool is_secondary(struct i2s_dai *i2s) | |||
95 | /* If operating in SoC-Slave mode */ | 111 | /* If operating in SoC-Slave mode */ |
96 | static inline bool is_slave(struct i2s_dai *i2s) | 112 | static inline bool is_slave(struct i2s_dai *i2s) |
97 | { | 113 | { |
98 | return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false; | 114 | u32 mod = readl(i2s->addr + I2SMOD); |
115 | return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false; | ||
99 | } | 116 | } |
100 | 117 | ||
101 | /* If this interface of the controller is transmitting data */ | 118 | /* If this interface of the controller is transmitting data */ |
@@ -200,14 +217,14 @@ static inline bool is_manager(struct i2s_dai *i2s) | |||
200 | static inline unsigned get_rfs(struct i2s_dai *i2s) | 217 | static inline unsigned get_rfs(struct i2s_dai *i2s) |
201 | { | 218 | { |
202 | u32 rfs; | 219 | u32 rfs; |
203 | 220 | rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off; | |
204 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) | 221 | rfs &= i2s->variant_regs->rfs_mask; |
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; | ||
209 | 222 | ||
210 | switch (rfs) { | 223 | switch (rfs) { |
224 | case 7: return 192; | ||
225 | case 6: return 96; | ||
226 | case 5: return 128; | ||
227 | case 4: return 64; | ||
211 | case 3: return 768; | 228 | case 3: return 768; |
212 | case 2: return 384; | 229 | case 2: return 384; |
213 | case 1: return 512; | 230 | case 1: return 512; |
@@ -219,15 +236,23 @@ static inline unsigned get_rfs(struct i2s_dai *i2s) | |||
219 | static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) | 236 | static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) |
220 | { | 237 | { |
221 | u32 mod = readl(i2s->addr + I2SMOD); | 238 | u32 mod = readl(i2s->addr + I2SMOD); |
222 | int rfs_shift; | 239 | int rfs_shift = i2s->variant_regs->rfs_off; |
223 | 240 | ||
224 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) | 241 | mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift); |
225 | rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT; | ||
226 | else | ||
227 | rfs_shift = MOD_RCLK_SHIFT; | ||
228 | mod &= ~(MOD_RCLK_MASK << rfs_shift); | ||
229 | 242 | ||
230 | switch (rfs) { | 243 | switch (rfs) { |
244 | case 192: | ||
245 | mod |= (EXYNOS7_MOD_RCLK_192FS << rfs_shift); | ||
246 | break; | ||
247 | case 96: | ||
248 | mod |= (EXYNOS7_MOD_RCLK_96FS << rfs_shift); | ||
249 | break; | ||
250 | case 128: | ||
251 | mod |= (EXYNOS7_MOD_RCLK_128FS << rfs_shift); | ||
252 | break; | ||
253 | case 64: | ||
254 | mod |= (EXYNOS7_MOD_RCLK_64FS << rfs_shift); | ||
255 | break; | ||
231 | case 768: | 256 | case 768: |
232 | mod |= (MOD_RCLK_768FS << rfs_shift); | 257 | mod |= (MOD_RCLK_768FS << rfs_shift); |
233 | break; | 258 | break; |
@@ -249,14 +274,8 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) | |||
249 | static inline unsigned get_bfs(struct i2s_dai *i2s) | 274 | static inline unsigned get_bfs(struct i2s_dai *i2s) |
250 | { | 275 | { |
251 | u32 bfs; | 276 | u32 bfs; |
252 | 277 | bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off; | |
253 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) { | 278 | bfs &= i2s->variant_regs->bfs_mask; |
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 | } | ||
260 | 279 | ||
261 | switch (bfs) { | 280 | switch (bfs) { |
262 | case 8: return 256; | 281 | case 8: return 256; |
@@ -275,16 +294,8 @@ static inline unsigned get_bfs(struct i2s_dai *i2s) | |||
275 | static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) | 294 | static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) |
276 | { | 295 | { |
277 | u32 mod = readl(i2s->addr + I2SMOD); | 296 | u32 mod = readl(i2s->addr + I2SMOD); |
278 | int bfs_shift; | ||
279 | int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; | 297 | int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; |
280 | 298 | int bfs_shift = i2s->variant_regs->bfs_off; | |
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 | 299 | ||
289 | /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ | 300 | /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ |
290 | if (!tdm && bfs > 48) { | 301 | if (!tdm && bfs > 48) { |
@@ -292,6 +303,8 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) | |||
292 | return; | 303 | return; |
293 | } | 304 | } |
294 | 305 | ||
306 | mod &= ~(i2s->variant_regs->bfs_mask << bfs_shift); | ||
307 | |||
295 | switch (bfs) { | 308 | switch (bfs) { |
296 | case 48: | 309 | case 48: |
297 | mod |= (MOD_BCLK_48FS << bfs_shift); | 310 | mod |= (MOD_BCLK_48FS << bfs_shift); |
@@ -346,8 +359,9 @@ static inline int get_blc(struct i2s_dai *i2s) | |||
346 | static void i2s_txctrl(struct i2s_dai *i2s, int on) | 359 | static void i2s_txctrl(struct i2s_dai *i2s, int on) |
347 | { | 360 | { |
348 | void __iomem *addr = i2s->addr; | 361 | void __iomem *addr = i2s->addr; |
362 | int txr_off = i2s->variant_regs->txr_off; | ||
349 | u32 con = readl(addr + I2SCON); | 363 | u32 con = readl(addr + I2SCON); |
350 | u32 mod = readl(addr + I2SMOD) & ~MOD_MASK; | 364 | u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); |
351 | 365 | ||
352 | if (on) { | 366 | if (on) { |
353 | con |= CON_ACTIVE; | 367 | con |= CON_ACTIVE; |
@@ -362,9 +376,9 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) | |||
362 | } | 376 | } |
363 | 377 | ||
364 | if (any_rx_active(i2s)) | 378 | if (any_rx_active(i2s)) |
365 | mod |= MOD_TXRX; | 379 | mod |= 2 << txr_off; |
366 | else | 380 | else |
367 | mod |= MOD_TXONLY; | 381 | mod |= 0 << txr_off; |
368 | } else { | 382 | } else { |
369 | if (is_secondary(i2s)) { | 383 | if (is_secondary(i2s)) { |
370 | con |= CON_TXSDMA_PAUSE; | 384 | con |= CON_TXSDMA_PAUSE; |
@@ -382,7 +396,7 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) | |||
382 | con |= CON_TXCH_PAUSE; | 396 | con |= CON_TXCH_PAUSE; |
383 | 397 | ||
384 | if (any_rx_active(i2s)) | 398 | if (any_rx_active(i2s)) |
385 | mod |= MOD_RXONLY; | 399 | mod |= 1 << txr_off; |
386 | else | 400 | else |
387 | con &= ~CON_ACTIVE; | 401 | con &= ~CON_ACTIVE; |
388 | } | 402 | } |
@@ -395,23 +409,24 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) | |||
395 | static void i2s_rxctrl(struct i2s_dai *i2s, int on) | 409 | static void i2s_rxctrl(struct i2s_dai *i2s, int on) |
396 | { | 410 | { |
397 | void __iomem *addr = i2s->addr; | 411 | void __iomem *addr = i2s->addr; |
412 | int txr_off = i2s->variant_regs->txr_off; | ||
398 | u32 con = readl(addr + I2SCON); | 413 | u32 con = readl(addr + I2SCON); |
399 | u32 mod = readl(addr + I2SMOD) & ~MOD_MASK; | 414 | u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); |
400 | 415 | ||
401 | if (on) { | 416 | if (on) { |
402 | con |= CON_RXDMA_ACTIVE | CON_ACTIVE; | 417 | con |= CON_RXDMA_ACTIVE | CON_ACTIVE; |
403 | con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE); | 418 | con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE); |
404 | 419 | ||
405 | if (any_tx_active(i2s)) | 420 | if (any_tx_active(i2s)) |
406 | mod |= MOD_TXRX; | 421 | mod |= 2 << txr_off; |
407 | else | 422 | else |
408 | mod |= MOD_RXONLY; | 423 | mod |= 1 << txr_off; |
409 | } else { | 424 | } else { |
410 | con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE; | 425 | con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE; |
411 | con &= ~CON_RXDMA_ACTIVE; | 426 | con &= ~CON_RXDMA_ACTIVE; |
412 | 427 | ||
413 | if (any_tx_active(i2s)) | 428 | if (any_tx_active(i2s)) |
414 | mod |= MOD_TXONLY; | 429 | mod |= 0 << txr_off; |
415 | else | 430 | else |
416 | con &= ~CON_ACTIVE; | 431 | con &= ~CON_ACTIVE; |
417 | } | 432 | } |
@@ -451,6 +466,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
451 | struct i2s_dai *i2s = to_info(dai); | 466 | struct i2s_dai *i2s = to_info(dai); |
452 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; | 467 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; |
453 | u32 mod = readl(i2s->addr + I2SMOD); | 468 | u32 mod = readl(i2s->addr + I2SMOD); |
469 | const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; | ||
470 | unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; | ||
471 | unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; | ||
454 | 472 | ||
455 | switch (clk_id) { | 473 | switch (clk_id) { |
456 | case SAMSUNG_I2S_OPCLK: | 474 | case SAMSUNG_I2S_OPCLK: |
@@ -465,18 +483,18 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
465 | if ((rfs && other && other->rfs && (other->rfs != rfs)) || | 483 | if ((rfs && other && other->rfs && (other->rfs != rfs)) || |
466 | (any_active(i2s) && | 484 | (any_active(i2s) && |
467 | (((dir == SND_SOC_CLOCK_IN) | 485 | (((dir == SND_SOC_CLOCK_IN) |
468 | && !(mod & MOD_CDCLKCON)) || | 486 | && !(mod & cdcon_mask)) || |
469 | ((dir == SND_SOC_CLOCK_OUT) | 487 | ((dir == SND_SOC_CLOCK_OUT) |
470 | && (mod & MOD_CDCLKCON))))) { | 488 | && (mod & cdcon_mask))))) { |
471 | dev_err(&i2s->pdev->dev, | 489 | dev_err(&i2s->pdev->dev, |
472 | "%s:%d Other DAI busy\n", __func__, __LINE__); | 490 | "%s:%d Other DAI busy\n", __func__, __LINE__); |
473 | return -EAGAIN; | 491 | return -EAGAIN; |
474 | } | 492 | } |
475 | 493 | ||
476 | if (dir == SND_SOC_CLOCK_IN) | 494 | if (dir == SND_SOC_CLOCK_IN) |
477 | mod |= MOD_CDCLKCON; | 495 | mod |= 1 << i2s_regs->cdclkcon_off; |
478 | else | 496 | else |
479 | mod &= ~MOD_CDCLKCON; | 497 | mod &= ~(1 << i2s_regs->cdclkcon_off); |
480 | 498 | ||
481 | i2s->rfs = rfs; | 499 | i2s->rfs = rfs; |
482 | break; | 500 | break; |
@@ -491,8 +509,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
491 | 509 | ||
492 | if (!any_active(i2s)) { | 510 | if (!any_active(i2s)) { |
493 | if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { | 511 | if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { |
494 | if ((clk_id && !(mod & MOD_IMS_SYSMUX)) || | 512 | if ((clk_id && !(mod & rsrc_mask)) || |
495 | (!clk_id && (mod & MOD_IMS_SYSMUX))) { | 513 | (!clk_id && (mod & rsrc_mask))) { |
496 | clk_disable_unprepare(i2s->op_clk); | 514 | clk_disable_unprepare(i2s->op_clk); |
497 | clk_put(i2s->op_clk); | 515 | clk_put(i2s->op_clk); |
498 | } else { | 516 | } else { |
@@ -520,8 +538,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
520 | other->op_clk = i2s->op_clk; | 538 | other->op_clk = i2s->op_clk; |
521 | other->rclk_srcrate = i2s->rclk_srcrate; | 539 | other->rclk_srcrate = i2s->rclk_srcrate; |
522 | } | 540 | } |
523 | } else if ((!clk_id && (mod & MOD_IMS_SYSMUX)) | 541 | } else if ((!clk_id && (mod & rsrc_mask)) |
524 | || (clk_id && !(mod & MOD_IMS_SYSMUX))) { | 542 | || (clk_id && !(mod & rsrc_mask))) { |
525 | dev_err(&i2s->pdev->dev, | 543 | dev_err(&i2s->pdev->dev, |
526 | "%s:%d Other DAI busy\n", __func__, __LINE__); | 544 | "%s:%d Other DAI busy\n", __func__, __LINE__); |
527 | return -EAGAIN; | 545 | return -EAGAIN; |
@@ -533,11 +551,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
533 | } | 551 | } |
534 | 552 | ||
535 | if (clk_id == 0) | 553 | if (clk_id == 0) |
536 | mod &= ~MOD_IMS_SYSMUX; | 554 | mod &= ~(1 << i2s_regs->rclksrc_off); |
537 | else | 555 | else |
538 | mod |= MOD_IMS_SYSMUX; | 556 | mod |= 1 << i2s_regs->rclksrc_off; |
539 | break; | ||
540 | 557 | ||
558 | break; | ||
541 | default: | 559 | default: |
542 | dev_err(&i2s->pdev->dev, "We don't serve that!\n"); | 560 | dev_err(&i2s->pdev->dev, "We don't serve that!\n"); |
543 | return -EINVAL; | 561 | return -EINVAL; |
@@ -553,16 +571,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, | |||
553 | { | 571 | { |
554 | struct i2s_dai *i2s = to_info(dai); | 572 | struct i2s_dai *i2s = to_info(dai); |
555 | u32 mod = readl(i2s->addr + I2SMOD); | 573 | u32 mod = readl(i2s->addr + I2SMOD); |
556 | int lrp_shift, sdf_shift, sdf_mask, lrp_rlow; | 574 | int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; |
557 | u32 tmp = 0; | 575 | u32 tmp = 0; |
558 | 576 | ||
559 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) { | 577 | lrp_shift = i2s->variant_regs->lrp_off; |
560 | lrp_shift = EXYNOS5420_MOD_LRP_SHIFT; | 578 | sdf_shift = i2s->variant_regs->sdf_off; |
561 | sdf_shift = EXYNOS5420_MOD_SDF_SHIFT; | 579 | mod_slave = 1 << i2s->variant_regs->mss_off; |
562 | } else { | ||
563 | lrp_shift = MOD_LRP_SHIFT; | ||
564 | sdf_shift = MOD_SDF_SHIFT; | ||
565 | } | ||
566 | 580 | ||
567 | sdf_mask = MOD_SDF_MASK << sdf_shift; | 581 | sdf_mask = MOD_SDF_MASK << sdf_shift; |
568 | lrp_rlow = MOD_LR_RLOW << lrp_shift; | 582 | lrp_rlow = MOD_LR_RLOW << lrp_shift; |
@@ -605,7 +619,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, | |||
605 | 619 | ||
606 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 620 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
607 | case SND_SOC_DAIFMT_CBM_CFM: | 621 | case SND_SOC_DAIFMT_CBM_CFM: |
608 | tmp |= MOD_SLAVE; | 622 | tmp |= mod_slave; |
609 | break; | 623 | break; |
610 | case SND_SOC_DAIFMT_CBS_CFS: | 624 | case SND_SOC_DAIFMT_CBS_CFS: |
611 | /* Set default source clock in Master mode */ | 625 | /* Set default source clock in Master mode */ |
@@ -623,13 +637,13 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, | |||
623 | * channel. | 637 | * channel. |
624 | */ | 638 | */ |
625 | if (any_active(i2s) && | 639 | if (any_active(i2s) && |
626 | ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) { | 640 | ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { |
627 | dev_err(&i2s->pdev->dev, | 641 | dev_err(&i2s->pdev->dev, |
628 | "%s:%d Other DAI busy\n", __func__, __LINE__); | 642 | "%s:%d Other DAI busy\n", __func__, __LINE__); |
629 | return -EAGAIN; | 643 | return -EAGAIN; |
630 | } | 644 | } |
631 | 645 | ||
632 | mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE); | 646 | mod &= ~(sdf_mask | lrp_rlow | mod_slave); |
633 | mod |= tmp; | 647 | mod |= tmp; |
634 | writel(mod, i2s->addr + I2SMOD); | 648 | writel(mod, i2s->addr + I2SMOD); |
635 | 649 | ||
@@ -751,6 +765,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, | |||
751 | struct i2s_dai *i2s = to_info(dai); | 765 | struct i2s_dai *i2s = to_info(dai); |
752 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; | 766 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; |
753 | unsigned long flags; | 767 | unsigned long flags; |
768 | const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; | ||
754 | 769 | ||
755 | spin_lock_irqsave(&lock, flags); | 770 | spin_lock_irqsave(&lock, flags); |
756 | 771 | ||
@@ -761,7 +776,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, | |||
761 | other->mode |= DAI_MANAGER; | 776 | other->mode |= DAI_MANAGER; |
762 | } else { | 777 | } else { |
763 | u32 mod = readl(i2s->addr + I2SMOD); | 778 | u32 mod = readl(i2s->addr + I2SMOD); |
764 | i2s->cdclk_out = !(mod & MOD_CDCLKCON); | 779 | i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off)); |
765 | if (other) | 780 | if (other) |
766 | other->cdclk_out = i2s->cdclk_out; | 781 | other->cdclk_out = i2s->cdclk_out; |
767 | } | 782 | } |
@@ -914,13 +929,14 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) | |||
914 | struct i2s_dai *i2s = to_info(dai); | 929 | struct i2s_dai *i2s = to_info(dai); |
915 | u32 reg = readl(i2s->addr + I2SFIC); | 930 | u32 reg = readl(i2s->addr + I2SFIC); |
916 | snd_pcm_sframes_t delay; | 931 | snd_pcm_sframes_t delay; |
932 | const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; | ||
917 | 933 | ||
918 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | 934 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
919 | delay = FIC_RXCOUNT(reg); | 935 | delay = FIC_RXCOUNT(reg); |
920 | else if (is_secondary(i2s)) | 936 | else if (is_secondary(i2s)) |
921 | delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS)); | 937 | delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS)); |
922 | else | 938 | else |
923 | delay = FIC_TXCOUNT(reg); | 939 | delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f; |
924 | 940 | ||
925 | return delay; | 941 | return delay; |
926 | } | 942 | } |
@@ -956,6 +972,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) | |||
956 | { | 972 | { |
957 | struct i2s_dai *i2s = to_info(dai); | 973 | struct i2s_dai *i2s = to_info(dai); |
958 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; | 974 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; |
975 | int ret; | ||
959 | 976 | ||
960 | if (other && other->clk) { /* If this is probe on secondary */ | 977 | if (other && other->clk) { /* If this is probe on secondary */ |
961 | samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, | 978 | samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, |
@@ -973,9 +990,14 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) | |||
973 | if (IS_ERR(i2s->clk)) { | 990 | if (IS_ERR(i2s->clk)) { |
974 | dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n"); | 991 | dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n"); |
975 | iounmap(i2s->addr); | 992 | iounmap(i2s->addr); |
976 | return -ENOENT; | 993 | return PTR_ERR(i2s->clk); |
994 | } | ||
995 | |||
996 | ret = clk_prepare_enable(i2s->clk); | ||
997 | if (ret != 0) { | ||
998 | dev_err(&i2s->pdev->dev, "failed to enable clock: %d\n", ret); | ||
999 | return ret; | ||
977 | } | 1000 | } |
978 | clk_prepare_enable(i2s->clk); | ||
979 | 1001 | ||
980 | samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); | 1002 | samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); |
981 | 1003 | ||
@@ -987,7 +1009,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) | |||
987 | if (i2s->quirks & QUIRK_NEED_RSTCLR) | 1009 | if (i2s->quirks & QUIRK_NEED_RSTCLR) |
988 | writel(CON_RSTCLR, i2s->addr + I2SCON); | 1010 | writel(CON_RSTCLR, i2s->addr + I2SCON); |
989 | 1011 | ||
990 | if (i2s->quirks & QUIRK_SEC_DAI) | 1012 | if (i2s->quirks & QUIRK_SUPPORTS_IDMA) |
991 | idma_reg_addr_init(i2s->addr, | 1013 | idma_reg_addr_init(i2s->addr, |
992 | i2s->sec_dai->idma_playback.dma_addr); | 1014 | i2s->sec_dai->idma_playback.dma_addr); |
993 | 1015 | ||
@@ -1199,10 +1221,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1199 | quirks = i2s_dai_data->quirks; | 1221 | quirks = i2s_dai_data->quirks; |
1200 | if (of_property_read_u32(np, "samsung,idma-addr", | 1222 | if (of_property_read_u32(np, "samsung,idma-addr", |
1201 | &idma_addr)) { | 1223 | &idma_addr)) { |
1202 | if (quirks & QUIRK_SEC_DAI) { | 1224 | if (quirks & QUIRK_SUPPORTS_IDMA) { |
1203 | dev_err(&pdev->dev, "idma address is not"\ | 1225 | dev_info(&pdev->dev, "idma address is not"\ |
1204 | "specified"); | 1226 | "specified"); |
1205 | return -EINVAL; | ||
1206 | } | 1227 | } |
1207 | } | 1228 | } |
1208 | } | 1229 | } |
@@ -1228,6 +1249,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1228 | pri_dai->dma_capture.dma_size = 4; | 1249 | pri_dai->dma_capture.dma_size = 4; |
1229 | pri_dai->base = regs_base; | 1250 | pri_dai->base = regs_base; |
1230 | pri_dai->quirks = quirks; | 1251 | pri_dai->quirks = quirks; |
1252 | pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; | ||
1231 | 1253 | ||
1232 | if (quirks & QUIRK_PRI_6CHAN) | 1254 | if (quirks & QUIRK_PRI_6CHAN) |
1233 | pri_dai->i2s_dai_drv.playback.channels_max = 6; | 1255 | pri_dai->i2s_dai_drv.playback.channels_max = 6; |
@@ -1302,20 +1324,93 @@ static int samsung_i2s_remove(struct platform_device *pdev) | |||
1302 | return 0; | 1324 | return 0; |
1303 | } | 1325 | } |
1304 | 1326 | ||
1327 | static const struct samsung_i2s_variant_regs i2sv3_regs = { | ||
1328 | .bfs_off = 1, | ||
1329 | .rfs_off = 3, | ||
1330 | .sdf_off = 5, | ||
1331 | .txr_off = 8, | ||
1332 | .rclksrc_off = 10, | ||
1333 | .mss_off = 11, | ||
1334 | .cdclkcon_off = 12, | ||
1335 | .lrp_off = 7, | ||
1336 | .bfs_mask = 0x3, | ||
1337 | .rfs_mask = 0x3, | ||
1338 | .ftx0cnt_off = 8, | ||
1339 | }; | ||
1340 | |||
1341 | static const struct samsung_i2s_variant_regs i2sv6_regs = { | ||
1342 | .bfs_off = 0, | ||
1343 | .rfs_off = 4, | ||
1344 | .sdf_off = 6, | ||
1345 | .txr_off = 8, | ||
1346 | .rclksrc_off = 10, | ||
1347 | .mss_off = 11, | ||
1348 | .cdclkcon_off = 12, | ||
1349 | .lrp_off = 15, | ||
1350 | .bfs_mask = 0xf, | ||
1351 | .rfs_mask = 0x3, | ||
1352 | .ftx0cnt_off = 8, | ||
1353 | }; | ||
1354 | |||
1355 | static const struct samsung_i2s_variant_regs i2sv7_regs = { | ||
1356 | .bfs_off = 0, | ||
1357 | .rfs_off = 4, | ||
1358 | .sdf_off = 7, | ||
1359 | .txr_off = 9, | ||
1360 | .rclksrc_off = 11, | ||
1361 | .mss_off = 12, | ||
1362 | .cdclkcon_off = 22, | ||
1363 | .lrp_off = 15, | ||
1364 | .bfs_mask = 0xf, | ||
1365 | .rfs_mask = 0x7, | ||
1366 | .ftx0cnt_off = 0, | ||
1367 | }; | ||
1368 | |||
1369 | static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = { | ||
1370 | .bfs_off = 0, | ||
1371 | .rfs_off = 3, | ||
1372 | .sdf_off = 6, | ||
1373 | .txr_off = 8, | ||
1374 | .rclksrc_off = 10, | ||
1375 | .mss_off = 11, | ||
1376 | .cdclkcon_off = 12, | ||
1377 | .lrp_off = 15, | ||
1378 | .bfs_mask = 0x7, | ||
1379 | .rfs_mask = 0x7, | ||
1380 | .ftx0cnt_off = 8, | ||
1381 | }; | ||
1382 | |||
1305 | static const struct samsung_i2s_dai_data i2sv3_dai_type = { | 1383 | static const struct samsung_i2s_dai_data i2sv3_dai_type = { |
1306 | .dai_type = TYPE_PRI, | 1384 | .dai_type = TYPE_PRI, |
1307 | .quirks = QUIRK_NO_MUXPSR, | 1385 | .quirks = QUIRK_NO_MUXPSR, |
1386 | .i2s_variant_regs = &i2sv3_regs, | ||
1308 | }; | 1387 | }; |
1309 | 1388 | ||
1310 | static const struct samsung_i2s_dai_data i2sv5_dai_type = { | 1389 | static const struct samsung_i2s_dai_data i2sv5_dai_type = { |
1311 | .dai_type = TYPE_PRI, | 1390 | .dai_type = TYPE_PRI, |
1312 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR, | 1391 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | |
1392 | QUIRK_SUPPORTS_IDMA, | ||
1393 | .i2s_variant_regs = &i2sv3_regs, | ||
1313 | }; | 1394 | }; |
1314 | 1395 | ||
1315 | static const struct samsung_i2s_dai_data i2sv6_dai_type = { | 1396 | static const struct samsung_i2s_dai_data i2sv6_dai_type = { |
1316 | .dai_type = TYPE_PRI, | 1397 | .dai_type = TYPE_PRI, |
1317 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | | 1398 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | |
1399 | QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA, | ||
1400 | .i2s_variant_regs = &i2sv6_regs, | ||
1401 | }; | ||
1402 | |||
1403 | static const struct samsung_i2s_dai_data i2sv7_dai_type = { | ||
1404 | .dai_type = TYPE_PRI, | ||
1405 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | | ||
1318 | QUIRK_SUPPORTS_TDM, | 1406 | QUIRK_SUPPORTS_TDM, |
1407 | .i2s_variant_regs = &i2sv7_regs, | ||
1408 | }; | ||
1409 | |||
1410 | static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = { | ||
1411 | .dai_type = TYPE_PRI, | ||
1412 | .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR, | ||
1413 | .i2s_variant_regs = &i2sv5_i2s1_regs, | ||
1319 | }; | 1414 | }; |
1320 | 1415 | ||
1321 | static const struct samsung_i2s_dai_data samsung_dai_type_pri = { | 1416 | static const struct samsung_i2s_dai_data samsung_dai_type_pri = { |
@@ -1329,10 +1424,13 @@ static const struct samsung_i2s_dai_data samsung_dai_type_sec = { | |||
1329 | static struct platform_device_id samsung_i2s_driver_ids[] = { | 1424 | static struct platform_device_id samsung_i2s_driver_ids[] = { |
1330 | { | 1425 | { |
1331 | .name = "samsung-i2s", | 1426 | .name = "samsung-i2s", |
1332 | .driver_data = (kernel_ulong_t)&samsung_dai_type_pri, | 1427 | .driver_data = (kernel_ulong_t)&i2sv3_dai_type, |
1333 | }, { | 1428 | }, { |
1334 | .name = "samsung-i2s-sec", | 1429 | .name = "samsung-i2s-sec", |
1335 | .driver_data = (kernel_ulong_t)&samsung_dai_type_sec, | 1430 | .driver_data = (kernel_ulong_t)&samsung_dai_type_sec, |
1431 | }, { | ||
1432 | .name = "samsung-i2sv4", | ||
1433 | .driver_data = (kernel_ulong_t)&i2sv5_dai_type, | ||
1336 | }, | 1434 | }, |
1337 | {}, | 1435 | {}, |
1338 | }; | 1436 | }; |
@@ -1349,6 +1447,12 @@ static const struct of_device_id exynos_i2s_match[] = { | |||
1349 | }, { | 1447 | }, { |
1350 | .compatible = "samsung,exynos5420-i2s", | 1448 | .compatible = "samsung,exynos5420-i2s", |
1351 | .data = &i2sv6_dai_type, | 1449 | .data = &i2sv6_dai_type, |
1450 | }, { | ||
1451 | .compatible = "samsung,exynos7-i2s", | ||
1452 | .data = &i2sv7_dai_type, | ||
1453 | }, { | ||
1454 | .compatible = "samsung,exynos7-i2s1", | ||
1455 | .data = &i2sv5_dai_type_i2s1, | ||
1352 | }, | 1456 | }, |
1353 | {}, | 1457 | {}, |
1354 | }; | 1458 | }; |
diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c index 3c8f60423e82..d7640e72cb1d 100644 --- a/sound/soc/samsung/odroidx2_max98090.c +++ b/sound/soc/samsung/odroidx2_max98090.c | |||
@@ -153,8 +153,8 @@ static int odroidx2_audio_remove(struct platform_device *pdev) | |||
153 | 153 | ||
154 | snd_soc_unregister_card(card); | 154 | snd_soc_unregister_card(card); |
155 | 155 | ||
156 | of_node_put((struct device_node *)odroidx2_dai[0].cpu_of_node); | 156 | of_node_put(odroidx2_dai[0].cpu_of_node); |
157 | of_node_put((struct device_node *)odroidx2_dai[0].codec_of_node); | 157 | of_node_put(odroidx2_dai[0].codec_of_node); |
158 | 158 | ||
159 | return 0; | 159 | return 0; |
160 | } | 160 | } |
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 88e5df474ccf..8869971d7884 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -842,12 +842,9 @@ static int fsi_clk_disable(struct device *dev, | |||
842 | return -EINVAL; | 842 | return -EINVAL; |
843 | 843 | ||
844 | if (1 == clock->count--) { | 844 | if (1 == clock->count--) { |
845 | if (clock->xck) | 845 | clk_disable(clock->xck); |
846 | clk_disable(clock->xck); | 846 | clk_disable(clock->ick); |
847 | if (clock->ick) | 847 | clk_disable(clock->div); |
848 | clk_disable(clock->ick); | ||
849 | if (clock->div) | ||
850 | clk_disable(clock->div); | ||
851 | } | 848 | } |
852 | 849 | ||
853 | return 0; | 850 | return 0; |
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 0af2e4dfd139..d5f567e085ff 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c | |||
@@ -272,7 +272,7 @@ static const struct snd_soc_dai_ops hac_dai_ops = { | |||
272 | static struct snd_soc_dai_driver sh4_hac_dai[] = { | 272 | static struct snd_soc_dai_driver sh4_hac_dai[] = { |
273 | { | 273 | { |
274 | .name = "hac-dai.0", | 274 | .name = "hac-dai.0", |
275 | .ac97_control = 1, | 275 | .bus_control = true, |
276 | .playback = { | 276 | .playback = { |
277 | .rates = AC97_RATES, | 277 | .rates = AC97_RATES, |
278 | .formats = AC97_FMTS, | 278 | .formats = AC97_FMTS, |
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index fc41a0e8b09f..14d1a7193469 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -430,7 +430,7 @@ int rsnd_adg_probe(struct platform_device *pdev, | |||
430 | adg->clk[CLKI] = devm_clk_get(dev, "clk_i"); | 430 | adg->clk[CLKI] = devm_clk_get(dev, "clk_i"); |
431 | 431 | ||
432 | for_each_rsnd_clk(clk, adg, i) | 432 | for_each_rsnd_clk(clk, adg, i) |
433 | dev_dbg(dev, "clk %d : %p\n", i, clk); | 433 | dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); |
434 | 434 | ||
435 | rsnd_adg_ssi_clk_init(priv, adg); | 435 | rsnd_adg_ssi_clk_init(priv, adg); |
436 | 436 | ||
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 70042197f9e2..75308bbc2ce8 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -349,7 +349,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | |||
349 | dma_name); | 349 | dma_name); |
350 | if (!dma->chan) { | 350 | if (!dma->chan) { |
351 | dev_err(dev, "can't get dma channel\n"); | 351 | dev_err(dev, "can't get dma channel\n"); |
352 | return -EIO; | 352 | goto rsnd_dma_channel_err; |
353 | } | 353 | } |
354 | 354 | ||
355 | ret = dmaengine_slave_config(dma->chan, &cfg); | 355 | ret = dmaengine_slave_config(dma->chan, &cfg); |
@@ -363,8 +363,15 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | |||
363 | 363 | ||
364 | rsnd_dma_init_err: | 364 | rsnd_dma_init_err: |
365 | rsnd_dma_quit(priv, dma); | 365 | rsnd_dma_quit(priv, dma); |
366 | rsnd_dma_channel_err: | ||
366 | 367 | ||
367 | return ret; | 368 | /* |
369 | * DMA failed. try to PIO mode | ||
370 | * see | ||
371 | * rsnd_ssi_fallback() | ||
372 | * rsnd_rdai_continuance_probe() | ||
373 | */ | ||
374 | return -EAGAIN; | ||
368 | } | 375 | } |
369 | 376 | ||
370 | void rsnd_dma_quit(struct rsnd_priv *priv, | 377 | void rsnd_dma_quit(struct rsnd_priv *priv, |
@@ -409,9 +416,16 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod) | |||
409 | ({ \ | 416 | ({ \ |
410 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ | 417 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ |
411 | struct device *dev = rsnd_priv_to_dev(priv); \ | 418 | struct device *dev = rsnd_priv_to_dev(priv); \ |
412 | dev_dbg(dev, "%s [%d] %s\n", \ | 419 | u32 mask = 1 << __rsnd_mod_shift_##func; \ |
413 | rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \ | 420 | u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func; \ |
414 | (mod)->ops->func(mod, rdai); \ | 421 | int ret = 0; \ |
422 | if ((mod->status & mask) == call) { \ | ||
423 | dev_dbg(dev, "%s[%d] %s\n", \ | ||
424 | rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \ | ||
425 | ret = (mod)->ops->func(mod, rdai); \ | ||
426 | mod->status = (mod->status & ~mask) | (~call & mask); \ | ||
427 | } \ | ||
428 | ret; \ | ||
415 | }) | 429 | }) |
416 | 430 | ||
417 | #define rsnd_mod_call(mod, func, rdai...) \ | 431 | #define rsnd_mod_call(mod, func, rdai...) \ |
@@ -456,6 +470,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, | |||
456 | return 0; | 470 | return 0; |
457 | } | 471 | } |
458 | 472 | ||
473 | static void rsnd_dai_disconnect(struct rsnd_mod *mod, | ||
474 | struct rsnd_dai_stream *io) | ||
475 | { | ||
476 | mod->io = NULL; | ||
477 | io->mod[mod->type] = NULL; | ||
478 | } | ||
479 | |||
459 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) | 480 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) |
460 | { | 481 | { |
461 | int id = rdai - priv->rdai; | 482 | int id = rdai - priv->rdai; |
@@ -686,6 +707,20 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { | |||
686 | ret; \ | 707 | ret; \ |
687 | }) | 708 | }) |
688 | 709 | ||
710 | #define rsnd_path_break(priv, io, type) \ | ||
711 | { \ | ||
712 | struct rsnd_mod *mod; \ | ||
713 | int id = -1; \ | ||
714 | \ | ||
715 | if (rsnd_is_enable_path(io, type)) { \ | ||
716 | id = rsnd_info_id(priv, io, type); \ | ||
717 | if (id >= 0) { \ | ||
718 | mod = rsnd_##type##_mod_get(priv, id); \ | ||
719 | rsnd_dai_disconnect(mod, io); \ | ||
720 | } \ | ||
721 | } \ | ||
722 | } | ||
723 | |||
689 | static int rsnd_path_init(struct rsnd_priv *priv, | 724 | static int rsnd_path_init(struct rsnd_priv *priv, |
690 | struct rsnd_dai *rdai, | 725 | struct rsnd_dai *rdai, |
691 | struct rsnd_dai_stream *io) | 726 | struct rsnd_dai_stream *io) |
@@ -934,6 +969,150 @@ static struct snd_pcm_ops rsnd_pcm_ops = { | |||
934 | }; | 969 | }; |
935 | 970 | ||
936 | /* | 971 | /* |
972 | * snd_kcontrol | ||
973 | */ | ||
974 | #define kcontrol_to_cfg(kctrl) ((struct rsnd_kctrl_cfg *)kctrl->private_value) | ||
975 | static int rsnd_kctrl_info(struct snd_kcontrol *kctrl, | ||
976 | struct snd_ctl_elem_info *uinfo) | ||
977 | { | ||
978 | struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl); | ||
979 | |||
980 | if (cfg->texts) { | ||
981 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
982 | uinfo->count = cfg->size; | ||
983 | uinfo->value.enumerated.items = cfg->max; | ||
984 | if (uinfo->value.enumerated.item >= cfg->max) | ||
985 | uinfo->value.enumerated.item = cfg->max - 1; | ||
986 | strlcpy(uinfo->value.enumerated.name, | ||
987 | cfg->texts[uinfo->value.enumerated.item], | ||
988 | sizeof(uinfo->value.enumerated.name)); | ||
989 | } else { | ||
990 | uinfo->count = cfg->size; | ||
991 | uinfo->value.integer.min = 0; | ||
992 | uinfo->value.integer.max = cfg->max; | ||
993 | uinfo->type = (cfg->max == 1) ? | ||
994 | SNDRV_CTL_ELEM_TYPE_BOOLEAN : | ||
995 | SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
996 | } | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | static int rsnd_kctrl_get(struct snd_kcontrol *kctrl, | ||
1002 | struct snd_ctl_elem_value *uc) | ||
1003 | { | ||
1004 | struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl); | ||
1005 | int i; | ||
1006 | |||
1007 | for (i = 0; i < cfg->size; i++) | ||
1008 | if (cfg->texts) | ||
1009 | uc->value.enumerated.item[i] = cfg->val[i]; | ||
1010 | else | ||
1011 | uc->value.integer.value[i] = cfg->val[i]; | ||
1012 | |||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, | ||
1017 | struct snd_ctl_elem_value *uc) | ||
1018 | { | ||
1019 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); | ||
1020 | struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl); | ||
1021 | int i, change = 0; | ||
1022 | |||
1023 | for (i = 0; i < cfg->size; i++) { | ||
1024 | if (cfg->texts) { | ||
1025 | change |= (uc->value.enumerated.item[i] != cfg->val[i]); | ||
1026 | cfg->val[i] = uc->value.enumerated.item[i]; | ||
1027 | } else { | ||
1028 | change |= (uc->value.integer.value[i] != cfg->val[i]); | ||
1029 | cfg->val[i] = uc->value.integer.value[i]; | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | if (change) | ||
1034 | cfg->update(mod); | ||
1035 | |||
1036 | return change; | ||
1037 | } | ||
1038 | |||
1039 | static int __rsnd_kctrl_new(struct rsnd_mod *mod, | ||
1040 | struct rsnd_dai *rdai, | ||
1041 | struct snd_soc_pcm_runtime *rtd, | ||
1042 | const unsigned char *name, | ||
1043 | struct rsnd_kctrl_cfg *cfg, | ||
1044 | void (*update)(struct rsnd_mod *mod)) | ||
1045 | { | ||
1046 | struct snd_card *card = rtd->card->snd_card; | ||
1047 | struct snd_kcontrol *kctrl; | ||
1048 | struct snd_kcontrol_new knew = { | ||
1049 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1050 | .name = name, | ||
1051 | .info = rsnd_kctrl_info, | ||
1052 | .get = rsnd_kctrl_get, | ||
1053 | .put = rsnd_kctrl_put, | ||
1054 | .private_value = (unsigned long)cfg, | ||
1055 | }; | ||
1056 | int ret; | ||
1057 | |||
1058 | kctrl = snd_ctl_new1(&knew, mod); | ||
1059 | if (!kctrl) | ||
1060 | return -ENOMEM; | ||
1061 | |||
1062 | ret = snd_ctl_add(card, kctrl); | ||
1063 | if (ret < 0) | ||
1064 | return ret; | ||
1065 | |||
1066 | cfg->update = update; | ||
1067 | |||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | int rsnd_kctrl_new_m(struct rsnd_mod *mod, | ||
1072 | struct rsnd_dai *rdai, | ||
1073 | struct snd_soc_pcm_runtime *rtd, | ||
1074 | const unsigned char *name, | ||
1075 | void (*update)(struct rsnd_mod *mod), | ||
1076 | struct rsnd_kctrl_cfg_m *_cfg, | ||
1077 | u32 max) | ||
1078 | { | ||
1079 | _cfg->cfg.max = max; | ||
1080 | _cfg->cfg.size = RSND_DVC_CHANNELS; | ||
1081 | _cfg->cfg.val = _cfg->val; | ||
1082 | return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update); | ||
1083 | } | ||
1084 | |||
1085 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, | ||
1086 | struct rsnd_dai *rdai, | ||
1087 | struct snd_soc_pcm_runtime *rtd, | ||
1088 | const unsigned char *name, | ||
1089 | void (*update)(struct rsnd_mod *mod), | ||
1090 | struct rsnd_kctrl_cfg_s *_cfg, | ||
1091 | u32 max) | ||
1092 | { | ||
1093 | _cfg->cfg.max = max; | ||
1094 | _cfg->cfg.size = 1; | ||
1095 | _cfg->cfg.val = &_cfg->val; | ||
1096 | return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update); | ||
1097 | } | ||
1098 | |||
1099 | int rsnd_kctrl_new_e(struct rsnd_mod *mod, | ||
1100 | struct rsnd_dai *rdai, | ||
1101 | struct snd_soc_pcm_runtime *rtd, | ||
1102 | const unsigned char *name, | ||
1103 | struct rsnd_kctrl_cfg_s *_cfg, | ||
1104 | void (*update)(struct rsnd_mod *mod), | ||
1105 | const char * const *texts, | ||
1106 | u32 max) | ||
1107 | { | ||
1108 | _cfg->cfg.max = max; | ||
1109 | _cfg->cfg.size = 1; | ||
1110 | _cfg->cfg.val = &_cfg->val; | ||
1111 | _cfg->cfg.texts = texts; | ||
1112 | return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update); | ||
1113 | } | ||
1114 | |||
1115 | /* | ||
937 | * snd_soc_platform | 1116 | * snd_soc_platform |
938 | */ | 1117 | */ |
939 | 1118 | ||
@@ -976,6 +1155,49 @@ static const struct snd_soc_component_driver rsnd_soc_component = { | |||
976 | .name = "rsnd", | 1155 | .name = "rsnd", |
977 | }; | 1156 | }; |
978 | 1157 | ||
1158 | static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, | ||
1159 | struct rsnd_dai *rdai, | ||
1160 | int is_play) | ||
1161 | { | ||
1162 | struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; | ||
1163 | int ret; | ||
1164 | |||
1165 | ret = rsnd_dai_call(probe, io, rdai); | ||
1166 | if (ret == -EAGAIN) { | ||
1167 | /* | ||
1168 | * Fallback to PIO mode | ||
1169 | */ | ||
1170 | |||
1171 | /* | ||
1172 | * call "remove" for SSI/SRC/DVC | ||
1173 | * SSI will be switch to PIO mode if it was DMA mode | ||
1174 | * see | ||
1175 | * rsnd_dma_init() | ||
1176 | * rsnd_ssi_fallback() | ||
1177 | */ | ||
1178 | rsnd_dai_call(remove, io, rdai); | ||
1179 | |||
1180 | /* | ||
1181 | * remove SRC/DVC from DAI, | ||
1182 | */ | ||
1183 | rsnd_path_break(priv, io, src); | ||
1184 | rsnd_path_break(priv, io, dvc); | ||
1185 | |||
1186 | /* | ||
1187 | * fallback | ||
1188 | */ | ||
1189 | rsnd_dai_call(fallback, io, rdai); | ||
1190 | |||
1191 | /* | ||
1192 | * retry to "probe". | ||
1193 | * DAI has SSI which is PIO mode only now. | ||
1194 | */ | ||
1195 | ret = rsnd_dai_call(probe, io, rdai); | ||
1196 | } | ||
1197 | |||
1198 | return ret; | ||
1199 | } | ||
1200 | |||
979 | /* | 1201 | /* |
980 | * rsnd probe | 1202 | * rsnd probe |
981 | */ | 1203 | */ |
@@ -1037,11 +1259,11 @@ static int rsnd_probe(struct platform_device *pdev) | |||
1037 | } | 1259 | } |
1038 | 1260 | ||
1039 | for_each_rsnd_dai(rdai, priv, i) { | 1261 | for_each_rsnd_dai(rdai, priv, i) { |
1040 | ret = rsnd_dai_call(probe, &rdai->playback, rdai); | 1262 | ret = rsnd_rdai_continuance_probe(priv, rdai, 1); |
1041 | if (ret) | 1263 | if (ret) |
1042 | goto exit_snd_probe; | 1264 | goto exit_snd_probe; |
1043 | 1265 | ||
1044 | ret = rsnd_dai_call(probe, &rdai->capture, rdai); | 1266 | ret = rsnd_rdai_continuance_probe(priv, rdai, 0); |
1045 | if (ret) | 1267 | if (ret) |
1046 | goto exit_snd_probe; | 1268 | goto exit_snd_probe; |
1047 | } | 1269 | } |
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 3f443930c2b1..5380a4827ba7 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c | |||
@@ -11,8 +11,6 @@ | |||
11 | #include "rsnd.h" | 11 | #include "rsnd.h" |
12 | 12 | ||
13 | #define RSND_DVC_NAME_SIZE 16 | 13 | #define RSND_DVC_NAME_SIZE 16 |
14 | #define RSND_DVC_VOLUME_MAX 100 | ||
15 | #define RSND_DVC_VOLUME_NUM 2 | ||
16 | 14 | ||
17 | #define DVC_NAME "dvc" | 15 | #define DVC_NAME "dvc" |
18 | 16 | ||
@@ -20,8 +18,11 @@ struct rsnd_dvc { | |||
20 | struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ | 18 | struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ |
21 | struct rsnd_mod mod; | 19 | struct rsnd_mod mod; |
22 | struct clk *clk; | 20 | struct clk *clk; |
23 | u8 volume[RSND_DVC_VOLUME_NUM]; | 21 | struct rsnd_kctrl_cfg_m volume; |
24 | u8 mute[RSND_DVC_VOLUME_NUM]; | 22 | struct rsnd_kctrl_cfg_m mute; |
23 | struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ | ||
24 | struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ | ||
25 | struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ | ||
25 | }; | 26 | }; |
26 | 27 | ||
27 | #define rsnd_mod_to_dvc(_mod) \ | 28 | #define rsnd_mod_to_dvc(_mod) \ |
@@ -33,23 +34,87 @@ struct rsnd_dvc { | |||
33 | ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ | 34 | ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ |
34 | i++) | 35 | i++) |
35 | 36 | ||
37 | static const char const *dvc_ramp_rate[] = { | ||
38 | "128 dB/1 step", /* 00000 */ | ||
39 | "64 dB/1 step", /* 00001 */ | ||
40 | "32 dB/1 step", /* 00010 */ | ||
41 | "16 dB/1 step", /* 00011 */ | ||
42 | "8 dB/1 step", /* 00100 */ | ||
43 | "4 dB/1 step", /* 00101 */ | ||
44 | "2 dB/1 step", /* 00110 */ | ||
45 | "1 dB/1 step", /* 00111 */ | ||
46 | "0.5 dB/1 step", /* 01000 */ | ||
47 | "0.25 dB/1 step", /* 01001 */ | ||
48 | "0.125 dB/1 step", /* 01010 */ | ||
49 | "0.125 dB/2 steps", /* 01011 */ | ||
50 | "0.125 dB/4 steps", /* 01100 */ | ||
51 | "0.125 dB/8 steps", /* 01101 */ | ||
52 | "0.125 dB/16 steps", /* 01110 */ | ||
53 | "0.125 dB/32 steps", /* 01111 */ | ||
54 | "0.125 dB/64 steps", /* 10000 */ | ||
55 | "0.125 dB/128 steps", /* 10001 */ | ||
56 | "0.125 dB/256 steps", /* 10010 */ | ||
57 | "0.125 dB/512 steps", /* 10011 */ | ||
58 | "0.125 dB/1024 steps", /* 10100 */ | ||
59 | "0.125 dB/2048 steps", /* 10101 */ | ||
60 | "0.125 dB/4096 steps", /* 10110 */ | ||
61 | "0.125 dB/8192 steps", /* 10111 */ | ||
62 | }; | ||
63 | |||
36 | static void rsnd_dvc_volume_update(struct rsnd_mod *mod) | 64 | static void rsnd_dvc_volume_update(struct rsnd_mod *mod) |
37 | { | 65 | { |
38 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 66 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
39 | u32 max = (0x00800000 - 1); | 67 | u32 val[RSND_DVC_CHANNELS]; |
40 | u32 vol[RSND_DVC_VOLUME_NUM]; | 68 | u32 dvucr = 0; |
41 | u32 mute = 0; | 69 | u32 mute = 0; |
42 | int i; | 70 | int i; |
43 | 71 | ||
44 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { | 72 | for (i = 0; i < dvc->mute.cfg.size; i++) |
45 | vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i]; | 73 | mute |= (!!dvc->mute.cfg.val[i]) << i; |
46 | mute |= (!!dvc->mute[i]) << i; | 74 | |
75 | /* Disable DVC Register access */ | ||
76 | rsnd_mod_write(mod, DVC_DVUER, 0); | ||
77 | |||
78 | /* Enable Ramp */ | ||
79 | if (dvc->ren.val) { | ||
80 | dvucr |= 0x10; | ||
81 | |||
82 | /* Digital Volume Max */ | ||
83 | for (i = 0; i < RSND_DVC_CHANNELS; i++) | ||
84 | val[i] = dvc->volume.cfg.max; | ||
85 | |||
86 | rsnd_mod_write(mod, DVC_VRCTR, 0xff); | ||
87 | rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 | | ||
88 | dvc->rdown.val); | ||
89 | /* | ||
90 | * FIXME !! | ||
91 | * use scale-downed Digital Volume | ||
92 | * as Volume Ramp | ||
93 | * 7F FFFF -> 3FF | ||
94 | */ | ||
95 | rsnd_mod_write(mod, DVC_VRDBR, | ||
96 | 0x3ff - (dvc->volume.val[0] >> 13)); | ||
97 | |||
98 | } else { | ||
99 | for (i = 0; i < RSND_DVC_CHANNELS; i++) | ||
100 | val[i] = dvc->volume.val[i]; | ||
101 | } | ||
102 | |||
103 | /* Enable Digital Volume */ | ||
104 | dvucr |= 0x100; | ||
105 | rsnd_mod_write(mod, DVC_VOL0R, val[0]); | ||
106 | rsnd_mod_write(mod, DVC_VOL1R, val[1]); | ||
107 | |||
108 | /* Enable Mute */ | ||
109 | if (mute) { | ||
110 | dvucr |= 0x1; | ||
111 | rsnd_mod_write(mod, DVC_ZCMCR, mute); | ||
47 | } | 112 | } |
48 | 113 | ||
49 | rsnd_mod_write(mod, DVC_VOL0R, vol[0]); | 114 | rsnd_mod_write(mod, DVC_DVUCR, dvucr); |
50 | rsnd_mod_write(mod, DVC_VOL1R, vol[1]); | ||
51 | 115 | ||
52 | rsnd_mod_write(mod, DVC_ZCMCR, mute); | 116 | /* Enable DVC Register access */ |
117 | rsnd_mod_write(mod, DVC_DVUER, 1); | ||
53 | } | 118 | } |
54 | 119 | ||
55 | static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, | 120 | static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, |
@@ -58,7 +123,8 @@ static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, | |||
58 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 123 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
59 | struct device *dev = rsnd_priv_to_dev(priv); | 124 | struct device *dev = rsnd_priv_to_dev(priv); |
60 | 125 | ||
61 | dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); | 126 | dev_dbg(dev, "%s[%d] (Gen2) is probed\n", |
127 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
62 | 128 | ||
63 | return 0; | 129 | return 0; |
64 | } | 130 | } |
@@ -102,16 +168,11 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, | |||
102 | 168 | ||
103 | rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); | 169 | rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); |
104 | 170 | ||
105 | /* enable Volume / Mute */ | ||
106 | rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101); | ||
107 | |||
108 | /* ch0/ch1 Volume */ | 171 | /* ch0/ch1 Volume */ |
109 | rsnd_dvc_volume_update(dvc_mod); | 172 | rsnd_dvc_volume_update(dvc_mod); |
110 | 173 | ||
111 | rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); | 174 | rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); |
112 | 175 | ||
113 | rsnd_mod_write(dvc_mod, DVC_DVUER, 1); | ||
114 | |||
115 | rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io); | 176 | rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io); |
116 | 177 | ||
117 | return 0; | 178 | return 0; |
@@ -143,86 +204,6 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod, | |||
143 | return 0; | 204 | return 0; |
144 | } | 205 | } |
145 | 206 | ||
146 | static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, | ||
147 | struct snd_ctl_elem_info *uinfo) | ||
148 | { | ||
149 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); | ||
150 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | ||
151 | u8 *val = (u8 *)kctrl->private_value; | ||
152 | |||
153 | uinfo->count = RSND_DVC_VOLUME_NUM; | ||
154 | uinfo->value.integer.min = 0; | ||
155 | |||
156 | if (val == dvc->volume) { | ||
157 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
158 | uinfo->value.integer.max = RSND_DVC_VOLUME_MAX; | ||
159 | } else { | ||
160 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
161 | uinfo->value.integer.max = 1; | ||
162 | } | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, | ||
168 | struct snd_ctl_elem_value *ucontrol) | ||
169 | { | ||
170 | u8 *val = (u8 *)kctrl->private_value; | ||
171 | int i; | ||
172 | |||
173 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) | ||
174 | ucontrol->value.integer.value[i] = val[i]; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl, | ||
180 | struct snd_ctl_elem_value *ucontrol) | ||
181 | { | ||
182 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); | ||
183 | u8 *val = (u8 *)kctrl->private_value; | ||
184 | int i, change = 0; | ||
185 | |||
186 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { | ||
187 | change |= (ucontrol->value.integer.value[i] != val[i]); | ||
188 | val[i] = ucontrol->value.integer.value[i]; | ||
189 | } | ||
190 | |||
191 | if (change) | ||
192 | rsnd_dvc_volume_update(mod); | ||
193 | |||
194 | return change; | ||
195 | } | ||
196 | |||
197 | static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod, | ||
198 | struct rsnd_dai *rdai, | ||
199 | struct snd_soc_pcm_runtime *rtd, | ||
200 | const unsigned char *name, | ||
201 | u8 *private) | ||
202 | { | ||
203 | struct snd_card *card = rtd->card->snd_card; | ||
204 | struct snd_kcontrol *kctrl; | ||
205 | struct snd_kcontrol_new knew = { | ||
206 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
207 | .name = name, | ||
208 | .info = rsnd_dvc_volume_info, | ||
209 | .get = rsnd_dvc_volume_get, | ||
210 | .put = rsnd_dvc_volume_put, | ||
211 | .private_value = (unsigned long)private, | ||
212 | }; | ||
213 | int ret; | ||
214 | |||
215 | kctrl = snd_ctl_new1(&knew, mod); | ||
216 | if (!kctrl) | ||
217 | return -ENOMEM; | ||
218 | |||
219 | ret = snd_ctl_add(card, kctrl); | ||
220 | if (ret < 0) | ||
221 | return ret; | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | 207 | static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, |
227 | struct rsnd_dai *rdai, | 208 | struct rsnd_dai *rdai, |
228 | struct snd_soc_pcm_runtime *rtd) | 209 | struct snd_soc_pcm_runtime *rtd) |
@@ -232,18 +213,48 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
232 | int ret; | 213 | int ret; |
233 | 214 | ||
234 | /* Volume */ | 215 | /* Volume */ |
235 | ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, | 216 | ret = rsnd_kctrl_new_m(mod, rdai, rtd, |
236 | rsnd_dai_is_play(rdai, io) ? | 217 | rsnd_dai_is_play(rdai, io) ? |
237 | "DVC Out Playback Volume" : "DVC In Capture Volume", | 218 | "DVC Out Playback Volume" : "DVC In Capture Volume", |
238 | dvc->volume); | 219 | rsnd_dvc_volume_update, |
220 | &dvc->volume, 0x00800000 - 1); | ||
239 | if (ret < 0) | 221 | if (ret < 0) |
240 | return ret; | 222 | return ret; |
241 | 223 | ||
242 | /* Mute */ | 224 | /* Mute */ |
243 | ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, | 225 | ret = rsnd_kctrl_new_m(mod, rdai, rtd, |
244 | rsnd_dai_is_play(rdai, io) ? | 226 | rsnd_dai_is_play(rdai, io) ? |
245 | "DVC Out Mute Switch" : "DVC In Mute Switch", | 227 | "DVC Out Mute Switch" : "DVC In Mute Switch", |
246 | dvc->mute); | 228 | rsnd_dvc_volume_update, |
229 | &dvc->mute, 1); | ||
230 | if (ret < 0) | ||
231 | return ret; | ||
232 | |||
233 | /* Ramp */ | ||
234 | ret = rsnd_kctrl_new_s(mod, rdai, rtd, | ||
235 | rsnd_dai_is_play(rdai, io) ? | ||
236 | "DVC Out Ramp Switch" : "DVC In Ramp Switch", | ||
237 | rsnd_dvc_volume_update, | ||
238 | &dvc->ren, 1); | ||
239 | if (ret < 0) | ||
240 | return ret; | ||
241 | |||
242 | ret = rsnd_kctrl_new_e(mod, rdai, rtd, | ||
243 | rsnd_dai_is_play(rdai, io) ? | ||
244 | "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", | ||
245 | &dvc->rup, | ||
246 | rsnd_dvc_volume_update, | ||
247 | dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate)); | ||
248 | if (ret < 0) | ||
249 | return ret; | ||
250 | |||
251 | ret = rsnd_kctrl_new_e(mod, rdai, rtd, | ||
252 | rsnd_dai_is_play(rdai, io) ? | ||
253 | "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", | ||
254 | &dvc->rdown, | ||
255 | rsnd_dvc_volume_update, | ||
256 | dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate)); | ||
257 | |||
247 | if (ret < 0) | 258 | if (ret < 0) |
248 | return ret; | 259 | return ret; |
249 | 260 | ||
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index f95e7ab135e8..87a6f2d62775 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -8,6 +8,17 @@ | |||
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | |||
12 | /* | ||
13 | * #define DEBUG | ||
14 | * | ||
15 | * you can also add below in | ||
16 | * ${LINUX}/drivers/base/regmap/regmap.c | ||
17 | * for regmap debug | ||
18 | * | ||
19 | * #define LOG_DEVICE "xxxx.rcar_sound" | ||
20 | */ | ||
21 | |||
11 | #include "rsnd.h" | 22 | #include "rsnd.h" |
12 | 23 | ||
13 | struct rsnd_gen { | 24 | struct rsnd_gen { |
@@ -67,9 +78,10 @@ u32 rsnd_read(struct rsnd_priv *priv, | |||
67 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 78 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
68 | return 0; | 79 | return 0; |
69 | 80 | ||
70 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); | 81 | dev_dbg(dev, "r %s[%d] - %4d : %08x\n", |
82 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val); | ||
71 | 83 | ||
72 | dev_dbg(dev, "r %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, val); | 84 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); |
73 | 85 | ||
74 | return val; | 86 | return val; |
75 | } | 87 | } |
@@ -84,9 +96,10 @@ void rsnd_write(struct rsnd_priv *priv, | |||
84 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 96 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
85 | return; | 97 | return; |
86 | 98 | ||
87 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); | 99 | dev_dbg(dev, "w %s[%d] - %4d : %08x\n", |
100 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); | ||
88 | 101 | ||
89 | dev_dbg(dev, "w %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, data); | 102 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); |
90 | } | 103 | } |
91 | 104 | ||
92 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | 105 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, |
@@ -98,11 +111,11 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | |||
98 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 111 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
99 | return; | 112 | return; |
100 | 113 | ||
114 | dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n", | ||
115 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask); | ||
116 | |||
101 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), | 117 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), |
102 | mask, data); | 118 | mask, data); |
103 | |||
104 | dev_dbg(dev, "b %s - 0x%04d : %08x/%08x\n", | ||
105 | rsnd_mod_name(mod), reg, data, mask); | ||
106 | } | 119 | } |
107 | 120 | ||
108 | #define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \ | 121 | #define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \ |
@@ -311,6 +324,9 @@ static int rsnd_gen2_probe(struct platform_device *pdev, | |||
311 | RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), | 324 | RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), |
312 | RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), | 325 | RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), |
313 | RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), | 326 | RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), |
327 | RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100), | ||
328 | RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100), | ||
329 | RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), | ||
314 | RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), | 330 | RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), |
315 | RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), | 331 | RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), |
316 | RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), | 332 | RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index d119adf97c9c..5826c8abf794 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -91,6 +91,9 @@ enum rsnd_reg { | |||
91 | RSND_REG_SHARE20, | 91 | RSND_REG_SHARE20, |
92 | RSND_REG_SHARE21, | 92 | RSND_REG_SHARE21, |
93 | RSND_REG_SHARE22, | 93 | RSND_REG_SHARE22, |
94 | RSND_REG_SHARE23, | ||
95 | RSND_REG_SHARE24, | ||
96 | RSND_REG_SHARE25, | ||
94 | 97 | ||
95 | RSND_REG_MAX, | 98 | RSND_REG_MAX, |
96 | }; | 99 | }; |
@@ -129,6 +132,9 @@ enum rsnd_reg { | |||
129 | #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 | 132 | #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 |
130 | #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 | 133 | #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 |
131 | #define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 | 134 | #define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 |
135 | #define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 | ||
136 | #define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 | ||
137 | #define RSND_REG_DVC_VRDBR RSND_REG_SHARE25 | ||
132 | 138 | ||
133 | struct rsnd_of_data; | 139 | struct rsnd_of_data; |
134 | struct rsnd_priv; | 140 | struct rsnd_priv; |
@@ -200,6 +206,8 @@ struct rsnd_mod_ops { | |||
200 | int (*pcm_new)(struct rsnd_mod *mod, | 206 | int (*pcm_new)(struct rsnd_mod *mod, |
201 | struct rsnd_dai *rdai, | 207 | struct rsnd_dai *rdai, |
202 | struct snd_soc_pcm_runtime *rtd); | 208 | struct snd_soc_pcm_runtime *rtd); |
209 | int (*fallback)(struct rsnd_mod *mod, | ||
210 | struct rsnd_dai *rdai); | ||
203 | }; | 211 | }; |
204 | 212 | ||
205 | struct rsnd_dai_stream; | 213 | struct rsnd_dai_stream; |
@@ -210,7 +218,35 @@ struct rsnd_mod { | |||
210 | struct rsnd_mod_ops *ops; | 218 | struct rsnd_mod_ops *ops; |
211 | struct rsnd_dma dma; | 219 | struct rsnd_dma dma; |
212 | struct rsnd_dai_stream *io; | 220 | struct rsnd_dai_stream *io; |
221 | u32 status; | ||
213 | }; | 222 | }; |
223 | /* | ||
224 | * status | ||
225 | * | ||
226 | * bit | ||
227 | * 0 0: probe 1: remove | ||
228 | * 1 0: init 1: quit | ||
229 | * 2 0: start 1: stop | ||
230 | * 3 0: pcm_new | ||
231 | * 4 0: fallback | ||
232 | */ | ||
233 | #define __rsnd_mod_shift_probe 0 | ||
234 | #define __rsnd_mod_shift_remove 0 | ||
235 | #define __rsnd_mod_shift_init 1 | ||
236 | #define __rsnd_mod_shift_quit 1 | ||
237 | #define __rsnd_mod_shift_start 2 | ||
238 | #define __rsnd_mod_shift_stop 2 | ||
239 | #define __rsnd_mod_shift_pcm_new 3 | ||
240 | #define __rsnd_mod_shift_fallback 4 | ||
241 | |||
242 | #define __rsnd_mod_call_probe 0 | ||
243 | #define __rsnd_mod_call_remove 1 | ||
244 | #define __rsnd_mod_call_init 0 | ||
245 | #define __rsnd_mod_call_quit 1 | ||
246 | #define __rsnd_mod_call_start 0 | ||
247 | #define __rsnd_mod_call_stop 1 | ||
248 | #define __rsnd_mod_call_pcm_new 0 | ||
249 | #define __rsnd_mod_call_fallback 0 | ||
214 | 250 | ||
215 | #define rsnd_mod_to_priv(mod) ((mod)->priv) | 251 | #define rsnd_mod_to_priv(mod) ((mod)->priv) |
216 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) | 252 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) |
@@ -267,7 +303,8 @@ struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); | |||
267 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); | 303 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); |
268 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); | 304 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); |
269 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) | 305 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) |
270 | #define rsnd_io_to_runtime(io) ((io)->substream->runtime) | 306 | #define rsnd_io_to_runtime(io) ((io)->substream ? \ |
307 | (io)->substream->runtime : NULL) | ||
271 | 308 | ||
272 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); | 309 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); |
273 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); | 310 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); |
@@ -382,6 +419,51 @@ struct rsnd_priv { | |||
382 | }) | 419 | }) |
383 | 420 | ||
384 | /* | 421 | /* |
422 | * rsnd_kctrl | ||
423 | */ | ||
424 | struct rsnd_kctrl_cfg { | ||
425 | unsigned int max; | ||
426 | unsigned int size; | ||
427 | u32 *val; | ||
428 | const char * const *texts; | ||
429 | void (*update)(struct rsnd_mod *mod); | ||
430 | }; | ||
431 | |||
432 | #define RSND_DVC_CHANNELS 2 | ||
433 | struct rsnd_kctrl_cfg_m { | ||
434 | struct rsnd_kctrl_cfg cfg; | ||
435 | u32 val[RSND_DVC_CHANNELS]; | ||
436 | }; | ||
437 | |||
438 | struct rsnd_kctrl_cfg_s { | ||
439 | struct rsnd_kctrl_cfg cfg; | ||
440 | u32 val; | ||
441 | }; | ||
442 | |||
443 | int rsnd_kctrl_new_m(struct rsnd_mod *mod, | ||
444 | struct rsnd_dai *rdai, | ||
445 | struct snd_soc_pcm_runtime *rtd, | ||
446 | const unsigned char *name, | ||
447 | void (*update)(struct rsnd_mod *mod), | ||
448 | struct rsnd_kctrl_cfg_m *_cfg, | ||
449 | u32 max); | ||
450 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, | ||
451 | struct rsnd_dai *rdai, | ||
452 | struct snd_soc_pcm_runtime *rtd, | ||
453 | const unsigned char *name, | ||
454 | void (*update)(struct rsnd_mod *mod), | ||
455 | struct rsnd_kctrl_cfg_s *_cfg, | ||
456 | u32 max); | ||
457 | int rsnd_kctrl_new_e(struct rsnd_mod *mod, | ||
458 | struct rsnd_dai *rdai, | ||
459 | struct snd_soc_pcm_runtime *rtd, | ||
460 | const unsigned char *name, | ||
461 | struct rsnd_kctrl_cfg_s *_cfg, | ||
462 | void (*update)(struct rsnd_mod *mod), | ||
463 | const char * const *texts, | ||
464 | u32 max); | ||
465 | |||
466 | /* | ||
385 | * R-Car SRC | 467 | * R-Car SRC |
386 | */ | 468 | */ |
387 | int rsnd_src_probe(struct platform_device *pdev, | 469 | int rsnd_src_probe(struct platform_device *pdev, |
@@ -395,10 +477,11 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | |||
395 | struct rsnd_dai *rdai, | 477 | struct rsnd_dai *rdai, |
396 | int use_busif); | 478 | int use_busif); |
397 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, | 479 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, |
398 | struct rsnd_dai *rdai, | 480 | struct rsnd_dai *rdai); |
399 | int use_busif); | 481 | int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod, |
400 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, | ||
401 | struct rsnd_dai *rdai); | 482 | struct rsnd_dai *rdai); |
483 | int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod, | ||
484 | struct rsnd_dai *rdai); | ||
402 | 485 | ||
403 | #define rsnd_src_nr(priv) ((priv)->src_nr) | 486 | #define rsnd_src_nr(priv) ((priv)->src_nr) |
404 | 487 | ||
@@ -410,6 +493,7 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
410 | struct rsnd_priv *priv); | 493 | struct rsnd_priv *priv); |
411 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | 494 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); |
412 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | 495 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); |
496 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); | ||
413 | 497 | ||
414 | /* | 498 | /* |
415 | * R-Car DVC | 499 | * R-Car DVC |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 9183e0145503..eede3ac6eed2 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -175,30 +175,47 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | |||
175 | } | 175 | } |
176 | 176 | ||
177 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, | 177 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, |
178 | struct rsnd_dai *rdai, | 178 | struct rsnd_dai *rdai) |
179 | int use_busif) | ||
180 | { | 179 | { |
181 | /* | 180 | /* |
182 | * DMA settings for SSIU | 181 | * DMA settings for SSIU |
183 | */ | 182 | */ |
184 | if (use_busif) | 183 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0); |
185 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0); | ||
186 | 184 | ||
187 | return 0; | 185 | return 0; |
188 | } | 186 | } |
189 | 187 | ||
190 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, | 188 | int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod, |
191 | struct rsnd_dai *rdai) | 189 | struct rsnd_dai *rdai) |
192 | { | 190 | { |
193 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | 191 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); |
194 | 192 | ||
195 | /* enable PIO interrupt if Gen2 */ | 193 | if (rsnd_is_gen1(priv)) |
196 | if (rsnd_is_gen2(priv)) | 194 | return 0; |
195 | |||
196 | /* enable SSI interrupt if Gen2 */ | ||
197 | if (rsnd_ssi_is_dma_mode(ssi_mod)) | ||
198 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0e000000); | ||
199 | else | ||
197 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); | 200 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); |
198 | 201 | ||
199 | return 0; | 202 | return 0; |
200 | } | 203 | } |
201 | 204 | ||
205 | int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod, | ||
206 | struct rsnd_dai *rdai) | ||
207 | { | ||
208 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
209 | |||
210 | if (rsnd_is_gen1(priv)) | ||
211 | return 0; | ||
212 | |||
213 | /* disable SSI interrupt if Gen2 */ | ||
214 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x00000000); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
202 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | 219 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, |
203 | struct rsnd_dai_stream *io, | 220 | struct rsnd_dai_stream *io, |
204 | struct snd_pcm_runtime *runtime) | 221 | struct snd_pcm_runtime *runtime) |
@@ -239,12 +256,6 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, | |||
239 | rsnd_mod_write(mod, SRC_SWRSR, 0); | 256 | rsnd_mod_write(mod, SRC_SWRSR, 0); |
240 | rsnd_mod_write(mod, SRC_SWRSR, 1); | 257 | rsnd_mod_write(mod, SRC_SWRSR, 1); |
241 | 258 | ||
242 | /* | ||
243 | * Initialize the operation of the SRC internal circuits | ||
244 | * see rsnd_src_start() | ||
245 | */ | ||
246 | rsnd_mod_write(mod, SRC_SRCIR, 1); | ||
247 | |||
248 | /* Set channel number and output bit length */ | 259 | /* Set channel number and output bit length */ |
249 | rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod)); | 260 | rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod)); |
250 | 261 | ||
@@ -269,6 +280,12 @@ static int rsnd_src_init(struct rsnd_mod *mod, | |||
269 | 280 | ||
270 | clk_prepare_enable(src->clk); | 281 | clk_prepare_enable(src->clk); |
271 | 282 | ||
283 | /* | ||
284 | * Initialize the operation of the SRC internal circuits | ||
285 | * see rsnd_src_start() | ||
286 | */ | ||
287 | rsnd_mod_write(mod, SRC_SRCIR, 1); | ||
288 | |||
272 | return 0; | 289 | return 0; |
273 | } | 290 | } |
274 | 291 | ||
@@ -282,32 +299,20 @@ static int rsnd_src_quit(struct rsnd_mod *mod, | |||
282 | return 0; | 299 | return 0; |
283 | } | 300 | } |
284 | 301 | ||
285 | static int rsnd_src_start(struct rsnd_mod *mod, | 302 | static int rsnd_src_start(struct rsnd_mod *mod) |
286 | struct rsnd_dai *rdai) | ||
287 | { | 303 | { |
288 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
289 | |||
290 | /* | 304 | /* |
291 | * Cancel the initialization and operate the SRC function | 305 | * Cancel the initialization and operate the SRC function |
292 | * see rsnd_src_set_convert_rate() | 306 | * see rsnd_src_init() |
293 | */ | 307 | */ |
294 | rsnd_mod_write(mod, SRC_SRCIR, 0); | 308 | rsnd_mod_write(mod, SRC_SRCIR, 0); |
295 | 309 | ||
296 | if (rsnd_src_convert_rate(src)) | ||
297 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
298 | |||
299 | return 0; | 310 | return 0; |
300 | } | 311 | } |
301 | 312 | ||
302 | 313 | static int rsnd_src_stop(struct rsnd_mod *mod) | |
303 | static int rsnd_src_stop(struct rsnd_mod *mod, | ||
304 | struct rsnd_dai *rdai) | ||
305 | { | 314 | { |
306 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 315 | /* nothing to do */ |
307 | |||
308 | if (rsnd_src_convert_rate(src)) | ||
309 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0); | ||
310 | |||
311 | return 0; | 316 | return 0; |
312 | } | 317 | } |
313 | 318 | ||
@@ -414,6 +419,7 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod, | |||
414 | static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, | 419 | static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, |
415 | struct rsnd_dai *rdai) | 420 | struct rsnd_dai *rdai) |
416 | { | 421 | { |
422 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
417 | int ret; | 423 | int ret; |
418 | 424 | ||
419 | ret = rsnd_src_set_convert_rate(mod, rdai); | 425 | ret = rsnd_src_set_convert_rate(mod, rdai); |
@@ -427,6 +433,10 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, | |||
427 | rsnd_mod_write(mod, SRC_MNFSR, | 433 | rsnd_mod_write(mod, SRC_MNFSR, |
428 | rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); | 434 | rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); |
429 | 435 | ||
436 | /* Gen1/Gen2 are not compatible */ | ||
437 | if (rsnd_src_convert_rate(src)) | ||
438 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
439 | |||
430 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ | 440 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ |
431 | 441 | ||
432 | return 0; | 442 | return 0; |
@@ -438,7 +448,8 @@ static int rsnd_src_probe_gen1(struct rsnd_mod *mod, | |||
438 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 448 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
439 | struct device *dev = rsnd_priv_to_dev(priv); | 449 | struct device *dev = rsnd_priv_to_dev(priv); |
440 | 450 | ||
441 | dev_dbg(dev, "%s (Gen1) is probed\n", rsnd_mod_name(mod)); | 451 | dev_dbg(dev, "%s[%d] (Gen1) is probed\n", |
452 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
442 | 453 | ||
443 | return 0; | 454 | return 0; |
444 | } | 455 | } |
@@ -474,7 +485,7 @@ static int rsnd_src_start_gen1(struct rsnd_mod *mod, | |||
474 | 485 | ||
475 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); | 486 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); |
476 | 487 | ||
477 | return rsnd_src_start(mod, rdai); | 488 | return rsnd_src_start(mod); |
478 | } | 489 | } |
479 | 490 | ||
480 | static int rsnd_src_stop_gen1(struct rsnd_mod *mod, | 491 | static int rsnd_src_stop_gen1(struct rsnd_mod *mod, |
@@ -484,7 +495,7 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod, | |||
484 | 495 | ||
485 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); | 496 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); |
486 | 497 | ||
487 | return rsnd_src_stop(mod, rdai); | 498 | return rsnd_src_stop(mod); |
488 | } | 499 | } |
489 | 500 | ||
490 | static struct rsnd_mod_ops rsnd_src_gen1_ops = { | 501 | static struct rsnd_mod_ops rsnd_src_gen1_ops = { |
@@ -507,16 +518,17 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, | |||
507 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 518 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
508 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 519 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
509 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 520 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
521 | u32 convert_rate = rsnd_src_convert_rate(src); | ||
510 | uint ratio; | 522 | uint ratio; |
511 | int ret; | 523 | int ret; |
512 | 524 | ||
513 | /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ | 525 | /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ |
514 | if (!rsnd_src_convert_rate(src)) | 526 | if (!convert_rate) |
515 | ratio = 0; | 527 | ratio = 0; |
516 | else if (rsnd_src_convert_rate(src) > runtime->rate) | 528 | else if (convert_rate > runtime->rate) |
517 | ratio = 100 * rsnd_src_convert_rate(src) / runtime->rate; | 529 | ratio = 100 * convert_rate / runtime->rate; |
518 | else | 530 | else |
519 | ratio = 100 * runtime->rate / rsnd_src_convert_rate(src); | 531 | ratio = 100 * runtime->rate / convert_rate; |
520 | 532 | ||
521 | if (ratio > 600) { | 533 | if (ratio > 600) { |
522 | dev_err(dev, "FSO/FSI ratio error\n"); | 534 | dev_err(dev, "FSO/FSI ratio error\n"); |
@@ -529,6 +541,11 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, | |||
529 | 541 | ||
530 | rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); | 542 | rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); |
531 | 543 | ||
544 | if (convert_rate) { | ||
545 | /* Gen1/Gen2 are not compatible */ | ||
546 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
547 | } | ||
548 | |||
532 | switch (rsnd_mod_id(mod)) { | 549 | switch (rsnd_mod_id(mod)) { |
533 | case 5: | 550 | case 5: |
534 | case 6: | 551 | case 6: |
@@ -578,9 +595,11 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, | |||
578 | rsnd_info_is_playback(priv, src), | 595 | rsnd_info_is_playback(priv, src), |
579 | src->info->dma_id); | 596 | src->info->dma_id); |
580 | if (ret < 0) | 597 | if (ret < 0) |
581 | dev_err(dev, "SRC DMA failed\n"); | 598 | dev_err(dev, "%s[%d] (Gen2) failed\n", |
582 | 599 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | |
583 | dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); | 600 | else |
601 | dev_dbg(dev, "%s[%d] (Gen2) is probed\n", | ||
602 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
584 | 603 | ||
585 | return ret; | 604 | return ret; |
586 | } | 605 | } |
@@ -624,7 +643,7 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, | |||
624 | 643 | ||
625 | rsnd_mod_write(mod, SRC_CTRL, val); | 644 | rsnd_mod_write(mod, SRC_CTRL, val); |
626 | 645 | ||
627 | return rsnd_src_start(mod, rdai); | 646 | return rsnd_src_start(mod); |
628 | } | 647 | } |
629 | 648 | ||
630 | static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | 649 | static int rsnd_src_stop_gen2(struct rsnd_mod *mod, |
@@ -636,7 +655,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | |||
636 | 655 | ||
637 | rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); | 656 | rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); |
638 | 657 | ||
639 | return rsnd_src_stop(mod, rdai); | 658 | return rsnd_src_stop(mod); |
640 | } | 659 | } |
641 | 660 | ||
642 | static struct rsnd_mod_ops rsnd_src_gen2_ops = { | 661 | static struct rsnd_mod_ops rsnd_src_gen2_ops = { |
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 34e84009162b..3844fbef4664 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -68,7 +68,6 @@ struct rsnd_ssi { | |||
68 | struct rsnd_dai *rdai; | 68 | struct rsnd_dai *rdai; |
69 | u32 cr_own; | 69 | u32 cr_own; |
70 | u32 cr_clk; | 70 | u32 cr_clk; |
71 | u32 cr_etc; | ||
72 | int err; | 71 | int err; |
73 | unsigned int usrcnt; | 72 | unsigned int usrcnt; |
74 | unsigned int rate; | 73 | unsigned int rate; |
@@ -83,7 +82,7 @@ struct rsnd_ssi { | |||
83 | #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) | 82 | #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) |
84 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | 83 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) |
85 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) | 84 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) |
86 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) | 85 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) |
87 | #define rsnd_ssi_dma_available(ssi) \ | 86 | #define rsnd_ssi_dma_available(ssi) \ |
88 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) | 87 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) |
89 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) | 88 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) |
@@ -96,6 +95,9 @@ static int rsnd_ssi_use_busif(struct rsnd_mod *mod) | |||
96 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 95 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
97 | int use_busif = 0; | 96 | int use_busif = 0; |
98 | 97 | ||
98 | if (!rsnd_ssi_is_dma_mode(mod)) | ||
99 | return 0; | ||
100 | |||
99 | if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF)) | 101 | if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF)) |
100 | use_busif = 1; | 102 | use_busif = 1; |
101 | if (rsnd_io_to_mod_src(io)) | 103 | if (rsnd_io_to_mod_src(io)) |
@@ -159,7 +161,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
159 | ssi->cr_clk = FORCE | SWL_32 | | 161 | ssi->cr_clk = FORCE | SWL_32 | |
160 | SCKD | SWSD | CKDV(j); | 162 | SCKD | SWSD | CKDV(j); |
161 | 163 | ||
162 | dev_dbg(dev, "ssi%d outputs %u Hz\n", | 164 | dev_dbg(dev, "%s[%d] outputs %u Hz\n", |
165 | rsnd_mod_name(&ssi->mod), | ||
163 | rsnd_mod_id(&ssi->mod), rate); | 166 | rsnd_mod_id(&ssi->mod), rate); |
164 | 167 | ||
165 | return 0; | 168 | return 0; |
@@ -184,6 +187,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
184 | { | 187 | { |
185 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | 188 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); |
186 | struct device *dev = rsnd_priv_to_dev(priv); | 189 | struct device *dev = rsnd_priv_to_dev(priv); |
190 | u32 cr_mode; | ||
187 | u32 cr; | 191 | u32 cr; |
188 | 192 | ||
189 | if (0 == ssi->usrcnt) { | 193 | if (0 == ssi->usrcnt) { |
@@ -197,16 +201,29 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
197 | } | 201 | } |
198 | } | 202 | } |
199 | 203 | ||
204 | cr_mode = rsnd_ssi_is_dma_mode(&ssi->mod) ? | ||
205 | DMEN : /* DMA : enable DMA */ | ||
206 | DIEN; /* PIO : enable Data interrupt */ | ||
207 | |||
208 | |||
200 | cr = ssi->cr_own | | 209 | cr = ssi->cr_own | |
201 | ssi->cr_clk | | 210 | ssi->cr_clk | |
202 | ssi->cr_etc | | 211 | cr_mode | |
203 | EN; | 212 | UIEN | OIEN | EN; |
204 | 213 | ||
205 | rsnd_mod_write(&ssi->mod, SSICR, cr); | 214 | rsnd_mod_write(&ssi->mod, SSICR, cr); |
206 | 215 | ||
216 | /* enable WS continue */ | ||
217 | if (rsnd_dai_is_clk_master(rdai)) | ||
218 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); | ||
219 | |||
220 | /* clear error status */ | ||
221 | rsnd_mod_write(&ssi->mod, SSISR, 0); | ||
222 | |||
207 | ssi->usrcnt++; | 223 | ssi->usrcnt++; |
208 | 224 | ||
209 | dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod)); | 225 | dev_dbg(dev, "%s[%d] hw started\n", |
226 | rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod)); | ||
210 | } | 227 | } |
211 | 228 | ||
212 | static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, | 229 | static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, |
@@ -249,7 +266,8 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, | |||
249 | clk_disable_unprepare(ssi->clk); | 266 | clk_disable_unprepare(ssi->clk); |
250 | } | 267 | } |
251 | 268 | ||
252 | dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod)); | 269 | dev_dbg(dev, "%s[%d] hw stopped\n", |
270 | rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod)); | ||
253 | } | 271 | } |
254 | 272 | ||
255 | /* | 273 | /* |
@@ -334,25 +352,54 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | |||
334 | } | 352 | } |
335 | } | 353 | } |
336 | 354 | ||
337 | /* | 355 | static int rsnd_ssi_start(struct rsnd_mod *mod, |
338 | * SSI PIO | 356 | struct rsnd_dai *rdai) |
339 | */ | 357 | { |
340 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | 358 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
359 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
360 | |||
361 | rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod)); | ||
362 | |||
363 | rsnd_ssi_hw_start(ssi, rdai, io); | ||
364 | |||
365 | rsnd_src_ssi_irq_enable(mod, rdai); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int rsnd_ssi_stop(struct rsnd_mod *mod, | ||
371 | struct rsnd_dai *rdai) | ||
372 | { | ||
373 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
374 | |||
375 | rsnd_src_ssi_irq_disable(mod, rdai); | ||
376 | |||
377 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); | ||
378 | |||
379 | rsnd_ssi_hw_stop(ssi, rdai); | ||
380 | |||
381 | rsnd_src_ssiu_stop(mod, rdai); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | ||
341 | { | 387 | { |
342 | struct rsnd_ssi *ssi = data; | 388 | struct rsnd_ssi *ssi = data; |
389 | struct rsnd_dai *rdai = ssi->rdai; | ||
343 | struct rsnd_mod *mod = &ssi->mod; | 390 | struct rsnd_mod *mod = &ssi->mod; |
344 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 391 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
345 | u32 status = rsnd_mod_read(mod, SSISR); | 392 | u32 status = rsnd_mod_read(mod, SSISR); |
346 | irqreturn_t ret = IRQ_NONE; | ||
347 | 393 | ||
348 | if (io && (status & DIRQ)) { | 394 | if (!io) |
349 | struct rsnd_dai *rdai = ssi->rdai; | 395 | return IRQ_NONE; |
396 | |||
397 | /* PIO only */ | ||
398 | if (status & DIRQ) { | ||
350 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 399 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
351 | u32 *buf = (u32 *)(runtime->dma_area + | 400 | u32 *buf = (u32 *)(runtime->dma_area + |
352 | rsnd_dai_pointer_offset(io, 0)); | 401 | rsnd_dai_pointer_offset(io, 0)); |
353 | 402 | ||
354 | rsnd_ssi_record_error(ssi, status); | ||
355 | |||
356 | /* | 403 | /* |
357 | * 8/16/32 data can be assesse to TDR/RDR register | 404 | * 8/16/32 data can be assesse to TDR/RDR register |
358 | * directly as 32bit data | 405 | * directly as 32bit data |
@@ -364,73 +411,60 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | |||
364 | *buf = rsnd_mod_read(mod, SSIRDR); | 411 | *buf = rsnd_mod_read(mod, SSIRDR); |
365 | 412 | ||
366 | rsnd_dai_pointer_update(io, sizeof(*buf)); | 413 | rsnd_dai_pointer_update(io, sizeof(*buf)); |
414 | } | ||
415 | |||
416 | /* PIO / DMA */ | ||
417 | if (status & (UIRQ | OIRQ)) { | ||
418 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
419 | struct device *dev = rsnd_priv_to_dev(priv); | ||
420 | |||
421 | /* | ||
422 | * restart SSI | ||
423 | */ | ||
424 | rsnd_ssi_stop(mod, rdai); | ||
425 | rsnd_ssi_start(mod, rdai); | ||
367 | 426 | ||
368 | ret = IRQ_HANDLED; | 427 | dev_dbg(dev, "%s[%d] restart\n", |
428 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
369 | } | 429 | } |
370 | 430 | ||
371 | return ret; | 431 | rsnd_ssi_record_error(ssi, status); |
432 | |||
433 | return IRQ_HANDLED; | ||
372 | } | 434 | } |
373 | 435 | ||
436 | /* | ||
437 | * SSI PIO | ||
438 | */ | ||
374 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, | 439 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, |
375 | struct rsnd_dai *rdai) | 440 | struct rsnd_dai *rdai) |
376 | { | 441 | { |
377 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 442 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
378 | struct device *dev = rsnd_priv_to_dev(priv); | 443 | struct device *dev = rsnd_priv_to_dev(priv); |
379 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 444 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
380 | int irq = ssi->info->pio_irq; | ||
381 | int ret; | 445 | int ret; |
382 | 446 | ||
383 | ret = devm_request_irq(dev, irq, | 447 | ret = devm_request_irq(dev, ssi->info->irq, |
384 | rsnd_ssi_pio_interrupt, | 448 | rsnd_ssi_interrupt, |
385 | IRQF_SHARED, | 449 | IRQF_SHARED, |
386 | dev_name(dev), ssi); | 450 | dev_name(dev), ssi); |
387 | if (ret) | 451 | if (ret) |
388 | dev_err(dev, "SSI request interrupt failed\n"); | 452 | dev_err(dev, "%s[%d] (PIO) request interrupt failed\n", |
389 | 453 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | |
390 | dev_dbg(dev, "%s (PIO) is probed\n", rsnd_mod_name(mod)); | 454 | else |
455 | dev_dbg(dev, "%s[%d] (PIO) is probed\n", | ||
456 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
391 | 457 | ||
392 | return ret; | 458 | return ret; |
393 | } | 459 | } |
394 | 460 | ||
395 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | ||
396 | struct rsnd_dai *rdai) | ||
397 | { | ||
398 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
399 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
400 | |||
401 | /* enable PIO IRQ */ | ||
402 | ssi->cr_etc = UIEN | OIEN | DIEN; | ||
403 | |||
404 | rsnd_src_ssiu_start(mod, rdai, 0); | ||
405 | |||
406 | rsnd_src_enable_ssi_irq(mod, rdai); | ||
407 | |||
408 | rsnd_ssi_hw_start(ssi, rdai, io); | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | ||
414 | struct rsnd_dai *rdai) | ||
415 | { | ||
416 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
417 | |||
418 | ssi->cr_etc = 0; | ||
419 | |||
420 | rsnd_ssi_hw_stop(ssi, rdai); | ||
421 | |||
422 | rsnd_src_ssiu_stop(mod, rdai, 0); | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 461 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
428 | .name = SSI_NAME, | 462 | .name = SSI_NAME, |
429 | .probe = rsnd_ssi_pio_probe, | 463 | .probe = rsnd_ssi_pio_probe, |
430 | .init = rsnd_ssi_init, | 464 | .init = rsnd_ssi_init, |
431 | .quit = rsnd_ssi_quit, | 465 | .quit = rsnd_ssi_quit, |
432 | .start = rsnd_ssi_pio_start, | 466 | .start = rsnd_ssi_start, |
433 | .stop = rsnd_ssi_pio_stop, | 467 | .stop = rsnd_ssi_stop, |
434 | }; | 468 | }; |
435 | 469 | ||
436 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | 470 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, |
@@ -442,15 +476,28 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | |||
442 | int dma_id = ssi->info->dma_id; | 476 | int dma_id = ssi->info->dma_id; |
443 | int ret; | 477 | int ret; |
444 | 478 | ||
479 | ret = devm_request_irq(dev, ssi->info->irq, | ||
480 | rsnd_ssi_interrupt, | ||
481 | IRQF_SHARED, | ||
482 | dev_name(dev), ssi); | ||
483 | if (ret) | ||
484 | goto rsnd_ssi_dma_probe_fail; | ||
485 | |||
445 | ret = rsnd_dma_init( | 486 | ret = rsnd_dma_init( |
446 | priv, rsnd_mod_to_dma(mod), | 487 | priv, rsnd_mod_to_dma(mod), |
447 | rsnd_info_is_playback(priv, ssi), | 488 | rsnd_info_is_playback(priv, ssi), |
448 | dma_id); | 489 | dma_id); |
490 | if (ret) | ||
491 | goto rsnd_ssi_dma_probe_fail; | ||
449 | 492 | ||
450 | if (ret < 0) | 493 | dev_dbg(dev, "%s[%d] (DMA) is probed\n", |
451 | dev_err(dev, "SSI DMA failed\n"); | 494 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
495 | |||
496 | return ret; | ||
452 | 497 | ||
453 | dev_dbg(dev, "%s (DMA) is probed\n", rsnd_mod_name(mod)); | 498 | rsnd_ssi_dma_probe_fail: |
499 | dev_err(dev, "%s[%d] (DMA) is failed\n", | ||
500 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
454 | 501 | ||
455 | return ret; | 502 | return ret; |
456 | } | 503 | } |
@@ -458,30 +505,48 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | |||
458 | static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, | 505 | static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, |
459 | struct rsnd_dai *rdai) | 506 | struct rsnd_dai *rdai) |
460 | { | 507 | { |
508 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
509 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
510 | struct device *dev = rsnd_priv_to_dev(priv); | ||
511 | int irq = ssi->info->irq; | ||
512 | |||
461 | rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); | 513 | rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); |
462 | 514 | ||
515 | /* PIO will request IRQ again */ | ||
516 | devm_free_irq(dev, irq, ssi); | ||
517 | |||
463 | return 0; | 518 | return 0; |
464 | } | 519 | } |
465 | 520 | ||
466 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | 521 | static int rsnd_ssi_fallback(struct rsnd_mod *mod, |
467 | struct rsnd_dai *rdai) | 522 | struct rsnd_dai *rdai) |
468 | { | 523 | { |
469 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 524 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
470 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); | 525 | struct device *dev = rsnd_priv_to_dev(priv); |
471 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
472 | 526 | ||
473 | /* enable DMA transfer */ | 527 | /* |
474 | ssi->cr_etc = DMEN; | 528 | * fallback to PIO |
529 | * | ||
530 | * SSI .probe might be called again. | ||
531 | * see | ||
532 | * rsnd_rdai_continuance_probe() | ||
533 | */ | ||
534 | mod->ops = &rsnd_ssi_pio_ops; | ||
475 | 535 | ||
476 | rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod)); | 536 | dev_info(dev, "%s[%d] fallback to PIO mode\n", |
537 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
477 | 538 | ||
478 | rsnd_dma_start(dma); | 539 | return 0; |
540 | } | ||
479 | 541 | ||
480 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); | 542 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, |
543 | struct rsnd_dai *rdai) | ||
544 | { | ||
545 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
481 | 546 | ||
482 | /* enable WS continue */ | 547 | rsnd_ssi_start(mod, rdai); |
483 | if (rsnd_dai_is_clk_master(rdai)) | 548 | |
484 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); | 549 | rsnd_dma_start(dma); |
485 | 550 | ||
486 | return 0; | 551 | return 0; |
487 | } | 552 | } |
@@ -489,18 +554,11 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | |||
489 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | 554 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, |
490 | struct rsnd_dai *rdai) | 555 | struct rsnd_dai *rdai) |
491 | { | 556 | { |
492 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 557 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); |
493 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); | ||
494 | |||
495 | ssi->cr_etc = 0; | ||
496 | |||
497 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); | ||
498 | |||
499 | rsnd_ssi_hw_stop(ssi, rdai); | ||
500 | 558 | ||
501 | rsnd_dma_stop(dma); | 559 | rsnd_dma_stop(dma); |
502 | 560 | ||
503 | rsnd_src_ssiu_stop(mod, rdai, 1); | 561 | rsnd_ssi_stop(mod, rdai); |
504 | 562 | ||
505 | return 0; | 563 | return 0; |
506 | } | 564 | } |
@@ -519,8 +577,15 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | |||
519 | .quit = rsnd_ssi_quit, | 577 | .quit = rsnd_ssi_quit, |
520 | .start = rsnd_ssi_dma_start, | 578 | .start = rsnd_ssi_dma_start, |
521 | .stop = rsnd_ssi_dma_stop, | 579 | .stop = rsnd_ssi_dma_stop, |
580 | .fallback = rsnd_ssi_fallback, | ||
522 | }; | 581 | }; |
523 | 582 | ||
583 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) | ||
584 | { | ||
585 | return mod->ops == &rsnd_ssi_dma_ops; | ||
586 | } | ||
587 | |||
588 | |||
524 | /* | 589 | /* |
525 | * Non SSI | 590 | * Non SSI |
526 | */ | 591 | */ |
@@ -614,7 +679,7 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, | |||
614 | /* | 679 | /* |
615 | * irq | 680 | * irq |
616 | */ | 681 | */ |
617 | ssi_info->pio_irq = irq_of_parse_and_map(np, 0); | 682 | ssi_info->irq = irq_of_parse_and_map(np, 0); |
618 | 683 | ||
619 | /* | 684 | /* |
620 | * DMA | 685 | * DMA |
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c new file mode 100644 index 000000000000..2e10e9a38376 --- /dev/null +++ b/sound/soc/soc-ac97.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * soc-ac97.c -- ALSA SoC Audio Layer AC97 support | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * Copyright (C) 2010 Slimlogic Ltd. | ||
7 | * Copyright (C) 2010 Texas Instruments Inc. | ||
8 | * | ||
9 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | ||
10 | * with code, comments and ideas from :- | ||
11 | * Richard Purdie <richard@openedhand.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/ctype.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/export.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/of_gpio.h> | ||
25 | #include <linux/of.h> | ||
26 | #include <linux/pinctrl/consumer.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <sound/ac97_codec.h> | ||
29 | #include <sound/soc.h> | ||
30 | |||
31 | struct snd_ac97_reset_cfg { | ||
32 | struct pinctrl *pctl; | ||
33 | struct pinctrl_state *pstate_reset; | ||
34 | struct pinctrl_state *pstate_warm_reset; | ||
35 | struct pinctrl_state *pstate_run; | ||
36 | int gpio_sdata; | ||
37 | int gpio_sync; | ||
38 | int gpio_reset; | ||
39 | }; | ||
40 | |||
41 | static struct snd_ac97_bus soc_ac97_bus = { | ||
42 | .ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */ | ||
43 | }; | ||
44 | |||
45 | static void soc_ac97_device_release(struct device *dev) | ||
46 | { | ||
47 | kfree(to_ac97_t(dev)); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * snd_soc_new_ac97_codec - initailise AC97 device | ||
52 | * @codec: audio codec | ||
53 | * | ||
54 | * Initialises AC97 codec resources for use by ad-hoc devices only. | ||
55 | */ | ||
56 | struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec) | ||
57 | { | ||
58 | struct snd_ac97 *ac97; | ||
59 | int ret; | ||
60 | |||
61 | ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); | ||
62 | if (ac97 == NULL) | ||
63 | return ERR_PTR(-ENOMEM); | ||
64 | |||
65 | ac97->bus = &soc_ac97_bus; | ||
66 | ac97->num = 0; | ||
67 | |||
68 | ac97->dev.bus = &ac97_bus_type; | ||
69 | ac97->dev.parent = codec->component.card->dev; | ||
70 | ac97->dev.release = soc_ac97_device_release; | ||
71 | |||
72 | dev_set_name(&ac97->dev, "%d-%d:%s", | ||
73 | codec->component.card->snd_card->number, 0, | ||
74 | codec->component.name); | ||
75 | |||
76 | ret = device_register(&ac97->dev); | ||
77 | if (ret) { | ||
78 | put_device(&ac97->dev); | ||
79 | return ERR_PTR(ret); | ||
80 | } | ||
81 | |||
82 | return ac97; | ||
83 | } | ||
84 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | ||
85 | |||
86 | /** | ||
87 | * snd_soc_free_ac97_codec - free AC97 codec device | ||
88 | * @codec: audio codec | ||
89 | * | ||
90 | * Frees AC97 codec device resources. | ||
91 | */ | ||
92 | void snd_soc_free_ac97_codec(struct snd_ac97 *ac97) | ||
93 | { | ||
94 | device_del(&ac97->dev); | ||
95 | ac97->bus = NULL; | ||
96 | put_device(&ac97->dev); | ||
97 | } | ||
98 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | ||
99 | |||
100 | static struct snd_ac97_reset_cfg snd_ac97_rst_cfg; | ||
101 | |||
102 | static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97) | ||
103 | { | ||
104 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
105 | |||
106 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset); | ||
107 | |||
108 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1); | ||
109 | |||
110 | udelay(10); | ||
111 | |||
112 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
113 | |||
114 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
115 | msleep(2); | ||
116 | } | ||
117 | |||
118 | static void snd_soc_ac97_reset(struct snd_ac97 *ac97) | ||
119 | { | ||
120 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
121 | |||
122 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset); | ||
123 | |||
124 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
125 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0); | ||
126 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0); | ||
127 | |||
128 | udelay(10); | ||
129 | |||
130 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1); | ||
131 | |||
132 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
133 | msleep(2); | ||
134 | } | ||
135 | |||
136 | static int snd_soc_ac97_parse_pinctl(struct device *dev, | ||
137 | struct snd_ac97_reset_cfg *cfg) | ||
138 | { | ||
139 | struct pinctrl *p; | ||
140 | struct pinctrl_state *state; | ||
141 | int gpio; | ||
142 | int ret; | ||
143 | |||
144 | p = devm_pinctrl_get(dev); | ||
145 | if (IS_ERR(p)) { | ||
146 | dev_err(dev, "Failed to get pinctrl\n"); | ||
147 | return PTR_ERR(p); | ||
148 | } | ||
149 | cfg->pctl = p; | ||
150 | |||
151 | state = pinctrl_lookup_state(p, "ac97-reset"); | ||
152 | if (IS_ERR(state)) { | ||
153 | dev_err(dev, "Can't find pinctrl state ac97-reset\n"); | ||
154 | return PTR_ERR(state); | ||
155 | } | ||
156 | cfg->pstate_reset = state; | ||
157 | |||
158 | state = pinctrl_lookup_state(p, "ac97-warm-reset"); | ||
159 | if (IS_ERR(state)) { | ||
160 | dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); | ||
161 | return PTR_ERR(state); | ||
162 | } | ||
163 | cfg->pstate_warm_reset = state; | ||
164 | |||
165 | state = pinctrl_lookup_state(p, "ac97-running"); | ||
166 | if (IS_ERR(state)) { | ||
167 | dev_err(dev, "Can't find pinctrl state ac97-running\n"); | ||
168 | return PTR_ERR(state); | ||
169 | } | ||
170 | cfg->pstate_run = state; | ||
171 | |||
172 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0); | ||
173 | if (gpio < 0) { | ||
174 | dev_err(dev, "Can't find ac97-sync gpio\n"); | ||
175 | return gpio; | ||
176 | } | ||
177 | ret = devm_gpio_request(dev, gpio, "AC97 link sync"); | ||
178 | if (ret) { | ||
179 | dev_err(dev, "Failed requesting ac97-sync gpio\n"); | ||
180 | return ret; | ||
181 | } | ||
182 | cfg->gpio_sync = gpio; | ||
183 | |||
184 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1); | ||
185 | if (gpio < 0) { | ||
186 | dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio); | ||
187 | return gpio; | ||
188 | } | ||
189 | ret = devm_gpio_request(dev, gpio, "AC97 link sdata"); | ||
190 | if (ret) { | ||
191 | dev_err(dev, "Failed requesting ac97-sdata gpio\n"); | ||
192 | return ret; | ||
193 | } | ||
194 | cfg->gpio_sdata = gpio; | ||
195 | |||
196 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); | ||
197 | if (gpio < 0) { | ||
198 | dev_err(dev, "Can't find ac97-reset gpio\n"); | ||
199 | return gpio; | ||
200 | } | ||
201 | ret = devm_gpio_request(dev, gpio, "AC97 link reset"); | ||
202 | if (ret) { | ||
203 | dev_err(dev, "Failed requesting ac97-reset gpio\n"); | ||
204 | return ret; | ||
205 | } | ||
206 | cfg->gpio_reset = gpio; | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | struct snd_ac97_bus_ops *soc_ac97_ops; | ||
212 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
213 | |||
214 | int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) | ||
215 | { | ||
216 | if (ops == soc_ac97_ops) | ||
217 | return 0; | ||
218 | |||
219 | if (soc_ac97_ops && ops) | ||
220 | return -EBUSY; | ||
221 | |||
222 | soc_ac97_ops = ops; | ||
223 | soc_ac97_bus.ops = ops; | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); | ||
228 | |||
229 | /** | ||
230 | * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions | ||
231 | * | ||
232 | * This function sets the reset and warm_reset properties of ops and parses | ||
233 | * the device node of pdev to get pinctrl states and gpio numbers to use. | ||
234 | */ | ||
235 | int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, | ||
236 | struct platform_device *pdev) | ||
237 | { | ||
238 | struct device *dev = &pdev->dev; | ||
239 | struct snd_ac97_reset_cfg cfg; | ||
240 | int ret; | ||
241 | |||
242 | ret = snd_soc_ac97_parse_pinctl(dev, &cfg); | ||
243 | if (ret) | ||
244 | return ret; | ||
245 | |||
246 | ret = snd_soc_set_ac97_ops(ops); | ||
247 | if (ret) | ||
248 | return ret; | ||
249 | |||
250 | ops->warm_reset = snd_soc_ac97_warm_reset; | ||
251 | ops->reset = snd_soc_ac97_reset; | ||
252 | |||
253 | snd_ac97_rst_cfg = cfg; | ||
254 | return 0; | ||
255 | } | ||
256 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); | ||
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index a9f82b5aba9d..07f43356f963 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -15,56 +15,6 @@ | |||
15 | #include <linux/export.h> | 15 | #include <linux/export.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | 17 | ||
18 | #include <trace/events/asoc.h> | ||
19 | |||
20 | static bool snd_soc_set_cache_val(void *base, unsigned int idx, | ||
21 | unsigned int val, unsigned int word_size) | ||
22 | { | ||
23 | switch (word_size) { | ||
24 | case 1: { | ||
25 | u8 *cache = base; | ||
26 | if (cache[idx] == val) | ||
27 | return true; | ||
28 | cache[idx] = val; | ||
29 | break; | ||
30 | } | ||
31 | case 2: { | ||
32 | u16 *cache = base; | ||
33 | if (cache[idx] == val) | ||
34 | return true; | ||
35 | cache[idx] = val; | ||
36 | break; | ||
37 | } | ||
38 | default: | ||
39 | WARN(1, "Invalid word_size %d\n", word_size); | ||
40 | break; | ||
41 | } | ||
42 | return false; | ||
43 | } | ||
44 | |||
45 | static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, | ||
46 | unsigned int word_size) | ||
47 | { | ||
48 | if (!base) | ||
49 | return -1; | ||
50 | |||
51 | switch (word_size) { | ||
52 | case 1: { | ||
53 | const u8 *cache = base; | ||
54 | return cache[idx]; | ||
55 | } | ||
56 | case 2: { | ||
57 | const u16 *cache = base; | ||
58 | return cache[idx]; | ||
59 | } | ||
60 | default: | ||
61 | WARN(1, "Invalid word_size %d\n", word_size); | ||
62 | break; | ||
63 | } | ||
64 | /* unreachable */ | ||
65 | return -1; | ||
66 | } | ||
67 | |||
68 | int snd_soc_cache_init(struct snd_soc_codec *codec) | 18 | int snd_soc_cache_init(struct snd_soc_codec *codec) |
69 | { | 19 | { |
70 | const struct snd_soc_codec_driver *codec_drv = codec->driver; | 20 | const struct snd_soc_codec_driver *codec_drv = codec->driver; |
@@ -75,8 +25,6 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) | |||
75 | if (!reg_size) | 25 | if (!reg_size) |
76 | return 0; | 26 | return 0; |
77 | 27 | ||
78 | mutex_init(&codec->cache_rw_mutex); | ||
79 | |||
80 | dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", | 28 | dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", |
81 | codec->component.name); | 29 | codec->component.name); |
82 | 30 | ||
@@ -103,100 +51,3 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) | |||
103 | codec->reg_cache = NULL; | 51 | codec->reg_cache = NULL; |
104 | return 0; | 52 | return 0; |
105 | } | 53 | } |
106 | |||
107 | /** | ||
108 | * snd_soc_cache_read: Fetch the value of a given register from the cache. | ||
109 | * | ||
110 | * @codec: CODEC to configure. | ||
111 | * @reg: The register index. | ||
112 | * @value: The value to be returned. | ||
113 | */ | ||
114 | int snd_soc_cache_read(struct snd_soc_codec *codec, | ||
115 | unsigned int reg, unsigned int *value) | ||
116 | { | ||
117 | if (!value) | ||
118 | return -EINVAL; | ||
119 | |||
120 | mutex_lock(&codec->cache_rw_mutex); | ||
121 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) | ||
122 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, | ||
123 | codec->driver->reg_word_size); | ||
124 | mutex_unlock(&codec->cache_rw_mutex); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | EXPORT_SYMBOL_GPL(snd_soc_cache_read); | ||
129 | |||
130 | /** | ||
131 | * snd_soc_cache_write: Set the value of a given register in the cache. | ||
132 | * | ||
133 | * @codec: CODEC to configure. | ||
134 | * @reg: The register index. | ||
135 | * @value: The new register value. | ||
136 | */ | ||
137 | int snd_soc_cache_write(struct snd_soc_codec *codec, | ||
138 | unsigned int reg, unsigned int value) | ||
139 | { | ||
140 | mutex_lock(&codec->cache_rw_mutex); | ||
141 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) | ||
142 | snd_soc_set_cache_val(codec->reg_cache, reg, value, | ||
143 | codec->driver->reg_word_size); | ||
144 | mutex_unlock(&codec->cache_rw_mutex); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | EXPORT_SYMBOL_GPL(snd_soc_cache_write); | ||
149 | |||
150 | static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) | ||
151 | { | ||
152 | int i; | ||
153 | int ret; | ||
154 | const struct snd_soc_codec_driver *codec_drv; | ||
155 | unsigned int val; | ||
156 | |||
157 | codec_drv = codec->driver; | ||
158 | for (i = 0; i < codec_drv->reg_cache_size; ++i) { | ||
159 | ret = snd_soc_cache_read(codec, i, &val); | ||
160 | if (ret) | ||
161 | return ret; | ||
162 | if (codec_drv->reg_cache_default) | ||
163 | if (snd_soc_get_cache_val(codec_drv->reg_cache_default, | ||
164 | i, codec_drv->reg_word_size) == val) | ||
165 | continue; | ||
166 | |||
167 | ret = snd_soc_write(codec, i, val); | ||
168 | if (ret) | ||
169 | return ret; | ||
170 | dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", | ||
171 | i, val); | ||
172 | } | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * snd_soc_cache_sync: Sync the register cache with the hardware. | ||
178 | * | ||
179 | * @codec: CODEC to configure. | ||
180 | * | ||
181 | * Any registers that should not be synced should be marked as | ||
182 | * volatile. In general drivers can choose not to use the provided | ||
183 | * syncing functionality if they so require. | ||
184 | */ | ||
185 | int snd_soc_cache_sync(struct snd_soc_codec *codec) | ||
186 | { | ||
187 | const char *name = "flat"; | ||
188 | int ret; | ||
189 | |||
190 | if (!codec->cache_sync) | ||
191 | return 0; | ||
192 | |||
193 | dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n", | ||
194 | codec->component.name); | ||
195 | trace_snd_soc_cache_sync(codec, name, "start"); | ||
196 | ret = snd_soc_flat_cache_sync(codec); | ||
197 | if (!ret) | ||
198 | codec->cache_sync = 0; | ||
199 | trace_snd_soc_cache_sync(codec, name, "end"); | ||
200 | return ret; | ||
201 | } | ||
202 | EXPORT_SYMBOL_GPL(snd_soc_cache_sync); | ||
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index cecfab3cc948..590a82f01d0b 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c | |||
@@ -258,10 +258,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) | |||
258 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) | 258 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) |
259 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | 259 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
260 | 260 | ||
261 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 261 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); |
262 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); | ||
263 | else | ||
264 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); | ||
265 | 262 | ||
266 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | 263 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; |
267 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 264 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
@@ -456,11 +453,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, | |||
456 | if (ret < 0) | 453 | if (ret < 0) |
457 | goto out; | 454 | goto out; |
458 | 455 | ||
459 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 456 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); |
460 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); | ||
461 | else | ||
462 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); | ||
463 | |||
464 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; | 457 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; |
465 | 458 | ||
466 | out: | 459 | out: |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b60ff56ebc0f..935721062c21 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -34,9 +34,6 @@ | |||
34 | #include <linux/ctype.h> | 34 | #include <linux/ctype.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/of.h> | 36 | #include <linux/of.h> |
37 | #include <linux/gpio.h> | ||
38 | #include <linux/of_gpio.h> | ||
39 | #include <sound/ac97_codec.h> | ||
40 | #include <sound/core.h> | 37 | #include <sound/core.h> |
41 | #include <sound/jack.h> | 38 | #include <sound/jack.h> |
42 | #include <sound/pcm.h> | 39 | #include <sound/pcm.h> |
@@ -69,16 +66,6 @@ static int pmdown_time = 5000; | |||
69 | module_param(pmdown_time, int, 0); | 66 | module_param(pmdown_time, int, 0); |
70 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); | 67 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); |
71 | 68 | ||
72 | struct snd_ac97_reset_cfg { | ||
73 | struct pinctrl *pctl; | ||
74 | struct pinctrl_state *pstate_reset; | ||
75 | struct pinctrl_state *pstate_warm_reset; | ||
76 | struct pinctrl_state *pstate_run; | ||
77 | int gpio_sdata; | ||
78 | int gpio_sync; | ||
79 | int gpio_reset; | ||
80 | }; | ||
81 | |||
82 | /* returns the minimum number of bytes needed to represent | 69 | /* returns the minimum number of bytes needed to represent |
83 | * a particular given value */ | 70 | * a particular given value */ |
84 | static int min_bytes_needed(unsigned long val) | 71 | static int min_bytes_needed(unsigned long val) |
@@ -309,9 +296,6 @@ static void soc_init_codec_debugfs(struct snd_soc_component *component) | |||
309 | { | 296 | { |
310 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); | 297 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); |
311 | 298 | ||
312 | debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, | ||
313 | &codec->cache_sync); | ||
314 | |||
315 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, | 299 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, |
316 | codec->component.debugfs_root, | 300 | codec->component.debugfs_root, |
317 | codec, &codec_reg_fops); | 301 | codec, &codec_reg_fops); |
@@ -499,40 +483,6 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, | |||
499 | } | 483 | } |
500 | EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); | 484 | EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); |
501 | 485 | ||
502 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
503 | /* unregister ac97 codec */ | ||
504 | static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) | ||
505 | { | ||
506 | if (codec->ac97->dev.bus) | ||
507 | device_unregister(&codec->ac97->dev); | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | /* stop no dev release warning */ | ||
512 | static void soc_ac97_device_release(struct device *dev){} | ||
513 | |||
514 | /* register ac97 codec to bus */ | ||
515 | static int soc_ac97_dev_register(struct snd_soc_codec *codec) | ||
516 | { | ||
517 | int err; | ||
518 | |||
519 | codec->ac97->dev.bus = &ac97_bus_type; | ||
520 | codec->ac97->dev.parent = codec->component.card->dev; | ||
521 | codec->ac97->dev.release = soc_ac97_device_release; | ||
522 | |||
523 | dev_set_name(&codec->ac97->dev, "%d-%d:%s", | ||
524 | codec->component.card->snd_card->number, 0, | ||
525 | codec->component.name); | ||
526 | err = device_register(&codec->ac97->dev); | ||
527 | if (err < 0) { | ||
528 | dev_err(codec->dev, "ASoC: Can't register ac97 bus\n"); | ||
529 | codec->ac97->dev.bus = NULL; | ||
530 | return err; | ||
531 | } | ||
532 | return 0; | ||
533 | } | ||
534 | #endif | ||
535 | |||
536 | static void codec2codec_close_delayed_work(struct work_struct *work) | 486 | static void codec2codec_close_delayed_work(struct work_struct *work) |
537 | { | 487 | { |
538 | /* Currently nothing to do for c2c links | 488 | /* Currently nothing to do for c2c links |
@@ -592,17 +542,12 @@ int snd_soc_suspend(struct device *dev) | |||
592 | 542 | ||
593 | for (i = 0; i < card->num_rtd; i++) { | 543 | for (i = 0; i < card->num_rtd; i++) { |
594 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 544 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
595 | struct snd_soc_platform *platform = card->rtd[i].platform; | ||
596 | 545 | ||
597 | if (card->rtd[i].dai_link->ignore_suspend) | 546 | if (card->rtd[i].dai_link->ignore_suspend) |
598 | continue; | 547 | continue; |
599 | 548 | ||
600 | if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) | 549 | if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) |
601 | cpu_dai->driver->suspend(cpu_dai); | 550 | cpu_dai->driver->suspend(cpu_dai); |
602 | if (platform->driver->suspend && !platform->suspended) { | ||
603 | platform->driver->suspend(cpu_dai); | ||
604 | platform->suspended = 1; | ||
605 | } | ||
606 | } | 551 | } |
607 | 552 | ||
608 | /* close any waiting streams and save state */ | 553 | /* close any waiting streams and save state */ |
@@ -629,8 +574,8 @@ int snd_soc_suspend(struct device *dev) | |||
629 | SND_SOC_DAPM_STREAM_SUSPEND); | 574 | SND_SOC_DAPM_STREAM_SUSPEND); |
630 | } | 575 | } |
631 | 576 | ||
632 | /* Recheck all analogue paths too */ | 577 | /* Recheck all endpoints too, their state is affected by suspend */ |
633 | dapm_mark_io_dirty(&card->dapm); | 578 | dapm_mark_endpoints_dirty(card); |
634 | snd_soc_dapm_sync(&card->dapm); | 579 | snd_soc_dapm_sync(&card->dapm); |
635 | 580 | ||
636 | /* suspend all CODECs */ | 581 | /* suspend all CODECs */ |
@@ -656,7 +601,6 @@ int snd_soc_suspend(struct device *dev) | |||
656 | if (codec->driver->suspend) | 601 | if (codec->driver->suspend) |
657 | codec->driver->suspend(codec); | 602 | codec->driver->suspend(codec); |
658 | codec->suspended = 1; | 603 | codec->suspended = 1; |
659 | codec->cache_sync = 1; | ||
660 | if (codec->component.regmap) | 604 | if (codec->component.regmap) |
661 | regcache_mark_dirty(codec->component.regmap); | 605 | regcache_mark_dirty(codec->component.regmap); |
662 | /* deactivate pins to sleep state */ | 606 | /* deactivate pins to sleep state */ |
@@ -676,7 +620,7 @@ int snd_soc_suspend(struct device *dev) | |||
676 | if (card->rtd[i].dai_link->ignore_suspend) | 620 | if (card->rtd[i].dai_link->ignore_suspend) |
677 | continue; | 621 | continue; |
678 | 622 | ||
679 | if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control) | 623 | if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) |
680 | cpu_dai->driver->suspend(cpu_dai); | 624 | cpu_dai->driver->suspend(cpu_dai); |
681 | 625 | ||
682 | /* deactivate pins to sleep state */ | 626 | /* deactivate pins to sleep state */ |
@@ -712,14 +656,14 @@ static void soc_resume_deferred(struct work_struct *work) | |||
712 | if (card->resume_pre) | 656 | if (card->resume_pre) |
713 | card->resume_pre(card); | 657 | card->resume_pre(card); |
714 | 658 | ||
715 | /* resume AC97 DAIs */ | 659 | /* resume control bus DAIs */ |
716 | for (i = 0; i < card->num_rtd; i++) { | 660 | for (i = 0; i < card->num_rtd; i++) { |
717 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 661 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
718 | 662 | ||
719 | if (card->rtd[i].dai_link->ignore_suspend) | 663 | if (card->rtd[i].dai_link->ignore_suspend) |
720 | continue; | 664 | continue; |
721 | 665 | ||
722 | if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control) | 666 | if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) |
723 | cpu_dai->driver->resume(cpu_dai); | 667 | cpu_dai->driver->resume(cpu_dai); |
724 | } | 668 | } |
725 | 669 | ||
@@ -775,17 +719,12 @@ static void soc_resume_deferred(struct work_struct *work) | |||
775 | 719 | ||
776 | for (i = 0; i < card->num_rtd; i++) { | 720 | for (i = 0; i < card->num_rtd; i++) { |
777 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 721 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
778 | struct snd_soc_platform *platform = card->rtd[i].platform; | ||
779 | 722 | ||
780 | if (card->rtd[i].dai_link->ignore_suspend) | 723 | if (card->rtd[i].dai_link->ignore_suspend) |
781 | continue; | 724 | continue; |
782 | 725 | ||
783 | if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) | 726 | if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) |
784 | cpu_dai->driver->resume(cpu_dai); | 727 | cpu_dai->driver->resume(cpu_dai); |
785 | if (platform->driver->resume && platform->suspended) { | ||
786 | platform->driver->resume(cpu_dai); | ||
787 | platform->suspended = 0; | ||
788 | } | ||
789 | } | 728 | } |
790 | 729 | ||
791 | if (card->resume_post) | 730 | if (card->resume_post) |
@@ -796,8 +735,8 @@ static void soc_resume_deferred(struct work_struct *work) | |||
796 | /* userspace can access us now we are back as we were before */ | 735 | /* userspace can access us now we are back as we were before */ |
797 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); | 736 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); |
798 | 737 | ||
799 | /* Recheck all analogue paths too */ | 738 | /* Recheck all endpoints too, their state is affected by suspend */ |
800 | dapm_mark_io_dirty(&card->dapm); | 739 | dapm_mark_endpoints_dirty(card); |
801 | snd_soc_dapm_sync(&card->dapm); | 740 | snd_soc_dapm_sync(&card->dapm); |
802 | } | 741 | } |
803 | 742 | ||
@@ -805,7 +744,8 @@ static void soc_resume_deferred(struct work_struct *work) | |||
805 | int snd_soc_resume(struct device *dev) | 744 | int snd_soc_resume(struct device *dev) |
806 | { | 745 | { |
807 | struct snd_soc_card *card = dev_get_drvdata(dev); | 746 | struct snd_soc_card *card = dev_get_drvdata(dev); |
808 | int i, ac97_control = 0; | 747 | bool bus_control = false; |
748 | int i; | ||
809 | 749 | ||
810 | /* If the card is not initialized yet there is nothing to do */ | 750 | /* If the card is not initialized yet there is nothing to do */ |
811 | if (!card->instantiated) | 751 | if (!card->instantiated) |
@@ -828,17 +768,18 @@ int snd_soc_resume(struct device *dev) | |||
828 | } | 768 | } |
829 | } | 769 | } |
830 | 770 | ||
831 | /* AC97 devices might have other drivers hanging off them so | 771 | /* |
832 | * need to resume immediately. Other drivers don't have that | 772 | * DAIs that also act as the control bus master might have other drivers |
833 | * problem and may take a substantial amount of time to resume | 773 | * hanging off them so need to resume immediately. Other drivers don't |
774 | * have that problem and may take a substantial amount of time to resume | ||
834 | * due to I/O costs and anti-pop so handle them out of line. | 775 | * due to I/O costs and anti-pop so handle them out of line. |
835 | */ | 776 | */ |
836 | for (i = 0; i < card->num_rtd; i++) { | 777 | for (i = 0; i < card->num_rtd; i++) { |
837 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 778 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
838 | ac97_control |= cpu_dai->driver->ac97_control; | 779 | bus_control |= cpu_dai->driver->bus_control; |
839 | } | 780 | } |
840 | if (ac97_control) { | 781 | if (bus_control) { |
841 | dev_dbg(dev, "ASoC: Resuming AC97 immediately\n"); | 782 | dev_dbg(dev, "ASoC: Resuming control bus master immediately\n"); |
842 | soc_resume_deferred(&card->deferred_resume_work); | 783 | soc_resume_deferred(&card->deferred_resume_work); |
843 | } else { | 784 | } else { |
844 | dev_dbg(dev, "ASoC: Scheduling resume work\n"); | 785 | dev_dbg(dev, "ASoC: Scheduling resume work\n"); |
@@ -1251,25 +1192,22 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, | |||
1251 | return 0; | 1192 | return 0; |
1252 | } | 1193 | } |
1253 | 1194 | ||
1254 | static int soc_probe_codec_dai(struct snd_soc_card *card, | 1195 | static int soc_probe_dai(struct snd_soc_dai *dai, int order) |
1255 | struct snd_soc_dai *codec_dai, | ||
1256 | int order) | ||
1257 | { | 1196 | { |
1258 | int ret; | 1197 | int ret; |
1259 | 1198 | ||
1260 | if (!codec_dai->probed && codec_dai->driver->probe_order == order) { | 1199 | if (!dai->probed && dai->driver->probe_order == order) { |
1261 | if (codec_dai->driver->probe) { | 1200 | if (dai->driver->probe) { |
1262 | ret = codec_dai->driver->probe(codec_dai); | 1201 | ret = dai->driver->probe(dai); |
1263 | if (ret < 0) { | 1202 | if (ret < 0) { |
1264 | dev_err(codec_dai->dev, | 1203 | dev_err(dai->dev, |
1265 | "ASoC: failed to probe CODEC DAI %s: %d\n", | 1204 | "ASoC: failed to probe DAI %s: %d\n", |
1266 | codec_dai->name, ret); | 1205 | dai->name, ret); |
1267 | return ret; | 1206 | return ret; |
1268 | } | 1207 | } |
1269 | } | 1208 | } |
1270 | 1209 | ||
1271 | /* mark codec_dai as probed and add to card dai list */ | 1210 | dai->probed = 1; |
1272 | codec_dai->probed = 1; | ||
1273 | } | 1211 | } |
1274 | 1212 | ||
1275 | return 0; | 1213 | return 0; |
@@ -1319,40 +1257,22 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1319 | { | 1257 | { |
1320 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 1258 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
1321 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1259 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1322 | struct snd_soc_platform *platform = rtd->platform; | ||
1323 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1260 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1324 | int i, ret; | 1261 | int i, ret; |
1325 | 1262 | ||
1326 | dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", | 1263 | dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", |
1327 | card->name, num, order); | 1264 | card->name, num, order); |
1328 | 1265 | ||
1329 | /* config components */ | ||
1330 | cpu_dai->platform = platform; | ||
1331 | cpu_dai->card = card; | ||
1332 | for (i = 0; i < rtd->num_codecs; i++) | ||
1333 | rtd->codec_dais[i]->card = card; | ||
1334 | |||
1335 | /* set default power off timeout */ | 1266 | /* set default power off timeout */ |
1336 | rtd->pmdown_time = pmdown_time; | 1267 | rtd->pmdown_time = pmdown_time; |
1337 | 1268 | ||
1338 | /* probe the cpu_dai */ | 1269 | ret = soc_probe_dai(cpu_dai, order); |
1339 | if (!cpu_dai->probed && | 1270 | if (ret) |
1340 | cpu_dai->driver->probe_order == order) { | 1271 | return ret; |
1341 | if (cpu_dai->driver->probe) { | ||
1342 | ret = cpu_dai->driver->probe(cpu_dai); | ||
1343 | if (ret < 0) { | ||
1344 | dev_err(cpu_dai->dev, | ||
1345 | "ASoC: failed to probe CPU DAI %s: %d\n", | ||
1346 | cpu_dai->name, ret); | ||
1347 | return ret; | ||
1348 | } | ||
1349 | } | ||
1350 | cpu_dai->probed = 1; | ||
1351 | } | ||
1352 | 1272 | ||
1353 | /* probe the CODEC DAI */ | 1273 | /* probe the CODEC DAI */ |
1354 | for (i = 0; i < rtd->num_codecs; i++) { | 1274 | for (i = 0; i < rtd->num_codecs; i++) { |
1355 | ret = soc_probe_codec_dai(card, rtd->codec_dais[i], order); | 1275 | ret = soc_probe_dai(rtd->codec_dais[i], order); |
1356 | if (ret) | 1276 | if (ret) |
1357 | return ret; | 1277 | return ret; |
1358 | } | 1278 | } |
@@ -1422,84 +1342,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1422 | } | 1342 | } |
1423 | } | 1343 | } |
1424 | 1344 | ||
1425 | /* add platform data for AC97 devices */ | ||
1426 | for (i = 0; i < rtd->num_codecs; i++) { | ||
1427 | if (rtd->codec_dais[i]->driver->ac97_control) | ||
1428 | snd_ac97_dev_add_pdata(rtd->codec_dais[i]->codec->ac97, | ||
1429 | rtd->cpu_dai->ac97_pdata); | ||
1430 | } | ||
1431 | |||
1432 | return 0; | 1345 | return 0; |
1433 | } | 1346 | } |
1434 | 1347 | ||
1435 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1436 | static int soc_register_ac97_codec(struct snd_soc_codec *codec, | ||
1437 | struct snd_soc_dai *codec_dai) | ||
1438 | { | ||
1439 | int ret; | ||
1440 | |||
1441 | /* Only instantiate AC97 if not already done by the adaptor | ||
1442 | * for the generic AC97 subsystem. | ||
1443 | */ | ||
1444 | if (codec_dai->driver->ac97_control && !codec->ac97_registered) { | ||
1445 | /* | ||
1446 | * It is possible that the AC97 device is already registered to | ||
1447 | * the device subsystem. This happens when the device is created | ||
1448 | * via snd_ac97_mixer(). Currently only SoC codec that does so | ||
1449 | * is the generic AC97 glue but others migh emerge. | ||
1450 | * | ||
1451 | * In those cases we don't try to register the device again. | ||
1452 | */ | ||
1453 | if (!codec->ac97_created) | ||
1454 | return 0; | ||
1455 | |||
1456 | ret = soc_ac97_dev_register(codec); | ||
1457 | if (ret < 0) { | ||
1458 | dev_err(codec->dev, | ||
1459 | "ASoC: AC97 device register failed: %d\n", ret); | ||
1460 | return ret; | ||
1461 | } | ||
1462 | |||
1463 | codec->ac97_registered = 1; | ||
1464 | } | ||
1465 | return 0; | ||
1466 | } | ||
1467 | |||
1468 | static void soc_unregister_ac97_codec(struct snd_soc_codec *codec) | ||
1469 | { | ||
1470 | if (codec->ac97_registered) { | ||
1471 | soc_ac97_dev_unregister(codec); | ||
1472 | codec->ac97_registered = 0; | ||
1473 | } | ||
1474 | } | ||
1475 | |||
1476 | static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) | ||
1477 | { | ||
1478 | int i, ret; | ||
1479 | |||
1480 | for (i = 0; i < rtd->num_codecs; i++) { | ||
1481 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; | ||
1482 | |||
1483 | ret = soc_register_ac97_codec(codec_dai->codec, codec_dai); | ||
1484 | if (ret) { | ||
1485 | while (--i >= 0) | ||
1486 | soc_unregister_ac97_codec(codec_dai->codec); | ||
1487 | return ret; | ||
1488 | } | ||
1489 | } | ||
1490 | |||
1491 | return 0; | ||
1492 | } | ||
1493 | |||
1494 | static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) | ||
1495 | { | ||
1496 | int i; | ||
1497 | |||
1498 | for (i = 0; i < rtd->num_codecs; i++) | ||
1499 | soc_unregister_ac97_codec(rtd->codec_dais[i]->codec); | ||
1500 | } | ||
1501 | #endif | ||
1502 | |||
1503 | static int soc_bind_aux_dev(struct snd_soc_card *card, int num) | 1348 | static int soc_bind_aux_dev(struct snd_soc_card *card, int num) |
1504 | { | 1349 | { |
1505 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; | 1350 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; |
@@ -1793,20 +1638,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1793 | goto probe_aux_dev_err; | 1638 | goto probe_aux_dev_err; |
1794 | } | 1639 | } |
1795 | 1640 | ||
1796 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1797 | /* register any AC97 codecs */ | ||
1798 | for (i = 0; i < card->num_rtd; i++) { | ||
1799 | ret = soc_register_ac97_dai_link(&card->rtd[i]); | ||
1800 | if (ret < 0) { | ||
1801 | dev_err(card->dev, | ||
1802 | "ASoC: failed to register AC97: %d\n", ret); | ||
1803 | while (--i >= 0) | ||
1804 | soc_unregister_ac97_dai_link(&card->rtd[i]); | ||
1805 | goto probe_aux_dev_err; | ||
1806 | } | ||
1807 | } | ||
1808 | #endif | ||
1809 | |||
1810 | card->instantiated = 1; | 1641 | card->instantiated = 1; |
1811 | snd_soc_dapm_sync(&card->dapm); | 1642 | snd_soc_dapm_sync(&card->dapm); |
1812 | mutex_unlock(&card->mutex); | 1643 | mutex_unlock(&card->mutex); |
@@ -1949,216 +1780,6 @@ static struct platform_driver soc_driver = { | |||
1949 | }; | 1780 | }; |
1950 | 1781 | ||
1951 | /** | 1782 | /** |
1952 | * snd_soc_new_ac97_codec - initailise AC97 device | ||
1953 | * @codec: audio codec | ||
1954 | * @ops: AC97 bus operations | ||
1955 | * @num: AC97 codec number | ||
1956 | * | ||
1957 | * Initialises AC97 codec resources for use by ad-hoc devices only. | ||
1958 | */ | ||
1959 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | ||
1960 | struct snd_ac97_bus_ops *ops, int num) | ||
1961 | { | ||
1962 | codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); | ||
1963 | if (codec->ac97 == NULL) | ||
1964 | return -ENOMEM; | ||
1965 | |||
1966 | codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); | ||
1967 | if (codec->ac97->bus == NULL) { | ||
1968 | kfree(codec->ac97); | ||
1969 | codec->ac97 = NULL; | ||
1970 | return -ENOMEM; | ||
1971 | } | ||
1972 | |||
1973 | codec->ac97->bus->ops = ops; | ||
1974 | codec->ac97->num = num; | ||
1975 | |||
1976 | /* | ||
1977 | * Mark the AC97 device to be created by us. This way we ensure that the | ||
1978 | * device will be registered with the device subsystem later on. | ||
1979 | */ | ||
1980 | codec->ac97_created = 1; | ||
1981 | |||
1982 | return 0; | ||
1983 | } | ||
1984 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | ||
1985 | |||
1986 | static struct snd_ac97_reset_cfg snd_ac97_rst_cfg; | ||
1987 | |||
1988 | static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97) | ||
1989 | { | ||
1990 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
1991 | |||
1992 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset); | ||
1993 | |||
1994 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1); | ||
1995 | |||
1996 | udelay(10); | ||
1997 | |||
1998 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
1999 | |||
2000 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
2001 | msleep(2); | ||
2002 | } | ||
2003 | |||
2004 | static void snd_soc_ac97_reset(struct snd_ac97 *ac97) | ||
2005 | { | ||
2006 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
2007 | |||
2008 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset); | ||
2009 | |||
2010 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
2011 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0); | ||
2012 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0); | ||
2013 | |||
2014 | udelay(10); | ||
2015 | |||
2016 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1); | ||
2017 | |||
2018 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
2019 | msleep(2); | ||
2020 | } | ||
2021 | |||
2022 | static int snd_soc_ac97_parse_pinctl(struct device *dev, | ||
2023 | struct snd_ac97_reset_cfg *cfg) | ||
2024 | { | ||
2025 | struct pinctrl *p; | ||
2026 | struct pinctrl_state *state; | ||
2027 | int gpio; | ||
2028 | int ret; | ||
2029 | |||
2030 | p = devm_pinctrl_get(dev); | ||
2031 | if (IS_ERR(p)) { | ||
2032 | dev_err(dev, "Failed to get pinctrl\n"); | ||
2033 | return PTR_ERR(p); | ||
2034 | } | ||
2035 | cfg->pctl = p; | ||
2036 | |||
2037 | state = pinctrl_lookup_state(p, "ac97-reset"); | ||
2038 | if (IS_ERR(state)) { | ||
2039 | dev_err(dev, "Can't find pinctrl state ac97-reset\n"); | ||
2040 | return PTR_ERR(state); | ||
2041 | } | ||
2042 | cfg->pstate_reset = state; | ||
2043 | |||
2044 | state = pinctrl_lookup_state(p, "ac97-warm-reset"); | ||
2045 | if (IS_ERR(state)) { | ||
2046 | dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); | ||
2047 | return PTR_ERR(state); | ||
2048 | } | ||
2049 | cfg->pstate_warm_reset = state; | ||
2050 | |||
2051 | state = pinctrl_lookup_state(p, "ac97-running"); | ||
2052 | if (IS_ERR(state)) { | ||
2053 | dev_err(dev, "Can't find pinctrl state ac97-running\n"); | ||
2054 | return PTR_ERR(state); | ||
2055 | } | ||
2056 | cfg->pstate_run = state; | ||
2057 | |||
2058 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0); | ||
2059 | if (gpio < 0) { | ||
2060 | dev_err(dev, "Can't find ac97-sync gpio\n"); | ||
2061 | return gpio; | ||
2062 | } | ||
2063 | ret = devm_gpio_request(dev, gpio, "AC97 link sync"); | ||
2064 | if (ret) { | ||
2065 | dev_err(dev, "Failed requesting ac97-sync gpio\n"); | ||
2066 | return ret; | ||
2067 | } | ||
2068 | cfg->gpio_sync = gpio; | ||
2069 | |||
2070 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1); | ||
2071 | if (gpio < 0) { | ||
2072 | dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio); | ||
2073 | return gpio; | ||
2074 | } | ||
2075 | ret = devm_gpio_request(dev, gpio, "AC97 link sdata"); | ||
2076 | if (ret) { | ||
2077 | dev_err(dev, "Failed requesting ac97-sdata gpio\n"); | ||
2078 | return ret; | ||
2079 | } | ||
2080 | cfg->gpio_sdata = gpio; | ||
2081 | |||
2082 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); | ||
2083 | if (gpio < 0) { | ||
2084 | dev_err(dev, "Can't find ac97-reset gpio\n"); | ||
2085 | return gpio; | ||
2086 | } | ||
2087 | ret = devm_gpio_request(dev, gpio, "AC97 link reset"); | ||
2088 | if (ret) { | ||
2089 | dev_err(dev, "Failed requesting ac97-reset gpio\n"); | ||
2090 | return ret; | ||
2091 | } | ||
2092 | cfg->gpio_reset = gpio; | ||
2093 | |||
2094 | return 0; | ||
2095 | } | ||
2096 | |||
2097 | struct snd_ac97_bus_ops *soc_ac97_ops; | ||
2098 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
2099 | |||
2100 | int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) | ||
2101 | { | ||
2102 | if (ops == soc_ac97_ops) | ||
2103 | return 0; | ||
2104 | |||
2105 | if (soc_ac97_ops && ops) | ||
2106 | return -EBUSY; | ||
2107 | |||
2108 | soc_ac97_ops = ops; | ||
2109 | |||
2110 | return 0; | ||
2111 | } | ||
2112 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); | ||
2113 | |||
2114 | /** | ||
2115 | * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions | ||
2116 | * | ||
2117 | * This function sets the reset and warm_reset properties of ops and parses | ||
2118 | * the device node of pdev to get pinctrl states and gpio numbers to use. | ||
2119 | */ | ||
2120 | int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, | ||
2121 | struct platform_device *pdev) | ||
2122 | { | ||
2123 | struct device *dev = &pdev->dev; | ||
2124 | struct snd_ac97_reset_cfg cfg; | ||
2125 | int ret; | ||
2126 | |||
2127 | ret = snd_soc_ac97_parse_pinctl(dev, &cfg); | ||
2128 | if (ret) | ||
2129 | return ret; | ||
2130 | |||
2131 | ret = snd_soc_set_ac97_ops(ops); | ||
2132 | if (ret) | ||
2133 | return ret; | ||
2134 | |||
2135 | ops->warm_reset = snd_soc_ac97_warm_reset; | ||
2136 | ops->reset = snd_soc_ac97_reset; | ||
2137 | |||
2138 | snd_ac97_rst_cfg = cfg; | ||
2139 | return 0; | ||
2140 | } | ||
2141 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); | ||
2142 | |||
2143 | /** | ||
2144 | * snd_soc_free_ac97_codec - free AC97 codec device | ||
2145 | * @codec: audio codec | ||
2146 | * | ||
2147 | * Frees AC97 codec device resources. | ||
2148 | */ | ||
2149 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) | ||
2150 | { | ||
2151 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
2152 | soc_unregister_ac97_codec(codec); | ||
2153 | #endif | ||
2154 | kfree(codec->ac97->bus); | ||
2155 | kfree(codec->ac97); | ||
2156 | codec->ac97 = NULL; | ||
2157 | codec->ac97_created = 0; | ||
2158 | } | ||
2159 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | ||
2160 | |||
2161 | /** | ||
2162 | * snd_soc_cnew - create new control | 1783 | * snd_soc_cnew - create new control |
2163 | * @_template: control template | 1784 | * @_template: control template |
2164 | * @data: control private data | 1785 | * @data: control private data |
@@ -2326,7 +1947,7 @@ EXPORT_SYMBOL_GPL(snd_soc_add_card_controls); | |||
2326 | int snd_soc_add_dai_controls(struct snd_soc_dai *dai, | 1947 | int snd_soc_add_dai_controls(struct snd_soc_dai *dai, |
2327 | const struct snd_kcontrol_new *controls, int num_controls) | 1948 | const struct snd_kcontrol_new *controls, int num_controls) |
2328 | { | 1949 | { |
2329 | struct snd_card *card = dai->card->snd_card; | 1950 | struct snd_card *card = dai->component->card->snd_card; |
2330 | 1951 | ||
2331 | return snd_soc_add_controls(card, dai->dev, controls, num_controls, | 1952 | return snd_soc_add_controls(card, dai->dev, controls, num_controls, |
2332 | NULL, dai); | 1953 | NULL, dai); |
@@ -2334,1020 +1955,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai, | |||
2334 | EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); | 1955 | EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); |
2335 | 1956 | ||
2336 | /** | 1957 | /** |
2337 | * snd_soc_info_enum_double - enumerated double mixer info callback | ||
2338 | * @kcontrol: mixer control | ||
2339 | * @uinfo: control element information | ||
2340 | * | ||
2341 | * Callback to provide information about a double enumerated | ||
2342 | * mixer control. | ||
2343 | * | ||
2344 | * Returns 0 for success. | ||
2345 | */ | ||
2346 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | ||
2347 | struct snd_ctl_elem_info *uinfo) | ||
2348 | { | ||
2349 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2350 | |||
2351 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2352 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | ||
2353 | uinfo->value.enumerated.items = e->items; | ||
2354 | |||
2355 | if (uinfo->value.enumerated.item >= e->items) | ||
2356 | uinfo->value.enumerated.item = e->items - 1; | ||
2357 | strlcpy(uinfo->value.enumerated.name, | ||
2358 | e->texts[uinfo->value.enumerated.item], | ||
2359 | sizeof(uinfo->value.enumerated.name)); | ||
2360 | return 0; | ||
2361 | } | ||
2362 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); | ||
2363 | |||
2364 | /** | ||
2365 | * snd_soc_get_enum_double - enumerated double mixer get callback | ||
2366 | * @kcontrol: mixer control | ||
2367 | * @ucontrol: control element information | ||
2368 | * | ||
2369 | * Callback to get the value of a double enumerated mixer. | ||
2370 | * | ||
2371 | * Returns 0 for success. | ||
2372 | */ | ||
2373 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | ||
2374 | struct snd_ctl_elem_value *ucontrol) | ||
2375 | { | ||
2376 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2377 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2378 | unsigned int val, item; | ||
2379 | unsigned int reg_val; | ||
2380 | int ret; | ||
2381 | |||
2382 | ret = snd_soc_component_read(component, e->reg, ®_val); | ||
2383 | if (ret) | ||
2384 | return ret; | ||
2385 | val = (reg_val >> e->shift_l) & e->mask; | ||
2386 | item = snd_soc_enum_val_to_item(e, val); | ||
2387 | ucontrol->value.enumerated.item[0] = item; | ||
2388 | if (e->shift_l != e->shift_r) { | ||
2389 | val = (reg_val >> e->shift_l) & e->mask; | ||
2390 | item = snd_soc_enum_val_to_item(e, val); | ||
2391 | ucontrol->value.enumerated.item[1] = item; | ||
2392 | } | ||
2393 | |||
2394 | return 0; | ||
2395 | } | ||
2396 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); | ||
2397 | |||
2398 | /** | ||
2399 | * snd_soc_put_enum_double - enumerated double mixer put callback | ||
2400 | * @kcontrol: mixer control | ||
2401 | * @ucontrol: control element information | ||
2402 | * | ||
2403 | * Callback to set the value of a double enumerated mixer. | ||
2404 | * | ||
2405 | * Returns 0 for success. | ||
2406 | */ | ||
2407 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | ||
2408 | struct snd_ctl_elem_value *ucontrol) | ||
2409 | { | ||
2410 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2411 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2412 | unsigned int *item = ucontrol->value.enumerated.item; | ||
2413 | unsigned int val; | ||
2414 | unsigned int mask; | ||
2415 | |||
2416 | if (item[0] >= e->items) | ||
2417 | return -EINVAL; | ||
2418 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; | ||
2419 | mask = e->mask << e->shift_l; | ||
2420 | if (e->shift_l != e->shift_r) { | ||
2421 | if (item[1] >= e->items) | ||
2422 | return -EINVAL; | ||
2423 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; | ||
2424 | mask |= e->mask << e->shift_r; | ||
2425 | } | ||
2426 | |||
2427 | return snd_soc_component_update_bits(component, e->reg, mask, val); | ||
2428 | } | ||
2429 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | ||
2430 | |||
2431 | /** | ||
2432 | * snd_soc_read_signed - Read a codec register and interprete as signed value | ||
2433 | * @component: component | ||
2434 | * @reg: Register to read | ||
2435 | * @mask: Mask to use after shifting the register value | ||
2436 | * @shift: Right shift of register value | ||
2437 | * @sign_bit: Bit that describes if a number is negative or not. | ||
2438 | * @signed_val: Pointer to where the read value should be stored | ||
2439 | * | ||
2440 | * This functions reads a codec register. The register value is shifted right | ||
2441 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates | ||
2442 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
2443 | * | ||
2444 | * Returns 0 on sucess, otherwise an error value | ||
2445 | */ | ||
2446 | static int snd_soc_read_signed(struct snd_soc_component *component, | ||
2447 | unsigned int reg, unsigned int mask, unsigned int shift, | ||
2448 | unsigned int sign_bit, int *signed_val) | ||
2449 | { | ||
2450 | int ret; | ||
2451 | unsigned int val; | ||
2452 | |||
2453 | ret = snd_soc_component_read(component, reg, &val); | ||
2454 | if (ret < 0) | ||
2455 | return ret; | ||
2456 | |||
2457 | val = (val >> shift) & mask; | ||
2458 | |||
2459 | if (!sign_bit) { | ||
2460 | *signed_val = val; | ||
2461 | return 0; | ||
2462 | } | ||
2463 | |||
2464 | /* non-negative number */ | ||
2465 | if (!(val & BIT(sign_bit))) { | ||
2466 | *signed_val = val; | ||
2467 | return 0; | ||
2468 | } | ||
2469 | |||
2470 | ret = val; | ||
2471 | |||
2472 | /* | ||
2473 | * The register most probably does not contain a full-sized int. | ||
2474 | * Instead we have an arbitrary number of bits in a signed | ||
2475 | * representation which has to be translated into a full-sized int. | ||
2476 | * This is done by filling up all bits above the sign-bit. | ||
2477 | */ | ||
2478 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
2479 | |||
2480 | *signed_val = ret; | ||
2481 | |||
2482 | return 0; | ||
2483 | } | ||
2484 | |||
2485 | /** | ||
2486 | * snd_soc_info_volsw - single mixer info callback | ||
2487 | * @kcontrol: mixer control | ||
2488 | * @uinfo: control element information | ||
2489 | * | ||
2490 | * Callback to provide information about a single mixer control, or a double | ||
2491 | * mixer control that spans 2 registers. | ||
2492 | * | ||
2493 | * Returns 0 for success. | ||
2494 | */ | ||
2495 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | ||
2496 | struct snd_ctl_elem_info *uinfo) | ||
2497 | { | ||
2498 | struct soc_mixer_control *mc = | ||
2499 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2500 | int platform_max; | ||
2501 | |||
2502 | if (!mc->platform_max) | ||
2503 | mc->platform_max = mc->max; | ||
2504 | platform_max = mc->platform_max; | ||
2505 | |||
2506 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | ||
2507 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
2508 | else | ||
2509 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2510 | |||
2511 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
2512 | uinfo->value.integer.min = 0; | ||
2513 | uinfo->value.integer.max = platform_max - mc->min; | ||
2514 | return 0; | ||
2515 | } | ||
2516 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | ||
2517 | |||
2518 | /** | ||
2519 | * snd_soc_get_volsw - single mixer get callback | ||
2520 | * @kcontrol: mixer control | ||
2521 | * @ucontrol: control element information | ||
2522 | * | ||
2523 | * Callback to get the value of a single mixer control, or a double mixer | ||
2524 | * control that spans 2 registers. | ||
2525 | * | ||
2526 | * Returns 0 for success. | ||
2527 | */ | ||
2528 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | ||
2529 | struct snd_ctl_elem_value *ucontrol) | ||
2530 | { | ||
2531 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2532 | struct soc_mixer_control *mc = | ||
2533 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2534 | unsigned int reg = mc->reg; | ||
2535 | unsigned int reg2 = mc->rreg; | ||
2536 | unsigned int shift = mc->shift; | ||
2537 | unsigned int rshift = mc->rshift; | ||
2538 | int max = mc->max; | ||
2539 | int min = mc->min; | ||
2540 | int sign_bit = mc->sign_bit; | ||
2541 | unsigned int mask = (1 << fls(max)) - 1; | ||
2542 | unsigned int invert = mc->invert; | ||
2543 | int val; | ||
2544 | int ret; | ||
2545 | |||
2546 | if (sign_bit) | ||
2547 | mask = BIT(sign_bit + 1) - 1; | ||
2548 | |||
2549 | ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val); | ||
2550 | if (ret) | ||
2551 | return ret; | ||
2552 | |||
2553 | ucontrol->value.integer.value[0] = val - min; | ||
2554 | if (invert) | ||
2555 | ucontrol->value.integer.value[0] = | ||
2556 | max - ucontrol->value.integer.value[0]; | ||
2557 | |||
2558 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2559 | if (reg == reg2) | ||
2560 | ret = snd_soc_read_signed(component, reg, mask, rshift, | ||
2561 | sign_bit, &val); | ||
2562 | else | ||
2563 | ret = snd_soc_read_signed(component, reg2, mask, shift, | ||
2564 | sign_bit, &val); | ||
2565 | if (ret) | ||
2566 | return ret; | ||
2567 | |||
2568 | ucontrol->value.integer.value[1] = val - min; | ||
2569 | if (invert) | ||
2570 | ucontrol->value.integer.value[1] = | ||
2571 | max - ucontrol->value.integer.value[1]; | ||
2572 | } | ||
2573 | |||
2574 | return 0; | ||
2575 | } | ||
2576 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | ||
2577 | |||
2578 | /** | ||
2579 | * snd_soc_put_volsw - single mixer put callback | ||
2580 | * @kcontrol: mixer control | ||
2581 | * @ucontrol: control element information | ||
2582 | * | ||
2583 | * Callback to set the value of a single mixer control, or a double mixer | ||
2584 | * control that spans 2 registers. | ||
2585 | * | ||
2586 | * Returns 0 for success. | ||
2587 | */ | ||
2588 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | ||
2589 | struct snd_ctl_elem_value *ucontrol) | ||
2590 | { | ||
2591 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2592 | struct soc_mixer_control *mc = | ||
2593 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2594 | unsigned int reg = mc->reg; | ||
2595 | unsigned int reg2 = mc->rreg; | ||
2596 | unsigned int shift = mc->shift; | ||
2597 | unsigned int rshift = mc->rshift; | ||
2598 | int max = mc->max; | ||
2599 | int min = mc->min; | ||
2600 | unsigned int sign_bit = mc->sign_bit; | ||
2601 | unsigned int mask = (1 << fls(max)) - 1; | ||
2602 | unsigned int invert = mc->invert; | ||
2603 | int err; | ||
2604 | bool type_2r = false; | ||
2605 | unsigned int val2 = 0; | ||
2606 | unsigned int val, val_mask; | ||
2607 | |||
2608 | if (sign_bit) | ||
2609 | mask = BIT(sign_bit + 1) - 1; | ||
2610 | |||
2611 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2612 | if (invert) | ||
2613 | val = max - val; | ||
2614 | val_mask = mask << shift; | ||
2615 | val = val << shift; | ||
2616 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2617 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); | ||
2618 | if (invert) | ||
2619 | val2 = max - val2; | ||
2620 | if (reg == reg2) { | ||
2621 | val_mask |= mask << rshift; | ||
2622 | val |= val2 << rshift; | ||
2623 | } else { | ||
2624 | val2 = val2 << shift; | ||
2625 | type_2r = true; | ||
2626 | } | ||
2627 | } | ||
2628 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
2629 | if (err < 0) | ||
2630 | return err; | ||
2631 | |||
2632 | if (type_2r) | ||
2633 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
2634 | val2); | ||
2635 | |||
2636 | return err; | ||
2637 | } | ||
2638 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | ||
2639 | |||
2640 | /** | ||
2641 | * snd_soc_get_volsw_sx - single mixer get callback | ||
2642 | * @kcontrol: mixer control | ||
2643 | * @ucontrol: control element information | ||
2644 | * | ||
2645 | * Callback to get the value of a single mixer control, or a double mixer | ||
2646 | * control that spans 2 registers. | ||
2647 | * | ||
2648 | * Returns 0 for success. | ||
2649 | */ | ||
2650 | int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, | ||
2651 | struct snd_ctl_elem_value *ucontrol) | ||
2652 | { | ||
2653 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2654 | struct soc_mixer_control *mc = | ||
2655 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2656 | unsigned int reg = mc->reg; | ||
2657 | unsigned int reg2 = mc->rreg; | ||
2658 | unsigned int shift = mc->shift; | ||
2659 | unsigned int rshift = mc->rshift; | ||
2660 | int max = mc->max; | ||
2661 | int min = mc->min; | ||
2662 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
2663 | unsigned int val; | ||
2664 | int ret; | ||
2665 | |||
2666 | ret = snd_soc_component_read(component, reg, &val); | ||
2667 | if (ret < 0) | ||
2668 | return ret; | ||
2669 | |||
2670 | ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask; | ||
2671 | |||
2672 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2673 | ret = snd_soc_component_read(component, reg2, &val); | ||
2674 | if (ret < 0) | ||
2675 | return ret; | ||
2676 | |||
2677 | val = ((val >> rshift) - min) & mask; | ||
2678 | ucontrol->value.integer.value[1] = val; | ||
2679 | } | ||
2680 | |||
2681 | return 0; | ||
2682 | } | ||
2683 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); | ||
2684 | |||
2685 | /** | ||
2686 | * snd_soc_put_volsw_sx - double mixer set callback | ||
2687 | * @kcontrol: mixer control | ||
2688 | * @uinfo: control element information | ||
2689 | * | ||
2690 | * Callback to set the value of a double mixer control that spans 2 registers. | ||
2691 | * | ||
2692 | * Returns 0 for success. | ||
2693 | */ | ||
2694 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, | ||
2695 | struct snd_ctl_elem_value *ucontrol) | ||
2696 | { | ||
2697 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2698 | struct soc_mixer_control *mc = | ||
2699 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2700 | |||
2701 | unsigned int reg = mc->reg; | ||
2702 | unsigned int reg2 = mc->rreg; | ||
2703 | unsigned int shift = mc->shift; | ||
2704 | unsigned int rshift = mc->rshift; | ||
2705 | int max = mc->max; | ||
2706 | int min = mc->min; | ||
2707 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
2708 | int err = 0; | ||
2709 | unsigned int val, val_mask, val2 = 0; | ||
2710 | |||
2711 | val_mask = mask << shift; | ||
2712 | val = (ucontrol->value.integer.value[0] + min) & mask; | ||
2713 | val = val << shift; | ||
2714 | |||
2715 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
2716 | if (err < 0) | ||
2717 | return err; | ||
2718 | |||
2719 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2720 | val_mask = mask << rshift; | ||
2721 | val2 = (ucontrol->value.integer.value[1] + min) & mask; | ||
2722 | val2 = val2 << rshift; | ||
2723 | |||
2724 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
2725 | val2); | ||
2726 | } | ||
2727 | return err; | ||
2728 | } | ||
2729 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); | ||
2730 | |||
2731 | /** | ||
2732 | * snd_soc_info_volsw_s8 - signed mixer info callback | ||
2733 | * @kcontrol: mixer control | ||
2734 | * @uinfo: control element information | ||
2735 | * | ||
2736 | * Callback to provide information about a signed mixer control. | ||
2737 | * | ||
2738 | * Returns 0 for success. | ||
2739 | */ | ||
2740 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | ||
2741 | struct snd_ctl_elem_info *uinfo) | ||
2742 | { | ||
2743 | struct soc_mixer_control *mc = | ||
2744 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2745 | int platform_max; | ||
2746 | int min = mc->min; | ||
2747 | |||
2748 | if (!mc->platform_max) | ||
2749 | mc->platform_max = mc->max; | ||
2750 | platform_max = mc->platform_max; | ||
2751 | |||
2752 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2753 | uinfo->count = 2; | ||
2754 | uinfo->value.integer.min = 0; | ||
2755 | uinfo->value.integer.max = platform_max - min; | ||
2756 | return 0; | ||
2757 | } | ||
2758 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); | ||
2759 | |||
2760 | /** | ||
2761 | * snd_soc_get_volsw_s8 - signed mixer get callback | ||
2762 | * @kcontrol: mixer control | ||
2763 | * @ucontrol: control element information | ||
2764 | * | ||
2765 | * Callback to get the value of a signed mixer control. | ||
2766 | * | ||
2767 | * Returns 0 for success. | ||
2768 | */ | ||
2769 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | ||
2770 | struct snd_ctl_elem_value *ucontrol) | ||
2771 | { | ||
2772 | struct soc_mixer_control *mc = | ||
2773 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2774 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2775 | unsigned int reg = mc->reg; | ||
2776 | unsigned int val; | ||
2777 | int min = mc->min; | ||
2778 | int ret; | ||
2779 | |||
2780 | ret = snd_soc_component_read(component, reg, &val); | ||
2781 | if (ret) | ||
2782 | return ret; | ||
2783 | |||
2784 | ucontrol->value.integer.value[0] = | ||
2785 | ((signed char)(val & 0xff))-min; | ||
2786 | ucontrol->value.integer.value[1] = | ||
2787 | ((signed char)((val >> 8) & 0xff))-min; | ||
2788 | return 0; | ||
2789 | } | ||
2790 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); | ||
2791 | |||
2792 | /** | ||
2793 | * snd_soc_put_volsw_sgn - signed mixer put callback | ||
2794 | * @kcontrol: mixer control | ||
2795 | * @ucontrol: control element information | ||
2796 | * | ||
2797 | * Callback to set the value of a signed mixer control. | ||
2798 | * | ||
2799 | * Returns 0 for success. | ||
2800 | */ | ||
2801 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | ||
2802 | struct snd_ctl_elem_value *ucontrol) | ||
2803 | { | ||
2804 | struct soc_mixer_control *mc = | ||
2805 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2806 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2807 | unsigned int reg = mc->reg; | ||
2808 | int min = mc->min; | ||
2809 | unsigned int val; | ||
2810 | |||
2811 | val = (ucontrol->value.integer.value[0]+min) & 0xff; | ||
2812 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; | ||
2813 | |||
2814 | return snd_soc_component_update_bits(component, reg, 0xffff, val); | ||
2815 | } | ||
2816 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); | ||
2817 | |||
2818 | /** | ||
2819 | * snd_soc_info_volsw_range - single mixer info callback with range. | ||
2820 | * @kcontrol: mixer control | ||
2821 | * @uinfo: control element information | ||
2822 | * | ||
2823 | * Callback to provide information, within a range, about a single | ||
2824 | * mixer control. | ||
2825 | * | ||
2826 | * returns 0 for success. | ||
2827 | */ | ||
2828 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | ||
2829 | struct snd_ctl_elem_info *uinfo) | ||
2830 | { | ||
2831 | struct soc_mixer_control *mc = | ||
2832 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2833 | int platform_max; | ||
2834 | int min = mc->min; | ||
2835 | |||
2836 | if (!mc->platform_max) | ||
2837 | mc->platform_max = mc->max; | ||
2838 | platform_max = mc->platform_max; | ||
2839 | |||
2840 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2841 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
2842 | uinfo->value.integer.min = 0; | ||
2843 | uinfo->value.integer.max = platform_max - min; | ||
2844 | |||
2845 | return 0; | ||
2846 | } | ||
2847 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range); | ||
2848 | |||
2849 | /** | ||
2850 | * snd_soc_put_volsw_range - single mixer put value callback with range. | ||
2851 | * @kcontrol: mixer control | ||
2852 | * @ucontrol: control element information | ||
2853 | * | ||
2854 | * Callback to set the value, within a range, for a single mixer control. | ||
2855 | * | ||
2856 | * Returns 0 for success. | ||
2857 | */ | ||
2858 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | ||
2859 | struct snd_ctl_elem_value *ucontrol) | ||
2860 | { | ||
2861 | struct soc_mixer_control *mc = | ||
2862 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2863 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2864 | unsigned int reg = mc->reg; | ||
2865 | unsigned int rreg = mc->rreg; | ||
2866 | unsigned int shift = mc->shift; | ||
2867 | int min = mc->min; | ||
2868 | int max = mc->max; | ||
2869 | unsigned int mask = (1 << fls(max)) - 1; | ||
2870 | unsigned int invert = mc->invert; | ||
2871 | unsigned int val, val_mask; | ||
2872 | int ret; | ||
2873 | |||
2874 | if (invert) | ||
2875 | val = (max - ucontrol->value.integer.value[0]) & mask; | ||
2876 | else | ||
2877 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2878 | val_mask = mask << shift; | ||
2879 | val = val << shift; | ||
2880 | |||
2881 | ret = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
2882 | if (ret < 0) | ||
2883 | return ret; | ||
2884 | |||
2885 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2886 | if (invert) | ||
2887 | val = (max - ucontrol->value.integer.value[1]) & mask; | ||
2888 | else | ||
2889 | val = ((ucontrol->value.integer.value[1] + min) & mask); | ||
2890 | val_mask = mask << shift; | ||
2891 | val = val << shift; | ||
2892 | |||
2893 | ret = snd_soc_component_update_bits(component, rreg, val_mask, | ||
2894 | val); | ||
2895 | } | ||
2896 | |||
2897 | return ret; | ||
2898 | } | ||
2899 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); | ||
2900 | |||
2901 | /** | ||
2902 | * snd_soc_get_volsw_range - single mixer get callback with range | ||
2903 | * @kcontrol: mixer control | ||
2904 | * @ucontrol: control element information | ||
2905 | * | ||
2906 | * Callback to get the value, within a range, of a single mixer control. | ||
2907 | * | ||
2908 | * Returns 0 for success. | ||
2909 | */ | ||
2910 | int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | ||
2911 | struct snd_ctl_elem_value *ucontrol) | ||
2912 | { | ||
2913 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2914 | struct soc_mixer_control *mc = | ||
2915 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2916 | unsigned int reg = mc->reg; | ||
2917 | unsigned int rreg = mc->rreg; | ||
2918 | unsigned int shift = mc->shift; | ||
2919 | int min = mc->min; | ||
2920 | int max = mc->max; | ||
2921 | unsigned int mask = (1 << fls(max)) - 1; | ||
2922 | unsigned int invert = mc->invert; | ||
2923 | unsigned int val; | ||
2924 | int ret; | ||
2925 | |||
2926 | ret = snd_soc_component_read(component, reg, &val); | ||
2927 | if (ret) | ||
2928 | return ret; | ||
2929 | |||
2930 | ucontrol->value.integer.value[0] = (val >> shift) & mask; | ||
2931 | if (invert) | ||
2932 | ucontrol->value.integer.value[0] = | ||
2933 | max - ucontrol->value.integer.value[0]; | ||
2934 | else | ||
2935 | ucontrol->value.integer.value[0] = | ||
2936 | ucontrol->value.integer.value[0] - min; | ||
2937 | |||
2938 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2939 | ret = snd_soc_component_read(component, rreg, &val); | ||
2940 | if (ret) | ||
2941 | return ret; | ||
2942 | |||
2943 | ucontrol->value.integer.value[1] = (val >> shift) & mask; | ||
2944 | if (invert) | ||
2945 | ucontrol->value.integer.value[1] = | ||
2946 | max - ucontrol->value.integer.value[1]; | ||
2947 | else | ||
2948 | ucontrol->value.integer.value[1] = | ||
2949 | ucontrol->value.integer.value[1] - min; | ||
2950 | } | ||
2951 | |||
2952 | return 0; | ||
2953 | } | ||
2954 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); | ||
2955 | |||
2956 | /** | ||
2957 | * snd_soc_limit_volume - Set new limit to an existing volume control. | ||
2958 | * | ||
2959 | * @codec: where to look for the control | ||
2960 | * @name: Name of the control | ||
2961 | * @max: new maximum limit | ||
2962 | * | ||
2963 | * Return 0 for success, else error. | ||
2964 | */ | ||
2965 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | ||
2966 | const char *name, int max) | ||
2967 | { | ||
2968 | struct snd_card *card = codec->component.card->snd_card; | ||
2969 | struct snd_kcontrol *kctl; | ||
2970 | struct soc_mixer_control *mc; | ||
2971 | int found = 0; | ||
2972 | int ret = -EINVAL; | ||
2973 | |||
2974 | /* Sanity check for name and max */ | ||
2975 | if (unlikely(!name || max <= 0)) | ||
2976 | return -EINVAL; | ||
2977 | |||
2978 | list_for_each_entry(kctl, &card->controls, list) { | ||
2979 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) { | ||
2980 | found = 1; | ||
2981 | break; | ||
2982 | } | ||
2983 | } | ||
2984 | if (found) { | ||
2985 | mc = (struct soc_mixer_control *)kctl->private_value; | ||
2986 | if (max <= mc->max) { | ||
2987 | mc->platform_max = max; | ||
2988 | ret = 0; | ||
2989 | } | ||
2990 | } | ||
2991 | return ret; | ||
2992 | } | ||
2993 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); | ||
2994 | |||
2995 | int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, | ||
2996 | struct snd_ctl_elem_info *uinfo) | ||
2997 | { | ||
2998 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2999 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
3000 | |||
3001 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
3002 | uinfo->count = params->num_regs * component->val_bytes; | ||
3003 | |||
3004 | return 0; | ||
3005 | } | ||
3006 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info); | ||
3007 | |||
3008 | int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, | ||
3009 | struct snd_ctl_elem_value *ucontrol) | ||
3010 | { | ||
3011 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3012 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
3013 | int ret; | ||
3014 | |||
3015 | if (component->regmap) | ||
3016 | ret = regmap_raw_read(component->regmap, params->base, | ||
3017 | ucontrol->value.bytes.data, | ||
3018 | params->num_regs * component->val_bytes); | ||
3019 | else | ||
3020 | ret = -EINVAL; | ||
3021 | |||
3022 | /* Hide any masked bytes to ensure consistent data reporting */ | ||
3023 | if (ret == 0 && params->mask) { | ||
3024 | switch (component->val_bytes) { | ||
3025 | case 1: | ||
3026 | ucontrol->value.bytes.data[0] &= ~params->mask; | ||
3027 | break; | ||
3028 | case 2: | ||
3029 | ((u16 *)(&ucontrol->value.bytes.data))[0] | ||
3030 | &= cpu_to_be16(~params->mask); | ||
3031 | break; | ||
3032 | case 4: | ||
3033 | ((u32 *)(&ucontrol->value.bytes.data))[0] | ||
3034 | &= cpu_to_be32(~params->mask); | ||
3035 | break; | ||
3036 | default: | ||
3037 | return -EINVAL; | ||
3038 | } | ||
3039 | } | ||
3040 | |||
3041 | return ret; | ||
3042 | } | ||
3043 | EXPORT_SYMBOL_GPL(snd_soc_bytes_get); | ||
3044 | |||
3045 | int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | ||
3046 | struct snd_ctl_elem_value *ucontrol) | ||
3047 | { | ||
3048 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3049 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
3050 | int ret, len; | ||
3051 | unsigned int val, mask; | ||
3052 | void *data; | ||
3053 | |||
3054 | if (!component->regmap || !params->num_regs) | ||
3055 | return -EINVAL; | ||
3056 | |||
3057 | len = params->num_regs * component->val_bytes; | ||
3058 | |||
3059 | data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); | ||
3060 | if (!data) | ||
3061 | return -ENOMEM; | ||
3062 | |||
3063 | /* | ||
3064 | * If we've got a mask then we need to preserve the register | ||
3065 | * bits. We shouldn't modify the incoming data so take a | ||
3066 | * copy. | ||
3067 | */ | ||
3068 | if (params->mask) { | ||
3069 | ret = regmap_read(component->regmap, params->base, &val); | ||
3070 | if (ret != 0) | ||
3071 | goto out; | ||
3072 | |||
3073 | val &= params->mask; | ||
3074 | |||
3075 | switch (component->val_bytes) { | ||
3076 | case 1: | ||
3077 | ((u8 *)data)[0] &= ~params->mask; | ||
3078 | ((u8 *)data)[0] |= val; | ||
3079 | break; | ||
3080 | case 2: | ||
3081 | mask = ~params->mask; | ||
3082 | ret = regmap_parse_val(component->regmap, | ||
3083 | &mask, &mask); | ||
3084 | if (ret != 0) | ||
3085 | goto out; | ||
3086 | |||
3087 | ((u16 *)data)[0] &= mask; | ||
3088 | |||
3089 | ret = regmap_parse_val(component->regmap, | ||
3090 | &val, &val); | ||
3091 | if (ret != 0) | ||
3092 | goto out; | ||
3093 | |||
3094 | ((u16 *)data)[0] |= val; | ||
3095 | break; | ||
3096 | case 4: | ||
3097 | mask = ~params->mask; | ||
3098 | ret = regmap_parse_val(component->regmap, | ||
3099 | &mask, &mask); | ||
3100 | if (ret != 0) | ||
3101 | goto out; | ||
3102 | |||
3103 | ((u32 *)data)[0] &= mask; | ||
3104 | |||
3105 | ret = regmap_parse_val(component->regmap, | ||
3106 | &val, &val); | ||
3107 | if (ret != 0) | ||
3108 | goto out; | ||
3109 | |||
3110 | ((u32 *)data)[0] |= val; | ||
3111 | break; | ||
3112 | default: | ||
3113 | ret = -EINVAL; | ||
3114 | goto out; | ||
3115 | } | ||
3116 | } | ||
3117 | |||
3118 | ret = regmap_raw_write(component->regmap, params->base, | ||
3119 | data, len); | ||
3120 | |||
3121 | out: | ||
3122 | kfree(data); | ||
3123 | |||
3124 | return ret; | ||
3125 | } | ||
3126 | EXPORT_SYMBOL_GPL(snd_soc_bytes_put); | ||
3127 | |||
3128 | int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, | ||
3129 | struct snd_ctl_elem_info *ucontrol) | ||
3130 | { | ||
3131 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
3132 | |||
3133 | ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
3134 | ucontrol->count = params->max; | ||
3135 | |||
3136 | return 0; | ||
3137 | } | ||
3138 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext); | ||
3139 | |||
3140 | int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, | ||
3141 | unsigned int size, unsigned int __user *tlv) | ||
3142 | { | ||
3143 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
3144 | unsigned int count = size < params->max ? size : params->max; | ||
3145 | int ret = -ENXIO; | ||
3146 | |||
3147 | switch (op_flag) { | ||
3148 | case SNDRV_CTL_TLV_OP_READ: | ||
3149 | if (params->get) | ||
3150 | ret = params->get(tlv, count); | ||
3151 | break; | ||
3152 | case SNDRV_CTL_TLV_OP_WRITE: | ||
3153 | if (params->put) | ||
3154 | ret = params->put(tlv, count); | ||
3155 | break; | ||
3156 | } | ||
3157 | return ret; | ||
3158 | } | ||
3159 | EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback); | ||
3160 | |||
3161 | /** | ||
3162 | * snd_soc_info_xr_sx - signed multi register info callback | ||
3163 | * @kcontrol: mreg control | ||
3164 | * @uinfo: control element information | ||
3165 | * | ||
3166 | * Callback to provide information of a control that can | ||
3167 | * span multiple codec registers which together | ||
3168 | * forms a single signed value in a MSB/LSB manner. | ||
3169 | * | ||
3170 | * Returns 0 for success. | ||
3171 | */ | ||
3172 | int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, | ||
3173 | struct snd_ctl_elem_info *uinfo) | ||
3174 | { | ||
3175 | struct soc_mreg_control *mc = | ||
3176 | (struct soc_mreg_control *)kcontrol->private_value; | ||
3177 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
3178 | uinfo->count = 1; | ||
3179 | uinfo->value.integer.min = mc->min; | ||
3180 | uinfo->value.integer.max = mc->max; | ||
3181 | |||
3182 | return 0; | ||
3183 | } | ||
3184 | EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx); | ||
3185 | |||
3186 | /** | ||
3187 | * snd_soc_get_xr_sx - signed multi register get callback | ||
3188 | * @kcontrol: mreg control | ||
3189 | * @ucontrol: control element information | ||
3190 | * | ||
3191 | * Callback to get the value of a control that can span | ||
3192 | * multiple codec registers which together forms a single | ||
3193 | * signed value in a MSB/LSB manner. The control supports | ||
3194 | * specifying total no of bits used to allow for bitfields | ||
3195 | * across the multiple codec registers. | ||
3196 | * | ||
3197 | * Returns 0 for success. | ||
3198 | */ | ||
3199 | int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, | ||
3200 | struct snd_ctl_elem_value *ucontrol) | ||
3201 | { | ||
3202 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3203 | struct soc_mreg_control *mc = | ||
3204 | (struct soc_mreg_control *)kcontrol->private_value; | ||
3205 | unsigned int regbase = mc->regbase; | ||
3206 | unsigned int regcount = mc->regcount; | ||
3207 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
3208 | unsigned int regwmask = (1<<regwshift)-1; | ||
3209 | unsigned int invert = mc->invert; | ||
3210 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
3211 | long min = mc->min; | ||
3212 | long max = mc->max; | ||
3213 | long val = 0; | ||
3214 | unsigned int regval; | ||
3215 | unsigned int i; | ||
3216 | int ret; | ||
3217 | |||
3218 | for (i = 0; i < regcount; i++) { | ||
3219 | ret = snd_soc_component_read(component, regbase+i, ®val); | ||
3220 | if (ret) | ||
3221 | return ret; | ||
3222 | val |= (regval & regwmask) << (regwshift*(regcount-i-1)); | ||
3223 | } | ||
3224 | val &= mask; | ||
3225 | if (min < 0 && val > max) | ||
3226 | val |= ~mask; | ||
3227 | if (invert) | ||
3228 | val = max - val; | ||
3229 | ucontrol->value.integer.value[0] = val; | ||
3230 | |||
3231 | return 0; | ||
3232 | } | ||
3233 | EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx); | ||
3234 | |||
3235 | /** | ||
3236 | * snd_soc_put_xr_sx - signed multi register get callback | ||
3237 | * @kcontrol: mreg control | ||
3238 | * @ucontrol: control element information | ||
3239 | * | ||
3240 | * Callback to set the value of a control that can span | ||
3241 | * multiple codec registers which together forms a single | ||
3242 | * signed value in a MSB/LSB manner. The control supports | ||
3243 | * specifying total no of bits used to allow for bitfields | ||
3244 | * across the multiple codec registers. | ||
3245 | * | ||
3246 | * Returns 0 for success. | ||
3247 | */ | ||
3248 | int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, | ||
3249 | struct snd_ctl_elem_value *ucontrol) | ||
3250 | { | ||
3251 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3252 | struct soc_mreg_control *mc = | ||
3253 | (struct soc_mreg_control *)kcontrol->private_value; | ||
3254 | unsigned int regbase = mc->regbase; | ||
3255 | unsigned int regcount = mc->regcount; | ||
3256 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
3257 | unsigned int regwmask = (1<<regwshift)-1; | ||
3258 | unsigned int invert = mc->invert; | ||
3259 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
3260 | long max = mc->max; | ||
3261 | long val = ucontrol->value.integer.value[0]; | ||
3262 | unsigned int i, regval, regmask; | ||
3263 | int err; | ||
3264 | |||
3265 | if (invert) | ||
3266 | val = max - val; | ||
3267 | val &= mask; | ||
3268 | for (i = 0; i < regcount; i++) { | ||
3269 | regval = (val >> (regwshift*(regcount-i-1))) & regwmask; | ||
3270 | regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; | ||
3271 | err = snd_soc_component_update_bits(component, regbase+i, | ||
3272 | regmask, regval); | ||
3273 | if (err < 0) | ||
3274 | return err; | ||
3275 | } | ||
3276 | |||
3277 | return 0; | ||
3278 | } | ||
3279 | EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx); | ||
3280 | |||
3281 | /** | ||
3282 | * snd_soc_get_strobe - strobe get callback | ||
3283 | * @kcontrol: mixer control | ||
3284 | * @ucontrol: control element information | ||
3285 | * | ||
3286 | * Callback get the value of a strobe mixer control. | ||
3287 | * | ||
3288 | * Returns 0 for success. | ||
3289 | */ | ||
3290 | int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, | ||
3291 | struct snd_ctl_elem_value *ucontrol) | ||
3292 | { | ||
3293 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3294 | struct soc_mixer_control *mc = | ||
3295 | (struct soc_mixer_control *)kcontrol->private_value; | ||
3296 | unsigned int reg = mc->reg; | ||
3297 | unsigned int shift = mc->shift; | ||
3298 | unsigned int mask = 1 << shift; | ||
3299 | unsigned int invert = mc->invert != 0; | ||
3300 | unsigned int val; | ||
3301 | int ret; | ||
3302 | |||
3303 | ret = snd_soc_component_read(component, reg, &val); | ||
3304 | if (ret) | ||
3305 | return ret; | ||
3306 | |||
3307 | val &= mask; | ||
3308 | |||
3309 | if (shift != 0 && val != 0) | ||
3310 | val = val >> shift; | ||
3311 | ucontrol->value.enumerated.item[0] = val ^ invert; | ||
3312 | |||
3313 | return 0; | ||
3314 | } | ||
3315 | EXPORT_SYMBOL_GPL(snd_soc_get_strobe); | ||
3316 | |||
3317 | /** | ||
3318 | * snd_soc_put_strobe - strobe put callback | ||
3319 | * @kcontrol: mixer control | ||
3320 | * @ucontrol: control element information | ||
3321 | * | ||
3322 | * Callback strobe a register bit to high then low (or the inverse) | ||
3323 | * in one pass of a single mixer enum control. | ||
3324 | * | ||
3325 | * Returns 1 for success. | ||
3326 | */ | ||
3327 | int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, | ||
3328 | struct snd_ctl_elem_value *ucontrol) | ||
3329 | { | ||
3330 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3331 | struct soc_mixer_control *mc = | ||
3332 | (struct soc_mixer_control *)kcontrol->private_value; | ||
3333 | unsigned int reg = mc->reg; | ||
3334 | unsigned int shift = mc->shift; | ||
3335 | unsigned int mask = 1 << shift; | ||
3336 | unsigned int invert = mc->invert != 0; | ||
3337 | unsigned int strobe = ucontrol->value.enumerated.item[0] != 0; | ||
3338 | unsigned int val1 = (strobe ^ invert) ? mask : 0; | ||
3339 | unsigned int val2 = (strobe ^ invert) ? 0 : mask; | ||
3340 | int err; | ||
3341 | |||
3342 | err = snd_soc_component_update_bits(component, reg, mask, val1); | ||
3343 | if (err < 0) | ||
3344 | return err; | ||
3345 | |||
3346 | return snd_soc_component_update_bits(component, reg, mask, val2); | ||
3347 | } | ||
3348 | EXPORT_SYMBOL_GPL(snd_soc_put_strobe); | ||
3349 | |||
3350 | /** | ||
3351 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. | 1958 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. |
3352 | * @dai: DAI | 1959 | * @dai: DAI |
3353 | * @clk_id: DAI specific clock ID | 1960 | * @clk_id: DAI specific clock ID |
@@ -3996,22 +2603,62 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, | |||
3996 | return 0; | 2603 | return 0; |
3997 | } | 2604 | } |
3998 | 2605 | ||
3999 | static void snd_soc_component_init_regmap(struct snd_soc_component *component) | 2606 | static void snd_soc_component_setup_regmap(struct snd_soc_component *component) |
4000 | { | 2607 | { |
4001 | if (!component->regmap) | 2608 | int val_bytes = regmap_get_val_bytes(component->regmap); |
4002 | component->regmap = dev_get_regmap(component->dev, NULL); | 2609 | |
4003 | if (component->regmap) { | 2610 | /* Errors are legitimate for non-integer byte multiples */ |
4004 | int val_bytes = regmap_get_val_bytes(component->regmap); | 2611 | if (val_bytes > 0) |
4005 | /* Errors are legitimate for non-integer byte multiples */ | 2612 | component->val_bytes = val_bytes; |
4006 | if (val_bytes > 0) | 2613 | } |
4007 | component->val_bytes = val_bytes; | 2614 | |
4008 | } | 2615 | #ifdef CONFIG_REGMAP |
2616 | |||
2617 | /** | ||
2618 | * snd_soc_component_init_regmap() - Initialize regmap instance for the component | ||
2619 | * @component: The component for which to initialize the regmap instance | ||
2620 | * @regmap: The regmap instance that should be used by the component | ||
2621 | * | ||
2622 | * This function allows deferred assignment of the regmap instance that is | ||
2623 | * associated with the component. Only use this if the regmap instance is not | ||
2624 | * yet ready when the component is registered. The function must also be called | ||
2625 | * before the first IO attempt of the component. | ||
2626 | */ | ||
2627 | void snd_soc_component_init_regmap(struct snd_soc_component *component, | ||
2628 | struct regmap *regmap) | ||
2629 | { | ||
2630 | component->regmap = regmap; | ||
2631 | snd_soc_component_setup_regmap(component); | ||
2632 | } | ||
2633 | EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); | ||
2634 | |||
2635 | /** | ||
2636 | * snd_soc_component_exit_regmap() - De-initialize regmap instance for the component | ||
2637 | * @component: The component for which to de-initialize the regmap instance | ||
2638 | * | ||
2639 | * Calls regmap_exit() on the regmap instance associated to the component and | ||
2640 | * removes the regmap instance from the component. | ||
2641 | * | ||
2642 | * This function should only be used if snd_soc_component_init_regmap() was used | ||
2643 | * to initialize the regmap instance. | ||
2644 | */ | ||
2645 | void snd_soc_component_exit_regmap(struct snd_soc_component *component) | ||
2646 | { | ||
2647 | regmap_exit(component->regmap); | ||
2648 | component->regmap = NULL; | ||
4009 | } | 2649 | } |
2650 | EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); | ||
2651 | |||
2652 | #endif | ||
4010 | 2653 | ||
4011 | static void snd_soc_component_add_unlocked(struct snd_soc_component *component) | 2654 | static void snd_soc_component_add_unlocked(struct snd_soc_component *component) |
4012 | { | 2655 | { |
4013 | if (!component->write && !component->read) | 2656 | if (!component->write && !component->read) { |
4014 | snd_soc_component_init_regmap(component); | 2657 | if (!component->regmap) |
2658 | component->regmap = dev_get_regmap(component->dev, NULL); | ||
2659 | if (component->regmap) | ||
2660 | snd_soc_component_setup_regmap(component); | ||
2661 | } | ||
4015 | 2662 | ||
4016 | list_add(&component->list, &component_list); | 2663 | list_add(&component->list, &component_list); |
4017 | } | 2664 | } |
@@ -4362,7 +3009,6 @@ int snd_soc_register_codec(struct device *dev, | |||
4362 | codec->dev = dev; | 3009 | codec->dev = dev; |
4363 | codec->driver = codec_drv; | 3010 | codec->driver = codec_drv; |
4364 | codec->component.val_bytes = codec_drv->reg_word_size; | 3011 | codec->component.val_bytes = codec_drv->reg_word_size; |
4365 | mutex_init(&codec->mutex); | ||
4366 | 3012 | ||
4367 | #ifdef CONFIG_DEBUG_FS | 3013 | #ifdef CONFIG_DEBUG_FS |
4368 | codec->component.init_debugfs = soc_init_codec_debugfs; | 3014 | codec->component.init_debugfs = soc_init_codec_debugfs; |
@@ -4585,7 +3231,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4585 | const char *propname) | 3231 | const char *propname) |
4586 | { | 3232 | { |
4587 | struct device_node *np = card->dev->of_node; | 3233 | struct device_node *np = card->dev->of_node; |
4588 | int num_routes; | 3234 | int num_routes, old_routes; |
4589 | struct snd_soc_dapm_route *routes; | 3235 | struct snd_soc_dapm_route *routes; |
4590 | int i, ret; | 3236 | int i, ret; |
4591 | 3237 | ||
@@ -4603,7 +3249,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4603 | return -EINVAL; | 3249 | return -EINVAL; |
4604 | } | 3250 | } |
4605 | 3251 | ||
4606 | routes = devm_kzalloc(card->dev, num_routes * sizeof(*routes), | 3252 | old_routes = card->num_dapm_routes; |
3253 | routes = devm_kzalloc(card->dev, | ||
3254 | (old_routes + num_routes) * sizeof(*routes), | ||
4607 | GFP_KERNEL); | 3255 | GFP_KERNEL); |
4608 | if (!routes) { | 3256 | if (!routes) { |
4609 | dev_err(card->dev, | 3257 | dev_err(card->dev, |
@@ -4611,9 +3259,11 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4611 | return -EINVAL; | 3259 | return -EINVAL; |
4612 | } | 3260 | } |
4613 | 3261 | ||
3262 | memcpy(routes, card->dapm_routes, old_routes * sizeof(*routes)); | ||
3263 | |||
4614 | for (i = 0; i < num_routes; i++) { | 3264 | for (i = 0; i < num_routes; i++) { |
4615 | ret = of_property_read_string_index(np, propname, | 3265 | ret = of_property_read_string_index(np, propname, |
4616 | 2 * i, &routes[i].sink); | 3266 | 2 * i, &routes[old_routes + i].sink); |
4617 | if (ret) { | 3267 | if (ret) { |
4618 | dev_err(card->dev, | 3268 | dev_err(card->dev, |
4619 | "ASoC: Property '%s' index %d could not be read: %d\n", | 3269 | "ASoC: Property '%s' index %d could not be read: %d\n", |
@@ -4621,7 +3271,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4621 | return -EINVAL; | 3271 | return -EINVAL; |
4622 | } | 3272 | } |
4623 | ret = of_property_read_string_index(np, propname, | 3273 | ret = of_property_read_string_index(np, propname, |
4624 | (2 * i) + 1, &routes[i].source); | 3274 | (2 * i) + 1, &routes[old_routes + i].source); |
4625 | if (ret) { | 3275 | if (ret) { |
4626 | dev_err(card->dev, | 3276 | dev_err(card->dev, |
4627 | "ASoC: Property '%s' index %d could not be read: %d\n", | 3277 | "ASoC: Property '%s' index %d could not be read: %d\n", |
@@ -4630,7 +3280,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4630 | } | 3280 | } |
4631 | } | 3281 | } |
4632 | 3282 | ||
4633 | card->num_dapm_routes = num_routes; | 3283 | card->num_dapm_routes += num_routes; |
4634 | card->dapm_routes = routes; | 3284 | card->dapm_routes = routes; |
4635 | 3285 | ||
4636 | return 0; | 3286 | return 0; |
@@ -4750,36 +3400,30 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | |||
4750 | } | 3400 | } |
4751 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); | 3401 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); |
4752 | 3402 | ||
4753 | int snd_soc_of_get_dai_name(struct device_node *of_node, | 3403 | static int snd_soc_get_dai_name(struct of_phandle_args *args, |
4754 | const char **dai_name) | 3404 | const char **dai_name) |
4755 | { | 3405 | { |
4756 | struct snd_soc_component *pos; | 3406 | struct snd_soc_component *pos; |
4757 | struct of_phandle_args args; | 3407 | int ret = -EPROBE_DEFER; |
4758 | int ret; | ||
4759 | |||
4760 | ret = of_parse_phandle_with_args(of_node, "sound-dai", | ||
4761 | "#sound-dai-cells", 0, &args); | ||
4762 | if (ret) | ||
4763 | return ret; | ||
4764 | |||
4765 | ret = -EPROBE_DEFER; | ||
4766 | 3408 | ||
4767 | mutex_lock(&client_mutex); | 3409 | mutex_lock(&client_mutex); |
4768 | list_for_each_entry(pos, &component_list, list) { | 3410 | list_for_each_entry(pos, &component_list, list) { |
4769 | if (pos->dev->of_node != args.np) | 3411 | if (pos->dev->of_node != args->np) |
4770 | continue; | 3412 | continue; |
4771 | 3413 | ||
4772 | if (pos->driver->of_xlate_dai_name) { | 3414 | if (pos->driver->of_xlate_dai_name) { |
4773 | ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); | 3415 | ret = pos->driver->of_xlate_dai_name(pos, |
3416 | args, | ||
3417 | dai_name); | ||
4774 | } else { | 3418 | } else { |
4775 | int id = -1; | 3419 | int id = -1; |
4776 | 3420 | ||
4777 | switch (args.args_count) { | 3421 | switch (args->args_count) { |
4778 | case 0: | 3422 | case 0: |
4779 | id = 0; /* same as dai_drv[0] */ | 3423 | id = 0; /* same as dai_drv[0] */ |
4780 | break; | 3424 | break; |
4781 | case 1: | 3425 | case 1: |
4782 | id = args.args[0]; | 3426 | id = args->args[0]; |
4783 | break; | 3427 | break; |
4784 | default: | 3428 | default: |
4785 | /* not supported */ | 3429 | /* not supported */ |
@@ -4801,6 +3445,21 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, | |||
4801 | break; | 3445 | break; |
4802 | } | 3446 | } |
4803 | mutex_unlock(&client_mutex); | 3447 | mutex_unlock(&client_mutex); |
3448 | return ret; | ||
3449 | } | ||
3450 | |||
3451 | int snd_soc_of_get_dai_name(struct device_node *of_node, | ||
3452 | const char **dai_name) | ||
3453 | { | ||
3454 | struct of_phandle_args args; | ||
3455 | int ret; | ||
3456 | |||
3457 | ret = of_parse_phandle_with_args(of_node, "sound-dai", | ||
3458 | "#sound-dai-cells", 0, &args); | ||
3459 | if (ret) | ||
3460 | return ret; | ||
3461 | |||
3462 | ret = snd_soc_get_dai_name(&args, dai_name); | ||
4804 | 3463 | ||
4805 | of_node_put(args.np); | 3464 | of_node_put(args.np); |
4806 | 3465 | ||
@@ -4808,6 +3467,77 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, | |||
4808 | } | 3467 | } |
4809 | EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); | 3468 | EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); |
4810 | 3469 | ||
3470 | /* | ||
3471 | * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree | ||
3472 | * @dev: Card device | ||
3473 | * @of_node: Device node | ||
3474 | * @dai_link: DAI link | ||
3475 | * | ||
3476 | * Builds an array of CODEC DAI components from the DAI link property | ||
3477 | * 'sound-dai'. | ||
3478 | * The array is set in the DAI link and the number of DAIs is set accordingly. | ||
3479 | * The device nodes in the array (of_node) must be dereferenced by the caller. | ||
3480 | * | ||
3481 | * Returns 0 for success | ||
3482 | */ | ||
3483 | int snd_soc_of_get_dai_link_codecs(struct device *dev, | ||
3484 | struct device_node *of_node, | ||
3485 | struct snd_soc_dai_link *dai_link) | ||
3486 | { | ||
3487 | struct of_phandle_args args; | ||
3488 | struct snd_soc_dai_link_component *component; | ||
3489 | char *name; | ||
3490 | int index, num_codecs, ret; | ||
3491 | |||
3492 | /* Count the number of CODECs */ | ||
3493 | name = "sound-dai"; | ||
3494 | num_codecs = of_count_phandle_with_args(of_node, name, | ||
3495 | "#sound-dai-cells"); | ||
3496 | if (num_codecs <= 0) { | ||
3497 | if (num_codecs == -ENOENT) | ||
3498 | dev_err(dev, "No 'sound-dai' property\n"); | ||
3499 | else | ||
3500 | dev_err(dev, "Bad phandle in 'sound-dai'\n"); | ||
3501 | return num_codecs; | ||
3502 | } | ||
3503 | component = devm_kzalloc(dev, | ||
3504 | sizeof *component * num_codecs, | ||
3505 | GFP_KERNEL); | ||
3506 | if (!component) | ||
3507 | return -ENOMEM; | ||
3508 | dai_link->codecs = component; | ||
3509 | dai_link->num_codecs = num_codecs; | ||
3510 | |||
3511 | /* Parse the list */ | ||
3512 | for (index = 0, component = dai_link->codecs; | ||
3513 | index < dai_link->num_codecs; | ||
3514 | index++, component++) { | ||
3515 | ret = of_parse_phandle_with_args(of_node, name, | ||
3516 | "#sound-dai-cells", | ||
3517 | index, &args); | ||
3518 | if (ret) | ||
3519 | goto err; | ||
3520 | component->of_node = args.np; | ||
3521 | ret = snd_soc_get_dai_name(&args, &component->dai_name); | ||
3522 | if (ret < 0) | ||
3523 | goto err; | ||
3524 | } | ||
3525 | return 0; | ||
3526 | err: | ||
3527 | for (index = 0, component = dai_link->codecs; | ||
3528 | index < dai_link->num_codecs; | ||
3529 | index++, component++) { | ||
3530 | if (!component->of_node) | ||
3531 | break; | ||
3532 | of_node_put(component->of_node); | ||
3533 | component->of_node = NULL; | ||
3534 | } | ||
3535 | dai_link->codecs = NULL; | ||
3536 | dai_link->num_codecs = 0; | ||
3537 | return ret; | ||
3538 | } | ||
3539 | EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs); | ||
3540 | |||
4811 | static int __init snd_soc_init(void) | 3541 | static int __init snd_soc_init(void) |
4812 | { | 3542 | { |
4813 | #ifdef CONFIG_DEBUG_FS | 3543 | #ifdef CONFIG_DEBUG_FS |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c61cb9cedbcd..c5136bb1f982 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -159,27 +159,135 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) | |||
159 | } | 159 | } |
160 | } | 160 | } |
161 | 161 | ||
162 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) | 162 | /* |
163 | * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input | ||
164 | * paths | ||
165 | * @w: The widget for which to invalidate the cached number of input paths | ||
166 | * | ||
167 | * The function resets the cached number of inputs for the specified widget and | ||
168 | * all widgets that can be reached via outgoing paths from the widget. | ||
169 | * | ||
170 | * This function must be called if the number of input paths for a widget might | ||
171 | * have changed. E.g. if the source state of a widget changes or a path is added | ||
172 | * or activated with the widget as the sink. | ||
173 | */ | ||
174 | static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) | ||
175 | { | ||
176 | struct snd_soc_dapm_widget *sink; | ||
177 | struct snd_soc_dapm_path *p; | ||
178 | LIST_HEAD(list); | ||
179 | |||
180 | dapm_assert_locked(w->dapm); | ||
181 | |||
182 | if (w->inputs == -1) | ||
183 | return; | ||
184 | |||
185 | w->inputs = -1; | ||
186 | list_add_tail(&w->work_list, &list); | ||
187 | |||
188 | list_for_each_entry(w, &list, work_list) { | ||
189 | list_for_each_entry(p, &w->sinks, list_source) { | ||
190 | if (p->is_supply || p->weak || !p->connect) | ||
191 | continue; | ||
192 | sink = p->sink; | ||
193 | if (sink->inputs != -1) { | ||
194 | sink->inputs = -1; | ||
195 | list_add_tail(&sink->work_list, &list); | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * dapm_widget_invalidate_output_paths() - Invalidate the cached number of | ||
203 | * output paths | ||
204 | * @w: The widget for which to invalidate the cached number of output paths | ||
205 | * | ||
206 | * Resets the cached number of outputs for the specified widget and all widgets | ||
207 | * that can be reached via incoming paths from the widget. | ||
208 | * | ||
209 | * This function must be called if the number of output paths for a widget might | ||
210 | * have changed. E.g. if the sink state of a widget changes or a path is added | ||
211 | * or activated with the widget as the source. | ||
212 | */ | ||
213 | static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w) | ||
214 | { | ||
215 | struct snd_soc_dapm_widget *source; | ||
216 | struct snd_soc_dapm_path *p; | ||
217 | LIST_HEAD(list); | ||
218 | |||
219 | dapm_assert_locked(w->dapm); | ||
220 | |||
221 | if (w->outputs == -1) | ||
222 | return; | ||
223 | |||
224 | w->outputs = -1; | ||
225 | list_add_tail(&w->work_list, &list); | ||
226 | |||
227 | list_for_each_entry(w, &list, work_list) { | ||
228 | list_for_each_entry(p, &w->sources, list_sink) { | ||
229 | if (p->is_supply || p->weak || !p->connect) | ||
230 | continue; | ||
231 | source = p->source; | ||
232 | if (source->outputs != -1) { | ||
233 | source->outputs = -1; | ||
234 | list_add_tail(&source->work_list, &list); | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs | ||
242 | * for the widgets connected to a path | ||
243 | * @p: The path to invalidate | ||
244 | * | ||
245 | * Resets the cached number of inputs for the sink of the path and the cached | ||
246 | * number of outputs for the source of the path. | ||
247 | * | ||
248 | * This function must be called when a path is added, removed or the connected | ||
249 | * state changes. | ||
250 | */ | ||
251 | static void dapm_path_invalidate(struct snd_soc_dapm_path *p) | ||
252 | { | ||
253 | /* | ||
254 | * Weak paths or supply paths do not influence the number of input or | ||
255 | * output paths of their neighbors. | ||
256 | */ | ||
257 | if (p->weak || p->is_supply) | ||
258 | return; | ||
259 | |||
260 | /* | ||
261 | * The number of connected endpoints is the sum of the number of | ||
262 | * connected endpoints of all neighbors. If a node with 0 connected | ||
263 | * endpoints is either connected or disconnected that sum won't change, | ||
264 | * so there is no need to re-check the path. | ||
265 | */ | ||
266 | if (p->source->inputs != 0) | ||
267 | dapm_widget_invalidate_input_paths(p->sink); | ||
268 | if (p->sink->outputs != 0) | ||
269 | dapm_widget_invalidate_output_paths(p->source); | ||
270 | } | ||
271 | |||
272 | void dapm_mark_endpoints_dirty(struct snd_soc_card *card) | ||
163 | { | 273 | { |
164 | struct snd_soc_card *card = dapm->card; | ||
165 | struct snd_soc_dapm_widget *w; | 274 | struct snd_soc_dapm_widget *w; |
166 | 275 | ||
167 | mutex_lock(&card->dapm_mutex); | 276 | mutex_lock(&card->dapm_mutex); |
168 | 277 | ||
169 | list_for_each_entry(w, &card->widgets, list) { | 278 | list_for_each_entry(w, &card->widgets, list) { |
170 | switch (w->id) { | 279 | if (w->is_sink || w->is_source) { |
171 | case snd_soc_dapm_input: | 280 | dapm_mark_dirty(w, "Rechecking endpoints"); |
172 | case snd_soc_dapm_output: | 281 | if (w->is_sink) |
173 | dapm_mark_dirty(w, "Rechecking inputs and outputs"); | 282 | dapm_widget_invalidate_output_paths(w); |
174 | break; | 283 | if (w->is_source) |
175 | default: | 284 | dapm_widget_invalidate_input_paths(w); |
176 | break; | ||
177 | } | 285 | } |
178 | } | 286 | } |
179 | 287 | ||
180 | mutex_unlock(&card->dapm_mutex); | 288 | mutex_unlock(&card->dapm_mutex); |
181 | } | 289 | } |
182 | EXPORT_SYMBOL_GPL(dapm_mark_io_dirty); | 290 | EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); |
183 | 291 | ||
184 | /* create a new dapm widget */ | 292 | /* create a new dapm widget */ |
185 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | 293 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( |
@@ -386,8 +494,6 @@ static void dapm_reset(struct snd_soc_card *card) | |||
386 | list_for_each_entry(w, &card->widgets, list) { | 494 | list_for_each_entry(w, &card->widgets, list) { |
387 | w->new_power = w->power; | 495 | w->new_power = w->power; |
388 | w->power_checked = false; | 496 | w->power_checked = false; |
389 | w->inputs = -1; | ||
390 | w->outputs = -1; | ||
391 | } | 497 | } |
392 | } | 498 | } |
393 | 499 | ||
@@ -469,10 +575,9 @@ out: | |||
469 | 575 | ||
470 | /* connect mux widget to its interconnecting audio paths */ | 576 | /* connect mux widget to its interconnecting audio paths */ |
471 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | 577 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, |
472 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | 578 | struct snd_soc_dapm_path *path, const char *control_name) |
473 | struct snd_soc_dapm_path *path, const char *control_name, | ||
474 | const struct snd_kcontrol_new *kcontrol) | ||
475 | { | 579 | { |
580 | const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0]; | ||
476 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 581 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
477 | unsigned int val, item; | 582 | unsigned int val, item; |
478 | int i; | 583 | int i; |
@@ -493,10 +598,7 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
493 | 598 | ||
494 | for (i = 0; i < e->items; i++) { | 599 | for (i = 0; i < e->items; i++) { |
495 | if (!(strcmp(control_name, e->texts[i]))) { | 600 | if (!(strcmp(control_name, e->texts[i]))) { |
496 | list_add(&path->list, &dapm->card->paths); | 601 | path->name = e->texts[i]; |
497 | list_add(&path->list_sink, &dest->sources); | ||
498 | list_add(&path->list_source, &src->sinks); | ||
499 | path->name = (char*)e->texts[i]; | ||
500 | if (i == item) | 602 | if (i == item) |
501 | path->connect = 1; | 603 | path->connect = 1; |
502 | else | 604 | else |
@@ -509,11 +611,10 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
509 | } | 611 | } |
510 | 612 | ||
511 | /* set up initial codec paths */ | 613 | /* set up initial codec paths */ |
512 | static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | 614 | static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) |
513 | struct snd_soc_dapm_path *p, int i) | ||
514 | { | 615 | { |
515 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | 616 | struct soc_mixer_control *mc = (struct soc_mixer_control *) |
516 | w->kcontrol_news[i].private_value; | 617 | p->sink->kcontrol_news[i].private_value; |
517 | unsigned int reg = mc->reg; | 618 | unsigned int reg = mc->reg; |
518 | unsigned int shift = mc->shift; | 619 | unsigned int shift = mc->shift; |
519 | unsigned int max = mc->max; | 620 | unsigned int max = mc->max; |
@@ -522,7 +623,7 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | |||
522 | unsigned int val; | 623 | unsigned int val; |
523 | 624 | ||
524 | if (reg != SND_SOC_NOPM) { | 625 | if (reg != SND_SOC_NOPM) { |
525 | soc_dapm_read(w->dapm, reg, &val); | 626 | soc_dapm_read(p->sink->dapm, reg, &val); |
526 | val = (val >> shift) & mask; | 627 | val = (val >> shift) & mask; |
527 | if (invert) | 628 | if (invert) |
528 | val = max - val; | 629 | val = max - val; |
@@ -534,19 +635,15 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | |||
534 | 635 | ||
535 | /* connect mixer widget to its interconnecting audio paths */ | 636 | /* connect mixer widget to its interconnecting audio paths */ |
536 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | 637 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, |
537 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | ||
538 | struct snd_soc_dapm_path *path, const char *control_name) | 638 | struct snd_soc_dapm_path *path, const char *control_name) |
539 | { | 639 | { |
540 | int i; | 640 | int i; |
541 | 641 | ||
542 | /* search for mixer kcontrol */ | 642 | /* search for mixer kcontrol */ |
543 | for (i = 0; i < dest->num_kcontrols; i++) { | 643 | for (i = 0; i < path->sink->num_kcontrols; i++) { |
544 | if (!strcmp(control_name, dest->kcontrol_news[i].name)) { | 644 | if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) { |
545 | list_add(&path->list, &dapm->card->paths); | 645 | path->name = path->sink->kcontrol_news[i].name; |
546 | list_add(&path->list_sink, &dest->sources); | 646 | dapm_set_mixer_path_status(path, i); |
547 | list_add(&path->list_source, &src->sinks); | ||
548 | path->name = dest->kcontrol_news[i].name; | ||
549 | dapm_set_mixer_path_status(dest, path, i); | ||
550 | return 0; | 647 | return 0; |
551 | } | 648 | } |
552 | } | 649 | } |
@@ -738,8 +835,10 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
738 | if (ret < 0) | 835 | if (ret < 0) |
739 | return ret; | 836 | return ret; |
740 | 837 | ||
741 | list_for_each_entry(path, &w->sources, list_sink) | 838 | list_for_each_entry(path, &w->sources, list_sink) { |
742 | dapm_kcontrol_add_path(w->kcontrols[0], path); | 839 | if (path->name) |
840 | dapm_kcontrol_add_path(w->kcontrols[0], path); | ||
841 | } | ||
743 | 842 | ||
744 | return 0; | 843 | return 0; |
745 | } | 844 | } |
@@ -754,34 +853,6 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) | |||
754 | return 0; | 853 | return 0; |
755 | } | 854 | } |
756 | 855 | ||
757 | /* reset 'walked' bit for each dapm path */ | ||
758 | static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm, | ||
759 | struct list_head *sink) | ||
760 | { | ||
761 | struct snd_soc_dapm_path *p; | ||
762 | |||
763 | list_for_each_entry(p, sink, list_source) { | ||
764 | if (p->walked) { | ||
765 | p->walked = 0; | ||
766 | dapm_clear_walk_output(dapm, &p->sink->sinks); | ||
767 | } | ||
768 | } | ||
769 | } | ||
770 | |||
771 | static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm, | ||
772 | struct list_head *source) | ||
773 | { | ||
774 | struct snd_soc_dapm_path *p; | ||
775 | |||
776 | list_for_each_entry(p, source, list_sink) { | ||
777 | if (p->walked) { | ||
778 | p->walked = 0; | ||
779 | dapm_clear_walk_input(dapm, &p->source->sources); | ||
780 | } | ||
781 | } | ||
782 | } | ||
783 | |||
784 | |||
785 | /* We implement power down on suspend by checking the power state of | 856 | /* We implement power down on suspend by checking the power state of |
786 | * the ALSA card - when we are suspending the ALSA state for the card | 857 | * the ALSA card - when we are suspending the ALSA state for the card |
787 | * is set to D3. | 858 | * is set to D3. |
@@ -856,61 +927,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, | |||
856 | 927 | ||
857 | DAPM_UPDATE_STAT(widget, path_checks); | 928 | DAPM_UPDATE_STAT(widget, path_checks); |
858 | 929 | ||
859 | switch (widget->id) { | 930 | if (widget->is_sink && widget->connected) { |
860 | case snd_soc_dapm_supply: | 931 | widget->outputs = snd_soc_dapm_suspend_check(widget); |
861 | case snd_soc_dapm_regulator_supply: | 932 | return widget->outputs; |
862 | case snd_soc_dapm_clock_supply: | ||
863 | case snd_soc_dapm_kcontrol: | ||
864 | return 0; | ||
865 | default: | ||
866 | break; | ||
867 | } | ||
868 | |||
869 | switch (widget->id) { | ||
870 | case snd_soc_dapm_adc: | ||
871 | case snd_soc_dapm_aif_out: | ||
872 | case snd_soc_dapm_dai_out: | ||
873 | if (widget->active) { | ||
874 | widget->outputs = snd_soc_dapm_suspend_check(widget); | ||
875 | return widget->outputs; | ||
876 | } | ||
877 | default: | ||
878 | break; | ||
879 | } | ||
880 | |||
881 | if (widget->connected) { | ||
882 | /* connected pin ? */ | ||
883 | if (widget->id == snd_soc_dapm_output && !widget->ext) { | ||
884 | widget->outputs = snd_soc_dapm_suspend_check(widget); | ||
885 | return widget->outputs; | ||
886 | } | ||
887 | |||
888 | /* connected jack or spk ? */ | ||
889 | if (widget->id == snd_soc_dapm_hp || | ||
890 | widget->id == snd_soc_dapm_spk || | ||
891 | (widget->id == snd_soc_dapm_line && | ||
892 | !list_empty(&widget->sources))) { | ||
893 | widget->outputs = snd_soc_dapm_suspend_check(widget); | ||
894 | return widget->outputs; | ||
895 | } | ||
896 | } | 933 | } |
897 | 934 | ||
898 | list_for_each_entry(path, &widget->sinks, list_source) { | 935 | list_for_each_entry(path, &widget->sinks, list_source) { |
899 | DAPM_UPDATE_STAT(widget, neighbour_checks); | 936 | DAPM_UPDATE_STAT(widget, neighbour_checks); |
900 | 937 | ||
901 | if (path->weak) | 938 | if (path->weak || path->is_supply) |
902 | continue; | 939 | continue; |
903 | 940 | ||
904 | if (path->walking) | 941 | if (path->walking) |
905 | return 1; | 942 | return 1; |
906 | 943 | ||
907 | if (path->walked) | ||
908 | continue; | ||
909 | |||
910 | trace_snd_soc_dapm_output_path(widget, path); | 944 | trace_snd_soc_dapm_output_path(widget, path); |
911 | 945 | ||
912 | if (path->sink && path->connect) { | 946 | if (path->connect) { |
913 | path->walked = 1; | ||
914 | path->walking = 1; | 947 | path->walking = 1; |
915 | 948 | ||
916 | /* do we need to add this widget to the list ? */ | 949 | /* do we need to add this widget to the list ? */ |
@@ -952,73 +985,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
952 | 985 | ||
953 | DAPM_UPDATE_STAT(widget, path_checks); | 986 | DAPM_UPDATE_STAT(widget, path_checks); |
954 | 987 | ||
955 | switch (widget->id) { | 988 | if (widget->is_source && widget->connected) { |
956 | case snd_soc_dapm_supply: | 989 | widget->inputs = snd_soc_dapm_suspend_check(widget); |
957 | case snd_soc_dapm_regulator_supply: | 990 | return widget->inputs; |
958 | case snd_soc_dapm_clock_supply: | ||
959 | case snd_soc_dapm_kcontrol: | ||
960 | return 0; | ||
961 | default: | ||
962 | break; | ||
963 | } | ||
964 | |||
965 | /* active stream ? */ | ||
966 | switch (widget->id) { | ||
967 | case snd_soc_dapm_dac: | ||
968 | case snd_soc_dapm_aif_in: | ||
969 | case snd_soc_dapm_dai_in: | ||
970 | if (widget->active) { | ||
971 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
972 | return widget->inputs; | ||
973 | } | ||
974 | default: | ||
975 | break; | ||
976 | } | ||
977 | |||
978 | if (widget->connected) { | ||
979 | /* connected pin ? */ | ||
980 | if (widget->id == snd_soc_dapm_input && !widget->ext) { | ||
981 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
982 | return widget->inputs; | ||
983 | } | ||
984 | |||
985 | /* connected VMID/Bias for lower pops */ | ||
986 | if (widget->id == snd_soc_dapm_vmid) { | ||
987 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
988 | return widget->inputs; | ||
989 | } | ||
990 | |||
991 | /* connected jack ? */ | ||
992 | if (widget->id == snd_soc_dapm_mic || | ||
993 | (widget->id == snd_soc_dapm_line && | ||
994 | !list_empty(&widget->sinks))) { | ||
995 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
996 | return widget->inputs; | ||
997 | } | ||
998 | |||
999 | /* signal generator */ | ||
1000 | if (widget->id == snd_soc_dapm_siggen) { | ||
1001 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
1002 | return widget->inputs; | ||
1003 | } | ||
1004 | } | 991 | } |
1005 | 992 | ||
1006 | list_for_each_entry(path, &widget->sources, list_sink) { | 993 | list_for_each_entry(path, &widget->sources, list_sink) { |
1007 | DAPM_UPDATE_STAT(widget, neighbour_checks); | 994 | DAPM_UPDATE_STAT(widget, neighbour_checks); |
1008 | 995 | ||
1009 | if (path->weak) | 996 | if (path->weak || path->is_supply) |
1010 | continue; | 997 | continue; |
1011 | 998 | ||
1012 | if (path->walking) | 999 | if (path->walking) |
1013 | return 1; | 1000 | return 1; |
1014 | 1001 | ||
1015 | if (path->walked) | ||
1016 | continue; | ||
1017 | |||
1018 | trace_snd_soc_dapm_input_path(widget, path); | 1002 | trace_snd_soc_dapm_input_path(widget, path); |
1019 | 1003 | ||
1020 | if (path->source && path->connect) { | 1004 | if (path->connect) { |
1021 | path->walked = 1; | ||
1022 | path->walking = 1; | 1005 | path->walking = 1; |
1023 | 1006 | ||
1024 | /* do we need to add this widget to the list ? */ | 1007 | /* do we need to add this widget to the list ? */ |
@@ -1060,21 +1043,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
1060 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, | 1043 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, |
1061 | struct snd_soc_dapm_widget_list **list) | 1044 | struct snd_soc_dapm_widget_list **list) |
1062 | { | 1045 | { |
1063 | struct snd_soc_card *card = dai->card; | 1046 | struct snd_soc_card *card = dai->component->card; |
1047 | struct snd_soc_dapm_widget *w; | ||
1064 | int paths; | 1048 | int paths; |
1065 | 1049 | ||
1066 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 1050 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
1067 | dapm_reset(card); | ||
1068 | 1051 | ||
1069 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 1052 | /* |
1053 | * For is_connected_{output,input}_ep fully discover the graph we need | ||
1054 | * to reset the cached number of inputs and outputs. | ||
1055 | */ | ||
1056 | list_for_each_entry(w, &card->widgets, list) { | ||
1057 | w->inputs = -1; | ||
1058 | w->outputs = -1; | ||
1059 | } | ||
1060 | |||
1061 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1070 | paths = is_connected_output_ep(dai->playback_widget, list); | 1062 | paths = is_connected_output_ep(dai->playback_widget, list); |
1071 | dapm_clear_walk_output(&card->dapm, | 1063 | else |
1072 | &dai->playback_widget->sinks); | ||
1073 | } else { | ||
1074 | paths = is_connected_input_ep(dai->capture_widget, list); | 1064 | paths = is_connected_input_ep(dai->capture_widget, list); |
1075 | dapm_clear_walk_input(&card->dapm, | ||
1076 | &dai->capture_widget->sources); | ||
1077 | } | ||
1078 | 1065 | ||
1079 | trace_snd_soc_dapm_connected(paths, stream); | 1066 | trace_snd_soc_dapm_connected(paths, stream); |
1080 | mutex_unlock(&card->dapm_mutex); | 1067 | mutex_unlock(&card->dapm_mutex); |
@@ -1163,44 +1150,10 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) | |||
1163 | DAPM_UPDATE_STAT(w, power_checks); | 1150 | DAPM_UPDATE_STAT(w, power_checks); |
1164 | 1151 | ||
1165 | in = is_connected_input_ep(w, NULL); | 1152 | in = is_connected_input_ep(w, NULL); |
1166 | dapm_clear_walk_input(w->dapm, &w->sources); | ||
1167 | out = is_connected_output_ep(w, NULL); | 1153 | out = is_connected_output_ep(w, NULL); |
1168 | dapm_clear_walk_output(w->dapm, &w->sinks); | ||
1169 | return out != 0 && in != 0; | 1154 | return out != 0 && in != 0; |
1170 | } | 1155 | } |
1171 | 1156 | ||
1172 | /* Check to see if an ADC has power */ | ||
1173 | static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) | ||
1174 | { | ||
1175 | int in; | ||
1176 | |||
1177 | DAPM_UPDATE_STAT(w, power_checks); | ||
1178 | |||
1179 | if (w->active) { | ||
1180 | in = is_connected_input_ep(w, NULL); | ||
1181 | dapm_clear_walk_input(w->dapm, &w->sources); | ||
1182 | return in != 0; | ||
1183 | } else { | ||
1184 | return dapm_generic_check_power(w); | ||
1185 | } | ||
1186 | } | ||
1187 | |||
1188 | /* Check to see if a DAC has power */ | ||
1189 | static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) | ||
1190 | { | ||
1191 | int out; | ||
1192 | |||
1193 | DAPM_UPDATE_STAT(w, power_checks); | ||
1194 | |||
1195 | if (w->active) { | ||
1196 | out = is_connected_output_ep(w, NULL); | ||
1197 | dapm_clear_walk_output(w->dapm, &w->sinks); | ||
1198 | return out != 0; | ||
1199 | } else { | ||
1200 | return dapm_generic_check_power(w); | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | /* Check to see if a power supply is needed */ | 1157 | /* Check to see if a power supply is needed */ |
1205 | static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | 1158 | static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) |
1206 | { | 1159 | { |
@@ -1219,9 +1172,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
1219 | !path->connected(path->source, path->sink)) | 1172 | !path->connected(path->source, path->sink)) |
1220 | continue; | 1173 | continue; |
1221 | 1174 | ||
1222 | if (!path->sink) | ||
1223 | continue; | ||
1224 | |||
1225 | if (dapm_widget_power_check(path->sink)) | 1175 | if (dapm_widget_power_check(path->sink)) |
1226 | return 1; | 1176 | return 1; |
1227 | } | 1177 | } |
@@ -1636,27 +1586,14 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1636 | /* If we changed our power state perhaps our neigbours changed | 1586 | /* If we changed our power state perhaps our neigbours changed |
1637 | * also. | 1587 | * also. |
1638 | */ | 1588 | */ |
1639 | list_for_each_entry(path, &w->sources, list_sink) { | 1589 | list_for_each_entry(path, &w->sources, list_sink) |
1640 | if (path->source) { | 1590 | dapm_widget_set_peer_power(path->source, power, path->connect); |
1641 | dapm_widget_set_peer_power(path->source, power, | 1591 | |
1592 | /* Supplies can't affect their outputs, only their inputs */ | ||
1593 | if (!w->is_supply) { | ||
1594 | list_for_each_entry(path, &w->sinks, list_source) | ||
1595 | dapm_widget_set_peer_power(path->sink, power, | ||
1642 | path->connect); | 1596 | path->connect); |
1643 | } | ||
1644 | } | ||
1645 | switch (w->id) { | ||
1646 | case snd_soc_dapm_supply: | ||
1647 | case snd_soc_dapm_regulator_supply: | ||
1648 | case snd_soc_dapm_clock_supply: | ||
1649 | case snd_soc_dapm_kcontrol: | ||
1650 | /* Supplies can't affect their outputs, only their inputs */ | ||
1651 | break; | ||
1652 | default: | ||
1653 | list_for_each_entry(path, &w->sinks, list_source) { | ||
1654 | if (path->sink) { | ||
1655 | dapm_widget_set_peer_power(path->sink, power, | ||
1656 | path->connect); | ||
1657 | } | ||
1658 | } | ||
1659 | break; | ||
1660 | } | 1597 | } |
1661 | 1598 | ||
1662 | if (power) | 1599 | if (power) |
@@ -1863,10 +1800,14 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1863 | if (!buf) | 1800 | if (!buf) |
1864 | return -ENOMEM; | 1801 | return -ENOMEM; |
1865 | 1802 | ||
1866 | in = is_connected_input_ep(w, NULL); | 1803 | /* Supply widgets are not handled by is_connected_{input,output}_ep() */ |
1867 | dapm_clear_walk_input(w->dapm, &w->sources); | 1804 | if (w->is_supply) { |
1868 | out = is_connected_output_ep(w, NULL); | 1805 | in = 0; |
1869 | dapm_clear_walk_output(w->dapm, &w->sinks); | 1806 | out = 0; |
1807 | } else { | ||
1808 | in = is_connected_input_ep(w, NULL); | ||
1809 | out = is_connected_output_ep(w, NULL); | ||
1810 | } | ||
1870 | 1811 | ||
1871 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", | 1812 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", |
1872 | w->name, w->power ? "On" : "Off", | 1813 | w->name, w->power ? "On" : "Off", |
@@ -2011,32 +1952,45 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | |||
2011 | 1952 | ||
2012 | #endif | 1953 | #endif |
2013 | 1954 | ||
1955 | /* | ||
1956 | * soc_dapm_connect_path() - Connects or disconnects a path | ||
1957 | * @path: The path to update | ||
1958 | * @connect: The new connect state of the path. True if the path is connected, | ||
1959 | * false if it is disconneted. | ||
1960 | * @reason: The reason why the path changed (for debugging only) | ||
1961 | */ | ||
1962 | static void soc_dapm_connect_path(struct snd_soc_dapm_path *path, | ||
1963 | bool connect, const char *reason) | ||
1964 | { | ||
1965 | if (path->connect == connect) | ||
1966 | return; | ||
1967 | |||
1968 | path->connect = connect; | ||
1969 | dapm_mark_dirty(path->source, reason); | ||
1970 | dapm_mark_dirty(path->sink, reason); | ||
1971 | dapm_path_invalidate(path); | ||
1972 | } | ||
1973 | |||
2014 | /* test and update the power status of a mux widget */ | 1974 | /* test and update the power status of a mux widget */ |
2015 | static int soc_dapm_mux_update_power(struct snd_soc_card *card, | 1975 | static int soc_dapm_mux_update_power(struct snd_soc_card *card, |
2016 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 1976 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) |
2017 | { | 1977 | { |
2018 | struct snd_soc_dapm_path *path; | 1978 | struct snd_soc_dapm_path *path; |
2019 | int found = 0; | 1979 | int found = 0; |
1980 | bool connect; | ||
2020 | 1981 | ||
2021 | lockdep_assert_held(&card->dapm_mutex); | 1982 | lockdep_assert_held(&card->dapm_mutex); |
2022 | 1983 | ||
2023 | /* find dapm widget path assoc with kcontrol */ | 1984 | /* find dapm widget path assoc with kcontrol */ |
2024 | dapm_kcontrol_for_each_path(path, kcontrol) { | 1985 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2025 | if (!path->name || !e->texts[mux]) | ||
2026 | continue; | ||
2027 | |||
2028 | found = 1; | 1986 | found = 1; |
2029 | /* we now need to match the string in the enum to the path */ | 1987 | /* we now need to match the string in the enum to the path */ |
2030 | if (!(strcmp(path->name, e->texts[mux]))) { | 1988 | if (!(strcmp(path->name, e->texts[mux]))) |
2031 | path->connect = 1; /* new connection */ | 1989 | connect = true; |
2032 | dapm_mark_dirty(path->source, "mux connection"); | 1990 | else |
2033 | } else { | 1991 | connect = false; |
2034 | if (path->connect) | 1992 | |
2035 | dapm_mark_dirty(path->source, | 1993 | soc_dapm_connect_path(path, connect, "mux update"); |
2036 | "mux disconnection"); | ||
2037 | path->connect = 0; /* old connection must be powered down */ | ||
2038 | } | ||
2039 | dapm_mark_dirty(path->sink, "mux change"); | ||
2040 | } | 1994 | } |
2041 | 1995 | ||
2042 | if (found) | 1996 | if (found) |
@@ -2075,9 +2029,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, | |||
2075 | /* find dapm widget path assoc with kcontrol */ | 2029 | /* find dapm widget path assoc with kcontrol */ |
2076 | dapm_kcontrol_for_each_path(path, kcontrol) { | 2030 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2077 | found = 1; | 2031 | found = 1; |
2078 | path->connect = connect; | 2032 | soc_dapm_connect_path(path, connect, "mixer update"); |
2079 | dapm_mark_dirty(path->source, "mixer connection"); | ||
2080 | dapm_mark_dirty(path->sink, "mixer update"); | ||
2081 | } | 2033 | } |
2082 | 2034 | ||
2083 | if (found) | 2035 | if (found) |
@@ -2255,8 +2207,11 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
2255 | return -EINVAL; | 2207 | return -EINVAL; |
2256 | } | 2208 | } |
2257 | 2209 | ||
2258 | if (w->connected != status) | 2210 | if (w->connected != status) { |
2259 | dapm_mark_dirty(w, "pin configuration"); | 2211 | dapm_mark_dirty(w, "pin configuration"); |
2212 | dapm_widget_invalidate_input_paths(w); | ||
2213 | dapm_widget_invalidate_output_paths(w); | ||
2214 | } | ||
2260 | 2215 | ||
2261 | w->connected = status; | 2216 | w->connected = status; |
2262 | if (status == 0) | 2217 | if (status == 0) |
@@ -2309,6 +2264,53 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
2309 | } | 2264 | } |
2310 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 2265 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
2311 | 2266 | ||
2267 | /* | ||
2268 | * dapm_update_widget_flags() - Re-compute widget sink and source flags | ||
2269 | * @w: The widget for which to update the flags | ||
2270 | * | ||
2271 | * Some widgets have a dynamic category which depends on which neighbors they | ||
2272 | * are connected to. This function update the category for these widgets. | ||
2273 | * | ||
2274 | * This function must be called whenever a path is added or removed to a widget. | ||
2275 | */ | ||
2276 | static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) | ||
2277 | { | ||
2278 | struct snd_soc_dapm_path *p; | ||
2279 | |||
2280 | switch (w->id) { | ||
2281 | case snd_soc_dapm_input: | ||
2282 | w->is_source = 1; | ||
2283 | list_for_each_entry(p, &w->sources, list_sink) { | ||
2284 | if (p->source->id == snd_soc_dapm_micbias || | ||
2285 | p->source->id == snd_soc_dapm_mic || | ||
2286 | p->source->id == snd_soc_dapm_line || | ||
2287 | p->source->id == snd_soc_dapm_output) { | ||
2288 | w->is_source = 0; | ||
2289 | break; | ||
2290 | } | ||
2291 | } | ||
2292 | break; | ||
2293 | case snd_soc_dapm_output: | ||
2294 | w->is_sink = 1; | ||
2295 | list_for_each_entry(p, &w->sinks, list_source) { | ||
2296 | if (p->sink->id == snd_soc_dapm_spk || | ||
2297 | p->sink->id == snd_soc_dapm_hp || | ||
2298 | p->sink->id == snd_soc_dapm_line || | ||
2299 | p->sink->id == snd_soc_dapm_input) { | ||
2300 | w->is_sink = 0; | ||
2301 | break; | ||
2302 | } | ||
2303 | } | ||
2304 | break; | ||
2305 | case snd_soc_dapm_line: | ||
2306 | w->is_sink = !list_empty(&w->sources); | ||
2307 | w->is_source = !list_empty(&w->sinks); | ||
2308 | break; | ||
2309 | default: | ||
2310 | break; | ||
2311 | } | ||
2312 | } | ||
2313 | |||
2312 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | 2314 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, |
2313 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, | 2315 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, |
2314 | const char *control, | 2316 | const char *control, |
@@ -2318,6 +2320,27 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2318 | struct snd_soc_dapm_path *path; | 2320 | struct snd_soc_dapm_path *path; |
2319 | int ret; | 2321 | int ret; |
2320 | 2322 | ||
2323 | if (wsink->is_supply && !wsource->is_supply) { | ||
2324 | dev_err(dapm->dev, | ||
2325 | "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n", | ||
2326 | wsource->name, wsink->name); | ||
2327 | return -EINVAL; | ||
2328 | } | ||
2329 | |||
2330 | if (connected && !wsource->is_supply) { | ||
2331 | dev_err(dapm->dev, | ||
2332 | "connected() callback only supported for supply widgets (%s -> %s)\n", | ||
2333 | wsource->name, wsink->name); | ||
2334 | return -EINVAL; | ||
2335 | } | ||
2336 | |||
2337 | if (wsource->is_supply && control) { | ||
2338 | dev_err(dapm->dev, | ||
2339 | "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n", | ||
2340 | wsource->name, control, wsink->name); | ||
2341 | return -EINVAL; | ||
2342 | } | ||
2343 | |||
2321 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); | 2344 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); |
2322 | if (!path) | 2345 | if (!path) |
2323 | return -ENOMEM; | 2346 | return -ENOMEM; |
@@ -2330,85 +2353,49 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2330 | INIT_LIST_HEAD(&path->list_source); | 2353 | INIT_LIST_HEAD(&path->list_source); |
2331 | INIT_LIST_HEAD(&path->list_sink); | 2354 | INIT_LIST_HEAD(&path->list_sink); |
2332 | 2355 | ||
2333 | /* check for external widgets */ | 2356 | if (wsource->is_supply || wsink->is_supply) |
2334 | if (wsink->id == snd_soc_dapm_input) { | 2357 | path->is_supply = 1; |
2335 | if (wsource->id == snd_soc_dapm_micbias || | ||
2336 | wsource->id == snd_soc_dapm_mic || | ||
2337 | wsource->id == snd_soc_dapm_line || | ||
2338 | wsource->id == snd_soc_dapm_output) | ||
2339 | wsink->ext = 1; | ||
2340 | } | ||
2341 | if (wsource->id == snd_soc_dapm_output) { | ||
2342 | if (wsink->id == snd_soc_dapm_spk || | ||
2343 | wsink->id == snd_soc_dapm_hp || | ||
2344 | wsink->id == snd_soc_dapm_line || | ||
2345 | wsink->id == snd_soc_dapm_input) | ||
2346 | wsource->ext = 1; | ||
2347 | } | ||
2348 | |||
2349 | dapm_mark_dirty(wsource, "Route added"); | ||
2350 | dapm_mark_dirty(wsink, "Route added"); | ||
2351 | 2358 | ||
2352 | /* connect static paths */ | 2359 | /* connect static paths */ |
2353 | if (control == NULL) { | 2360 | if (control == NULL) { |
2354 | list_add(&path->list, &dapm->card->paths); | ||
2355 | list_add(&path->list_sink, &wsink->sources); | ||
2356 | list_add(&path->list_source, &wsource->sinks); | ||
2357 | path->connect = 1; | 2361 | path->connect = 1; |
2358 | return 0; | 2362 | } else { |
2359 | } | 2363 | /* connect dynamic paths */ |
2360 | 2364 | switch (wsink->id) { | |
2361 | /* connect dynamic paths */ | 2365 | case snd_soc_dapm_mux: |
2362 | switch (wsink->id) { | 2366 | ret = dapm_connect_mux(dapm, path, control); |
2363 | case snd_soc_dapm_adc: | 2367 | if (ret != 0) |
2364 | case snd_soc_dapm_dac: | 2368 | goto err; |
2365 | case snd_soc_dapm_pga: | 2369 | break; |
2366 | case snd_soc_dapm_out_drv: | 2370 | case snd_soc_dapm_switch: |
2367 | case snd_soc_dapm_input: | 2371 | case snd_soc_dapm_mixer: |
2368 | case snd_soc_dapm_output: | 2372 | case snd_soc_dapm_mixer_named_ctl: |
2369 | case snd_soc_dapm_siggen: | 2373 | ret = dapm_connect_mixer(dapm, path, control); |
2370 | case snd_soc_dapm_micbias: | 2374 | if (ret != 0) |
2371 | case snd_soc_dapm_vmid: | 2375 | goto err; |
2372 | case snd_soc_dapm_pre: | 2376 | break; |
2373 | case snd_soc_dapm_post: | 2377 | default: |
2374 | case snd_soc_dapm_supply: | 2378 | dev_err(dapm->dev, |
2375 | case snd_soc_dapm_regulator_supply: | 2379 | "Control not supported for path %s -> [%s] -> %s\n", |
2376 | case snd_soc_dapm_clock_supply: | 2380 | wsource->name, control, wsink->name); |
2377 | case snd_soc_dapm_aif_in: | 2381 | ret = -EINVAL; |
2378 | case snd_soc_dapm_aif_out: | ||
2379 | case snd_soc_dapm_dai_in: | ||
2380 | case snd_soc_dapm_dai_out: | ||
2381 | case snd_soc_dapm_dai_link: | ||
2382 | case snd_soc_dapm_kcontrol: | ||
2383 | list_add(&path->list, &dapm->card->paths); | ||
2384 | list_add(&path->list_sink, &wsink->sources); | ||
2385 | list_add(&path->list_source, &wsource->sinks); | ||
2386 | path->connect = 1; | ||
2387 | return 0; | ||
2388 | case snd_soc_dapm_mux: | ||
2389 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, | ||
2390 | &wsink->kcontrol_news[0]); | ||
2391 | if (ret != 0) | ||
2392 | goto err; | ||
2393 | break; | ||
2394 | case snd_soc_dapm_switch: | ||
2395 | case snd_soc_dapm_mixer: | ||
2396 | case snd_soc_dapm_mixer_named_ctl: | ||
2397 | ret = dapm_connect_mixer(dapm, wsource, wsink, path, control); | ||
2398 | if (ret != 0) | ||
2399 | goto err; | 2382 | goto err; |
2400 | break; | 2383 | } |
2401 | case snd_soc_dapm_hp: | ||
2402 | case snd_soc_dapm_mic: | ||
2403 | case snd_soc_dapm_line: | ||
2404 | case snd_soc_dapm_spk: | ||
2405 | list_add(&path->list, &dapm->card->paths); | ||
2406 | list_add(&path->list_sink, &wsink->sources); | ||
2407 | list_add(&path->list_source, &wsource->sinks); | ||
2408 | path->connect = 0; | ||
2409 | return 0; | ||
2410 | } | 2384 | } |
2411 | 2385 | ||
2386 | list_add(&path->list, &dapm->card->paths); | ||
2387 | list_add(&path->list_sink, &wsink->sources); | ||
2388 | list_add(&path->list_source, &wsource->sinks); | ||
2389 | |||
2390 | dapm_update_widget_flags(wsource); | ||
2391 | dapm_update_widget_flags(wsink); | ||
2392 | |||
2393 | dapm_mark_dirty(wsource, "Route added"); | ||
2394 | dapm_mark_dirty(wsink, "Route added"); | ||
2395 | |||
2396 | if (dapm->card->instantiated && path->connect) | ||
2397 | dapm_path_invalidate(path); | ||
2398 | |||
2412 | return 0; | 2399 | return 0; |
2413 | err: | 2400 | err: |
2414 | kfree(path); | 2401 | kfree(path); |
@@ -2489,6 +2476,7 @@ err: | |||
2489 | static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | 2476 | static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, |
2490 | const struct snd_soc_dapm_route *route) | 2477 | const struct snd_soc_dapm_route *route) |
2491 | { | 2478 | { |
2479 | struct snd_soc_dapm_widget *wsource, *wsink; | ||
2492 | struct snd_soc_dapm_path *path, *p; | 2480 | struct snd_soc_dapm_path *path, *p; |
2493 | const char *sink; | 2481 | const char *sink; |
2494 | const char *source; | 2482 | const char *source; |
@@ -2526,10 +2514,19 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | |||
2526 | } | 2514 | } |
2527 | 2515 | ||
2528 | if (path) { | 2516 | if (path) { |
2529 | dapm_mark_dirty(path->source, "Route removed"); | 2517 | wsource = path->source; |
2530 | dapm_mark_dirty(path->sink, "Route removed"); | 2518 | wsink = path->sink; |
2519 | |||
2520 | dapm_mark_dirty(wsource, "Route removed"); | ||
2521 | dapm_mark_dirty(wsink, "Route removed"); | ||
2522 | if (path->connect) | ||
2523 | dapm_path_invalidate(path); | ||
2531 | 2524 | ||
2532 | dapm_free_path(path); | 2525 | dapm_free_path(path); |
2526 | |||
2527 | /* Update any path related flags */ | ||
2528 | dapm_update_widget_flags(wsource); | ||
2529 | dapm_update_widget_flags(wsink); | ||
2533 | } else { | 2530 | } else { |
2534 | dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", | 2531 | dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", |
2535 | source, sink); | 2532 | source, sink); |
@@ -3087,40 +3084,44 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3087 | } | 3084 | } |
3088 | 3085 | ||
3089 | switch (w->id) { | 3086 | switch (w->id) { |
3090 | case snd_soc_dapm_switch: | 3087 | case snd_soc_dapm_mic: |
3091 | case snd_soc_dapm_mixer: | 3088 | case snd_soc_dapm_input: |
3092 | case snd_soc_dapm_mixer_named_ctl: | 3089 | w->is_source = 1; |
3093 | w->power_check = dapm_generic_check_power; | 3090 | w->power_check = dapm_generic_check_power; |
3094 | break; | 3091 | break; |
3095 | case snd_soc_dapm_mux: | 3092 | case snd_soc_dapm_spk: |
3093 | case snd_soc_dapm_hp: | ||
3094 | case snd_soc_dapm_output: | ||
3095 | w->is_sink = 1; | ||
3096 | w->power_check = dapm_generic_check_power; | 3096 | w->power_check = dapm_generic_check_power; |
3097 | break; | 3097 | break; |
3098 | case snd_soc_dapm_dai_out: | 3098 | case snd_soc_dapm_vmid: |
3099 | w->power_check = dapm_adc_check_power; | 3099 | case snd_soc_dapm_siggen: |
3100 | break; | 3100 | w->is_source = 1; |
3101 | case snd_soc_dapm_dai_in: | 3101 | w->power_check = dapm_always_on_check_power; |
3102 | w->power_check = dapm_dac_check_power; | ||
3103 | break; | 3102 | break; |
3103 | case snd_soc_dapm_mux: | ||
3104 | case snd_soc_dapm_switch: | ||
3105 | case snd_soc_dapm_mixer: | ||
3106 | case snd_soc_dapm_mixer_named_ctl: | ||
3104 | case snd_soc_dapm_adc: | 3107 | case snd_soc_dapm_adc: |
3105 | case snd_soc_dapm_aif_out: | 3108 | case snd_soc_dapm_aif_out: |
3106 | case snd_soc_dapm_dac: | 3109 | case snd_soc_dapm_dac: |
3107 | case snd_soc_dapm_aif_in: | 3110 | case snd_soc_dapm_aif_in: |
3108 | case snd_soc_dapm_pga: | 3111 | case snd_soc_dapm_pga: |
3109 | case snd_soc_dapm_out_drv: | 3112 | case snd_soc_dapm_out_drv: |
3110 | case snd_soc_dapm_input: | ||
3111 | case snd_soc_dapm_output: | ||
3112 | case snd_soc_dapm_micbias: | 3113 | case snd_soc_dapm_micbias: |
3113 | case snd_soc_dapm_spk: | ||
3114 | case snd_soc_dapm_hp: | ||
3115 | case snd_soc_dapm_mic: | ||
3116 | case snd_soc_dapm_line: | 3114 | case snd_soc_dapm_line: |
3117 | case snd_soc_dapm_dai_link: | 3115 | case snd_soc_dapm_dai_link: |
3116 | case snd_soc_dapm_dai_out: | ||
3117 | case snd_soc_dapm_dai_in: | ||
3118 | w->power_check = dapm_generic_check_power; | 3118 | w->power_check = dapm_generic_check_power; |
3119 | break; | 3119 | break; |
3120 | case snd_soc_dapm_supply: | 3120 | case snd_soc_dapm_supply: |
3121 | case snd_soc_dapm_regulator_supply: | 3121 | case snd_soc_dapm_regulator_supply: |
3122 | case snd_soc_dapm_clock_supply: | 3122 | case snd_soc_dapm_clock_supply: |
3123 | case snd_soc_dapm_kcontrol: | 3123 | case snd_soc_dapm_kcontrol: |
3124 | w->is_supply = 1; | ||
3124 | w->power_check = dapm_supply_check_power; | 3125 | w->power_check = dapm_supply_check_power; |
3125 | break; | 3126 | break; |
3126 | default: | 3127 | default: |
@@ -3137,6 +3138,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3137 | INIT_LIST_HEAD(&w->dirty); | 3138 | INIT_LIST_HEAD(&w->dirty); |
3138 | list_add(&w->list, &dapm->card->widgets); | 3139 | list_add(&w->list, &dapm->card->widgets); |
3139 | 3140 | ||
3141 | w->inputs = -1; | ||
3142 | w->outputs = -1; | ||
3143 | |||
3140 | /* machine layer set ups unconnected pins and insertions */ | 3144 | /* machine layer set ups unconnected pins and insertions */ |
3141 | w->connected = 1; | 3145 | w->connected = 1; |
3142 | return w; | 3146 | return w; |
@@ -3484,6 +3488,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, | |||
3484 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | 3488 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: |
3485 | break; | 3489 | break; |
3486 | } | 3490 | } |
3491 | |||
3492 | if (w->id == snd_soc_dapm_dai_in) { | ||
3493 | w->is_source = w->active; | ||
3494 | dapm_widget_invalidate_input_paths(w); | ||
3495 | } else { | ||
3496 | w->is_sink = w->active; | ||
3497 | dapm_widget_invalidate_output_paths(w); | ||
3498 | } | ||
3487 | } | 3499 | } |
3488 | } | 3500 | } |
3489 | 3501 | ||
@@ -3610,7 +3622,15 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, | |||
3610 | } | 3622 | } |
3611 | 3623 | ||
3612 | dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin); | 3624 | dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin); |
3613 | w->connected = 1; | 3625 | if (!w->connected) { |
3626 | /* | ||
3627 | * w->force does not affect the number of input or output paths, | ||
3628 | * so we only have to recheck if w->connected is changed | ||
3629 | */ | ||
3630 | dapm_widget_invalidate_input_paths(w); | ||
3631 | dapm_widget_invalidate_output_paths(w); | ||
3632 | w->connected = 1; | ||
3633 | } | ||
3614 | w->force = 1; | 3634 | w->force = 1; |
3615 | dapm_mark_dirty(w, "force enable"); | 3635 | dapm_mark_dirty(w, "force enable"); |
3616 | 3636 | ||
@@ -3788,35 +3808,54 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, | |||
3788 | } | 3808 | } |
3789 | EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); | 3809 | EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); |
3790 | 3810 | ||
3811 | /** | ||
3812 | * dapm_is_external_path() - Checks if a path is a external path | ||
3813 | * @card: The card the path belongs to | ||
3814 | * @path: The path to check | ||
3815 | * | ||
3816 | * Returns true if the path is either between two different DAPM contexts or | ||
3817 | * between two external pins of the same DAPM context. Otherwise returns | ||
3818 | * false. | ||
3819 | */ | ||
3820 | static bool dapm_is_external_path(struct snd_soc_card *card, | ||
3821 | struct snd_soc_dapm_path *path) | ||
3822 | { | ||
3823 | dev_dbg(card->dev, | ||
3824 | "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n", | ||
3825 | path->source->name, path->source->id, path->source->dapm, | ||
3826 | path->sink->name, path->sink->id, path->sink->dapm); | ||
3827 | |||
3828 | /* Connection between two different DAPM contexts */ | ||
3829 | if (path->source->dapm != path->sink->dapm) | ||
3830 | return true; | ||
3831 | |||
3832 | /* Loopback connection from external pin to external pin */ | ||
3833 | if (path->sink->id == snd_soc_dapm_input) { | ||
3834 | switch (path->source->id) { | ||
3835 | case snd_soc_dapm_output: | ||
3836 | case snd_soc_dapm_micbias: | ||
3837 | return true; | ||
3838 | default: | ||
3839 | break; | ||
3840 | } | ||
3841 | } | ||
3842 | |||
3843 | return false; | ||
3844 | } | ||
3845 | |||
3791 | static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, | 3846 | static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, |
3792 | struct snd_soc_dapm_widget *w) | 3847 | struct snd_soc_dapm_widget *w) |
3793 | { | 3848 | { |
3794 | struct snd_soc_dapm_path *p; | 3849 | struct snd_soc_dapm_path *p; |
3795 | 3850 | ||
3796 | list_for_each_entry(p, &card->paths, list) { | 3851 | list_for_each_entry(p, &w->sources, list_sink) { |
3797 | if ((p->source == w) || (p->sink == w)) { | 3852 | if (dapm_is_external_path(card, p)) |
3798 | dev_dbg(card->dev, | 3853 | return true; |
3799 | "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n", | 3854 | } |
3800 | p->source->name, p->source->id, p->source->dapm, | ||
3801 | p->sink->name, p->sink->id, p->sink->dapm); | ||
3802 | 3855 | ||
3803 | /* Connected to something other than the codec */ | 3856 | list_for_each_entry(p, &w->sinks, list_source) { |
3804 | if (p->source->dapm != p->sink->dapm) | 3857 | if (dapm_is_external_path(card, p)) |
3805 | return true; | 3858 | return true; |
3806 | /* | ||
3807 | * Loopback connection from codec external pin to | ||
3808 | * codec external pin | ||
3809 | */ | ||
3810 | if (p->sink->id == snd_soc_dapm_input) { | ||
3811 | switch (p->source->id) { | ||
3812 | case snd_soc_dapm_output: | ||
3813 | case snd_soc_dapm_micbias: | ||
3814 | return true; | ||
3815 | default: | ||
3816 | break; | ||
3817 | } | ||
3818 | } | ||
3819 | } | ||
3820 | } | 3859 | } |
3821 | 3860 | ||
3822 | return false; | 3861 | return false; |
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index ab47fea997a3..4380dcc064a5 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c | |||
@@ -116,7 +116,7 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_report); | |||
116 | * | 116 | * |
117 | * @jack: ASoC jack | 117 | * @jack: ASoC jack |
118 | * @count: Number of zones | 118 | * @count: Number of zones |
119 | * @zone: Array of zones | 119 | * @zones: Array of zones |
120 | * | 120 | * |
121 | * After this function has been called the zones specified in the | 121 | * After this function has been called the zones specified in the |
122 | * array will be associated with the jack. | 122 | * array will be associated with the jack. |
@@ -309,7 +309,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | |||
309 | /* GPIO descriptor */ | 309 | /* GPIO descriptor */ |
310 | gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev, | 310 | gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev, |
311 | gpios[i].name, | 311 | gpios[i].name, |
312 | gpios[i].idx); | 312 | gpios[i].idx, GPIOD_IN); |
313 | if (IS_ERR(gpios[i].desc)) { | 313 | if (IS_ERR(gpios[i].desc)) { |
314 | ret = PTR_ERR(gpios[i].desc); | 314 | ret = PTR_ERR(gpios[i].desc); |
315 | dev_err(gpios[i].gpiod_dev, | 315 | dev_err(gpios[i].gpiod_dev, |
@@ -327,17 +327,14 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | |||
327 | goto undo; | 327 | goto undo; |
328 | } | 328 | } |
329 | 329 | ||
330 | ret = gpio_request(gpios[i].gpio, gpios[i].name); | 330 | ret = gpio_request_one(gpios[i].gpio, GPIOF_IN, |
331 | gpios[i].name); | ||
331 | if (ret) | 332 | if (ret) |
332 | goto undo; | 333 | goto undo; |
333 | 334 | ||
334 | gpios[i].desc = gpio_to_desc(gpios[i].gpio); | 335 | gpios[i].desc = gpio_to_desc(gpios[i].gpio); |
335 | } | 336 | } |
336 | 337 | ||
337 | ret = gpiod_direction_input(gpios[i].desc); | ||
338 | if (ret) | ||
339 | goto err; | ||
340 | |||
341 | INIT_DELAYED_WORK(&gpios[i].work, gpio_work); | 338 | INIT_DELAYED_WORK(&gpios[i].work, gpio_work); |
342 | gpios[i].jack = jack; | 339 | gpios[i].jack = jack; |
343 | 340 | ||
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c new file mode 100644 index 000000000000..100d92b5b77e --- /dev/null +++ b/sound/soc/soc-ops.c | |||
@@ -0,0 +1,952 @@ | |||
1 | /* | ||
2 | * soc-ops.c -- Generic ASoC operations | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * Copyright (C) 2010 Slimlogic Ltd. | ||
7 | * Copyright (C) 2010 Texas Instruments Inc. | ||
8 | * | ||
9 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | ||
10 | * with code, comments and ideas from :- | ||
11 | * Richard Purdie <richard@openedhand.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/pm.h> | ||
24 | #include <linux/bitops.h> | ||
25 | #include <linux/ctype.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/jack.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dpcm.h> | ||
33 | #include <sound/initval.h> | ||
34 | |||
35 | /** | ||
36 | * snd_soc_info_enum_double - enumerated double mixer info callback | ||
37 | * @kcontrol: mixer control | ||
38 | * @uinfo: control element information | ||
39 | * | ||
40 | * Callback to provide information about a double enumerated | ||
41 | * mixer control. | ||
42 | * | ||
43 | * Returns 0 for success. | ||
44 | */ | ||
45 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | ||
46 | struct snd_ctl_elem_info *uinfo) | ||
47 | { | ||
48 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
49 | |||
50 | return snd_ctl_enum_info(uinfo, e->shift_l == e->shift_r ? 1 : 2, | ||
51 | e->items, e->texts); | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); | ||
54 | |||
55 | /** | ||
56 | * snd_soc_get_enum_double - enumerated double mixer get callback | ||
57 | * @kcontrol: mixer control | ||
58 | * @ucontrol: control element information | ||
59 | * | ||
60 | * Callback to get the value of a double enumerated mixer. | ||
61 | * | ||
62 | * Returns 0 for success. | ||
63 | */ | ||
64 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | ||
65 | struct snd_ctl_elem_value *ucontrol) | ||
66 | { | ||
67 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
68 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
69 | unsigned int val, item; | ||
70 | unsigned int reg_val; | ||
71 | int ret; | ||
72 | |||
73 | ret = snd_soc_component_read(component, e->reg, ®_val); | ||
74 | if (ret) | ||
75 | return ret; | ||
76 | val = (reg_val >> e->shift_l) & e->mask; | ||
77 | item = snd_soc_enum_val_to_item(e, val); | ||
78 | ucontrol->value.enumerated.item[0] = item; | ||
79 | if (e->shift_l != e->shift_r) { | ||
80 | val = (reg_val >> e->shift_l) & e->mask; | ||
81 | item = snd_soc_enum_val_to_item(e, val); | ||
82 | ucontrol->value.enumerated.item[1] = item; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); | ||
88 | |||
89 | /** | ||
90 | * snd_soc_put_enum_double - enumerated double mixer put callback | ||
91 | * @kcontrol: mixer control | ||
92 | * @ucontrol: control element information | ||
93 | * | ||
94 | * Callback to set the value of a double enumerated mixer. | ||
95 | * | ||
96 | * Returns 0 for success. | ||
97 | */ | ||
98 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | ||
99 | struct snd_ctl_elem_value *ucontrol) | ||
100 | { | ||
101 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
102 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
103 | unsigned int *item = ucontrol->value.enumerated.item; | ||
104 | unsigned int val; | ||
105 | unsigned int mask; | ||
106 | |||
107 | if (item[0] >= e->items) | ||
108 | return -EINVAL; | ||
109 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; | ||
110 | mask = e->mask << e->shift_l; | ||
111 | if (e->shift_l != e->shift_r) { | ||
112 | if (item[1] >= e->items) | ||
113 | return -EINVAL; | ||
114 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; | ||
115 | mask |= e->mask << e->shift_r; | ||
116 | } | ||
117 | |||
118 | return snd_soc_component_update_bits(component, e->reg, mask, val); | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | ||
121 | |||
122 | /** | ||
123 | * snd_soc_read_signed - Read a codec register and interprete as signed value | ||
124 | * @component: component | ||
125 | * @reg: Register to read | ||
126 | * @mask: Mask to use after shifting the register value | ||
127 | * @shift: Right shift of register value | ||
128 | * @sign_bit: Bit that describes if a number is negative or not. | ||
129 | * @signed_val: Pointer to where the read value should be stored | ||
130 | * | ||
131 | * This functions reads a codec register. The register value is shifted right | ||
132 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates | ||
133 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
134 | * | ||
135 | * Returns 0 on sucess, otherwise an error value | ||
136 | */ | ||
137 | static int snd_soc_read_signed(struct snd_soc_component *component, | ||
138 | unsigned int reg, unsigned int mask, unsigned int shift, | ||
139 | unsigned int sign_bit, int *signed_val) | ||
140 | { | ||
141 | int ret; | ||
142 | unsigned int val; | ||
143 | |||
144 | ret = snd_soc_component_read(component, reg, &val); | ||
145 | if (ret < 0) | ||
146 | return ret; | ||
147 | |||
148 | val = (val >> shift) & mask; | ||
149 | |||
150 | if (!sign_bit) { | ||
151 | *signed_val = val; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /* non-negative number */ | ||
156 | if (!(val & BIT(sign_bit))) { | ||
157 | *signed_val = val; | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | ret = val; | ||
162 | |||
163 | /* | ||
164 | * The register most probably does not contain a full-sized int. | ||
165 | * Instead we have an arbitrary number of bits in a signed | ||
166 | * representation which has to be translated into a full-sized int. | ||
167 | * This is done by filling up all bits above the sign-bit. | ||
168 | */ | ||
169 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
170 | |||
171 | *signed_val = ret; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * snd_soc_info_volsw - single mixer info callback | ||
178 | * @kcontrol: mixer control | ||
179 | * @uinfo: control element information | ||
180 | * | ||
181 | * Callback to provide information about a single mixer control, or a double | ||
182 | * mixer control that spans 2 registers. | ||
183 | * | ||
184 | * Returns 0 for success. | ||
185 | */ | ||
186 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | ||
187 | struct snd_ctl_elem_info *uinfo) | ||
188 | { | ||
189 | struct soc_mixer_control *mc = | ||
190 | (struct soc_mixer_control *)kcontrol->private_value; | ||
191 | int platform_max; | ||
192 | |||
193 | if (!mc->platform_max) | ||
194 | mc->platform_max = mc->max; | ||
195 | platform_max = mc->platform_max; | ||
196 | |||
197 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | ||
198 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
199 | else | ||
200 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
201 | |||
202 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
203 | uinfo->value.integer.min = 0; | ||
204 | uinfo->value.integer.max = platform_max - mc->min; | ||
205 | return 0; | ||
206 | } | ||
207 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | ||
208 | |||
209 | /** | ||
210 | * snd_soc_get_volsw - single mixer get callback | ||
211 | * @kcontrol: mixer control | ||
212 | * @ucontrol: control element information | ||
213 | * | ||
214 | * Callback to get the value of a single mixer control, or a double mixer | ||
215 | * control that spans 2 registers. | ||
216 | * | ||
217 | * Returns 0 for success. | ||
218 | */ | ||
219 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | ||
220 | struct snd_ctl_elem_value *ucontrol) | ||
221 | { | ||
222 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
223 | struct soc_mixer_control *mc = | ||
224 | (struct soc_mixer_control *)kcontrol->private_value; | ||
225 | unsigned int reg = mc->reg; | ||
226 | unsigned int reg2 = mc->rreg; | ||
227 | unsigned int shift = mc->shift; | ||
228 | unsigned int rshift = mc->rshift; | ||
229 | int max = mc->max; | ||
230 | int min = mc->min; | ||
231 | int sign_bit = mc->sign_bit; | ||
232 | unsigned int mask = (1 << fls(max)) - 1; | ||
233 | unsigned int invert = mc->invert; | ||
234 | int val; | ||
235 | int ret; | ||
236 | |||
237 | if (sign_bit) | ||
238 | mask = BIT(sign_bit + 1) - 1; | ||
239 | |||
240 | ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val); | ||
241 | if (ret) | ||
242 | return ret; | ||
243 | |||
244 | ucontrol->value.integer.value[0] = val - min; | ||
245 | if (invert) | ||
246 | ucontrol->value.integer.value[0] = | ||
247 | max - ucontrol->value.integer.value[0]; | ||
248 | |||
249 | if (snd_soc_volsw_is_stereo(mc)) { | ||
250 | if (reg == reg2) | ||
251 | ret = snd_soc_read_signed(component, reg, mask, rshift, | ||
252 | sign_bit, &val); | ||
253 | else | ||
254 | ret = snd_soc_read_signed(component, reg2, mask, shift, | ||
255 | sign_bit, &val); | ||
256 | if (ret) | ||
257 | return ret; | ||
258 | |||
259 | ucontrol->value.integer.value[1] = val - min; | ||
260 | if (invert) | ||
261 | ucontrol->value.integer.value[1] = | ||
262 | max - ucontrol->value.integer.value[1]; | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | ||
268 | |||
269 | /** | ||
270 | * snd_soc_put_volsw - single mixer put callback | ||
271 | * @kcontrol: mixer control | ||
272 | * @ucontrol: control element information | ||
273 | * | ||
274 | * Callback to set the value of a single mixer control, or a double mixer | ||
275 | * control that spans 2 registers. | ||
276 | * | ||
277 | * Returns 0 for success. | ||
278 | */ | ||
279 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | ||
280 | struct snd_ctl_elem_value *ucontrol) | ||
281 | { | ||
282 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
283 | struct soc_mixer_control *mc = | ||
284 | (struct soc_mixer_control *)kcontrol->private_value; | ||
285 | unsigned int reg = mc->reg; | ||
286 | unsigned int reg2 = mc->rreg; | ||
287 | unsigned int shift = mc->shift; | ||
288 | unsigned int rshift = mc->rshift; | ||
289 | int max = mc->max; | ||
290 | int min = mc->min; | ||
291 | unsigned int sign_bit = mc->sign_bit; | ||
292 | unsigned int mask = (1 << fls(max)) - 1; | ||
293 | unsigned int invert = mc->invert; | ||
294 | int err; | ||
295 | bool type_2r = false; | ||
296 | unsigned int val2 = 0; | ||
297 | unsigned int val, val_mask; | ||
298 | |||
299 | if (sign_bit) | ||
300 | mask = BIT(sign_bit + 1) - 1; | ||
301 | |||
302 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
303 | if (invert) | ||
304 | val = max - val; | ||
305 | val_mask = mask << shift; | ||
306 | val = val << shift; | ||
307 | if (snd_soc_volsw_is_stereo(mc)) { | ||
308 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); | ||
309 | if (invert) | ||
310 | val2 = max - val2; | ||
311 | if (reg == reg2) { | ||
312 | val_mask |= mask << rshift; | ||
313 | val |= val2 << rshift; | ||
314 | } else { | ||
315 | val2 = val2 << shift; | ||
316 | type_2r = true; | ||
317 | } | ||
318 | } | ||
319 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
320 | if (err < 0) | ||
321 | return err; | ||
322 | |||
323 | if (type_2r) | ||
324 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
325 | val2); | ||
326 | |||
327 | return err; | ||
328 | } | ||
329 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | ||
330 | |||
331 | /** | ||
332 | * snd_soc_get_volsw_sx - single mixer get callback | ||
333 | * @kcontrol: mixer control | ||
334 | * @ucontrol: control element information | ||
335 | * | ||
336 | * Callback to get the value of a single mixer control, or a double mixer | ||
337 | * control that spans 2 registers. | ||
338 | * | ||
339 | * Returns 0 for success. | ||
340 | */ | ||
341 | int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, | ||
342 | struct snd_ctl_elem_value *ucontrol) | ||
343 | { | ||
344 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
345 | struct soc_mixer_control *mc = | ||
346 | (struct soc_mixer_control *)kcontrol->private_value; | ||
347 | unsigned int reg = mc->reg; | ||
348 | unsigned int reg2 = mc->rreg; | ||
349 | unsigned int shift = mc->shift; | ||
350 | unsigned int rshift = mc->rshift; | ||
351 | int max = mc->max; | ||
352 | int min = mc->min; | ||
353 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
354 | unsigned int val; | ||
355 | int ret; | ||
356 | |||
357 | ret = snd_soc_component_read(component, reg, &val); | ||
358 | if (ret < 0) | ||
359 | return ret; | ||
360 | |||
361 | ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask; | ||
362 | |||
363 | if (snd_soc_volsw_is_stereo(mc)) { | ||
364 | ret = snd_soc_component_read(component, reg2, &val); | ||
365 | if (ret < 0) | ||
366 | return ret; | ||
367 | |||
368 | val = ((val >> rshift) - min) & mask; | ||
369 | ucontrol->value.integer.value[1] = val; | ||
370 | } | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); | ||
375 | |||
376 | /** | ||
377 | * snd_soc_put_volsw_sx - double mixer set callback | ||
378 | * @kcontrol: mixer control | ||
379 | * @uinfo: control element information | ||
380 | * | ||
381 | * Callback to set the value of a double mixer control that spans 2 registers. | ||
382 | * | ||
383 | * Returns 0 for success. | ||
384 | */ | ||
385 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, | ||
386 | struct snd_ctl_elem_value *ucontrol) | ||
387 | { | ||
388 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
389 | struct soc_mixer_control *mc = | ||
390 | (struct soc_mixer_control *)kcontrol->private_value; | ||
391 | |||
392 | unsigned int reg = mc->reg; | ||
393 | unsigned int reg2 = mc->rreg; | ||
394 | unsigned int shift = mc->shift; | ||
395 | unsigned int rshift = mc->rshift; | ||
396 | int max = mc->max; | ||
397 | int min = mc->min; | ||
398 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
399 | int err = 0; | ||
400 | unsigned int val, val_mask, val2 = 0; | ||
401 | |||
402 | val_mask = mask << shift; | ||
403 | val = (ucontrol->value.integer.value[0] + min) & mask; | ||
404 | val = val << shift; | ||
405 | |||
406 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
407 | if (err < 0) | ||
408 | return err; | ||
409 | |||
410 | if (snd_soc_volsw_is_stereo(mc)) { | ||
411 | val_mask = mask << rshift; | ||
412 | val2 = (ucontrol->value.integer.value[1] + min) & mask; | ||
413 | val2 = val2 << rshift; | ||
414 | |||
415 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
416 | val2); | ||
417 | } | ||
418 | return err; | ||
419 | } | ||
420 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); | ||
421 | |||
422 | /** | ||
423 | * snd_soc_info_volsw_range - single mixer info callback with range. | ||
424 | * @kcontrol: mixer control | ||
425 | * @uinfo: control element information | ||
426 | * | ||
427 | * Callback to provide information, within a range, about a single | ||
428 | * mixer control. | ||
429 | * | ||
430 | * returns 0 for success. | ||
431 | */ | ||
432 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | ||
433 | struct snd_ctl_elem_info *uinfo) | ||
434 | { | ||
435 | struct soc_mixer_control *mc = | ||
436 | (struct soc_mixer_control *)kcontrol->private_value; | ||
437 | int platform_max; | ||
438 | int min = mc->min; | ||
439 | |||
440 | if (!mc->platform_max) | ||
441 | mc->platform_max = mc->max; | ||
442 | platform_max = mc->platform_max; | ||
443 | |||
444 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
445 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
446 | uinfo->value.integer.min = 0; | ||
447 | uinfo->value.integer.max = platform_max - min; | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range); | ||
452 | |||
453 | /** | ||
454 | * snd_soc_put_volsw_range - single mixer put value callback with range. | ||
455 | * @kcontrol: mixer control | ||
456 | * @ucontrol: control element information | ||
457 | * | ||
458 | * Callback to set the value, within a range, for a single mixer control. | ||
459 | * | ||
460 | * Returns 0 for success. | ||
461 | */ | ||
462 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | ||
463 | struct snd_ctl_elem_value *ucontrol) | ||
464 | { | ||
465 | struct soc_mixer_control *mc = | ||
466 | (struct soc_mixer_control *)kcontrol->private_value; | ||
467 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
468 | unsigned int reg = mc->reg; | ||
469 | unsigned int rreg = mc->rreg; | ||
470 | unsigned int shift = mc->shift; | ||
471 | int min = mc->min; | ||
472 | int max = mc->max; | ||
473 | unsigned int mask = (1 << fls(max)) - 1; | ||
474 | unsigned int invert = mc->invert; | ||
475 | unsigned int val, val_mask; | ||
476 | int ret; | ||
477 | |||
478 | if (invert) | ||
479 | val = (max - ucontrol->value.integer.value[0]) & mask; | ||
480 | else | ||
481 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
482 | val_mask = mask << shift; | ||
483 | val = val << shift; | ||
484 | |||
485 | ret = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
486 | if (ret < 0) | ||
487 | return ret; | ||
488 | |||
489 | if (snd_soc_volsw_is_stereo(mc)) { | ||
490 | if (invert) | ||
491 | val = (max - ucontrol->value.integer.value[1]) & mask; | ||
492 | else | ||
493 | val = ((ucontrol->value.integer.value[1] + min) & mask); | ||
494 | val_mask = mask << shift; | ||
495 | val = val << shift; | ||
496 | |||
497 | ret = snd_soc_component_update_bits(component, rreg, val_mask, | ||
498 | val); | ||
499 | } | ||
500 | |||
501 | return ret; | ||
502 | } | ||
503 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); | ||
504 | |||
505 | /** | ||
506 | * snd_soc_get_volsw_range - single mixer get callback with range | ||
507 | * @kcontrol: mixer control | ||
508 | * @ucontrol: control element information | ||
509 | * | ||
510 | * Callback to get the value, within a range, of a single mixer control. | ||
511 | * | ||
512 | * Returns 0 for success. | ||
513 | */ | ||
514 | int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | ||
515 | struct snd_ctl_elem_value *ucontrol) | ||
516 | { | ||
517 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
518 | struct soc_mixer_control *mc = | ||
519 | (struct soc_mixer_control *)kcontrol->private_value; | ||
520 | unsigned int reg = mc->reg; | ||
521 | unsigned int rreg = mc->rreg; | ||
522 | unsigned int shift = mc->shift; | ||
523 | int min = mc->min; | ||
524 | int max = mc->max; | ||
525 | unsigned int mask = (1 << fls(max)) - 1; | ||
526 | unsigned int invert = mc->invert; | ||
527 | unsigned int val; | ||
528 | int ret; | ||
529 | |||
530 | ret = snd_soc_component_read(component, reg, &val); | ||
531 | if (ret) | ||
532 | return ret; | ||
533 | |||
534 | ucontrol->value.integer.value[0] = (val >> shift) & mask; | ||
535 | if (invert) | ||
536 | ucontrol->value.integer.value[0] = | ||
537 | max - ucontrol->value.integer.value[0]; | ||
538 | else | ||
539 | ucontrol->value.integer.value[0] = | ||
540 | ucontrol->value.integer.value[0] - min; | ||
541 | |||
542 | if (snd_soc_volsw_is_stereo(mc)) { | ||
543 | ret = snd_soc_component_read(component, rreg, &val); | ||
544 | if (ret) | ||
545 | return ret; | ||
546 | |||
547 | ucontrol->value.integer.value[1] = (val >> shift) & mask; | ||
548 | if (invert) | ||
549 | ucontrol->value.integer.value[1] = | ||
550 | max - ucontrol->value.integer.value[1]; | ||
551 | else | ||
552 | ucontrol->value.integer.value[1] = | ||
553 | ucontrol->value.integer.value[1] - min; | ||
554 | } | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); | ||
559 | |||
560 | /** | ||
561 | * snd_soc_limit_volume - Set new limit to an existing volume control. | ||
562 | * | ||
563 | * @codec: where to look for the control | ||
564 | * @name: Name of the control | ||
565 | * @max: new maximum limit | ||
566 | * | ||
567 | * Return 0 for success, else error. | ||
568 | */ | ||
569 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | ||
570 | const char *name, int max) | ||
571 | { | ||
572 | struct snd_card *card = codec->component.card->snd_card; | ||
573 | struct snd_kcontrol *kctl; | ||
574 | struct soc_mixer_control *mc; | ||
575 | int found = 0; | ||
576 | int ret = -EINVAL; | ||
577 | |||
578 | /* Sanity check for name and max */ | ||
579 | if (unlikely(!name || max <= 0)) | ||
580 | return -EINVAL; | ||
581 | |||
582 | list_for_each_entry(kctl, &card->controls, list) { | ||
583 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) { | ||
584 | found = 1; | ||
585 | break; | ||
586 | } | ||
587 | } | ||
588 | if (found) { | ||
589 | mc = (struct soc_mixer_control *)kctl->private_value; | ||
590 | if (max <= mc->max) { | ||
591 | mc->platform_max = max; | ||
592 | ret = 0; | ||
593 | } | ||
594 | } | ||
595 | return ret; | ||
596 | } | ||
597 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); | ||
598 | |||
599 | int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, | ||
600 | struct snd_ctl_elem_info *uinfo) | ||
601 | { | ||
602 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
603 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
604 | |||
605 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
606 | uinfo->count = params->num_regs * component->val_bytes; | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info); | ||
611 | |||
612 | int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, | ||
613 | struct snd_ctl_elem_value *ucontrol) | ||
614 | { | ||
615 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
616 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
617 | int ret; | ||
618 | |||
619 | if (component->regmap) | ||
620 | ret = regmap_raw_read(component->regmap, params->base, | ||
621 | ucontrol->value.bytes.data, | ||
622 | params->num_regs * component->val_bytes); | ||
623 | else | ||
624 | ret = -EINVAL; | ||
625 | |||
626 | /* Hide any masked bytes to ensure consistent data reporting */ | ||
627 | if (ret == 0 && params->mask) { | ||
628 | switch (component->val_bytes) { | ||
629 | case 1: | ||
630 | ucontrol->value.bytes.data[0] &= ~params->mask; | ||
631 | break; | ||
632 | case 2: | ||
633 | ((u16 *)(&ucontrol->value.bytes.data))[0] | ||
634 | &= cpu_to_be16(~params->mask); | ||
635 | break; | ||
636 | case 4: | ||
637 | ((u32 *)(&ucontrol->value.bytes.data))[0] | ||
638 | &= cpu_to_be32(~params->mask); | ||
639 | break; | ||
640 | default: | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | return ret; | ||
646 | } | ||
647 | EXPORT_SYMBOL_GPL(snd_soc_bytes_get); | ||
648 | |||
649 | int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | ||
650 | struct snd_ctl_elem_value *ucontrol) | ||
651 | { | ||
652 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
653 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
654 | int ret, len; | ||
655 | unsigned int val, mask; | ||
656 | void *data; | ||
657 | |||
658 | if (!component->regmap || !params->num_regs) | ||
659 | return -EINVAL; | ||
660 | |||
661 | len = params->num_regs * component->val_bytes; | ||
662 | |||
663 | data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); | ||
664 | if (!data) | ||
665 | return -ENOMEM; | ||
666 | |||
667 | /* | ||
668 | * If we've got a mask then we need to preserve the register | ||
669 | * bits. We shouldn't modify the incoming data so take a | ||
670 | * copy. | ||
671 | */ | ||
672 | if (params->mask) { | ||
673 | ret = regmap_read(component->regmap, params->base, &val); | ||
674 | if (ret != 0) | ||
675 | goto out; | ||
676 | |||
677 | val &= params->mask; | ||
678 | |||
679 | switch (component->val_bytes) { | ||
680 | case 1: | ||
681 | ((u8 *)data)[0] &= ~params->mask; | ||
682 | ((u8 *)data)[0] |= val; | ||
683 | break; | ||
684 | case 2: | ||
685 | mask = ~params->mask; | ||
686 | ret = regmap_parse_val(component->regmap, | ||
687 | &mask, &mask); | ||
688 | if (ret != 0) | ||
689 | goto out; | ||
690 | |||
691 | ((u16 *)data)[0] &= mask; | ||
692 | |||
693 | ret = regmap_parse_val(component->regmap, | ||
694 | &val, &val); | ||
695 | if (ret != 0) | ||
696 | goto out; | ||
697 | |||
698 | ((u16 *)data)[0] |= val; | ||
699 | break; | ||
700 | case 4: | ||
701 | mask = ~params->mask; | ||
702 | ret = regmap_parse_val(component->regmap, | ||
703 | &mask, &mask); | ||
704 | if (ret != 0) | ||
705 | goto out; | ||
706 | |||
707 | ((u32 *)data)[0] &= mask; | ||
708 | |||
709 | ret = regmap_parse_val(component->regmap, | ||
710 | &val, &val); | ||
711 | if (ret != 0) | ||
712 | goto out; | ||
713 | |||
714 | ((u32 *)data)[0] |= val; | ||
715 | break; | ||
716 | default: | ||
717 | ret = -EINVAL; | ||
718 | goto out; | ||
719 | } | ||
720 | } | ||
721 | |||
722 | ret = regmap_raw_write(component->regmap, params->base, | ||
723 | data, len); | ||
724 | |||
725 | out: | ||
726 | kfree(data); | ||
727 | |||
728 | return ret; | ||
729 | } | ||
730 | EXPORT_SYMBOL_GPL(snd_soc_bytes_put); | ||
731 | |||
732 | int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, | ||
733 | struct snd_ctl_elem_info *ucontrol) | ||
734 | { | ||
735 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
736 | |||
737 | ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
738 | ucontrol->count = params->max; | ||
739 | |||
740 | return 0; | ||
741 | } | ||
742 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext); | ||
743 | |||
744 | int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, | ||
745 | unsigned int size, unsigned int __user *tlv) | ||
746 | { | ||
747 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
748 | unsigned int count = size < params->max ? size : params->max; | ||
749 | int ret = -ENXIO; | ||
750 | |||
751 | switch (op_flag) { | ||
752 | case SNDRV_CTL_TLV_OP_READ: | ||
753 | if (params->get) | ||
754 | ret = params->get(tlv, count); | ||
755 | break; | ||
756 | case SNDRV_CTL_TLV_OP_WRITE: | ||
757 | if (params->put) | ||
758 | ret = params->put(tlv, count); | ||
759 | break; | ||
760 | } | ||
761 | return ret; | ||
762 | } | ||
763 | EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback); | ||
764 | |||
765 | /** | ||
766 | * snd_soc_info_xr_sx - signed multi register info callback | ||
767 | * @kcontrol: mreg control | ||
768 | * @uinfo: control element information | ||
769 | * | ||
770 | * Callback to provide information of a control that can | ||
771 | * span multiple codec registers which together | ||
772 | * forms a single signed value in a MSB/LSB manner. | ||
773 | * | ||
774 | * Returns 0 for success. | ||
775 | */ | ||
776 | int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, | ||
777 | struct snd_ctl_elem_info *uinfo) | ||
778 | { | ||
779 | struct soc_mreg_control *mc = | ||
780 | (struct soc_mreg_control *)kcontrol->private_value; | ||
781 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
782 | uinfo->count = 1; | ||
783 | uinfo->value.integer.min = mc->min; | ||
784 | uinfo->value.integer.max = mc->max; | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx); | ||
789 | |||
790 | /** | ||
791 | * snd_soc_get_xr_sx - signed multi register get callback | ||
792 | * @kcontrol: mreg control | ||
793 | * @ucontrol: control element information | ||
794 | * | ||
795 | * Callback to get the value of a control that can span | ||
796 | * multiple codec registers which together forms a single | ||
797 | * signed value in a MSB/LSB manner. The control supports | ||
798 | * specifying total no of bits used to allow for bitfields | ||
799 | * across the multiple codec registers. | ||
800 | * | ||
801 | * Returns 0 for success. | ||
802 | */ | ||
803 | int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, | ||
804 | struct snd_ctl_elem_value *ucontrol) | ||
805 | { | ||
806 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
807 | struct soc_mreg_control *mc = | ||
808 | (struct soc_mreg_control *)kcontrol->private_value; | ||
809 | unsigned int regbase = mc->regbase; | ||
810 | unsigned int regcount = mc->regcount; | ||
811 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
812 | unsigned int regwmask = (1<<regwshift)-1; | ||
813 | unsigned int invert = mc->invert; | ||
814 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
815 | long min = mc->min; | ||
816 | long max = mc->max; | ||
817 | long val = 0; | ||
818 | unsigned int regval; | ||
819 | unsigned int i; | ||
820 | int ret; | ||
821 | |||
822 | for (i = 0; i < regcount; i++) { | ||
823 | ret = snd_soc_component_read(component, regbase+i, ®val); | ||
824 | if (ret) | ||
825 | return ret; | ||
826 | val |= (regval & regwmask) << (regwshift*(regcount-i-1)); | ||
827 | } | ||
828 | val &= mask; | ||
829 | if (min < 0 && val > max) | ||
830 | val |= ~mask; | ||
831 | if (invert) | ||
832 | val = max - val; | ||
833 | ucontrol->value.integer.value[0] = val; | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx); | ||
838 | |||
839 | /** | ||
840 | * snd_soc_put_xr_sx - signed multi register get callback | ||
841 | * @kcontrol: mreg control | ||
842 | * @ucontrol: control element information | ||
843 | * | ||
844 | * Callback to set the value of a control that can span | ||
845 | * multiple codec registers which together forms a single | ||
846 | * signed value in a MSB/LSB manner. The control supports | ||
847 | * specifying total no of bits used to allow for bitfields | ||
848 | * across the multiple codec registers. | ||
849 | * | ||
850 | * Returns 0 for success. | ||
851 | */ | ||
852 | int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, | ||
853 | struct snd_ctl_elem_value *ucontrol) | ||
854 | { | ||
855 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
856 | struct soc_mreg_control *mc = | ||
857 | (struct soc_mreg_control *)kcontrol->private_value; | ||
858 | unsigned int regbase = mc->regbase; | ||
859 | unsigned int regcount = mc->regcount; | ||
860 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
861 | unsigned int regwmask = (1<<regwshift)-1; | ||
862 | unsigned int invert = mc->invert; | ||
863 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
864 | long max = mc->max; | ||
865 | long val = ucontrol->value.integer.value[0]; | ||
866 | unsigned int i, regval, regmask; | ||
867 | int err; | ||
868 | |||
869 | if (invert) | ||
870 | val = max - val; | ||
871 | val &= mask; | ||
872 | for (i = 0; i < regcount; i++) { | ||
873 | regval = (val >> (regwshift*(regcount-i-1))) & regwmask; | ||
874 | regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; | ||
875 | err = snd_soc_component_update_bits(component, regbase+i, | ||
876 | regmask, regval); | ||
877 | if (err < 0) | ||
878 | return err; | ||
879 | } | ||
880 | |||
881 | return 0; | ||
882 | } | ||
883 | EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx); | ||
884 | |||
885 | /** | ||
886 | * snd_soc_get_strobe - strobe get callback | ||
887 | * @kcontrol: mixer control | ||
888 | * @ucontrol: control element information | ||
889 | * | ||
890 | * Callback get the value of a strobe mixer control. | ||
891 | * | ||
892 | * Returns 0 for success. | ||
893 | */ | ||
894 | int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, | ||
895 | struct snd_ctl_elem_value *ucontrol) | ||
896 | { | ||
897 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
898 | struct soc_mixer_control *mc = | ||
899 | (struct soc_mixer_control *)kcontrol->private_value; | ||
900 | unsigned int reg = mc->reg; | ||
901 | unsigned int shift = mc->shift; | ||
902 | unsigned int mask = 1 << shift; | ||
903 | unsigned int invert = mc->invert != 0; | ||
904 | unsigned int val; | ||
905 | int ret; | ||
906 | |||
907 | ret = snd_soc_component_read(component, reg, &val); | ||
908 | if (ret) | ||
909 | return ret; | ||
910 | |||
911 | val &= mask; | ||
912 | |||
913 | if (shift != 0 && val != 0) | ||
914 | val = val >> shift; | ||
915 | ucontrol->value.enumerated.item[0] = val ^ invert; | ||
916 | |||
917 | return 0; | ||
918 | } | ||
919 | EXPORT_SYMBOL_GPL(snd_soc_get_strobe); | ||
920 | |||
921 | /** | ||
922 | * snd_soc_put_strobe - strobe put callback | ||
923 | * @kcontrol: mixer control | ||
924 | * @ucontrol: control element information | ||
925 | * | ||
926 | * Callback strobe a register bit to high then low (or the inverse) | ||
927 | * in one pass of a single mixer enum control. | ||
928 | * | ||
929 | * Returns 1 for success. | ||
930 | */ | ||
931 | int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, | ||
932 | struct snd_ctl_elem_value *ucontrol) | ||
933 | { | ||
934 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
935 | struct soc_mixer_control *mc = | ||
936 | (struct soc_mixer_control *)kcontrol->private_value; | ||
937 | unsigned int reg = mc->reg; | ||
938 | unsigned int shift = mc->shift; | ||
939 | unsigned int mask = 1 << shift; | ||
940 | unsigned int invert = mc->invert != 0; | ||
941 | unsigned int strobe = ucontrol->value.enumerated.item[0] != 0; | ||
942 | unsigned int val1 = (strobe ^ invert) ? mask : 0; | ||
943 | unsigned int val2 = (strobe ^ invert) ? 0 : mask; | ||
944 | int err; | ||
945 | |||
946 | err = snd_soc_component_update_bits(component, reg, mask, val1); | ||
947 | if (err < 0) | ||
948 | return err; | ||
949 | |||
950 | return snd_soc_component_update_bits(component, reg, mask, val2); | ||
951 | } | ||
952 | EXPORT_SYMBOL_GPL(snd_soc_put_strobe); | ||
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 57277dd79e11..eb87d96e2cf0 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -654,6 +654,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
654 | codec_dai->rate = 0; | 654 | codec_dai->rate = 0; |
655 | } | 655 | } |
656 | 656 | ||
657 | snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream); | ||
658 | |||
657 | if (cpu_dai->driver->ops->shutdown) | 659 | if (cpu_dai->driver->ops->shutdown) |
658 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 660 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
659 | 661 | ||
@@ -772,6 +774,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
772 | for (i = 0; i < rtd->num_codecs; i++) | 774 | for (i = 0; i < rtd->num_codecs; i++) |
773 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, | 775 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, |
774 | substream->stream); | 776 | substream->stream); |
777 | snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); | ||
775 | 778 | ||
776 | out: | 779 | out: |
777 | mutex_unlock(&rtd->pcm_mutex); | 780 | mutex_unlock(&rtd->pcm_mutex); |
@@ -1664,6 +1667,10 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) | |||
1664 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | 1667 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) |
1665 | continue; | 1668 | continue; |
1666 | 1669 | ||
1670 | /* do not free hw if this BE is used by other FE */ | ||
1671 | if (be->dpcm[stream].users > 1) | ||
1672 | continue; | ||
1673 | |||
1667 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | 1674 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && |
1668 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && | 1675 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && |
1669 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | 1676 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && |
@@ -2288,7 +2295,13 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) | |||
2288 | fe->dai_link->name); | 2295 | fe->dai_link->name); |
2289 | 2296 | ||
2290 | /* skip if FE doesn't have playback capability */ | 2297 | /* skip if FE doesn't have playback capability */ |
2291 | if (!fe->cpu_dai->driver->playback.channels_min) | 2298 | if (!fe->cpu_dai->driver->playback.channels_min |
2299 | || !fe->codec_dai->driver->playback.channels_min) | ||
2300 | goto capture; | ||
2301 | |||
2302 | /* skip if FE isn't currently playing */ | ||
2303 | if (!fe->cpu_dai->playback_active | ||
2304 | || !fe->codec_dai->playback_active) | ||
2292 | goto capture; | 2305 | goto capture; |
2293 | 2306 | ||
2294 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); | 2307 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); |
@@ -2318,7 +2331,13 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) | |||
2318 | dpcm_path_put(&list); | 2331 | dpcm_path_put(&list); |
2319 | capture: | 2332 | capture: |
2320 | /* skip if FE doesn't have capture capability */ | 2333 | /* skip if FE doesn't have capture capability */ |
2321 | if (!fe->cpu_dai->driver->capture.channels_min) | 2334 | if (!fe->cpu_dai->driver->capture.channels_min |
2335 | || !fe->codec_dai->driver->capture.channels_min) | ||
2336 | continue; | ||
2337 | |||
2338 | /* skip if FE isn't currently capturing */ | ||
2339 | if (!fe->cpu_dai->capture_active | ||
2340 | || !fe->codec_dai->capture_active) | ||
2322 | continue; | 2341 | continue; |
2323 | 2342 | ||
2324 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); | 2343 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); |
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 3b0fa12dbff7..29a9957d335a 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c | |||
@@ -228,7 +228,7 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai) | |||
228 | 228 | ||
229 | static struct snd_soc_dai_driver tegra20_ac97_dai = { | 229 | static struct snd_soc_dai_driver tegra20_ac97_dai = { |
230 | .name = "tegra-ac97-pcm", | 230 | .name = "tegra-ac97-pcm", |
231 | .ac97_control = 1, | 231 | .bus_control = true, |
232 | .probe = tegra20_ac97_probe, | 232 | .probe = tegra20_ac97_probe, |
233 | .playback = { | 233 | .playback = { |
234 | .stream_name = "PCM Playback", | 234 | .stream_name = "PCM Playback", |
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index a6898831fb9f..4ebe3871e610 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c | |||
@@ -44,6 +44,7 @@ | |||
44 | struct tegra_rt5640 { | 44 | struct tegra_rt5640 { |
45 | struct tegra_asoc_utils_data util_data; | 45 | struct tegra_asoc_utils_data util_data; |
46 | int gpio_hp_det; | 46 | int gpio_hp_det; |
47 | enum of_gpio_flags gpio_hp_det_flags; | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream, | 50 | static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream, |
@@ -119,6 +120,8 @@ static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd) | |||
119 | 120 | ||
120 | if (gpio_is_valid(machine->gpio_hp_det)) { | 121 | if (gpio_is_valid(machine->gpio_hp_det)) { |
121 | tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det; | 122 | tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det; |
123 | tegra_rt5640_hp_jack_gpio.invert = | ||
124 | !!(machine->gpio_hp_det_flags & OF_GPIO_ACTIVE_LOW); | ||
122 | snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack, | 125 | snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack, |
123 | 1, | 126 | 1, |
124 | &tegra_rt5640_hp_jack_gpio); | 127 | &tegra_rt5640_hp_jack_gpio); |
@@ -180,7 +183,8 @@ static int tegra_rt5640_probe(struct platform_device *pdev) | |||
180 | platform_set_drvdata(pdev, card); | 183 | platform_set_drvdata(pdev, card); |
181 | snd_soc_card_set_drvdata(card, machine); | 184 | snd_soc_card_set_drvdata(card, machine); |
182 | 185 | ||
183 | machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); | 186 | machine->gpio_hp_det = of_get_named_gpio_flags( |
187 | np, "nvidia,hp-det-gpios", 0, &machine->gpio_hp_det_flags); | ||
184 | if (machine->gpio_hp_det == -EPROBE_DEFER) | 188 | if (machine->gpio_hp_det == -EPROBE_DEFER) |
185 | return -EPROBE_DEFER; | 189 | return -EPROBE_DEFER; |
186 | 190 | ||
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index 9edd68db9f48..f7135cdaa2ca 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c | |||
@@ -152,7 +152,7 @@ static int txx9aclc_ac97_remove(struct snd_soc_dai *dai) | |||
152 | } | 152 | } |
153 | 153 | ||
154 | static struct snd_soc_dai_driver txx9aclc_ac97_dai = { | 154 | static struct snd_soc_dai_driver txx9aclc_ac97_dai = { |
155 | .ac97_control = 1, | 155 | .bus_control = true, |
156 | .probe = txx9aclc_ac97_probe, | 156 | .probe = txx9aclc_ac97_probe, |
157 | .remove = txx9aclc_ac97_remove, | 157 | .remove = txx9aclc_ac97_remove, |
158 | .playback = { | 158 | .playback = { |
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index cd71fd889d8b..00b7e2d02690 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c | |||
@@ -292,7 +292,7 @@ static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
292 | struct snd_card *card = rtd->card->snd_card; | 292 | struct snd_card *card = rtd->card->snd_card; |
293 | struct snd_soc_dai *dai = rtd->cpu_dai; | 293 | struct snd_soc_dai *dai = rtd->cpu_dai; |
294 | struct snd_pcm *pcm = rtd->pcm; | 294 | struct snd_pcm *pcm = rtd->pcm; |
295 | struct platform_device *pdev = to_platform_device(dai->platform->dev); | 295 | struct platform_device *pdev = to_platform_device(rtd->platform->dev); |
296 | struct txx9aclc_soc_device *dev; | 296 | struct txx9aclc_soc_device *dev; |
297 | struct resource *r; | 297 | struct resource *r; |
298 | int i; | 298 | int i; |
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index b3b66aa98dce..9f2d045ee118 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c | |||
@@ -63,12 +63,8 @@ static void mop500_of_node_put(void) | |||
63 | int i; | 63 | int i; |
64 | 64 | ||
65 | for (i = 0; i < 2; i++) { | 65 | for (i = 0; i < 2; i++) { |
66 | if (mop500_dai_links[i].cpu_of_node) | 66 | of_node_put(mop500_dai_links[i].cpu_of_node); |
67 | of_node_put((struct device_node *) | 67 | of_node_put(mop500_dai_links[i].codec_of_node); |
68 | mop500_dai_links[i].cpu_of_node); | ||
69 | if (mop500_dai_links[i].codec_of_node) | ||
70 | of_node_put((struct device_node *) | ||
71 | mop500_dai_links[i].codec_of_node); | ||
72 | } | 68 | } |
73 | } | 69 | } |
74 | 70 | ||