Merge tag 'sound-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 May 2012 15:45:25 +0000 (08:45 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 May 2012 15:45:25 +0000 (08:45 -0700)
Pull sound update from Takashi Iwai:
 "This is the second updates for 3.5-rc1.  It's mainly for OMAP4 HDMI
  updates and the device tree updates for OMAP, in addition to a couple
  of PCM accuray improvement and Realtek ALC269VD codec support."

* tag 'sound-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (21 commits)
  ALSA: hda/realtek - Add new codec support for ALC269VD
  ALSA: core: group read of pointer, tstamp and jiffies
  ASoC: OMAP: HDMI: Rename sound card source file
  ASoC: OMAP: HDMI: Make sound card naming more generic
  ASoC: OMAP: HDMI: Make build config options more generic
  ASoC: OMAP: HDMI: Expand capabilities of the HDMI DAI
  ASoC: OMAP: HDMI: Improve how the display state is verified
  ASoC: OMAP: HDMI: Expand configuration of hw_params
  ASoC: OMAP: HDMI: Use the DSS audio interface
  ASoC: OMAP: HDMI: Create a structure for private data of the CPU DAI
  ASoC: OMAP: HDMI: Change error values in HDMI CPU DAI
  ASoC: OMAP: HDMI: Update the platform device names
  ASoC: omap-abe-twl6040: Introduce driver data for runtime parameters
  ASoC: omap-abe-twl6040: Move Digital Mic widget into dapm table
  ASoC: omap-abe-twl6040: Keep only one snd_soc_dai_link structure
  ASoC: omap-dmic: Add device tree bindings
  ASoC: omap-mcpdm: Add device tree bindings
  ASoC: omap-mcbsp: buffer size constraint only applies to playback stream
  ASoC: omap-mcbsp: Use the common interrupt line if supported by the SoC
  ASoC: omap-mcbsp: Remove unused FRAME dma_op_mode
  ...

16 files changed:
Documentation/devicetree/bindings/sound/omap-dmic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/omap-mcpdm.txt [new file with mode: 0644]
sound/core/pcm_lib.c
sound/pci/hda/patch_realtek.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/mcbsp.c
sound/soc/omap/mcbsp.h
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-dmic.c
sound/soc/omap/omap-hdmi-card.c [new file with mode: 0644]
sound/soc/omap/omap-hdmi.c
sound/soc/omap/omap-hdmi.h
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap4-hdmi-card.c [deleted file]

diff --git a/Documentation/devicetree/bindings/sound/omap-dmic.txt b/Documentation/devicetree/bindings/sound/omap-dmic.txt
new file mode 100644 (file)
index 0000000..fd8105f
--- /dev/null
@@ -0,0 +1,21 @@
+* Texas Instruments OMAP4+ Digital Microphone Module
+
+Required properties:
+- compatible: "ti,omap4-dmic"
+- reg: Register location and size as an array:
+       <MPU access base address, size>,
+       <L3 interconnect address, size>;
+- 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 (file)
index 0000000..0741dff
--- /dev/null
@@ -0,0 +1,21 @@
+* Texas Instruments OMAP4+ McPDM
+
+Required properties:
+- compatible: "ti,omap4-mcpdm"
+- reg: Register location and size as an array:
+       <MPU access base address, size>,
+       <L3 interconnect address, size>;
+- 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";
+};
index faedb1481b240d9195b097f1448f98df3dcb6912..8f312fa6c282c88db2cd0c84389096228fe70fc4 100644 (file)
@@ -313,9 +313,22 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
        snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
        snd_pcm_sframes_t hdelta, delta;
        unsigned long jdelta;
+       unsigned long curr_jiffies;
+       struct timespec curr_tstamp;
 
        old_hw_ptr = runtime->status->hw_ptr;
+
+       /*
+        * group pointer, time and jiffies reads to allow for more
+        * accurate correlations/corrections.
+        * The values are stored at the end of this routine after
+        * corrections for hw_ptr position
+        */
        pos = substream->ops->pointer(substream);
