From fd23b7dee5e4d369f620979cb120f53629389355 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 19 Mar 2010 14:52:55 +0000 Subject: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream This fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start. All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused. Reported-by: Sven Neumann Reported-by: Michael Hirsch Signed-off-by: Daniel Mack Acked-by: Peter Ujfalusi Acked-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 23 ++++++++++++----------- sound/soc/pxa/pxa2xx-ac97.c | 17 ++++++++++++----- sound/soc/pxa/pxa2xx-i2s.c | 7 +++++-- sound/soc/pxa/pxa2xx-pcm.c | 4 +++- 4 files changed, 32 insertions(+), 19 deletions(-) (limited to 'sound/soc/pxa') diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index e69397f40f72..5d65a00e4bc0 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -103,10 +103,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, ssp_disable(&priv->dev); } - if (cpu_dai->dma_data) { - kfree(cpu_dai->dma_data); - cpu_dai->dma_data = NULL; - } + kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); + snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); + return ret; } @@ -122,10 +121,8 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, clk_disable(priv->dev.ssp->clk); } - if (cpu_dai->dma_data) { - kfree(cpu_dai->dma_data); - cpu_dai->dma_data = NULL; - } + kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); + snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); } #ifdef CONFIG_PM @@ -538,19 +535,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, u32 sspsp; int width = snd_pcm_format_physical_width(params_format(params)); int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf; + struct pxa2xx_pcm_dma_params *dma_data; + + dma_data = snd_soc_dai_get_dma_data(dai, substream); /* generate correct DMA params */ - if (cpu_dai->dma_data) - kfree(cpu_dai->dma_data); + kfree(dma_data); /* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - cpu_dai->dma_data = ssp_get_dma_params(ssp, + dma_data = ssp_get_dma_params(ssp, ((chn == 2) && (ttsa != 1)) || (width == 32), substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_dma_data(dai, substream, dma_data); + /* we can only change the settings if the port is not in use */ if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) return 0; diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index e9ae7b3a7e00..d314115e3dd7 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -122,11 +122,14 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct pxa2xx_pcm_dma_params *dma_data; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; + dma_data = &pxa2xx_ac97_pcm_stereo_out; else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; + dma_data = &pxa2xx_ac97_pcm_stereo_in; + + snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); return 0; } @@ -137,11 +140,14 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct pxa2xx_pcm_dma_params *dma_data; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; + dma_data = &pxa2xx_ac97_pcm_aux_mono_out; else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + + snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); return 0; } @@ -156,7 +162,8 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) return -ENODEV; else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; + snd_soc_dai_set_dma_data(cpu_dai, substream, + &pxa2xx_ac97_pcm_mic_mono_in); return 0; } diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 6b8f655d1ad8..c1a5275721e4 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -164,6 +164,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct pxa2xx_pcm_dma_params *dma_data; BUG_ON(IS_ERR(clk_i2s)); clk_enable(clk_i2s); @@ -171,9 +172,11 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, pxa_i2s_wait(); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + dma_data = &pxa2xx_i2s_pcm_stereo_out; else - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + dma_data = &pxa2xx_i2s_pcm_stereo_in; + + snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); /* is port used by another stream */ if (!(SACR0 & SACR0_ENB)) { diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index d38e39575f51..adc7e6f15f93 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -25,9 +25,11 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct pxa2xx_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; + struct pxa2xx_pcm_dma_params *dma; int ret; + dma = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); + /* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma) -- cgit v1.2.3 From 6ca0c22ef8a4e988e2487d25964d55e6c37c5785 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 8 Apr 2010 20:48:51 +0200 Subject: ASoC: WM8750: Convert to new API Register the WM8750 as a SPI or I2C device. This patch mostly shuffles code around. Hugely inspired by WM8753 which was already converted. Also, this patch fixes the Jive and Spitz machine. Signed-off-by: Marek Vasut Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/pxa/spitz.c | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) (limited to 'sound/soc/pxa') diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index c4cd2acaacb4..1941a357e8c4 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -322,19 +322,44 @@ static struct snd_soc_card snd_soc_spitz = { .num_links = 1, }; -/* spitz audio private data */ -static struct wm8750_setup_data spitz_wm8750_setup = { - .i2c_bus = 0, - .i2c_address = 0x1b, -}; - /* spitz audio subsystem */ static struct snd_soc_device spitz_snd_devdata = { .card = &snd_soc_spitz, .codec_dev = &soc_codec_dev_wm8750, - .codec_data = &spitz_wm8750_setup, }; +/* + * FIXME: This is a temporary bodge to avoid cross-tree merge issues. + * New drivers should register the wm8750 I2C device in the machine + * setup code (under arch/arm for ARM systems). + */ +static int wm8750_i2c_register(void) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = 0x1b; + strlcpy(info.type, "wm8750", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(0); + if (!adapter) { + printk(KERN_ERR "can't get i2c adapter 0\n"); + return -ENODEV; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + printk(KERN_ERR "can't add i2c device at 0x%x\n", + (unsigned int)info.addr); + return -ENODEV; + } + + return 0; +} + static struct platform_device *spitz_snd_device; static int __init spitz_init(void) @@ -344,6 +369,10 @@ static int __init spitz_init(void) if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita())) return -ENODEV; + ret = wm8750_i2c_setup(); + if (ret != 0) + return ret; + spitz_snd_device = platform_device_alloc("soc-audio", -1); if (!spitz_snd_device) return -ENOMEM; -- cgit v1.2.3 From d21e0f4cd16656f71207683ee27465600ad21625 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 5 Apr 2010 06:13:38 +0200 Subject: ASoC: Zipit Z2 WM8750 ASoC driver This patch adds support for sound through the WM8750 codec on Zipit Z2. Also, this patch incorporates support for detecting headset jack insertion through the jack detection API. Signed-off-by: Marek Vasut Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 8 ++ sound/soc/pxa/Makefile | 2 + sound/soc/pxa/z2.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100644 sound/soc/pxa/z2.c (limited to 'sound/soc/pxa') diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 376e14a9c273..495a36fba360 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -42,6 +42,14 @@ config SND_PXA2XX_SOC_SPITZ Say Y if you want to add support for SoC audio on Sharp Zaurus SL-Cxx00 models (Spitz, Borzoi and Akita). +config SND_PXA2XX_SOC_Z2 + tristate "SoC Audio support for Zipit Z2" + depends on SND_PXA2XX_SOC && MACH_ZIPIT2 + select SND_PXA2XX_SOC_I2S + select SND_SOC_WM8750 + help + Say Y if you want to add support for SoC audio on Zipit Z2. + config SND_PXA2XX_SOC_POODLE tristate "SoC Audio support for Poodle" depends on SND_PXA2XX_SOC && MACH_POODLE diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index f3e08fd40ca2..caa03d8f4789 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -22,6 +22,7 @@ snd-soc-palm27x-objs := palm27x.o snd-soc-zylonite-objs := zylonite.o snd-soc-magician-objs := magician.o snd-soc-mioa701-objs := mioa701_wm9713.o +snd-soc-z2-objs := z2.o snd-soc-imote2-objs := imote2.o snd-soc-raumfeld-objs := raumfeld.o @@ -36,6 +37,7 @@ obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o +obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c new file mode 100644 index 000000000000..4e4d2fa8ddc5 --- /dev/null +++ b/sound/soc/pxa/z2.c @@ -0,0 +1,246 @@ +/* + * linux/sound/soc/pxa/z2.c + * + * SoC Audio driver for Aeronix Zipit Z2 + * + * Copyright (C) 2009 Ken McGuire + * Copyright (C) 2010 Marek Vasut + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../codecs/wm8750.h" +#include "pxa2xx-pcm.h" +#include "pxa2xx-i2s.h" + +static struct snd_soc_card snd_soc_z2; + +static int z2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int clk = 0; + int ret = 0; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + clk = 12288000; + break; + case 11025: + case 22050: + case 44100: + clk = 11289600; + break; + } + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* set the I2S system clock as input (unused) */ + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_jack hs_jack; + +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin hs_jack_pins[] = { + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, +}; + +/* Headset jack detection gpios */ +static struct snd_soc_jack_gpio hs_jack_gpios[] = { + { + .gpio = GPIO37_ZIPITZ2_HEADSET_DETECT, + .name = "hsdet-gpio", + .report = SND_JACK_HEADSET, + .debounce_time = 200, + }, +}; + +/* z2 machine dapm widgets */ +static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + + /* headset is a mic and mono headphone */ + SND_SOC_DAPM_HP("Headset Jack", NULL), +}; + +/* Z2 machine audio_map */ +static const struct snd_soc_dapm_route audio_map[] = { + + /* headphone connected to LOUT1, ROUT1 */ + {"Headphone Jack", NULL, "LOUT1"}, + {"Headphone Jack", NULL, "ROUT1"}, + + /* ext speaker connected to LOUT2, ROUT2 */ + {"Ext Spk", NULL , "ROUT2"}, + {"Ext Spk", NULL , "LOUT2"}, + + /* mic is connected to R input 2 - with bias */ + {"RINPUT2", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Mic Jack"}, +}; + +/* + * Logic for a wm8750 as connected on a Z2 Device + */ +static int z2_wm8750_init(struct snd_soc_codec *codec) +{ + int ret; + + /* NC codec pins */ + snd_soc_dapm_disable_pin(codec, "LINPUT3"); + snd_soc_dapm_disable_pin(codec, "RINPUT3"); + snd_soc_dapm_disable_pin(codec, "OUT3"); + snd_soc_dapm_disable_pin(codec, "MONO"); + + /* Add z2 specific widgets */ + snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, + ARRAY_SIZE(wm8750_dapm_widgets)); + + /* Set up z2 specific audio paths */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + ret = snd_soc_dapm_sync(codec); + if (ret) + goto err; + + /* Jack detection API stuff */ + ret = snd_soc_jack_new(&snd_soc_z2, "Headset Jack", SND_JACK_HEADSET, + &hs_jack); + if (ret) + goto err; + + ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), + hs_jack_pins); + if (ret) + goto err; + + ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), + hs_jack_gpios); + if (ret) + goto err; + + return 0; + +err: + return ret; +} + +static struct snd_soc_ops z2_ops = { + .hw_params = z2_hw_params, +}; + +/* z2 digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link z2_dai = { + .name = "wm8750", + .stream_name = "WM8750", + .cpu_dai = &pxa_i2s_dai, + .codec_dai = &wm8750_dai, + .init = z2_wm8750_init, + .ops = &z2_ops, +}; + +/* z2 audio machine driver */ +static struct snd_soc_card snd_soc_z2 = { + .name = "Z2", + .platform = &pxa2xx_soc_platform, + .dai_link = &z2_dai, + .num_links = 1, +}; + +/* z2 audio subsystem */ +static struct snd_soc_device z2_snd_devdata = { + .card = &snd_soc_z2, + .codec_dev = &soc_codec_dev_wm8750, +}; + +static struct platform_device *z2_snd_device; + +static int __init z2_init(void) +{ + int ret; + + if (!machine_is_zipit2()) + return -ENODEV; + + z2_snd_device = platform_device_alloc("soc-audio", -1); + if (!z2_snd_device) + return -ENOMEM; + + platform_set_drvdata(z2_snd_device, &z2_snd_devdata); + z2_snd_devdata.dev = &z2_snd_device->dev; + ret = platform_device_add(z2_snd_device); + + if (ret) + platform_device_put(z2_snd_device); + + return ret; +} + +static void __exit z2_exit(void) +{ + platform_device_unregister(z2_snd_device); +} + +module_init(z2_init); +module_exit(z2_exit); + +MODULE_AUTHOR("Ken McGuire , " + "Marek Vasut "); +MODULE_DESCRIPTION("ALSA SoC ZipitZ2"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3