aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2014-05-22 18:14:53 -0400
committerMark Brown <broonie@linaro.org>2014-05-26 09:32:34 -0400
commitfb6b8e71448aef58628eb9da007c30e731925260 (patch)
treeef47b51e3386916a0517615b299caaf6c4a0d3fb /sound
parentc9eaa447e77efe77b7fa4c953bd62de8297fd6c5 (diff)
ASoC: tegra: free jack GPIOs before the sound card is freed
snd_soc_jack_add_gpios() schedules a work queue item to poll the GPIO to generate an initial jack status report. If sound card initialization fails, that work item needs to be cancelled, so it doesn't run after the card has been freed. Specifically, freeing the card calls snd_jack_dev_free() which calls snd_jack_dev_disconnect() which sets jack->input_dev = NULL, and input_dev is used by snd_jack_report(), which is called from the work queue item. snd_soc_jack_free_gpios() cancels the work item. The Tegra ASoC machine drivers do call this function in the platform driver remove() callback. However, this happens after the sound card is freed, at least when the card is freed due to errors late during snd_soc_instantiate_card(). This leaves a window where the work item can execute after the card is freed. In next-20140522, sound card initialization does fail for unrelated reasons, and hits the problem described above. To solve this, fix the Tegra ASoC machine drivers to clean up the Jack GPIOs during the snd_soc_card's .remove() callback, which is executed before the overall card object is freed. also, gGuard the cleanup call based on whether we actually setup up the GPIOs in the first place. Ideally, we'd do the cleanup in a struct snd_soc_dai_link .fini/remove function to match where the GPIOs get set up. However, there is no such callback. This change fixes all Tegra machine drivers. By code inspection, I believe some non-Tegra machine drivers have the same issue. I'll send a patch for that separately, once this is reviewed. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/tegra/tegra_alc5632.c16
-rw-r--r--sound/soc/tegra/tegra_max98090.c16
-rw-r--r--sound/soc/tegra/tegra_rt5640.c16
-rw-r--r--sound/soc/tegra/tegra_wm8903.c11
4 files changed, 45 insertions, 14 deletions
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index c61ea3a1030f..02734bd4f09b 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -125,6 +125,18 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
125 return 0; 125 return 0;
126} 126}
127 127
128static int tegra_alc5632_card_remove(struct snd_soc_card *card)
129{
130 struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
131
132 if (gpio_is_valid(machine->gpio_hp_det)) {
133 snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1,
134 &tegra_alc5632_hp_jack_gpio);
135 }
136
137 return 0;
138}
139
128static struct snd_soc_dai_link tegra_alc5632_dai = { 140static struct snd_soc_dai_link tegra_alc5632_dai = {
129 .name = "ALC5632", 141 .name = "ALC5632",
130 .stream_name = "ALC5632 PCM", 142 .stream_name = "ALC5632 PCM",
@@ -139,6 +151,7 @@ static struct snd_soc_dai_link tegra_alc5632_dai = {
139static struct snd_soc_card snd_soc_tegra_alc5632 = { 151static struct snd_soc_card snd_soc_tegra_alc5632 = {
140 .name = "tegra-alc5632", 152 .name = "tegra-alc5632",
141 .owner = THIS_MODULE, 153 .owner = THIS_MODULE,
154 .remove = tegra_alc5632_card_remove,
142 .dai_link = &tegra_alc5632_dai, 155 .dai_link = &tegra_alc5632_dai,
143 .num_links = 1, 156 .num_links = 1,
144 .controls = tegra_alc5632_controls, 157 .controls = tegra_alc5632_controls,
@@ -223,9 +236,6 @@ static int tegra_alc5632_remove(struct platform_device *pdev)
223 struct snd_soc_card *card = platform_get_drvdata(pdev); 236 struct snd_soc_card *card = platform_get_drvdata(pdev);
224 struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card); 237 struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
225 238
226 snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1,
227 &tegra_alc5632_hp_jack_gpio);
228
229 snd_soc_unregister_card(card); 239 snd_soc_unregister_card(card);
230 240
231 tegra_asoc_utils_fini(&machine->util_data); 241 tegra_asoc_utils_fini(&machine->util_data);
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
index 0283cfb7c031..ce73e1f62c4b 100644
--- a/sound/soc/tegra/tegra_max98090.c
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -145,6 +145,18 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
145 return 0; 145 return 0;
146} 146}
147 147
148static int tegra_max98090_card_remove(struct snd_soc_card *card)
149{
150 struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
151
152 if (gpio_is_valid(machine->gpio_hp_det)) {
153 snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
154 &tegra_max98090_hp_jack_gpio);
155 }
156
157 return 0;
158}
159
148static struct snd_soc_dai_link tegra_max98090_dai = { 160static struct snd_soc_dai_link tegra_max98090_dai = {
149 .name = "max98090", 161 .name = "max98090",
150 .stream_name = "max98090 PCM", 162 .stream_name = "max98090 PCM",
@@ -158,6 +170,7 @@ static struct snd_soc_dai_link tegra_max98090_dai = {
158static struct snd_soc_card snd_soc_tegra_max98090 = { 170static struct snd_soc_card snd_soc_tegra_max98090 = {
159 .name = "tegra-max98090", 171 .name = "tegra-max98090",
160 .owner = THIS_MODULE, 172 .owner = THIS_MODULE,
173 .remove = tegra_max98090_card_remove,
161 .dai_link = &tegra_max98090_dai, 174 .dai_link = &tegra_max98090_dai,
162 .num_links = 1, 175 .num_links = 1,
163 .controls = tegra_max98090_controls, 176 .controls = tegra_max98090_controls,
@@ -241,9 +254,6 @@ static int tegra_max98090_remove(struct platform_device *pdev)
241 struct snd_soc_card *card = platform_get_drvdata(pdev); 254 struct snd_soc_card *card = platform_get_drvdata(pdev);
242 struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card); 255 struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
243 256
244 snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
245 &tegra_max98090_hp_jack_gpio);
246
247 snd_soc_unregister_card(card); 257 snd_soc_unregister_card(card);
248 258
249 tegra_asoc_utils_fini(&machine->util_data); 259 tegra_asoc_utils_fini(&machine->util_data);
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index 4511c5a875ec..4feb16a99e02 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -128,6 +128,18 @@ static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd)
128 return 0; 128 return 0;
129} 129}
130 130
131static int tegra_rt5640_card_remove(struct snd_soc_card *card)
132{
133 struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
134
135 if (gpio_is_valid(machine->gpio_hp_det)) {
136 snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1,
137 &tegra_rt5640_hp_jack_gpio);
138 }
139
140 return 0;
141}
142
131static struct snd_soc_dai_link tegra_rt5640_dai = { 143static struct snd_soc_dai_link tegra_rt5640_dai = {
132 .name = "RT5640", 144 .name = "RT5640",
133 .stream_name = "RT5640 PCM", 145 .stream_name = "RT5640 PCM",
@@ -141,6 +153,7 @@ static struct snd_soc_dai_link tegra_rt5640_dai = {
141static struct snd_soc_card snd_soc_tegra_rt5640 = { 153static struct snd_soc_card snd_soc_tegra_rt5640 = {
142 .name = "tegra-rt5640", 154 .name = "tegra-rt5640",
143 .owner = THIS_MODULE, 155 .owner = THIS_MODULE,
156 .remove = tegra_rt5640_card_remove,
144 .dai_link = &tegra_rt5640_dai, 157 .dai_link = &tegra_rt5640_dai,
145 .num_links = 1, 158 .num_links = 1,
146 .controls = tegra_rt5640_controls, 159 .controls = tegra_rt5640_controls,
@@ -224,9 +237,6 @@ static int tegra_rt5640_remove(struct platform_device *pdev)
224 struct snd_soc_card *card = platform_get_drvdata(pdev); 237 struct snd_soc_card *card = platform_get_drvdata(pdev);
225 struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); 238 struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
226 239
227 snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1,
228 &tegra_rt5640_hp_jack_gpio);
229
230 snd_soc_unregister_card(card); 240 snd_soc_unregister_card(card);
231 241
232 tegra_asoc_utils_fini(&machine->util_data); 242 tegra_asoc_utils_fini(&machine->util_data);
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 4ac73730d79a..0939661df60b 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -206,6 +206,12 @@ static int tegra_wm8903_remove(struct snd_soc_card *card)
206 struct snd_soc_pcm_runtime *rtd = &(card->rtd[0]); 206 struct snd_soc_pcm_runtime *rtd = &(card->rtd[0]);
207 struct snd_soc_dai *codec_dai = rtd->codec_dai; 207 struct snd_soc_dai *codec_dai = rtd->codec_dai;
208 struct snd_soc_codec *codec = codec_dai->codec; 208 struct snd_soc_codec *codec = codec_dai->codec;
209 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
210
211 if (gpio_is_valid(machine->gpio_hp_det)) {
212 snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1,
213 &tegra_wm8903_hp_jack_gpio);
214 }
209 215
210 wm8903_mic_detect(codec, NULL, 0, 0); 216 wm8903_mic_detect(codec, NULL, 0, 0);
211 217
@@ -228,9 +234,7 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = {
228 .owner = THIS_MODULE, 234 .owner = THIS_MODULE,
229 .dai_link = &tegra_wm8903_dai, 235 .dai_link = &tegra_wm8903_dai,
230 .num_links = 1, 236 .num_links = 1,
231
232 .remove = tegra_wm8903_remove, 237 .remove = tegra_wm8903_remove,
233
234 .controls = tegra_wm8903_controls, 238 .controls = tegra_wm8903_controls,
235 .num_controls = ARRAY_SIZE(tegra_wm8903_controls), 239 .num_controls = ARRAY_SIZE(tegra_wm8903_controls),
236 .dapm_widgets = tegra_wm8903_dapm_widgets, 240 .dapm_widgets = tegra_wm8903_dapm_widgets,
@@ -368,9 +372,6 @@ static int tegra_wm8903_driver_remove(struct platform_device *pdev)
368 struct snd_soc_card *card = platform_get_drvdata(pdev); 372 struct snd_soc_card *card = platform_get_drvdata(pdev);
369 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 373 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
370 374
371 snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1,
372 &tegra_wm8903_hp_jack_gpio);
373
374 snd_soc_unregister_card(card); 375 snd_soc_unregister_card(card);
375 376
376 tegra_asoc_utils_fini(&machine->util_data); 377 tegra_asoc_utils_fini(&machine->util_data);