[alsa-devel] [PATCH 1/5] soc - Support PXA3xx AC97
The PXA3xx does not support the use of interrupts during reset and access to the GPIO status requires similar handling to that for PXA27x.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/pxa/pxa2xx-ac97.c | 29 +++++++++++++++++++++++++++-- 1 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 815c153..95ae509 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -55,7 +55,7 @@ static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, mutex_lock(&car_mutex);
/* set up primary or secondary codec/modem space */ -#ifdef CONFIG_PXA27x +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; #else if (reg == AC97_GPIO_STATUS) @@ -105,7 +105,7 @@ static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, mutex_lock(&car_mutex);
/* set up primary or secondary codec/modem space */ -#ifdef CONFIG_PXA27x +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; #else if (reg == AC97_GPIO_STATUS) @@ -128,6 +128,9 @@ static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) { +#ifdef CONFIG_PXA3xx + int timeout = 100; +#endif gsr_bits = 0;
#ifdef CONFIG_PXA27x @@ -138,6 +141,11 @@ static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) GCR |= GCR_WARM_RST; pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); udelay(500); +#elif defined(CONFIG_PXA3xx) + /* Can't use interrupts */ + GCR |= GCR_WARM_RST; + while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(1); #else GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN; wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); @@ -153,6 +161,16 @@ static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) { +#ifdef CONFIG_PXA3xx + int timeout = 1000; + + /* Hold CLKBPB for 100us */ + GCR = 0; + GCR = GCR_CLKBPB; + udelay(100); + GCR = 0; +#endif + GCR &= GCR_COLD_RST; /* clear everything but nCRST */ GCR &= ~GCR_COLD_RST; /* then assert nCRST */
@@ -164,6 +182,13 @@ static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) pxa_set_cken(CKEN_AC97CONF, 0); GCR = GCR_COLD_RST; udelay(50); +#elif defined(CONFIG_PXA3xx) + /* Can't use interrupts on PXA3xx */ + GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); + + GCR = GCR_WARM_RST | GCR_COLD_RST; + while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(10); #else GCR = GCR_COLD_RST; GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/arm/pxa2xx-ac97.c | 24 ++++++++++++++++++++++++ 1 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index cfea4eb..355ce28 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -106,6 +106,16 @@ static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigne static void pxa2xx_ac97_reset(struct snd_ac97 *ac97) { /* First, try cold reset */ +#ifdef CONFIG_PXA3xx + int timeout; + + /* Hold CLKBPB for 100us */ + GCR = 0; + GCR = GCR_CLKBPB; + udelay(100); + GCR = 0; +#endif + GCR &= GCR_COLD_RST; /* clear everything but nCRST */ GCR &= ~GCR_COLD_RST; /* then assert nCRST */
@@ -117,6 +127,14 @@ static void pxa2xx_ac97_reset(struct snd_ac97 *ac97) pxa_set_cken(CKEN_AC97CONF, 0); GCR = GCR_COLD_RST; udelay(50); +#elif defined(CONFIG_PXA3xx) + timeout = 1000; + /* Can't use interrupts on PXA3xx */ + GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); + + GCR = GCR_WARM_RST | GCR_COLD_RST; + while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(10); #else GCR = GCR_COLD_RST; GCR |= GCR_CDONE_IE|GCR_SDONE_IE; @@ -137,6 +155,12 @@ static void pxa2xx_ac97_reset(struct snd_ac97 *ac97) GCR |= GCR_WARM_RST; pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); udelay(500); +#elif defined(CONFIG_PXA3xx) + timeout = 100; + /* Can't use interrupts */ + GCR |= GCR_WARM_RST; + while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(1); #else GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN; wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
From: Jarkko Nikula jarkko.nikula@nokia.com
Add common OMAP ASoC drivers and machine driver for Nokia N810. Currently supported features are:
- Covers OMAPs from 1510 to 2420 - Common DMA driver - DAI link driver using McBSP port in I2S mode - Basic machine driver for Nokia N810
Signed-off-by: Jarkko Nikula jarkko.nikula@nokia.com Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 2 +- sound/soc/omap/Kconfig | 19 ++ sound/soc/omap/Makefile | 11 ++ sound/soc/omap/n810.c | 336 +++++++++++++++++++++++++++++++++++ sound/soc/omap/omap-mcbsp.c | 414 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/omap/omap-mcbsp.h | 49 +++++ sound/soc/omap/omap-pcm.c | 357 +++++++++++++++++++++++++++++++++++++ sound/soc/omap/omap-pcm.h | 35 ++++ 9 files changed, 1223 insertions(+), 1 deletions(-) create mode 100644 sound/soc/omap/Kconfig create mode 100644 sound/soc/omap/Makefile create mode 100644 sound/soc/omap/n810.c create mode 100644 sound/soc/omap/omap-mcbsp.c create mode 100644 sound/soc/omap/omap-mcbsp.h create mode 100644 sound/soc/omap/omap-pcm.c create mode 100644 sound/soc/omap/omap-pcm.h
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index a3b51df..18f28ac 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -30,6 +30,7 @@ source "sound/soc/s3c24xx/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/fsl/Kconfig" source "sound/soc/davinci/Kconfig" +source "sound/soc/omap/Kconfig"
# Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index e489dbd..782db21 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,4 +1,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o
obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ +obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ omap/ diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig new file mode 100644 index 0000000..0230d83 --- /dev/null +++ b/sound/soc/omap/Kconfig @@ -0,0 +1,19 @@ +menu "SoC Audio for the Texas Instruments OMAP" + +config SND_OMAP_SOC + tristate "SoC Audio for the Texas Instruments OMAP chips" + depends on ARCH_OMAP && SND_SOC + +config SND_OMAP_SOC_MCBSP + tristate + select OMAP_MCBSP + +config SND_OMAP_SOC_N810 + tristate "SoC Audio support for Nokia N810" + depends on SND_OMAP_SOC && MACH_NOKIA_N810 + select SND_OMAP_SOC_MCBSP + select SND_SOC_TLV320AIC3X + help + Say Y if you want to add support for SoC audio on Nokia N810. + +endmenu diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile new file mode 100644 index 0000000..d8d8d58 --- /dev/null +++ b/sound/soc/omap/Makefile @@ -0,0 +1,11 @@ +# OMAP Platform Support +snd-soc-omap-objs := omap-pcm.o +snd-soc-omap-mcbsp-objs := omap-mcbsp.o + +obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o +obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o + +# OMAP Machine Support +snd-soc-n810-objs := n810.o + +obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c new file mode 100644 index 0000000..83b1eb4 --- /dev/null +++ b/sound/soc/omap/n810.c @@ -0,0 +1,336 @@ +/* + * n810.c -- SoC audio for Nokia N810 + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Jarkko Nikula jarkko.nikula@nokia.com + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include <asm/mach-types.h> +#include <asm/arch/hardware.h> +#include <asm/arch/gpio.h> +#include <asm/arch/mcbsp.h> + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/tlv320aic3x.h" + +#define RX44_HEADSET_AMP_GPIO 10 +#define RX44_SPEAKER_AMP_GPIO 101 + +static struct clk *sys_clkout2; +static struct clk *sys_clkout2_src; +static struct clk *func96m_clk; + +static int n810_spk_func; +static int n810_jack_func; + +static void n810_ext_control(struct snd_soc_codec *codec) +{ + snd_soc_dapm_set_endpoint(codec, "Ext Spk", n810_spk_func); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", n810_jack_func); + + snd_soc_dapm_sync_endpoints(codec); +} + +static int n810_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + n810_ext_control(codec); + return clk_enable(sys_clkout2); +} + +static void n810_shutdown(struct snd_pcm_substream *substream) +{ + clk_disable(sys_clkout2); +} + +static int n810_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_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + int err; + + /* Set codec DAI configuration */ + err = codec_dai->dai_ops.set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (err < 0) + return err; + + /* Set cpu DAI configuration */ + err = cpu_dai->dai_ops.set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (err < 0) + return err; + + /* Set the codec system clock for DAC and ADC */ + err = codec_dai->dai_ops.set_sysclk(codec_dai, 0, 12000000, + SND_SOC_CLOCK_IN); + + return err; +} + +static struct snd_soc_ops n810_ops = { + .startup = n810_startup, + .hw_params = n810_hw_params, + .shutdown = n810_shutdown, +}; + +static int n810_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = n810_spk_func; + + return 0; +} + +static int n810_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (n810_spk_func == ucontrol->value.integer.value[0]) + return 0; + + n810_spk_func = ucontrol->value.integer.value[0]; + n810_ext_control(codec); + + return 1; +} + +static int n810_get_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = n810_jack_func; + + return 0; +} + +static int n810_set_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (n810_jack_func == ucontrol->value.integer.value[0]) + return 0; + + n810_jack_func = ucontrol->value.integer.value[0]; + n810_ext_control(codec); + + return 1; +} + +static int n810_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 1); + else + omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 0); + + return 0; +} + +static int n810_jack_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 1); + else + omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 0); + + return 0; +} + +static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), + SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), +}; + +static const char *audio_map[][3] = { + {"Headphone Jack", NULL, "HPLOUT"}, + {"Headphone Jack", NULL, "HPROUT"}, + + {"Ext Spk", NULL, "LLOUT"}, + {"Ext Spk", NULL, "RLOUT"}, +}; + +static const char *spk_function[] = {"Off", "On"}; +static const char *jack_function[] = {"Off", "Headphone"}; +static const struct soc_enum n810_enum[] = { + SOC_ENUM_SINGLE_EXT(2, spk_function), + SOC_ENUM_SINGLE_EXT(3, jack_function), +}; + +static const struct snd_kcontrol_new aic33_n810_controls[] = { + SOC_ENUM_EXT("Speaker Function", n810_enum[0], + n810_get_spk, n810_set_spk), + SOC_ENUM_EXT("Jack Function", n810_enum[1], + n810_get_jack, n810_set_jack), +}; + +static int n810_aic33_init(struct snd_soc_codec *codec) +{ + int i, err; + + /* Not connected */ + snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0); + snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0); + snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0); + + /* Add N810 specific controls */ + for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&aic33_n810_controls[i], codec, NULL)); + if (err < 0) + return err; + } + + /* Add N810 specific widgets */ + for (i = 0; i < ARRAY_SIZE(aic33_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &aic33_dapm_widgets[i]); + + /* Set up N810 specific audio path audio_map */ + for (i = 0; i < ARRAY_SIZE(audio_map); i++) + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + + snd_soc_dapm_sync_endpoints(codec); + + return 0; +} + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link n810_dai = { + .name = "TLV320AIC33", + .stream_name = "AIC33", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &aic3x_dai, + .init = n810_aic33_init, + .ops = &n810_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_n810 = { + .name = "N810", + .dai_link = &n810_dai, + .num_links = 1, +}; + +/* Audio private data */ +static struct aic3x_setup_data n810_aic33_setup = { + .i2c_address = 0x18, +}; + +/* Audio subsystem */ +static struct snd_soc_device n810_snd_devdata = { + .machine = &snd_soc_machine_n810, + .platform = &omap_soc_platform, + .codec_dev = &soc_codec_dev_aic3x, + .codec_data = &n810_aic33_setup, +}; + +static struct platform_device *n810_snd_device; + +static int __init n810_soc_init(void) +{ + int err; + struct device *dev; + + if (!machine_is_nokia_n810()) + return -ENODEV; + + n810_snd_device = platform_device_alloc("soc-audio", -1); + if (!n810_snd_device) + return -ENOMEM; + + platform_set_drvdata(n810_snd_device, &n810_snd_devdata); + n810_snd_devdata.dev = &n810_snd_device->dev; + *(unsigned int *)n810_dai.cpu_dai->private_data = 1; /* McBSP2 */ + err = platform_device_add(n810_snd_device); + if (err) + goto err1; + + dev = &n810_snd_device->dev; + + sys_clkout2_src = clk_get(dev, "sys_clkout2_src"); + if (IS_ERR(sys_clkout2_src)) { + dev_err(dev, "Could not get sys_clkout2_src clock\n"); + return -ENODEV; + } + sys_clkout2 = clk_get(dev, "sys_clkout2"); + if (IS_ERR(sys_clkout2)) { + dev_err(dev, "Could not get sys_clkout2\n"); + goto err1; + } + /* + * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use + * 96 MHz as its parent in order to get 12 MHz + */ + func96m_clk = clk_get(dev, "func_96m_ck"); + if (IS_ERR(func96m_clk)) { + dev_err(dev, "Could not get func 96M clock\n"); + goto err2; + } + clk_set_parent(sys_clkout2_src, func96m_clk); + clk_set_rate(sys_clkout2, 12000000); + + if (omap_request_gpio(RX44_HEADSET_AMP_GPIO) < 0) + BUG(); + if (omap_request_gpio(RX44_SPEAKER_AMP_GPIO) < 0) + BUG(); + omap_set_gpio_direction(RX44_HEADSET_AMP_GPIO, 0); + omap_set_gpio_direction(RX44_SPEAKER_AMP_GPIO, 0); + + return 0; +err2: + clk_put(sys_clkout2); + platform_device_del(n810_snd_device); +err1: + platform_device_put(n810_snd_device); + + return err; + +} + +static void __exit n810_soc_exit(void) +{ + platform_device_unregister(n810_snd_device); +} + +module_init(n810_soc_init); +module_exit(n810_soc_exit); + +MODULE_AUTHOR("Jarkko Nikula jarkko.nikula@nokia.com"); +MODULE_DESCRIPTION("ALSA SoC Nokia N810"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c new file mode 100644 index 0000000..40d87e6 --- /dev/null +++ b/sound/soc/omap/omap-mcbsp.c @@ -0,0 +1,414 @@ +/* + * omap-mcbsp.c -- OMAP ALSA SoC DAI driver using McBSP port + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Jarkko Nikula jarkko.nikula@nokia.com + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include <asm/arch/control.h> +#include <asm/arch/dma.h> +#include <asm/arch/mcbsp.h> +#include "omap-mcbsp.h" +#include "omap-pcm.h" + +#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_KNOT) + +struct omap_mcbsp_data { + unsigned int bus_id; + struct omap_mcbsp_reg_cfg regs; + /* + * Flags indicating is the bus already activated and configured by + * another substream + */ + int active; + int configured; +}; + +#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id) + +static struct omap_mcbsp_data mcbsp_data[NUM_LINKS]; + +/* + * Stream DMA parameters. DMA request line and port address are set runtime + * since they are different between OMAP1 and later OMAPs + */ +static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = { +{ + { .name = "I2S PCM Stereo out", }, + { .name = "I2S PCM Stereo in", }, +}, +}; + +#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) +static const int omap1_dma_reqs[][2] = { + { OMAP_DMA_MCBSP1_TX, OMAP_DMA_MCBSP1_RX }, + { OMAP_DMA_MCBSP2_TX, OMAP_DMA_MCBSP2_RX }, + { OMAP_DMA_MCBSP3_TX, OMAP_DMA_MCBSP3_RX }, +}; +static const unsigned long omap1_mcbsp_port[][2] = { + { OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1, + OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 }, + { OMAP1510_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1, + OMAP1510_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 }, + { OMAP1510_MCBSP3_BASE + OMAP_MCBSP_REG_DXR1, + OMAP1510_MCBSP3_BASE + OMAP_MCBSP_REG_DRR1 }, +}; +#else +static const int omap1_dma_reqs[][2] = {}; +static const unsigned long omap1_mcbsp_port[][2] = {}; +#endif +#if defined(CONFIG_ARCH_OMAP2420) +static const int omap2420_dma_reqs[][2] = { + { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, + { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, +}; +static const unsigned long omap2420_mcbsp_port[][2] = { + { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1, + OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 }, + { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1, + OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 }, +}; +#else +static const int omap2420_dma_reqs[][2] = {}; +static const unsigned long omap2420_mcbsp_port[][2] = {}; +#endif + +static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + int err = 0; + + if (!cpu_dai->active) + err = omap_mcbsp_request(mcbsp_data->bus_id); + + return err; +} + +static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + + if (!cpu_dai->active) { + omap_mcbsp_free(mcbsp_data->bus_id); + mcbsp_data->configured = 0; + } +} + +static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + int err = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (!mcbsp_data->active++) + omap_mcbsp_start(mcbsp_data->bus_id); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (!--mcbsp_data->active) + omap_mcbsp_stop(mcbsp_data->bus_id); + break; + default: + err = -EINVAL; + } + + return err; +} + +static int omap_mcbsp_dai_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_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; + unsigned long port; + + if (cpu_class_is_omap1()) { + dma = omap1_dma_reqs[bus_id][substream->stream]; + port = omap1_mcbsp_port[bus_id][substream->stream]; + } else if (cpu_is_omap2420()) { + dma = omap2420_dma_reqs[bus_id][substream->stream]; + port = omap2420_mcbsp_port[bus_id][substream->stream]; + } else { + /* + * TODO: Add support for 2430 and 3430 + */ + return -ENODEV; + } + omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; + omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; + cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; + + if (mcbsp_data->configured) { + /* McBSP already configured by another stream */ + return 0; + } + + switch (params_channels(params)) { + case 2: + /* Set 1 word per (McBPSP) frame and use dual-phase frames */ + regs->rcr2 |= RFRLEN2(1 - 1) | RPHASE; + regs->rcr1 |= RFRLEN1(1 - 1); + regs->xcr2 |= XFRLEN2(1 - 1) | XPHASE; + regs->xcr1 |= XFRLEN1(1 - 1); + break; + default: + /* Unsupported number of channels */ + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + /* Set word lengths */ + regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); + regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); + regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); + regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16); + /* Set FS period and length in terms of bit clock periods */ + regs->srgr2 |= FPER(16 * 2 - 1); + regs->srgr1 |= FWID(16 - 1); + break; + default: + /* Unsupported PCM format */ + return -EINVAL; + } + + omap_mcbsp_config(bus_id, &mcbsp_data->regs); + mcbsp_data->configured = 1; + + return 0; +} + +/* + * This must be called before _set_clkdiv and _set_sysclk since McBSP register + * cache is initialized here + */ +static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, + unsigned int fmt) +{ + struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + + if (mcbsp_data->configured) + return 0; + + memset(regs, 0, sizeof(*regs)); + /* Generic McBSP register settings */ + regs->spcr2 |= XINTM(3) | FREE; + regs->spcr1 |= RINTM(3); + regs->rcr2 |= RFIG; + regs->xcr2 |= XFIG; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* 1-bit data delay */ + regs->rcr2 |= RDATDLY(1); + regs->xcr2 |= XDATDLY(1); + break; + default: + /* Unsupported data format */ + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* McBSP master. Set FS and bit clocks as outputs */ + regs->pcr0 |= FSXM | FSRM | + CLKXM | CLKRM; + /* Sample rate generator drives the FS */ + regs->srgr2 |= FSGM; + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* McBSP slave */ + break; + default: + /* Unsupported master/slave configuration */ + return -EINVAL; + } + + /* Set bit clock (CLKX/CLKR) and FS polarities */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + /* + * Normal BCLK + FS. + * FS active low. TX data driven on falling edge of bit clock + * and RX data sampled on rising edge of bit clock. + */ + regs->pcr0 |= FSXP | FSRP | + CLKXP | CLKRP; + break; + case SND_SOC_DAIFMT_NB_IF: + regs->pcr0 |= CLKXP | CLKRP; + break; + case SND_SOC_DAIFMT_IB_NF: + regs->pcr0 |= FSXP | FSRP; + break; + case SND_SOC_DAIFMT_IB_IF: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, + int div_id, int div) +{ + struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + + if (div_id != OMAP_MCBSP_CLKGDV) + return -ENODEV; + + regs->srgr1 |= CLKGDV(div - 1); + + return 0; +} + +static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, + int clk_id) +{ + int sel_bit; + u16 reg; + + if (cpu_class_is_omap1()) { + /* OMAP1's can use only external source clock */ + if (unlikely(clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)) + return -EINVAL; + else + return 0; + } + + switch (mcbsp_data->bus_id) { + case 0: + reg = OMAP2_CONTROL_DEVCONF0; + sel_bit = 2; + break; + case 1: + reg = OMAP2_CONTROL_DEVCONF0; + sel_bit = 6; + break; + /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */ + default: + return -EINVAL; + } + + if (cpu_class_is_omap2()) { + if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) { + omap_ctrl_writel(omap_ctrl_readl(reg) & + ~(1 << sel_bit), reg); + } else { + omap_ctrl_writel(omap_ctrl_readl(reg) | + (1 << sel_bit), reg); + } + } + + return 0; +} + +static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, + int clk_id, unsigned int freq, + int dir) +{ + struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + int err = 0; + + switch (clk_id) { + case OMAP_MCBSP_SYSCLK_CLK: + regs->srgr2 |= CLKSM; + break; + case OMAP_MCBSP_SYSCLK_CLKS_FCLK: + case OMAP_MCBSP_SYSCLK_CLKS_EXT: + err = omap_mcbsp_dai_set_clks_src(mcbsp_data, clk_id); + break; + + case OMAP_MCBSP_SYSCLK_CLKX_EXT: + regs->srgr2 |= CLKSM; + case OMAP_MCBSP_SYSCLK_CLKR_EXT: + regs->pcr0 |= SCLKME; + break; + default: + err = -ENODEV; + } + + return err; +} + +struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS] = { +{ + .name = "omap-mcbsp-dai", + .id = 0, + .type = SND_SOC_DAI_I2S, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = OMAP_MCBSP_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = OMAP_MCBSP_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = { + .startup = omap_mcbsp_dai_startup, + .shutdown = omap_mcbsp_dai_shutdown, + .trigger = omap_mcbsp_dai_trigger, + .hw_params = omap_mcbsp_dai_hw_params, + }, + .dai_ops = { + .set_fmt = omap_mcbsp_dai_set_dai_fmt, + .set_clkdiv = omap_mcbsp_dai_set_clkdiv, + .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, + }, + .private_data = &mcbsp_data[0].bus_id, +}, +}; +EXPORT_SYMBOL_GPL(omap_mcbsp_dai); + +MODULE_AUTHOR("Jarkko Nikula jarkko.nikula@nokia.com"); +MODULE_DESCRIPTION("OMAP I2S SoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h new file mode 100644 index 0000000..9965fd4 --- /dev/null +++ b/sound/soc/omap/omap-mcbsp.h @@ -0,0 +1,49 @@ +/* + * omap-mcbsp.h + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Jarkko Nikula jarkko.nikula@nokia.com + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __OMAP_I2S_H__ +#define __OMAP_I2S_H__ + +/* Source clocks for McBSP sample rate generator */ +enum omap_mcbsp_clksrg_clk { + OMAP_MCBSP_SYSCLK_CLKS_FCLK, /* Internal FCLK */ + OMAP_MCBSP_SYSCLK_CLKS_EXT, /* External CLKS pin */ + OMAP_MCBSP_SYSCLK_CLK, /* Internal ICLK */ + OMAP_MCBSP_SYSCLK_CLKX_EXT, /* External CLKX pin */ + OMAP_MCBSP_SYSCLK_CLKR_EXT, /* External CLKR pin */ +}; + +/* McBSP dividers */ +enum omap_mcbsp_div { + OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */ +}; + +/* + * REVISIT: Preparation for the ASoC v2. Let the number of available links to + * be same than number of McBSP ports found in OMAP(s) we are compiling for. + */ +#define NUM_LINKS 1 + +extern struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS]; + +#endif diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c new file mode 100644 index 0000000..6237020 --- /dev/null +++ b/sound/soc/omap/omap-pcm.c @@ -0,0 +1,357 @@ +/* + * omap-pcm.c -- ALSA PCM interface for the OMAP SoC + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Jarkko Nikula jarkko.nikula@nokia.com + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/dma-mapping.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include <asm/arch/dma.h> +#include "omap-pcm.h" + +static const struct snd_pcm_hardware omap_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = 32, + .period_bytes_max = 64 * 1024, + .periods_min = 2, + .periods_max = 255, + .buffer_bytes_max = 128 * 1024, +}; + +struct omap_runtime_data { + spinlock_t lock; + struct omap_pcm_dma_data *dma_data; + int dma_ch; + int period_index; +}; + +static void omap_pcm_dma_irq(int ch, u16 stat, void *data) +{ + struct snd_pcm_substream *substream = data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct omap_runtime_data *prtd = runtime->private_data; + unsigned long flags; + + if (cpu_is_omap1510()) { + /* + * OMAP1510 doesn't support DMA chaining so have to restart + * the transfer after all periods are transferred + */ + spin_lock_irqsave(&prtd->lock, flags); + if (prtd->period_index >= 0) { + if (++prtd->period_index == runtime->periods) { + prtd->period_index = 0; + omap_start_dma(prtd->dma_ch); + } + } + spin_unlock_irqrestore(&prtd->lock, flags); + } + + snd_pcm_period_elapsed(substream); +} + +/* this may get called several times by oss emulation */ +static int omap_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct omap_runtime_data *prtd = runtime->private_data; + struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; + int err = 0; + + if (!dma_data) + return -ENODEV; + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + if (prtd->dma_data) + return 0; + prtd->dma_data = dma_data; + err = omap_request_dma(dma_data->dma_req, dma_data->name, + omap_pcm_dma_irq, substream, &prtd->dma_ch); + if (!cpu_is_omap1510()) { + /* + * Link channel with itself so DMA doesn't need any + * reprogramming while looping the buffer + */ + omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch); + } + + return err; +} + +static int omap_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct omap_runtime_data *prtd = runtime->private_data; + + if (prtd->dma_data == NULL) + return 0; + + if (!cpu_is_omap1510()) + omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch); + omap_free_dma(prtd->dma_ch); + prtd->dma_data = NULL; + + snd_pcm_set_runtime_buffer(substream, NULL); + + return 0; +} + +static int omap_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct omap_runtime_data *prtd = runtime->private_data; + struct omap_pcm_dma_data *dma_data = prtd->dma_data; + struct omap_dma_channel_params dma_params; + + memset(&dma_params, 0, sizeof(dma_params)); + /* + * Note: Regardless of interface data formats supported by OMAP McBSP + * or EAC blocks, internal representation is always fixed 16-bit/sample + */ + dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; + dma_params.trigger = dma_data->dma_req; + dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; + dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; + dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC; + dma_params.src_start = runtime->dma_addr; + dma_params.dst_start = dma_data->port_addr; + } else { + dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; + dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; + dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC; + dma_params.src_start = dma_data->port_addr; + dma_params.dst_start = runtime->dma_addr; + } + /* + * Set DMA transfer frame size equal to ALSA period size and frame + * count as no. of ALSA periods. Then with DMA frame interrupt enabled, + * we can transfer the whole ALSA buffer with single DMA transfer but + * still can get an interrupt at each period bounary + */ + dma_params.elem_count = snd_pcm_lib_period_bytes(substream) / 2; + dma_params.frame_count = runtime->periods; + omap_set_dma_params(prtd->dma_ch, &dma_params); + + omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); + + return 0; +} + +static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct omap_runtime_data *prtd = runtime->private_data; + int ret = 0; + + spin_lock_irq(&prtd->lock); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + prtd->period_index = 0; + omap_start_dma(prtd->dma_ch); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + prtd->period_index = -1; + omap_stop_dma(prtd->dma_ch); + break; + default: + ret = -EINVAL; + } + spin_unlock_irq(&prtd->lock); + + return ret; +} + +static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct omap_runtime_data *prtd = runtime->private_data; + dma_addr_t ptr; + snd_pcm_uframes_t offset; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ptr = omap_get_dma_src_pos(prtd->dma_ch); + else + ptr = omap_get_dma_dst_pos(prtd->dma_ch); + + offset = bytes_to_frames(runtime, ptr - runtime->dma_addr); + if (offset >= runtime->buffer_size) + offset = 0; + + return offset; +} + +static int omap_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct omap_runtime_data *prtd; + int ret; + + snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware); + + /* Ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(prtd), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + spin_lock_init(&prtd->lock); + runtime->private_data = prtd; + +out: + return ret; +} + +static int omap_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + kfree(runtime->private_data); + return 0; +} + +static int omap_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +struct snd_pcm_ops omap_pcm_ops = { + .open = omap_pcm_open, + .close = omap_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = omap_pcm_hw_params, + .hw_free = omap_pcm_hw_free, + .prepare = omap_pcm_prepare, + .trigger = omap_pcm_trigger, + .pointer = omap_pcm_pointer, + .mmap = omap_pcm_mmap, +}; + +static u64 omap_pcm_dmamask = DMA_BIT_MASK(32); + +static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = omap_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + + buf->bytes = size; + return 0; +} + +static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +int omap_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, + struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &omap_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_32BIT_MASK; + + if (dai->playback.channels_min) { + ret = omap_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = omap_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + +out: + return ret; +} + +struct snd_soc_platform omap_soc_platform = { + .name = "omap-pcm-audio", + .pcm_ops = &omap_pcm_ops, + .pcm_new = omap_pcm_new, + .pcm_free = omap_pcm_free_dma_buffers, +}; +EXPORT_SYMBOL_GPL(omap_soc_platform); + +MODULE_AUTHOR("Jarkko Nikula jarkko.nikula@nokia.com"); +MODULE_DESCRIPTION("OMAP PCM DMA module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h new file mode 100644 index 0000000..e4369bd --- /dev/null +++ b/sound/soc/omap/omap-pcm.h @@ -0,0 +1,35 @@ +/* + * omap-pcm.h + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Jarkko Nikula jarkko.nikula@nokia.com + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __OMAP_PCM_H__ +#define __OMAP_PCM_H__ + +struct omap_pcm_dma_data { + char *name; /* stream identifier */ + int dma_req; /* DMA request line */ + unsigned long port_addr; /* transmit/receive register */ +}; + +extern struct snd_soc_platform omap_soc_platform; + +#endif
From: Tim Niemeyer reddog@mastersword.de
Signed-off-by: Tim Niemeyer reddog@mastersword.de Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/s3c24xx/neo1973_wm8753.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 6ee115c..962cc20 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -659,6 +659,7 @@ static int __init neo1973_init(void)
static void __exit neo1973_exit(void) { + i2c_del_driver(&lm4857_i2c_driver); platform_device_unregister(neo1973_snd_device); }
From: Tim Niemeyer tim.niemeyer@mastersword.de
Add some debug messages for suspend/resume and to add a clear prefix to s3c24xx-i2s and s3c24xx-pcm.
Signed-off-by: Tim Niemeyer reddog@mastersword.de Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/s3c24xx/s3c24xx-i2s.c | 4 +++- sound/soc/s3c24xx/s3c24xx-pcm.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 6b3cbbf..b7eca98 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -46,7 +46,7 @@
#define S3C24XX_I2S_DEBUG 0 #if S3C24XX_I2S_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x) #else #define DBG(x...) #endif @@ -415,6 +415,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev) int s3c24xx_i2s_suspend(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai) { + DBG("Entered %s\n", __FUNCTION__); s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); @@ -428,6 +429,7 @@ int s3c24xx_i2s_suspend(struct platform_device *pdev, int s3c24xx_i2s_resume(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai) { + DBG("Entered %s\n", __FUNCTION__); clk_enable(s3c24xx_i2s.iis_clk);
writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 29a6c82..5394a40 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -39,7 +39,7 @@
#define S3C24XX_PCM_DEBUG 0 #if S3C24XX_PCM_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x) #else #define DBG(x...) #endif
At Tue, 22 Apr 2008 14:14:39 +0100, Mark Brown wrote:
From: Tim Niemeyer tim.niemeyer@mastersword.de
Add some debug messages for suspend/resume and to add a clear prefix to s3c24xx-i2s and s3c24xx-pcm.
Signed-off-by: Tim Niemeyer reddog@mastersword.de Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
Got the following checkpatch warnings. Please fix.
WARNING: __func__ should be used instead of gcc specific __FUNCTION__ #17: FILE: soc/s3c24xx/s3c24xx-i2s.c:418: + DBG("Entered %s\n", __FUNCTION__);
WARNING: __func__ should be used instead of gcc specific __FUNCTION__ #25: FILE: soc/s3c24xx/s3c24xx-i2s.c:432: + DBG("Entered %s\n", __FUNCTION__);
thanks,
Takashi
sound/soc/s3c24xx/s3c24xx-i2s.c | 4 +++- sound/soc/s3c24xx/s3c24xx-pcm.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 6b3cbbf..b7eca98 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -46,7 +46,7 @@
#define S3C24XX_I2S_DEBUG 0 #if S3C24XX_I2S_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x) #else #define DBG(x...) #endif @@ -415,6 +415,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev) int s3c24xx_i2s_suspend(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai) {
- DBG("Entered %s\n", __FUNCTION__); s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
@@ -428,6 +429,7 @@ int s3c24xx_i2s_suspend(struct platform_device *pdev, int s3c24xx_i2s_resume(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai) {
DBG("Entered %s\n", __FUNCTION__); clk_enable(s3c24xx_i2s.iis_clk);
writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 29a6c82..5394a40 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -39,7 +39,7 @@
#define S3C24XX_PCM_DEBUG 0 #if S3C24XX_PCM_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x) #else #define DBG(x...)
#endif
1.5.5
Hallo Takashi,
i think, if i change this, the other lines in the file, that use also the __FUNCTION__, should be changed also. Later in the evening, i could do this, but at the moment i have to listen to my BWL-lesson.
* Takashi Iwai tiwai@suse.de [22-04-08 16:14]:
At Tue, 22 Apr 2008 14:14:39 +0100, Mark Brown wrote:
From: Tim Niemeyer tim.niemeyer@mastersword.de
Add some debug messages for suspend/resume and to add a clear prefix to s3c24xx-i2s and s3c24xx-pcm.
Signed-off-by: Tim Niemeyer reddog@mastersword.de Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
Got the following checkpatch warnings. Please fix.
WARNING: __func__ should be used instead of gcc specific __FUNCTION__ #17: FILE: soc/s3c24xx/s3c24xx-i2s.c:418:
- DBG("Entered %s\n", __FUNCTION__);
WARNING: __func__ should be used instead of gcc specific __FUNCTION__ #25: FILE: soc/s3c24xx/s3c24xx-i2s.c:432:
- DBG("Entered %s\n", __FUNCTION__);
thanks,
Takashi
sound/soc/s3c24xx/s3c24xx-i2s.c | 4 +++- sound/soc/s3c24xx/s3c24xx-pcm.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 6b3cbbf..b7eca98 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -46,7 +46,7 @@
#define S3C24XX_I2S_DEBUG 0 #if S3C24XX_I2S_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x) #else #define DBG(x...) #endif @@ -415,6 +415,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev) int s3c24xx_i2s_suspend(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai) {
- DBG("Entered %s\n", __FUNCTION__); s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
@@ -428,6 +429,7 @@ int s3c24xx_i2s_suspend(struct platform_device *pdev, int s3c24xx_i2s_resume(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai) {
DBG("Entered %s\n", __FUNCTION__); clk_enable(s3c24xx_i2s.iis_clk);
writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 29a6c82..5394a40 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -39,7 +39,7 @@
#define S3C24XX_PCM_DEBUG 0 #if S3C24XX_PCM_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x) #else #define DBG(x...)
#endif
1.5.5
Tim Niemeyer
At Tue, 22 Apr 2008 16:26:15 +0200, Tim Niemeyer wrote:
Hallo Takashi,
i think, if i change this, the other lines in the file, that use also the __FUNCTION__, should be changed also.
Yes, but as a separate patch. At least, the new change should be free from checkpatch-complaints.
thanks,
Takashi
Later in the evening, i could do this, but at the moment i have to listen to my BWL-lesson.
- Takashi Iwai tiwai@suse.de [22-04-08 16:14]:
At Tue, 22 Apr 2008 14:14:39 +0100, Mark Brown wrote:
From: Tim Niemeyer tim.niemeyer@mastersword.de
Add some debug messages for suspend/resume and to add a clear prefix to s3c24xx-i2s and s3c24xx-pcm.
Signed-off-by: Tim Niemeyer reddog@mastersword.de Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
Got the following checkpatch warnings. Please fix.
WARNING: __func__ should be used instead of gcc specific __FUNCTION__ #17: FILE: soc/s3c24xx/s3c24xx-i2s.c:418:
- DBG("Entered %s\n", __FUNCTION__);
WARNING: __func__ should be used instead of gcc specific __FUNCTION__ #25: FILE: soc/s3c24xx/s3c24xx-i2s.c:432:
- DBG("Entered %s\n", __FUNCTION__);
thanks,
Takashi
sound/soc/s3c24xx/s3c24xx-i2s.c | 4 +++- sound/soc/s3c24xx/s3c24xx-pcm.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 6b3cbbf..b7eca98 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -46,7 +46,7 @@
#define S3C24XX_I2S_DEBUG 0 #if S3C24XX_I2S_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x) #else #define DBG(x...) #endif @@ -415,6 +415,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev) int s3c24xx_i2s_suspend(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai) {
- DBG("Entered %s\n", __FUNCTION__); s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
@@ -428,6 +429,7 @@ int s3c24xx_i2s_suspend(struct platform_device *pdev, int s3c24xx_i2s_resume(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai) {
DBG("Entered %s\n", __FUNCTION__); clk_enable(s3c24xx_i2s.iis_clk);
writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 29a6c82..5394a40 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -39,7 +39,7 @@
#define S3C24XX_PCM_DEBUG 0 #if S3C24XX_PCM_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x) #else #define DBG(x...)
#endif
1.5.5
Tim Niemeyer
At Tue, 22 Apr 2008 14:14:38 +0100, Mark Brown wrote:
From: Tim Niemeyer reddog@mastersword.de
Signed-off-by: Tim Niemeyer reddog@mastersword.de Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
Applied to HG tree. Thanks.
Takashi
sound/soc/s3c24xx/neo1973_wm8753.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 6ee115c..962cc20 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -659,6 +659,7 @@ static int __init neo1973_init(void)
static void __exit neo1973_exit(void) {
- i2c_del_driver(&lm4857_i2c_driver); platform_device_unregister(neo1973_snd_device);
}
-- 1.5.5
At Tue, 22 Apr 2008 14:14:37 +0100, Mark Brown wrote:
From: Jarkko Nikula jarkko.nikula@nokia.com
Add common OMAP ASoC drivers and machine driver for Nokia N810. Currently supported features are:
- Covers OMAPs from 1510 to 2420
- Common DMA driver
- DAI link driver using McBSP port in I2S mode
- Basic machine driver for Nokia N810
Signed-off-by: Jarkko Nikula jarkko.nikula@nokia.com Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
I postpone this patch until 2.6.26 merge is closed. This is obviously a new stuff and it must be cooked for a while in mm tree.
Thanks,
Takashi
On Tue, Apr 22, 2008 at 04:13:11PM +0200, Takashi Iwai wrote:
Mark Brown wrote:
Add common OMAP ASoC drivers and machine driver for Nokia N810. Currently supported features are:
I postpone this patch until 2.6.26 merge is closed. This is obviously a new stuff and it must be cooked for a while in mm tree.
The main reason why this is new is that it depends on the architecture being added via the ARM tree - as with the PXA3xx AC97 changes it had been waiting for the required patches to be submitted by rmk, which just happened. Given this it seems safe to merge it as-is - the entire machine shares the same sort of testing status and the patch isn't new in itself.
At Tue, 22 Apr 2008 15:43:31 +0100, Mark Brown wrote:
On Tue, Apr 22, 2008 at 04:13:11PM +0200, Takashi Iwai wrote:
Mark Brown wrote:
Add common OMAP ASoC drivers and machine driver for Nokia N810. Currently supported features are:
I postpone this patch until 2.6.26 merge is closed. This is obviously a new stuff and it must be cooked for a while in mm tree.
The main reason why this is new is that it depends on the architecture being added via the ARM tree - as with the PXA3xx AC97 changes it had been waiting for the required patches to be submitted by rmk, which just happened. Given this it seems safe to merge it as-is - the entire machine shares the same sort of testing status and the patch isn't new in itself.
The problem is that it wasn't passed through mm tree at all. It's a generic rule for merging a new stuff to the upstream tree.
If the stuff has to cooperate with the changes in other trees, pass it seprately to Andrew (or give me a hint) so that it's put to mm tree rightly at the next time.
Takashi
On Tue, Apr 22, 2008 at 04:56:21PM +0200, Takashi Iwai wrote:
The problem is that it wasn't passed through mm tree at all.
Oh, I see. I had thought that you already maintained a separate -mm tree. Looking again it seems your linus tree is actually just for backported fixes rather than a general submission to Linus tree. I must've looked at it at the wrong point in the cycle when figuring these things out.
If the stuff has to cooperate with the changes in other trees, pass it seprately to Andrew (or give me a hint) so that it's put to mm tree rightly at the next time.
I could also ask Andrew to pull the ASoC upstream branch (which is based off the ALSA -mm branch) and keep any dodgy commits there without e-mailing you. I'm not sure if having a branch rebased off another branch he's pulling would be too clever, though, but that would probably be the lowest maintinence option.
At Tue, 22 Apr 2008 19:38:42 +0100, Mark Brown wrote:
On Tue, Apr 22, 2008 at 04:56:21PM +0200, Takashi Iwai wrote:
The problem is that it wasn't passed through mm tree at all.
Oh, I see. I had thought that you already maintained a separate -mm tree. Looking again it seems your linus tree is actually just for backported fixes rather than a general submission to Linus tree.
Hm? No, right now it's identical with the master branch, too.
I must've looked at it at the wrong point in the cycle when figuring these things out.
Actually I have a separate branch on my git tree. The master is for mm tree and for-linus is for Linus. The appropriate patches are copied (and rebased) to for-linus branch once after the merge window is opened. So, it's no no problem at all to have patches that are only for mm.
If the stuff has to cooperate with the changes in other trees, pass it seprately to Andrew (or give me a hint) so that it's put to mm tree rightly at the next time.
I could also ask Andrew to pull the ASoC upstream branch (which is based off the ALSA -mm branch) and keep any dodgy commits there without e-mailing you.
Well, Andrew prefers patches merged into the subsystem tree, so it's better to just mail me as before. Then we have one more review automatically.
My previous comment was about the patch that affects several subsystem / arch changes. In this case, the change isn't only in the subsystem tree. So, we'd need to cope with others anyway. Keeping such a patch in mm tree separately is one option.
thanks,
Takashi
On Wed, Apr 23, 2008 at 10:41:48AM +0200, Takashi Iwai wrote:
Actually I have a separate branch on my git tree. The master is for mm tree and for-linus is for Linus. The appropriate patches are
what's the current status of the git trees? There was some talk about moving the primary revision control system for the kernel bits over to git during the 2.6.26 cycle.
My previous comment was about the patch that affects several subsystem / arch changes. In this case, the change isn't only in the subsystem tree. So, we'd need to cope with others anyway. Keeping such a patch in mm tree separately is one option.
I think that just putting the patches into ALSA is a better bet - it's more in tune with what most of the other subsystems are doing and it avoids possible confusion about what's actually made it into -mm.
At Wed, 23 Apr 2008 11:15:11 +0100, Mark Brown wrote:
On Wed, Apr 23, 2008 at 10:41:48AM +0200, Takashi Iwai wrote:
Actually I have a separate branch on my git tree. The master is for mm tree and for-linus is for Linus. The appropriate patches are
what's the current status of the git trees? There was some talk about moving the primary revision control system for the kernel bits over to git during the 2.6.26 cycle.
No advance since then unfortuantely. Instead I'm keeping my own git tree for maintenance purpose too: http://git.kernel.org/?p=linux/kernel/git/tiwai/sound-2.6.git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
My previous comment was about the patch that affects several subsystem / arch changes. In this case, the change isn't only in the subsystem tree. So, we'd need to cope with others anyway. Keeping such a patch in mm tree separately is one option.
I think that just putting the patches into ALSA is a better bet - it's more in tune with what most of the other subsystems are doing and it avoids possible confusion about what's actually made it into -mm.
It should be case-by-case, but yes, as long as the patch doesn't break builds, it's no problem to keep it in ALSA tree in general.
Takashi
On Tue, 22 Apr 2008 16:56:21 +0200 "ext Takashi Iwai" tiwai@suse.de wrote:
If the stuff has to cooperate with the changes in other trees, pass it seprately to Andrew (or give me a hint) so that it's put to mm tree rightly at the next time.
That's a good idea. There is a work in progress in linux-omap to update low-level OMAP McBSP driver and to have support for newer OMAPs and I would like to update my driver as soon as that work is ready without waiting over one release cycle :-)
Jarkko
At Wed, 23 Apr 2008 08:57:31 +0300, Jarkko Nikula wrote:
On Tue, 22 Apr 2008 16:56:21 +0200 "ext Takashi Iwai" tiwai@suse.de wrote:
If the stuff has to cooperate with the changes in other trees, pass it seprately to Andrew (or give me a hint) so that it's put to mm tree rightly at the next time.
That's a good idea. There is a work in progress in linux-omap to update low-level OMAP McBSP driver and to have support for newer OMAPs and I would like to update my driver as soon as that work is ready without waiting over one release cycle :-)
Yeah, this time is a very pity. I didn't know of (or totally forgot) about this change at the right time. If I knew of this at the time I asked on alsa-devel ML, it could be into the tree without a problem.
So, at the next time, if you have something you want to merge, please check the current ALSA tree status. If the patch isn't there, submit the patch soon. The merge to the subsystem tree is easy as long as no big API changes happens. Tossing to the upstream is another issue, though.
Takashi
On Wed, Apr 23, 2008 at 11:08:54AM +0200, Takashi Iwai wrote:
So, at the next time, if you have something you want to merge, please check the current ALSA tree status. If the patch isn't there, submit the patch soon. The merge to the subsystem tree is easy as long as no
He's actually done all that - the patch has been posted on alsa-devel a few times and has been sitting in ASoC for almost a month waiting for the ARM bits it needs to be merged.
big API changes happens. Tossing to the upstream is another issue, though.
For stuff that doesn't touch any core code (especially things like this which will only be selectable on one platform) it shouldn't be too much of an issue, I'd expect - there's not much risk of breaking anything else.
At Wed, 23 Apr 2008 10:20:23 +0100, Mark Brown wrote:
On Wed, Apr 23, 2008 at 11:08:54AM +0200, Takashi Iwai wrote:
So, at the next time, if you have something you want to merge, please check the current ALSA tree status. If the patch isn't there, submit the patch soon. The merge to the subsystem tree is easy as long as no
He's actually done all that - the patch has been posted on alsa-devel a few times and has been sitting in ASoC for almost a month waiting for the ARM bits it needs to be merged.
Yeah, an unfortunate situation indeed.
big API changes happens. Tossing to the upstream is another issue, though.
For stuff that doesn't touch any core code (especially things like this which will only be selectable on one platform) it shouldn't be too much of an issue, I'd expect - there's not much risk of breaking anything else.
We could have merged this in prior. The driver codes are with ARCH_OMAP Kconfig, so it wouldn't cause build errors even if no omap is supported.
Takashi
On Wed, Apr 23, 2008 at 11:33:19AM +0200, Takashi Iwai wrote:
We could have merged this in prior. The driver codes are with ARCH_OMAP Kconfig, so it wouldn't cause build errors even if no omap is supported.
In that case the best approach is probably to just submit patches without worrying if it's buildable in mainline - for the embedded stuff it'll pretty much always be the case that there's some Kconfig setting protecting the new code.
At Wed, 23 Apr 2008 10:36:00 +0100, Mark Brown wrote:
On Wed, Apr 23, 2008 at 11:33:19AM +0200, Takashi Iwai wrote:
We could have merged this in prior. The driver codes are with ARCH_OMAP Kconfig, so it wouldn't cause build errors even if no omap is supported.
In that case the best approach is probably to just submit patches without worrying if it's buildable in mainline - for the embedded stuff it'll pretty much always be the case that there's some Kconfig setting protecting the new code.
Just to avoid confusion - submit (merge) to the mainline is another story, of course. We shouldn't put a non-working stuff. What we are talking about is the merge into the subsystem tree for mm.
Takashi
At Tue, 22 Apr 2008 14:14:36 +0100, Mark Brown wrote:
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
Applied, too. Thanks.
Takashi
sound/arm/pxa2xx-ac97.c | 24 ++++++++++++++++++++++++ 1 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index cfea4eb..355ce28 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -106,6 +106,16 @@ static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigne static void pxa2xx_ac97_reset(struct snd_ac97 *ac97) { /* First, try cold reset */ +#ifdef CONFIG_PXA3xx
- int timeout;
- /* Hold CLKBPB for 100us */
- GCR = 0;
- GCR = GCR_CLKBPB;
- udelay(100);
- GCR = 0;
+#endif
- GCR &= GCR_COLD_RST; /* clear everything but nCRST */ GCR &= ~GCR_COLD_RST; /* then assert nCRST */
@@ -117,6 +127,14 @@ static void pxa2xx_ac97_reset(struct snd_ac97 *ac97) pxa_set_cken(CKEN_AC97CONF, 0); GCR = GCR_COLD_RST; udelay(50); +#elif defined(CONFIG_PXA3xx)
- timeout = 1000;
- /* Can't use interrupts on PXA3xx */
- GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
- GCR = GCR_WARM_RST | GCR_COLD_RST;
- while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
mdelay(10);
#else GCR = GCR_COLD_RST; GCR |= GCR_CDONE_IE|GCR_SDONE_IE; @@ -137,6 +155,12 @@ static void pxa2xx_ac97_reset(struct snd_ac97 *ac97) GCR |= GCR_WARM_RST; pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); udelay(500); +#elif defined(CONFIG_PXA3xx)
timeout = 100;
/* Can't use interrupts */
GCR |= GCR_WARM_RST;
while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
mdelay(1);
#else GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN; wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); -- 1.5.5
At Tue, 22 Apr 2008 14:14:35 +0100, Mark Brown wrote:
The PXA3xx does not support the use of interrupts during reset and access to the GPIO status requires similar handling to that for PXA27x.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
Applied to HG tree now. Thanks.
Takashi
sound/soc/pxa/pxa2xx-ac97.c | 29 +++++++++++++++++++++++++++-- 1 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 815c153..95ae509 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -55,7 +55,7 @@ static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, mutex_lock(&car_mutex);
/* set up primary or secondary codec/modem space */ -#ifdef CONFIG_PXA27x +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; #else if (reg == AC97_GPIO_STATUS) @@ -105,7 +105,7 @@ static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, mutex_lock(&car_mutex);
/* set up primary or secondary codec/modem space */ -#ifdef CONFIG_PXA27x +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; #else if (reg == AC97_GPIO_STATUS) @@ -128,6 +128,9 @@ static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) { +#ifdef CONFIG_PXA3xx
- int timeout = 100;
+#endif gsr_bits = 0;
#ifdef CONFIG_PXA27x @@ -138,6 +141,11 @@ static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) GCR |= GCR_WARM_RST; pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); udelay(500); +#elif defined(CONFIG_PXA3xx)
- /* Can't use interrupts */
- GCR |= GCR_WARM_RST;
- while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
mdelay(1);
#else GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN; wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); @@ -153,6 +161,16 @@ static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) { +#ifdef CONFIG_PXA3xx
- int timeout = 1000;
- /* Hold CLKBPB for 100us */
- GCR = 0;
- GCR = GCR_CLKBPB;
- udelay(100);
- GCR = 0;
+#endif
- GCR &= GCR_COLD_RST; /* clear everything but nCRST */ GCR &= ~GCR_COLD_RST; /* then assert nCRST */
@@ -164,6 +182,13 @@ static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) pxa_set_cken(CKEN_AC97CONF, 0); GCR = GCR_COLD_RST; udelay(50); +#elif defined(CONFIG_PXA3xx)
- /* Can't use interrupts on PXA3xx */
- GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
- GCR = GCR_WARM_RST | GCR_COLD_RST;
- while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
mdelay(10);
#else GCR = GCR_COLD_RST; GCR |= GCR_CDONE_IE|GCR_SDONE_IE; -- 1.5.5
participants (4)
-
Jarkko Nikula
-
Mark Brown
-
Takashi Iwai
-
Tim Niemeyer