+       curr_jiffies = jiffies;
+       if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+               snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
+
        if (pos == SNDRV_PCM_POS_XRUN) {
                xrun(substream);
                return -EPIPE;
@@ -343,7 +356,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                delta = runtime->hw_ptr_interrupt + runtime->period_size;
                if (delta > new_hw_ptr) {
                        /* check for double acknowledged interrupts */
-                       hdelta = jiffies - runtime->hw_ptr_jiffies;
+                       hdelta = curr_jiffies - runtime->hw_ptr_jiffies;
                        if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
                                hw_base += runtime->buffer_size;
                                if (hw_base >= runtime->boundary)
@@ -388,7 +401,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                 * Without regular period interrupts, we have to check
                 * the elapsed time to detect xruns.
                 */
-               jdelta = jiffies - runtime->hw_ptr_jiffies;
+               jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
                if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
                        goto no_delta_check;
                hdelta = jdelta - delta * HZ / runtime->rate;
@@ -430,7 +443,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
        if (hdelta < runtime->delay)
                goto no_jiffies_check;
        hdelta -= runtime->delay;
-       jdelta = jiffies - runtime->hw_ptr_jiffies;
+       jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
        if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
                delta = jdelta /
                        (((runtime->period_size * HZ) / runtime->rate)
@@ -492,9 +505,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
        }
        runtime->hw_ptr_base = hw_base;
        runtime->status->hw_ptr = new_hw_ptr;
-       runtime->hw_ptr_jiffies = jiffies;
+       runtime->hw_ptr_jiffies = curr_jiffies;
        if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
-               snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
+               runtime->status->tstamp = curr_tstamp;
 
        return snd_pcm_update_state(substream, runtime);
 }
index ff71dcef08ef1c0d3b2790121fbfda1ebd989758..224410e8e9e7461431063a8d1f23b8650362faca 100644 (file)
@@ -2368,6 +2368,7 @@ static struct alc_codec_rename_table rename_tbl[] = {
        { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
        { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
        { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
+       { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
        { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
        { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
        { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
@@ -5614,6 +5615,7 @@ enum {
        ALC269_TYPE_ALC269VA,
        ALC269_TYPE_ALC269VB,
        ALC269_TYPE_ALC269VC,
+       ALC269_TYPE_ALC269VD,
 };
 
 /*
@@ -5625,8 +5627,21 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
        static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
        struct alc_spec *spec = codec->spec;
-       const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ?
-               alc269va_ssids : alc269_ssids;
+       const hda_nid_t *ssids;
+
+       switch (spec->codec_variant) {
+       case ALC269_TYPE_ALC269VA:
+       case ALC269_TYPE_ALC269VC:
+               ssids = alc269va_ssids;
+               break;
+       case ALC269_TYPE_ALC269VB:
+       case ALC269_TYPE_ALC269VD:
+               ssids = alc269_ssids;
+               break;
+       default:
+               ssids = alc269_ssids;
+               break;
+       }
 
        return alc_parse_auto_config(codec, alc269_ignore, ssids);
 }
@@ -5643,6 +5658,11 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
 
 static void alc269_shutup(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->codec_variant != ALC269_TYPE_ALC269VB)
+               return;
+
        if ((alc_get_coef0(codec) & 0x00ff) == 0x017)
                alc269_toggle_power_output(codec, 0);
        if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
@@ -5654,19 +5674,24 @@ static void alc269_shutup(struct hda_codec *codec)
 #ifdef CONFIG_PM
 static int alc269_resume(struct hda_codec *codec)
 {
-       if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB ||
+                       (alc_get_coef0(codec) & 0x00ff) == 0x018) {
                alc269_toggle_power_output(codec, 0);
                msleep(150);
        }
 
        codec->patch_ops.init(codec);
 
-       if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB ||
+                       (alc_get_coef0(codec) & 0x00ff) == 0x017) {
                alc269_toggle_power_output(codec, 1);
                msleep(200);
        }
 
-       if ((alc_get_coef0(codec) & 0x00ff) == 0x018)
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB ||
+                       (alc_get_coef0(codec) & 0x00ff) == 0x018)
                alc269_toggle_power_output(codec, 1);
 
        snd_hda_codec_resume_amp(codec);
@@ -6081,6 +6106,9 @@ static int patch_alc269(struct hda_codec *codec)
                                err = alc_codec_rename(codec, "ALC3202");
                        spec->codec_variant = ALC269_TYPE_ALC269VC;
                        break;
+               case 0x0030:
+                       spec->codec_variant = ALC269_TYPE_ALC269VD;
+                       break;
                default:
                        alc_fix_pll_init(codec, 0x20, 0x04, 15);
                }
index 9ccfa5e1c11b4f236128663b4cfaca8bae197a75..57a2fa751085cc025abe5490deb2e8513b0a7d6b 100644 (file)
@@ -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
index 1d656bce01d48e599f18e7a1ec74f91cd1fcb573..0e14dd3225650b0e6988f8ad1ec90d70788de3e5 100644 (file)
@@ -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
index e5f44440d1b948fda1de18196bd1190b5aa707a4..34835e8a9160ce16b1d074a1f8495d1124e5eac8 100644 (file)
@@ -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->irq) {
+               err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
+                                 "McBSP", (void *)mcbsp);
+               if (err != 0) {
+                       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;
+               }
 
-       if (mcbsp->rx_irq) {
-               err = request_irq(mcbsp->rx_irq,
-                               omap_mcbsp_rx_irq_handler,
-                               0, "McBSP", (void *)mcbsp);
+               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 %d "
-                                       "for McBSP%d\n", mcbsp->rx_irq,
-                                       mcbsp->id);
+                       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");
-
-       /* 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;
+       /*
+        * 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");
+
+               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");
index a944fcc9073c619f82667c7c5a2bd0a8861f4f3f..262a6152111fe67badda011198c875974e76d377 100644 (file)
@@ -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;
 
index 93bb8eee22b32cdcf00f4d6d2b1fa54510711fb4..9d93793d3077c61d8819760d4bd12b75e3896557 100644 (file)
 #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)
index 4dcb5a7e40e874c37440cbcf82073844ebf6d4d7..75f5dca0e8d2c0a1dd4d107ece0cd2023c9ad583 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/of_device.h>
 #include <plat/dma.h>
 
 #include <sound/core.h>
@@ -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 (file)
index 0000000..eaa2ea0
--- /dev/null
@@ -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 <ricardo.neri@ti.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/module.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/mach-types.h>
+#include <video/omapdss.h>
+
+#define DRV_NAME "omap-hdmi-audio"
+
+static struct snd_soc_dai_link omap_hdmi_dai = {
+       .name = "HDMI",
+       .stream_name = "HDMI",
+       .cpu_dai_name = "omap-hdmi-audio-dai",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "hdmi-audio-codec",
+       .codec_dai_name = "omap-hdmi-hifi",
+};
+
+static struct snd_soc_card snd_soc_omap_hdmi = {
+       .name = "OMAPHDMI",
+       .owner = THIS_MODULE,
+       .dai_link = &omap_hdmi_dai,
+       .num_links = 1,
+};
+
+static __devinit int omap_hdmi_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &snd_soc_omap_hdmi;
+       int ret;
+
+       card->dev = &pdev->dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+               card->dev = NULL;
+               return ret;
+       }
+       return 0;
+}
+
+static int __devexit omap_hdmi_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+       card->dev = NULL;
+       return 0;
+}
+
+static struct platform_driver omap_hdmi_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = omap_hdmi_probe,
+       .remove = __devexit_p(omap_hdmi_remove),
+};
+
+module_platform_driver(omap_hdmi_driver);
+
+MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
+MODULE_DESCRIPTION("OMAP HDMI machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 38e0defa7078a9cf57f4d9c8fd7c2a6c3336fdd0..a08245d9203cddfd20e38254d02104c25c18f9a8 100644 (file)
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/asound.h>
+#include <sound/asoundef.h>
+#include <video/omapdss.h>
 
 #include <plat/dma.h>
 #include "omap-pcm.h"
 #include "omap-hdmi.h"
 
-#define DRV_NAME "hdmi-audio-dai"
+#define DRV_NAME "omap-hdmi-audio-dai"
 
-static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = {
-       .name = "HDMI playback",
-       .sync_mode = OMAP_DMA_SYNC_PACKET,
+struct hdmi_priv {
+       struct omap_pcm_dma_data dma_params;
+       struct omap_dss_audio dss_audio;
+       struct snd_aes_iec958 iec;
+       struct snd_cea_861_aud_if cea;
+       struct omap_dss_device *dssdev;
 };
 
 static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
+       struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
        int err;
        /*
         * Make sure that the period bytes are multiple of the DMA packet size.
@@ -52,46 +59,201 @@ static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
         */
        err = snd_pcm_hw_constraint_step(substream->runtime, 0,
                                 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(dai->dev, "could not apply constraint\n");
                return err;
+       }
 
+       if (!priv->dssdev->driver->audio_supported(priv->dssdev)) {
+               dev_err(dai->dev, "audio not supported\n");
+               return -ENODEV;
+       }
        return 0;
 }
 
+static int omap_hdmi_dai_prepare(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+       return priv->dssdev->driver->audio_enable(priv->dssdev);
+}
+
 static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params,
                                    struct snd_soc_dai *dai)
 {
+       struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
+       struct snd_aes_iec958 *iec = &priv->iec;
+       struct snd_cea_861_aud_if *cea = &priv->cea;
        int err = 0;
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               omap_hdmi_dai_dma_params.packet_size = 16;
+               priv->dma_params.packet_size = 16;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
-               omap_hdmi_dai_dma_params.packet_size = 32;
+               priv->dma_params.packet_size = 32;
                break;
        default:
-               err = -EINVAL;
+               dev_err(dai->dev, "format not supported!\n");
+               return -EINVAL;
        }
 
-       omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+       priv->dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
 
        snd_soc_dai_set_dma_data(dai, substream,
-                                &omap_hdmi_dai_dma_params);
+                                &priv->dma_params);
+
+       /*
+        * fill the IEC-60958 channel status word
+        */
+
+       /* specify IEC-60958-3 (commercial use) */
+       iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
+
+       /* specify that the audio is LPCM*/
+       iec->status[0] &= ~IEC958_AES0_NONAUDIO;
+
+       iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
+
+       iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
+
+       iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID;
+
+       iec->status[1] = IEC958_AES1_CON_GENERAL;
+
+       iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
+
+       iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
+
+       switch (params_rate(params)) {
+       case 32000:
+               iec->status[3] |= IEC958_AES3_CON_FS_32000;
+               break;
+       case 44100:
+               iec->status[3] |= IEC958_AES3_CON_FS_44100;
+               break;
+       case 48000:
+               iec->status[3] |= IEC958_AES3_CON_FS_48000;
+               break;
+       case 88200:
+               iec->status[3] |= IEC958_AES3_CON_FS_88200;
+               break;
+       case 96000:
+               iec->status[3] |= IEC958_AES3_CON_FS_96000;
+               break;
+       case 176400:
+               iec->status[3] |= IEC958_AES3_CON_FS_176400;
+               break;
+       case 192000:
+               iec->status[3] |= IEC958_AES3_CON_FS_192000;
+               break;
+       default:
+               dev_err(dai->dev, "rate not supported!\n");
+               return -EINVAL;
+       }
+
+       /* specify the clock accuracy */
+       iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
+
+       /*
+        * specify the word length. The same word length value can mean
+        * two different lengths. Hence, we need to specify the maximum
+        * word length as well.
+        */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
+               iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
+               iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
+               break;
+       default:
+               dev_err(dai->dev, "format not supported!\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Fill the CEA-861 audio infoframe (see spec for details)
+        */
+
+       cea->db1_ct_cc = (params_channels(params) - 1)
+               & CEA861_AUDIO_INFOFRAME_DB1CC;
+       cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
+
+       cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
+       cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
+
+       cea->db3 = 0; /* not used, all zeros */
+
+       /*
+        * The OMAP HDMI IP requires to use the 8-channel channel code when
+        * transmitting more than two channels.
+        */
+       if (params_channels(params) == 2)
+               cea->db4_ca = 0x0;
+       else
+               cea->db4_ca = 0x13;
+
+       cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
+       /* the expression is trivial but makes clear what we are doing */
+       cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
+
+       priv->dss_audio.iec = iec;
+       priv->dss_audio.cea = cea;
+
+       err = priv->dssdev->driver->audio_config(priv->dssdev,
+                                                &priv->dss_audio);
 
        return err;
 }
 
+static int omap_hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
+       int err = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               err = priv->dssdev->driver->audio_start(priv->dssdev);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               priv->dssdev->driver->audio_stop(priv->dssdev);
+               break;
+       default:
+               err = -EINVAL;
+       }
+       return err;
+}
+
+static void omap_hdmi_dai_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+       priv->dssdev->driver->audio_disable(priv->dssdev);
+}
+
 static const struct snd_soc_dai_ops omap_hdmi_dai_ops = {
        .startup        = omap_hdmi_dai_startup,
        .hw_params      = omap_hdmi_dai_hw_params,
+       .prepare        = omap_hdmi_dai_prepare,
+       .trigger        = omap_hdmi_dai_trigger,
+       .shutdown       = omap_hdmi_dai_shutdown,
 };
 
 static struct snd_soc_dai_driver omap_hdmi_dai = {
        .playback = {
                .channels_min = 2,
-               .channels_max = 2,
+               .channels_max = 8,
                .rates = OMAP_HDMI_RATES,
                .formats = OMAP_HDMI_FORMATS,
        },
@@ -102,31 +264,77 @@ static __devinit int omap_hdmi_probe(struct platform_device *pdev)
 {
        int ret;
        struct resource *hdmi_rsrc;
+       struct hdmi_priv *hdmi_data;
+       bool hdmi_dev_found = false;
+
+       hdmi_data = devm_kzalloc(&pdev->dev, sizeof(*hdmi_data), GFP_KERNEL);
+       if (hdmi_data == NULL) {
+               dev_err(&pdev->dev, "Cannot allocate memory for HDMI data\n");
+               return -ENOMEM;
+       }
 
        hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!hdmi_rsrc) {
                dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n");
-               return -EINVAL;
+               return -ENODEV;
        }
 
-       omap_hdmi_dai_dma_params.port_addr =  hdmi_rsrc->start
+       hdmi_data->dma_params.port_addr =  hdmi_rsrc->start
                + OMAP_HDMI_AUDIO_DMA_PORT;
 
        hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!hdmi_rsrc) {
                dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n");
-               return -EINVAL;
+               return -ENODEV;
        }
 
-       omap_hdmi_dai_dma_params.dma_req =  hdmi_rsrc->start;
+       hdmi_data->dma_params.dma_req =  hdmi_rsrc->start;
+       hdmi_data->dma_params.name = "HDMI playback";
+       hdmi_data->dma_params.sync_mode = OMAP_DMA_SYNC_PACKET;
+
+       /*
+        * TODO: We assume that there is only one DSS HDMI device. Future
+        * OMAP implementations may support more than one HDMI devices and
+        * we should provided separate audio support for all of them.
+        */
+       /* Find an HDMI device. */
+       for_each_dss_dev(hdmi_data->dssdev) {
+               omap_dss_get_device(hdmi_data->dssdev);
 
+               if (!hdmi_data->dssdev->driver) {
+                       omap_dss_put_device(hdmi_data->dssdev);
+                       continue;
+               }
+
+               if (hdmi_data->dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
+                       hdmi_dev_found = true;
+                       break;
+               }
+       }
+
+       if (!hdmi_dev_found) {
+               dev_err(&pdev->dev, "no driver for HDMI display found\n");
+               return -ENODEV;
+       }
+
+       dev_set_drvdata(&pdev->dev, hdmi_data);
        ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
+
        return ret;
 }
 
 static int __devexit omap_hdmi_remove(struct platform_device *pdev)
 {
+       struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
+
        snd_soc_unregister_dai(&pdev->dev);
+
+       if (hdmi_data == NULL) {
+               dev_err(&pdev->dev, "cannot obtain HDMi data\n");
+               return -ENODEV;
+       }
+
+       omap_dss_put_device(hdmi_data->dssdev);
        return 0;
 }
 
index 34c298d5057e26dac9864a7e184aad7882c4c18a..6ad2bf4f269783e3d95513a19c3b8290368d8127 100644 (file)
@@ -28,7 +28,9 @@
 #define OMAP_HDMI_AUDIO_DMA_PORT 0x8c
 
 #define OMAP_HDMI_RATES        (SNDRV_PCM_RATE_32000 | \
-                               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+                               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+                               SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
+                               SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
 
 #define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
                                SNDRV_PCM_FMTBIT_S24_LE)
index 6912ac7cb6250ae8cf30b886d507e0ffdfe2df9a..1046083e90a079f594b99ef0f88b72bb7e8e5150 100644 (file)
@@ -71,18 +71,17 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
 
        dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
-       /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
-       if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
-               /*
-                * Configure McBSP threshold based on either:
-                * packet_size, when the sDMA is in packet mode, or
-                * based on the period size.
-                */
-               if (dma_data->packet_size)
-                       words = dma_data->packet_size;
-               else
-                       words = snd_pcm_lib_period_bytes(substream) /
-                                                       (mcbsp->wlen / 8);
+       /*
+        * Configure McBSP threshold based on either:
+        * packet_size, when the sDMA is in packet mode, or based on the
+        * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
+        * for mono streams.
+        */
+       if (dma_data->packet_size)
+               words = dma_data->packet_size;
+       else if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
+               words = snd_pcm_lib_period_bytes(substream) /
+                                               (mcbsp->wlen / 8);
        else
                words = 1;
 
@@ -139,13 +138,15 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
        if (mcbsp->pdata->buffer_size) {
                /*
                * Rule for the buffer size. We should not allow
-               * smaller buffer than the FIFO size to avoid underruns
+               * smaller buffer than the FIFO size to avoid underruns.
+               * This applies only for the playback stream.
                */
-               snd_pcm_hw_rule_add(substream->runtime, 0,
-                                   SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
-                                   omap_mcbsp_hwrule_min_buffersize,
-                                   mcbsp,
-                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       snd_pcm_hw_rule_add(substream->runtime, 0,
+                                           SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                           omap_mcbsp_hwrule_min_buffersize,
+                                           mcbsp,
+                                           SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
                /* Make sure, that the period size is always even */
                snd_pcm_hw_constraint_step(substream->runtime, 0,
@@ -230,6 +231,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        unsigned int format, div, framesize, master;
 
        dma_data = &mcbsp->dma_data[substream->stream];
+       channels = params_channels(params);
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
@@ -245,7 +247,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        }
        if (mcbsp->pdata->buffer_size) {
                dma_data->set_threshold = omap_mcbsp_set_threshold;
-               /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
                if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
                        int period_words, max_thrsh;
 
@@ -283,6 +284,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                        } else {
                                sync_mode = OMAP_DMA_SYNC_FRAME;
                        }
+               } else if (channels > 1) {
+                       /* Use packet mode for non mono streams */
+                       pkt_size = channels;
+                       sync_mode = OMAP_DMA_SYNC_PACKET;
                }
        }
 
@@ -301,7 +306,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        regs->rcr1      &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
        regs->xcr1      &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
        format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
-       wpf = channels = params_channels(params);
+       wpf = channels;
        if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
                              format == SND_SOC_DAIFMT_LEFT_J)) {
                /* Use dual-phase frames */
index 39705561131a6c10f4a62a486a31208ccbe075a4..59d47ab5b15d72dd996cb13b4a06f274d961d7df 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/irq.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -507,10 +508,17 @@ static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id omap_mcpdm_of_match[] = {
+       { .compatible = "ti,omap4-mcpdm", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, omap_mcpdm_of_match);
+
 static struct platform_driver asoc_mcpdm_driver = {
        .driver = {
                .name   = "omap-mcpdm",
                .owner  = THIS_MODULE,
+               .of_match_table = omap_mcpdm_of_match,
        },
 
        .probe  = asoc_mcpdm_probe,
diff --git a/sound/soc/omap/omap4-hdmi-card.c b/sound/soc/omap/omap4-hdmi-card.c
deleted file mode 100644 (file)
index 28d689b..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * omap4-hdmi-card.c
- *
- * OMAP ALSA SoC machine driver for TI OMAP4 HDMI
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
- * Author: Ricardo Neri <ricardo.neri@ti.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/module.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/mach-types.h>
-#include <video/omapdss.h>
-
-#define DRV_NAME "omap4-hdmi-audio"
-
-static int omap4_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
-               struct snd_pcm_hw_params *params)
-{
-       int i;
-       struct omap_overlay_manager *mgr = NULL;
-       struct device *dev = substream->pcm->card->dev;
-
-       /* Find DSS HDMI device */
-       for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
-               mgr = omap_dss_get_overlay_manager(i);
-               if (mgr && mgr->device
-                       && mgr->device->type == OMAP_DISPLAY_TYPE_HDMI)
-                       break;
-       }
-
-       if (i == omap_dss_get_num_overlay_managers()) {
-               dev_err(dev, "HDMI display device not found!\n");
-               return -ENODEV;
-       }
-
-       /* Make sure HDMI is power-on to avoid L3 interconnect errors */
-       if (mgr->device->state != OMAP_DSS_DISPLAY_ACTIVE) {
-               dev_err(dev, "HDMI display is not active!\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_ops omap4_hdmi_dai_ops = {
-       .hw_params = omap4_hdmi_dai_hw_params,
-};
-
-static struct snd_soc_dai_link omap4_hdmi_dai = {
-       .name = "HDMI",
-       .stream_name = "HDMI",
-       .cpu_dai_name = "hdmi-audio-dai",
-       .platform_name = "omap-pcm-audio",
-       .codec_name = "omapdss_hdmi",
-       .codec_dai_name = "hdmi-audio-codec",
-       .ops = &omap4_hdmi_dai_ops,
-};
-
-static struct snd_soc_card snd_soc_omap4_hdmi = {
-       .name = "OMAP4HDMI",
-       .owner = THIS_MODULE,
-       .dai_link = &omap4_hdmi_dai,
-       .num_links = 1,
-};
-
-static __devinit int omap4_hdmi_probe(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = &snd_soc_omap4_hdmi;
-       int ret;
-
-       card->dev = &pdev->dev;
-
-       ret = snd_soc_register_card(card);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
-               card->dev = NULL;
-               return ret;
-       }
-       return 0;
-}
-
-static int __devexit omap4_hdmi_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-       card->dev = NULL;
-       return 0;
-}
-
-static struct platform_driver omap4_hdmi_driver = {
-       .driver = {
-               .name = "omap4-hdmi-audio",
-               .owner = THIS_MODULE,
-       },
-       .probe = omap4_hdmi_probe,
-       .remove = __devexit_p(omap4_hdmi_remove),
-};
-
-module_platform_driver(omap4_hdmi_driver);
-
-MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("OMAP4 HDMI machine ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);