diff options
Diffstat (limited to 'sound/soc/omap')
-rw-r--r-- | sound/soc/omap/Kconfig | 43 | ||||
-rw-r--r-- | sound/soc/omap/Makefile | 10 | ||||
-rw-r--r-- | sound/soc/omap/n810.c | 16 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 239 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcbsp.h | 16 | ||||
-rw-r--r-- | sound/soc/omap/omap-pcm.c | 18 | ||||
-rw-r--r-- | sound/soc/omap/omap2evm.c | 151 | ||||
-rw-r--r-- | sound/soc/omap/omap3beagle.c | 149 | ||||
-rw-r--r-- | sound/soc/omap/omap3pandora.c | 311 | ||||
-rw-r--r-- | sound/soc/omap/osk5912.c | 232 | ||||
-rw-r--r-- | sound/soc/omap/overo.c | 148 | ||||
-rw-r--r-- | sound/soc/omap/sdp3430.c | 152 |
12 files changed, 1403 insertions, 82 deletions
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index aea27e70043..a7b1d77b210 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -1,6 +1,6 @@ config SND_OMAP_SOC tristate "SoC Audio for the Texas Instruments OMAP chips" - depends on ARCH_OMAP && SND_SOC + depends on ARCH_OMAP config SND_OMAP_SOC_MCBSP tristate @@ -13,3 +13,44 @@ config SND_OMAP_SOC_N810 select SND_SOC_TLV320AIC3X help Say Y if you want to add support for SoC audio on Nokia N810. + +config SND_OMAP_SOC_OSK5912 + tristate "SoC Audio support for omap osk5912" + depends on SND_OMAP_SOC && MACH_OMAP_OSK + select SND_OMAP_SOC_MCBSP + select SND_SOC_TLV320AIC23 + help + Say Y if you want to add support for SoC audio on osk5912. + +config SND_OMAP_SOC_OVERO + tristate "SoC Audio support for Gumstix Overo" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the Gumstix Overo. + +config SND_OMAP_SOC_OMAP2EVM + tristate "SoC Audio support for OMAP2EVM board" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP2EVM + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the omap2evm board. + +config SND_OMAP_SOC_SDP3430 + tristate "SoC Audio support for Texas Instruments SDP3430" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on Texas Instruments + SDP3430. + +config SND_OMAP_SOC_OMAP3_PANDORA + tristate "SoC Audio support for OMAP3 Pandora" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the OMAP3 Pandora. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index d8d8d58075e..76fedd96e36 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -7,5 +7,15 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o # OMAP Machine Support snd-soc-n810-objs := n810.o +snd-soc-osk5912-objs := osk5912.o +snd-soc-overo-objs := overo.o +snd-soc-omap2evm-objs := omap2evm.o +snd-soc-sdp3430-objs := sdp3430.o +snd-soc-omap3pandora-objs := omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o +obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o +obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o +obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o +obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index d166b6b2a60..25593fee912 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -70,9 +70,13 @@ static void n810_ext_control(struct snd_soc_codec *codec) static int n810_startup(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->socdev->codec; + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); + n810_ext_control(codec); return clk_enable(sys_clkout2); } @@ -247,9 +251,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec) int i, err; /* Not connected */ - snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); - snd_soc_dapm_disable_pin(codec, "HPLCOM"); - snd_soc_dapm_disable_pin(codec, "HPRCOM"); + snd_soc_dapm_nc_pin(codec, "MONO_LOUT"); + snd_soc_dapm_nc_pin(codec, "HPLCOM"); + snd_soc_dapm_nc_pin(codec, "HPRCOM"); /* Add N810 specific controls */ for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { @@ -282,8 +286,9 @@ static struct snd_soc_dai_link n810_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_n810 = { +static struct snd_soc_card snd_soc_n810 = { .name = "N810", + .platform = &omap_soc_platform, .dai_link = &n810_dai, .num_links = 1, }; @@ -298,8 +303,7 @@ static struct aic3x_setup_data n810_aic33_setup = { /* Audio subsystem */ static struct snd_soc_device n810_snd_devdata = { - .machine = &snd_soc_machine_n810, - .platform = &omap_soc_platform, + .card = &snd_soc_n810, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &n810_aic33_setup, }; diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 35310e16d7f..ec5e18a7875 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -36,13 +36,12 @@ #include "omap-mcbsp.h" #include "omap-pcm.h" -#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_KNOT) +#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) struct omap_mcbsp_data { unsigned int bus_id; struct omap_mcbsp_reg_cfg regs; + unsigned int fmt; /* * Flags indicating is the bus already activated and configured by * another substream @@ -59,12 +58,7 @@ 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", }, -}, -}; +static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2]; #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) static const int omap1_dma_reqs[][2] = { @@ -84,11 +78,22 @@ static const unsigned long omap1_mcbsp_port[][2] = { 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] = { + +#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +static const int omap24xx_dma_reqs[][2] = { { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) + { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX }, + { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX }, + { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX }, +#endif }; +#else +static const int omap24xx_dma_reqs[][2] = {}; +#endif + +#if defined(CONFIG_ARCH_OMAP2420) static const unsigned long omap2420_mcbsp_port[][2] = { { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1, OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 }, @@ -96,11 +101,45 @@ static const unsigned long omap2420_mcbsp_port[][2] = { 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) +#if defined(CONFIG_ARCH_OMAP2430) +static const unsigned long omap2430_mcbsp_port[][2] = { + { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, + OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, + { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR, + OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR }, + { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR, + OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR }, + { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR, + OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR }, + { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR, + OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR }, +}; +#else +static const unsigned long omap2430_mcbsp_port[][2] = {}; +#endif + +#if defined(CONFIG_ARCH_OMAP34XX) +static const unsigned long omap34xx_mcbsp_port[][2] = { + { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, + OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, + { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR, + OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR }, + { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR, + OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR }, + { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR, + OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR }, + { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR, + OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR }, +}; +#else +static const unsigned long omap34xx_mcbsp_port[][2] = {}; +#endif + +static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -113,7 +152,8 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) return err; } -static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) +static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -125,7 +165,8 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) } } -static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) +static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -154,27 +195,34 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) } static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_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; + int wlen, channels; 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]; + dma = omap24xx_dma_reqs[bus_id][substream->stream]; port = omap2420_mcbsp_port[bus_id][substream->stream]; + } else if (cpu_is_omap2430()) { + dma = omap24xx_dma_reqs[bus_id][substream->stream]; + port = omap2430_mcbsp_port[bus_id][substream->stream]; + } else if (cpu_is_omap343x()) { + dma = omap24xx_dma_reqs[bus_id][substream->stream]; + port = omap34xx_mcbsp_port[bus_id][substream->stream]; } else { - /* - * TODO: Add support for 2430 and 3430 - */ return -ENODEV; } + omap_mcbsp_dai_dma_params[id][substream->stream].name = + substream->stream ? "Audio Capture" : "Audio Playback"; 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]; @@ -184,12 +232,17 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, return 0; } - switch (params_channels(params)) { + channels = params_channels(params); + switch (channels) { case 2: - /* Set 1 word per (McBPSP) frame and use dual-phase frames */ - regs->rcr2 |= RFRLEN2(1 - 1) | RPHASE; + /* Use dual-phase frames */ + regs->rcr2 |= RPHASE; + regs->xcr2 |= XPHASE; + case 1: + /* Set 1 word per (McBSP) frame */ + regs->rcr2 |= RFRLEN2(1 - 1); regs->rcr1 |= RFRLEN1(1 - 1); - regs->xcr2 |= XFRLEN2(1 - 1) | XPHASE; + regs->xcr2 |= XFRLEN2(1 - 1); regs->xcr1 |= XFRLEN1(1 - 1); break; default: @@ -200,19 +253,29 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: /* Set word lengths */ + wlen = 16; 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; } + /* Set FS period and length in terms of bit clock periods */ + switch (mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + regs->srgr2 |= FPER(wlen * 2 - 1); + regs->srgr1 |= FWID(wlen - 1); + break; + case SND_SOC_DAIFMT_DSP_B: + regs->srgr2 |= FPER(wlen * channels - 1); + regs->srgr1 |= FWID(wlen * channels - 2); + break; + } + omap_mcbsp_config(bus_id, &mcbsp_data->regs); mcbsp_data->configured = 1; @@ -232,6 +295,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, if (mcbsp_data->configured) return 0; + mcbsp_data->fmt = fmt; memset(regs, 0, sizeof(*regs)); /* Generic McBSP register settings */ regs->spcr2 |= XINTM(3) | FREE; @@ -245,6 +309,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); break; + case SND_SOC_DAIFMT_DSP_B: + /* 0-bit data delay */ + regs->rcr2 |= RDATDLY(0); + regs->xcr2 |= XDATDLY(0); + break; default: /* Unsupported data format */ return -EINVAL; @@ -310,7 +379,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, int clk_id) { int sel_bit; - u16 reg; + u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1; if (cpu_class_is_omap1()) { /* OMAP1's can use only external source clock */ @@ -320,6 +389,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, return 0; } + if (cpu_is_omap2420() && mcbsp_data->bus_id > 1) + return -EINVAL; + + if (cpu_is_omap343x()) + reg_devconf1 = OMAP343X_CONTROL_DEVCONF1; + switch (mcbsp_data->bus_id) { case 0: reg = OMAP2_CONTROL_DEVCONF0; @@ -329,20 +404,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, reg = OMAP2_CONTROL_DEVCONF0; sel_bit = 6; break; - /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */ + case 2: + reg = reg_devconf1; + sel_bit = 0; + break; + case 3: + reg = reg_devconf1; + sel_bit = 2; + break; + case 4: + reg = reg_devconf1; + sel_bit = 4; + break; 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); - } - } + 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; } @@ -376,39 +457,61 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, return err; } -struct snd_soc_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, -}, +#define OMAP_MCBSP_DAI_BUILDER(link_id) \ +{ \ + .name = "omap-mcbsp-dai-"#link_id, \ + .id = (link_id), \ + .playback = { \ + .channels_min = 1, \ + .channels_max = 2, \ + .rates = OMAP_MCBSP_RATES, \ + .formats = SNDRV_PCM_FMTBIT_S16_LE, \ + }, \ + .capture = { \ + .channels_min = 1, \ + .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, \ + .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[(link_id)].bus_id, \ +} + +struct snd_soc_dai omap_mcbsp_dai[] = { + OMAP_MCBSP_DAI_BUILDER(0), + OMAP_MCBSP_DAI_BUILDER(1), +#if NUM_LINKS >= 3 + OMAP_MCBSP_DAI_BUILDER(2), +#endif +#if NUM_LINKS == 5 + OMAP_MCBSP_DAI_BUILDER(3), + OMAP_MCBSP_DAI_BUILDER(4), +#endif }; + EXPORT_SYMBOL_GPL(omap_mcbsp_dai); +static int __init snd_omap_mcbsp_init(void) +{ + return snd_soc_register_dais(omap_mcbsp_dai, + ARRAY_SIZE(omap_mcbsp_dai)); +} +module_init(snd_omap_mcbsp_init); + +static void __exit snd_omap_mcbsp_exit(void) +{ + snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); +} +module_exit(snd_omap_mcbsp_exit); + 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 index ed8afb55067..df7ad13ba73 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h @@ -38,11 +38,17 @@ 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 +#if defined(CONFIG_ARCH_OMAP2420) +#define NUM_LINKS 2 +#endif +#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) +#undef NUM_LINKS +#define NUM_LINKS 3 +#endif +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) +#undef NUM_LINKS +#define NUM_LINKS 5 +#endif extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 690bfeaec4a..b0362dfd5b7 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, 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()) { + if (!err && !cpu_is_omap1510()) { /* * Link channel with itself so DMA doesn't need any * reprogramming while looping the buffer @@ -147,12 +147,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) 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; + dma_params.dst_port = OMAP_DMA_PORT_MPUI; } 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; + dma_params.src_port = OMAP_DMA_PORT_MPUI; } /* * Set DMA transfer frame size equal to ALSA period size and frame @@ -231,7 +233,7 @@ static int omap_pcm_open(struct snd_pcm_substream *substream) if (ret < 0) goto out; - prtd = kzalloc(sizeof(prtd), GFP_KERNEL); + prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); if (prtd == NULL) { ret = -ENOMEM; goto out; @@ -352,6 +354,18 @@ struct snd_soc_platform omap_soc_platform = { }; EXPORT_SYMBOL_GPL(omap_soc_platform); +static int __init omap_soc_platform_init(void) +{ + return snd_soc_register_platform(&omap_soc_platform); +} +module_init(omap_soc_platform_init); + +static void __exit omap_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&omap_soc_platform); +} +module_exit(omap_soc_platform_exit); + MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>"); MODULE_DESCRIPTION("OMAP PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c new file mode 100644 index 00000000000..0c2322dcf02 --- /dev/null +++ b/sound/soc/omap/omap2evm.c @@ -0,0 +1,151 @@ +/* + * omap2evm.c -- SoC audio machine driver for omap2evm board + * + * Author: Arun KS <arunks@mistralsolutions.com> + * + * Based on sound/soc/omap/overo.c by Steve Sakoman + * + * 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 <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/mcbsp.h> + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int omap2evm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + 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; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + 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_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops omap2evm_ops = { + .hw_params = omap2evm_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap2evm_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &omap2evm_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_omap2evm = { + .name = "omap2evm", + .platform = &omap_soc_platform, + .dai_link = &omap2evm_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device omap2evm_snd_devdata = { + .card = &snd_soc_omap2evm, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap2evm_snd_device; + +static int __init omap2evm_soc_init(void) +{ + int ret; + + if (!machine_is_omap2evm()) { + pr_debug("Not omap2evm!\n"); + return -ENODEV; + } + printk(KERN_INFO "omap2evm SoC init\n"); + + omap2evm_snd_device = platform_device_alloc("soc-audio", -1); + if (!omap2evm_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata); + omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev; + *(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(omap2evm_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(omap2evm_snd_device); + + return ret; +} +module_init(omap2evm_soc_init); + +static void __exit omap2evm_soc_exit(void) +{ + platform_device_unregister(omap2evm_snd_device); +} +module_exit(omap2evm_soc_exit); + +MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); +MODULE_DESCRIPTION("ALSA SoC omap2evm"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c new file mode 100644 index 00000000000..fd24a4acd2f --- /dev/null +++ b/sound/soc/omap/omap3beagle.c @@ -0,0 +1,149 @@ +/* + * omap3beagle.c -- SoC audio for OMAP3 Beagle + * + * Author: Steve Sakoman <steve@sakoman.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 <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/mcbsp.h> + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int omap3beagle_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; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + 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_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops omap3beagle_ops = { + .hw_params = omap3beagle_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap3beagle_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &omap3beagle_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_omap3beagle = { + .name = "omap3beagle", + .platform = &omap_soc_platform, + .dai_link = &omap3beagle_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device omap3beagle_snd_devdata = { + .card = &snd_soc_omap3beagle, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap3beagle_snd_device; + +static int __init omap3beagle_soc_init(void) +{ + int ret; + + if (!machine_is_omap3_beagle()) { + pr_debug("Not OMAP3 Beagle!\n"); + return -ENODEV; + } + pr_info("OMAP3 Beagle SoC init\n"); + + omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); + if (!omap3beagle_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata); + omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev; + *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(omap3beagle_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(omap3beagle_snd_device); + + return ret; +} + +static void __exit omap3beagle_soc_exit(void) +{ + platform_device_unregister(omap3beagle_snd_device); +} + +module_init(omap3beagle_soc_init); +module_exit(omap3beagle_soc_exit); + +MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>"); +MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c new file mode 100644 index 00000000000..bd91594496b --- /dev/null +++ b/sound/soc/omap/omap3pandora.c @@ -0,0 +1,311 @@ +/* + * omap3pandora.c -- SoC audio for Pandora Handheld Console + * + * Author: GraÅžvydas Ignotas <notasas@gmail.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 <linux/gpio.h> +#include <linux/delay.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include <asm/mach-types.h> + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +#define OMAP3_PANDORA_DAC_POWER_GPIO 118 +#define OMAP3_PANDORA_AMP_POWER_GPIO 14 + +#define PREFIX "ASoC omap3pandora: " + +static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai, + struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + pr_err(PREFIX "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + pr_err(PREFIX "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + pr_err(PREFIX "can't set codec system clock\n"); + return ret; + } + + /* Set McBSP clock to external */ + ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) { + pr_err(PREFIX "can't set cpu system clock\n"); + return ret; + } + + ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8); + if (ret < 0) { + pr_err(PREFIX "can't set SRG clock divider\n"); + return ret; + } + + return 0; +} + +static int omap3pandora_out_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; + + return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBS_CFS); +} + +static int omap3pandora_in_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; + + return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); +} + +static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); + gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1); + } else { + gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0); + mdelay(1); + gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0); + } + + return 0; +} + +/* + * Audio paths on Pandora board: + * + * |O| ---> PCM DAC +-> AMP -> Headphone Jack + * |M| A +--------> Line Out + * |A| <~~clk~~+ + * |P| <--- TWL4030 <--------- Line In and MICs + */ +static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { + SND_SOC_DAPM_DAC("PCM DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, + 0, 0, NULL, 0, omap3pandora_hp_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), +}; + +static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic (Internal)", NULL), + SND_SOC_DAPM_MIC("Mic (external)", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), +}; + +static const struct snd_soc_dapm_route omap3pandora_out_map[] = { + {"Headphone Amplifier", NULL, "PCM DAC"}, + {"Line Out", NULL, "PCM DAC"}, + {"Headphone Jack", NULL, "Headphone Amplifier"}, +}; + +static const struct snd_soc_dapm_route omap3pandora_in_map[] = { + {"INL", NULL, "Line In"}, + {"INR", NULL, "Line In"}, + {"INL", NULL, "Mic (Internal)"}, + {"INR", NULL, "Mic (external)"}, +}; + +static int omap3pandora_out_init(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets, + ARRAY_SIZE(omap3pandora_out_dapm_widgets)); + if (ret < 0) + return ret; + + snd_soc_dapm_add_routes(codec, omap3pandora_out_map, + ARRAY_SIZE(omap3pandora_out_map)); + + return snd_soc_dapm_sync(codec); +} + +static int omap3pandora_in_init(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, + ARRAY_SIZE(omap3pandora_in_dapm_widgets)); + if (ret < 0) + return ret; + + snd_soc_dapm_add_routes(codec, omap3pandora_in_map, + ARRAY_SIZE(omap3pandora_in_map)); + + return snd_soc_dapm_sync(codec); +} + +static struct snd_soc_ops omap3pandora_out_ops = { + .hw_params = omap3pandora_out_hw_params, +}; + +static struct snd_soc_ops omap3pandora_in_ops = { + .hw_params = omap3pandora_in_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap3pandora_dai[] = { + { + .name = "PCM1773", + .stream_name = "HiFi Out", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &omap3pandora_out_ops, + .init = omap3pandora_out_init, + }, { + .name = "TWL4030", + .stream_name = "Line/Mic In", + .cpu_dai = &omap_mcbsp_dai[1], + .codec_dai = &twl4030_dai, + .ops = &omap3pandora_in_ops, + .init = omap3pandora_in_init, + } +}; + +/* SoC card */ +static struct snd_soc_card snd_soc_card_omap3pandora = { + .name = "omap3pandora", + .platform = &omap_soc_platform, + .dai_link = omap3pandora_dai, + .num_links = ARRAY_SIZE(omap3pandora_dai), +}; + +/* Audio subsystem */ +static struct snd_soc_device omap3pandora_snd_data = { + .card = &snd_soc_card_omap3pandora, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap3pandora_snd_device; + +static int __init omap3pandora_soc_init(void) +{ + int ret; + + if (!machine_is_omap3_pandora()) { + pr_debug(PREFIX "Not OMAP3 Pandora\n"); + return -ENODEV; + } + pr_info("OMAP3 Pandora SoC init\n"); + + ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power"); + if (ret) { + pr_err(PREFIX "Failed to get DAC power GPIO\n"); + return ret; + } + + ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0); + if (ret) { + pr_err(PREFIX "Failed to set DAC power GPIO direction\n"); + goto fail0; + } + + ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power"); + if (ret) { + pr_err(PREFIX "Failed to get amp power GPIO\n"); + goto fail0; + } + + ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0); + if (ret) { + pr_err(PREFIX "Failed to set amp power GPIO direction\n"); + goto fail1; + } + + omap3pandora_snd_device = platform_device_alloc("soc-audio", -1); + if (omap3pandora_snd_device == NULL) { + pr_err(PREFIX "Platform device allocation failed\n"); + ret = -ENOMEM; + goto fail1; + } + + platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data); + omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev; + *(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */ + *(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */ + + ret = platform_device_add(omap3pandora_snd_device); + if (ret) { + pr_err(PREFIX "Unable to add platform device\n"); + goto fail2; + } + + return 0; + +fail2: + platform_device_put(omap3pandora_snd_device); +fail1: + gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); +fail0: + gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); + return ret; +} +module_init(omap3pandora_soc_init); + +static void __exit omap3pandora_soc_exit(void) +{ + platform_device_unregister(omap3pandora_snd_device); + gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); + gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); +} +module_exit(omap3pandora_soc_exit); + +MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>"); +MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c new file mode 100644 index 00000000000..cd41a948df7 --- /dev/null +++ b/sound/soc/omap/osk5912.c @@ -0,0 +1,232 @@ +/* + * osk5912.c -- SoC audio for OSK 5912 + * + * Copyright (C) 2008 Mistral Solutions + * + * Contact: Arun KS <arunks@mistralsolutions.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 <mach/hardware.h> +#include <linux/gpio.h> +#include <mach/mcbsp.h> + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/tlv320aic23.h" + +#define CODEC_CLOCK 12000000 + +static struct clk *tlv320aic23_mclk; + +static int osk_startup(struct snd_pcm_substream *substream) +{ + return clk_enable(tlv320aic23_mclk); +} + +static void osk_shutdown(struct snd_pcm_substream *substream) +{ + clk_disable(tlv320aic23_mclk); +} + +static int osk_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; + int err; + + /* Set codec DAI configuration */ + err = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBM_CFM); + if (err < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return err; + } + + /* Set cpu DAI configuration */ + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBM_CFM); + if (err < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return err; + } + + /* Set the codec system clock for DAC and ADC */ + err = + snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); + + if (err < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return err; + } + + return err; +} + +static struct snd_soc_ops osk_ops = { + .startup = osk_startup, + .hw_params = osk_hw_params, + .shutdown = osk_shutdown, +}; + +static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + {"Headphone Jack", NULL, "LHPOUT"}, + {"Headphone Jack", NULL, "RHPOUT"}, + + {"LLINEIN", NULL, "Line In"}, + {"RLINEIN", NULL, "Line In"}, + + {"MICIN", NULL, "Mic Jack"}, +}; + +static int osk_tlv320aic23_init(struct snd_soc_codec *codec) +{ + + /* Add osk5912 specific widgets */ + snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, + ARRAY_SIZE(tlv320aic23_dapm_widgets)); + + /* Set up osk5912 specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + snd_soc_dapm_enable_pin(codec, "Line In"); + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + + snd_soc_dapm_sync(codec); + + return 0; +} + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link osk_dai = { + .name = "TLV320AIC23", + .stream_name = "AIC23", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &tlv320aic23_dai, + .init = osk_tlv320aic23_init, + .ops = &osk_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_card_osk = { + .name = "OSK5912", + .platform = &omap_soc_platform, + .dai_link = &osk_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device osk_snd_devdata = { + .card = &snd_soc_card_osk, + .codec_dev = &soc_codec_dev_tlv320aic23, +}; + +static struct platform_device *osk_snd_device; + +static int __init osk_soc_init(void) +{ + int err; + u32 curRate; + struct device *dev; + + if (!(machine_is_omap_osk())) + return -ENODEV; + + osk_snd_device = platform_device_alloc("soc-audio", -1); + if (!osk_snd_device) + return -ENOMEM; + + platform_set_drvdata(osk_snd_device, &osk_snd_devdata); + osk_snd_devdata.dev = &osk_snd_device->dev; + *(unsigned int *)osk_dai.cpu_dai->private_data = 0; /* McBSP1 */ + err = platform_device_add(osk_snd_device); + if (err) + goto err1; + + dev = &osk_snd_device->dev; + + tlv320aic23_mclk = clk_get(dev, "mclk"); + if (IS_ERR(tlv320aic23_mclk)) { + printk(KERN_ERR "Could not get mclk clock\n"); + return -ENODEV; + } + + if (clk_get_usecount(tlv320aic23_mclk) > 0) { + /* MCLK is already in use */ + printk(KERN_WARNING + "MCLK in use at %d Hz. We change it to %d Hz\n", + (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK); + } + + /* + * Configure 12 MHz output on MCLK. + */ + curRate = (uint) clk_get_rate(tlv320aic23_mclk); + if (curRate != CODEC_CLOCK) { + if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) { + printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n"); + err = -ECANCELED; + goto err1; + } + } + + printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n", + (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK, + clk_get_usecount(tlv320aic23_mclk)); + + return 0; +err1: + clk_put(tlv320aic23_mclk); + platform_device_del(osk_snd_device); + platform_device_put(osk_snd_device); + + return err; + +} + +static void __exit osk_soc_exit(void) +{ + platform_device_unregister(osk_snd_device); +} + +module_init(osk_soc_init); +module_exit(osk_soc_exit); + +MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); +MODULE_DESCRIPTION("ALSA SoC OSK 5912"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c new file mode 100644 index 00000000000..a72dc4e159e --- /dev/null +++ b/sound/soc/omap/overo.c @@ -0,0 +1,148 @@ +/* + * overo.c -- SoC audio for Gumstix Overo + * + * Author: Steve Sakoman <steve@sakoman.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 <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/mcbsp.h> + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int overo_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; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + 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_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops overo_ops = { + .hw_params = overo_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link overo_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &overo_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_card_overo = { + .name = "overo", + .platform = &omap_soc_platform, + .dai_link = &overo_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device overo_snd_devdata = { + .card = &snd_soc_card_overo, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *overo_snd_device; + +static int __init overo_soc_init(void) +{ + int ret; + + if (!machine_is_overo()) { + pr_debug("Not Overo!\n"); + return -ENODEV; + } + printk(KERN_INFO "overo SoC init\n"); + + overo_snd_device = platform_device_alloc("soc-audio", -1); + if (!overo_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(overo_snd_device, &overo_snd_devdata); + overo_snd_devdata.dev = &overo_snd_device->dev; + *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(overo_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(overo_snd_device); + + return ret; +} +module_init(overo_soc_init); + +static void __exit overo_soc_exit(void) +{ + platform_device_unregister(overo_snd_device); +} +module_exit(overo_soc_exit); + +MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>"); +MODULE_DESCRIPTION("ALSA SoC overo"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c new file mode 100644 index 00000000000..ad97836818b --- /dev/null +++ b/sound/soc/omap/sdp3430.c @@ -0,0 +1,152 @@ +/* + * sdp3430.c -- SoC audio for TI OMAP3430 SDP + * + * Author: Misael Lopez Cruz <x0052729@ti.com> + * + * Based on: + * Author: Steve Sakoman <steve@sakoman.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 <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/mcbsp.h> + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int sdp3430_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; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + 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_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops sdp3430_ops = { + .hw_params = sdp3430_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link sdp3430_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &sdp3430_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_sdp3430 = { + .name = "SDP3430", + .platform = &omap_soc_platform, + .dai_link = &sdp3430_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device sdp3430_snd_devdata = { + .machine = &snd_soc_machine_sdp3430, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *sdp3430_snd_device; + +static int __init sdp3430_soc_init(void) +{ + int ret; + + if (!machine_is_omap_3430sdp()) { + pr_debug("Not SDP3430!\n"); + return -ENODEV; + } + printk(KERN_INFO "SDP3430 SoC init\n"); + + sdp3430_snd_device = platform_device_alloc("soc-audio", -1); + if (!sdp3430_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata); + sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev; + *(unsigned int *)sdp3430_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(sdp3430_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(sdp3430_snd_device); + + return ret; +} +module_init(sdp3430_soc_init); + +static void __exit sdp3430_soc_exit(void) +{ + platform_device_unregister(sdp3430_snd_device); +} +module_exit(sdp3430_soc_exit); + +MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>"); +MODULE_DESCRIPTION("ALSA SoC SDP3430"); +MODULE_LICENSE("GPL"); + |