diff --git a/Documentation/devicetree/bindings/sound/omap-dmic.txt b/Documentation/devicetree/bindings/sound/omap-dmic.txt new file mode 100644 index 000000000000..fd8105f18978 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-dmic.txt @@ -0,0 +1,21 @@ +* Texas Instruments OMAP4+ Digital Microphone Module + +Required properties: +- compatible: "ti,omap4-dmic" +- reg: Register location and size as an array: + , + ; +- interrupts: Interrupt number for DMIC +- interrupt-parent: The parent interrupt controller +- ti,hwmods: Name of the hwmod associated with OMAP dmic IP + +Example: + +dmic: dmic@4012e000 { + compatible = "ti,omap4-dmic"; + reg = <0x4012e000 0x7f>, /* MPU private access */ + <0x4902e000 0x7f>; /* L3 Interconnect */ + interrupts = <0 114 0x4>; + interrupt-parent = <&gic>; + ti,hwmods = "dmic"; +}; diff --git a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt new file mode 100644 index 000000000000..0741dff048dd --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt @@ -0,0 +1,21 @@ +* Texas Instruments OMAP4+ McPDM + +Required properties: +- compatible: "ti,omap4-mcpdm" +- reg: Register location and size as an array: + , + ; +- interrupts: Interrupt number for McPDM +- interrupt-parent: The parent interrupt controller +- ti,hwmods: Name of the hwmod associated to the McPDM + +Example: + +mcpdm: mcpdm@40132000 { + compatible = "ti,omap4-mcpdm"; + reg = <0x40132000 0x7f>, /* MPU private access */ + <0x49032000 0x7f>; /* L3 Interconnect */ + interrupts = <0 112 0x4>; + interrupt-parent = <&gic>; + ti,hwmods = "mcpdm"; +}; diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 9ccfa5e1c11b..57a2fa751085 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -109,11 +109,12 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040 - PandaBoard (4430) - PandaBoardES (4460) -config SND_OMAP_SOC_OMAP4_HDMI - tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" - depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 +config SND_OMAP_SOC_OMAP_HDMI + tristate "SoC Audio support for Texas Instruments OMAP HDMI" + depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS select SND_OMAP_SOC_HDMI select SND_SOC_OMAP_HDMI_CODEC + select OMAP4_DSS_HDMI_AUDIO help Say Y if you want to add support for SoC HDMI audio on Texas Instruments OMAP4 chips diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 1d656bce01d4..0e14dd322565 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -25,7 +25,7 @@ snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-zoom2-objs := zoom2.o snd-soc-igep0020-objs := igep0020.o -snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o +snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o @@ -41,4 +41,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index e5f44440d1b9..34835e8a9160 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -109,6 +109,47 @@ static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp) dev_dbg(mcbsp->dev, "***********************\n"); } +static irqreturn_t omap_mcbsp_irq_handler(int irq, void *dev_id) +{ + struct omap_mcbsp *mcbsp = dev_id; + u16 irqst; + + irqst = MCBSP_READ(mcbsp, IRQST); + dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst); + + if (irqst & RSYNCERREN) + dev_err(mcbsp->dev, "RX Frame Sync Error!\n"); + if (irqst & RFSREN) + dev_dbg(mcbsp->dev, "RX Frame Sync\n"); + if (irqst & REOFEN) + dev_dbg(mcbsp->dev, "RX End Of Frame\n"); + if (irqst & RRDYEN) + dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n"); + if (irqst & RUNDFLEN) + dev_err(mcbsp->dev, "RX Buffer Underflow!\n"); + if (irqst & ROVFLEN) + dev_err(mcbsp->dev, "RX Buffer Overflow!\n"); + + if (irqst & XSYNCERREN) + dev_err(mcbsp->dev, "TX Frame Sync Error!\n"); + if (irqst & XFSXEN) + dev_dbg(mcbsp->dev, "TX Frame Sync\n"); + if (irqst & XEOFEN) + dev_dbg(mcbsp->dev, "TX End Of Frame\n"); + if (irqst & XRDYEN) + dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n"); + if (irqst & XUNDFLEN) + dev_err(mcbsp->dev, "TX Buffer Underflow!\n"); + if (irqst & XOVFLEN) + dev_err(mcbsp->dev, "TX Buffer Overflow!\n"); + if (irqst & XEMPTYEOFEN) + dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n"); + + MCBSP_WRITE(mcbsp, IRQST, irqst); + + return IRQ_HANDLED; +} + static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) { struct omap_mcbsp *mcbsp_tx = dev_id; @@ -176,6 +217,10 @@ void omap_mcbsp_config(struct omap_mcbsp *mcbsp, /* Enable wakeup behavior */ if (mcbsp->pdata->has_wakeup) MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); + + /* Enable TX/RX sync error interrupts by default */ + if (mcbsp->irq) + MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN); } /** @@ -489,23 +534,25 @@ int omap_mcbsp_request(struct omap_mcbsp *mcbsp) MCBSP_WRITE(mcbsp, SPCR1, 0); MCBSP_WRITE(mcbsp, SPCR2, 0); - err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, - 0, "McBSP", (void *)mcbsp); - if (err != 0) { - dev_err(mcbsp->dev, "Unable to request TX IRQ %d " - "for McBSP%d\n", mcbsp->tx_irq, - mcbsp->id); - goto err_clk_disable; - } - - if (mcbsp->rx_irq) { - err = request_irq(mcbsp->rx_irq, - omap_mcbsp_rx_irq_handler, - 0, "McBSP", (void *)mcbsp); + if (mcbsp->irq) { + err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0, + "McBSP", (void *)mcbsp); if (err != 0) { - dev_err(mcbsp->dev, "Unable to request RX IRQ %d " - "for McBSP%d\n", mcbsp->rx_irq, - mcbsp->id); + dev_err(mcbsp->dev, "Unable to request IRQ\n"); + goto err_clk_disable; + } + } else { + err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0, + "McBSP TX", (void *)mcbsp); + if (err != 0) { + dev_err(mcbsp->dev, "Unable to request TX IRQ\n"); + goto err_clk_disable; + } + + err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0, + "McBSP RX", (void *)mcbsp); + if (err != 0) { + dev_err(mcbsp->dev, "Unable to request RX IRQ\n"); goto err_free_irq; } } @@ -542,9 +589,16 @@ void omap_mcbsp_free(struct omap_mcbsp *mcbsp) if (mcbsp->pdata->has_wakeup) MCBSP_WRITE(mcbsp, WAKEUPEN, 0); - if (mcbsp->rx_irq) + /* Disable interrupt requests */ + if (mcbsp->irq) + MCBSP_WRITE(mcbsp, IRQEN, 0); + + if (mcbsp->irq) { + free_irq(mcbsp->irq, (void *)mcbsp); + } else { free_irq(mcbsp->rx_irq, (void *)mcbsp); - free_irq(mcbsp->tx_irq, (void *)mcbsp); + free_irq(mcbsp->tx_irq, (void *)mcbsp); + } reg_cache = mcbsp->reg_cache; @@ -754,7 +808,7 @@ THRESHOLD_PROP_BUILDER(max_tx_thres); THRESHOLD_PROP_BUILDER(max_rx_thres); static const char *dma_op_modes[] = { - "element", "threshold", "frame", + "element", "threshold", }; static ssize_t dma_op_mode_show(struct device *dev, @@ -949,13 +1003,24 @@ int __devinit omap_mcbsp_init(struct platform_device *pdev) else mcbsp->phys_dma_base = res->start; - mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx"); - mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx"); + /* + * OMAP1, 2 uses two interrupt lines: TX, RX + * OMAP2430, OMAP3 SoC have combined IRQ line as well. + * OMAP4 and newer SoC only have the combined IRQ line. + * Use the combined IRQ if available since it gives better debugging + * possibilities. + */ + mcbsp->irq = platform_get_irq_byname(pdev, "common"); + if (mcbsp->irq == -ENXIO) { + mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx"); - /* From OMAP4 there will be a single irq line */ - if (mcbsp->tx_irq == -ENXIO) { - mcbsp->tx_irq = platform_get_irq(pdev, 0); - mcbsp->rx_irq = 0; + if (mcbsp->tx_irq == -ENXIO) { + mcbsp->irq = platform_get_irq(pdev, 0); + mcbsp->tx_irq = 0; + } else { + mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx"); + mcbsp->irq = 0; + } } res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h index a944fcc9073c..262a6152111f 100644 --- a/sound/soc/omap/mcbsp.h +++ b/sound/soc/omap/mcbsp.h @@ -217,17 +217,20 @@ enum { /********************** McBSP DMA operating modes **************************/ #define MCBSP_DMA_MODE_ELEMENT 0 #define MCBSP_DMA_MODE_THRESHOLD 1 -#define MCBSP_DMA_MODE_FRAME 2 -/********************** McBSP WAKEUPEN bit definitions *********************/ +/********************** McBSP WAKEUPEN/IRQST/IRQEN bit definitions *********/ #define RSYNCERREN BIT(0) #define RFSREN BIT(1) #define REOFEN BIT(2) #define RRDYEN BIT(3) +#define RUNDFLEN BIT(4) +#define ROVFLEN BIT(5) #define XSYNCERREN BIT(7) #define XFSXEN BIT(8) #define XEOFEN BIT(9) #define XRDYEN BIT(10) +#define XUNDFLEN BIT(11) +#define XOVFLEN BIT(12) #define XEMPTYEOFEN BIT(14) /* Clock signal muxing options */ @@ -295,6 +298,7 @@ struct omap_mcbsp { int configured; u8 free; + int irq; int rx_irq; int tx_irq; diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 93bb8eee22b3..9d93793d3077 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -40,6 +40,11 @@ #include "omap-pcm.h" #include "../codecs/twl6040.h" +struct abe_twl6040 { + int jack_detection; /* board can detect jack events */ + int mclk_freq; /* MCLK frequency speed for twl6040 */ +}; + static int omap_abe_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -47,13 +52,13 @@ static int omap_abe_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; - struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev); + struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); int clk_id, freq; int ret; clk_id = twl6040_get_clk_id(rtd->codec); if (clk_id == TWL6040_SYSCLK_SEL_HPPLL) - freq = pdata->mclk_freq; + freq = priv->mclk_freq; else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL) freq = 32768; else @@ -128,6 +133,9 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { SND_SOC_DAPM_MIC("Main Handset Mic", NULL), SND_SOC_DAPM_MIC("Sub Handset Mic", NULL), SND_SOC_DAPM_LINE("Line In", NULL), + + /* Digital microphones */ + SND_SOC_DAPM_MIC("Digital Mic", NULL), }; static const struct snd_soc_dapm_route audio_map[] = { @@ -173,6 +181,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = codec->card; struct snd_soc_dapm_context *dapm = &codec->dapm; struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev); + struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); int hs_trim; int ret = 0; @@ -196,7 +205,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) TWL6040_HSF_TRIM_RIGHT(hs_trim)); /* Headset jack detection only if it is supported */ - if (pdata->jack_detection) { + if (priv->jack_detection) { ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, &hs_jack); if (ret) @@ -210,10 +219,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) return ret; } -static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Digital Mic", NULL), -}; - static const struct snd_soc_dapm_route dmic_audio_map[] = { {"DMic", NULL, "Digital Mic"}, {"Digital Mic", NULL, "Digital Mic1 Bias"}, @@ -223,19 +228,13 @@ static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; - - ret = snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets, - ARRAY_SIZE(dmic_dapm_widgets)); - if (ret) - return ret; return snd_soc_dapm_add_routes(dapm, dmic_audio_map, ARRAY_SIZE(dmic_audio_map)); } /* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link twl6040_dmic_dai[] = { +static struct snd_soc_dai_link abe_twl6040_dai_links[] = { { .name = "TWL6040", .stream_name = "TWL6040", @@ -258,19 +257,6 @@ static struct snd_soc_dai_link twl6040_dmic_dai[] = { }, }; -static struct snd_soc_dai_link twl6040_only_dai[] = { - { - .name = "TWL6040", - .stream_name = "TWL6040", - .cpu_dai_name = "omap-mcpdm", - .codec_dai_name = "twl6040-legacy", - .platform_name = "omap-pcm-audio", - .codec_name = "twl6040-codec", - .init = omap_abe_twl6040_init, - .ops = &omap_abe_ops, - }, -}; - /* Audio machine driver */ static struct snd_soc_card omap_abe_card = { .owner = THIS_MODULE, @@ -285,6 +271,8 @@ static __devinit int omap_abe_probe(struct platform_device *pdev) { struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); struct snd_soc_card *card = &omap_abe_card; + struct abe_twl6040 *priv; + int num_links = 0; int ret; card->dev = &pdev->dev; @@ -294,6 +282,10 @@ static __devinit int omap_abe_probe(struct platform_device *pdev) return -ENODEV; } + priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + if (pdata->card_name) { card->name = pdata->card_name; } else { @@ -301,18 +293,24 @@ static __devinit int omap_abe_probe(struct platform_device *pdev) return -ENODEV; } - if (!pdata->mclk_freq) { + priv->jack_detection = pdata->jack_detection; + priv->mclk_freq = pdata->mclk_freq; + + + if (!priv->mclk_freq) { dev_err(&pdev->dev, "MCLK frequency missing\n"); return -ENODEV; } - if (pdata->has_dmic) { - card->dai_link = twl6040_dmic_dai; - card->num_links = ARRAY_SIZE(twl6040_dmic_dai); - } else { - card->dai_link = twl6040_only_dai; - card->num_links = ARRAY_SIZE(twl6040_only_dai); - } + if (pdata->has_dmic) + num_links = 2; + else + num_links = 1; + + card->dai_link = abe_twl6040_dai_links; + card->num_links = num_links; + + snd_soc_card_set_drvdata(card, priv); ret = snd_soc_register_card(card); if (ret) diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 4dcb5a7e40e8..75f5dca0e8d2 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -528,10 +529,17 @@ static int __devexit asoc_dmic_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id omap_dmic_of_match[] = { + { .compatible = "ti,omap4-dmic", }, + { } +}; +MODULE_DEVICE_TABLE(of, omap_dmic_of_match); + static struct platform_driver asoc_dmic_driver = { .driver = { .name = "omap-dmic", .owner = THIS_MODULE, + .of_match_table = omap_dmic_of_match, }, .probe = asoc_dmic_probe, .remove = __devexit_p(asoc_dmic_remove), diff --git a/sound/soc/omap/omap-hdmi-card.c b/sound/soc/omap/omap-hdmi-card.c new file mode 100644 index 000000000000..eaa2ea0e3f81 --- /dev/null +++ b/sound/soc/omap/omap-hdmi-card.c @@ -0,0 +1,87 @@ +/* + * omap-hdmi-card.c + * + * OMAP ALSA SoC machine driver for TI OMAP HDMI + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Ricardo Neri + * + * 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 +#include +#include +#include +#include