Commit 599ed4b0aeceb6d45ea33f64639e745e3da72766

Authored by Takashi Iwai

Merge branch 'for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/asoc into topic/asoc

Showing 14 changed files Side-by-side Diff

Documentation/devicetree/bindings/sound/omap-dmic.txt
  1 +* Texas Instruments OMAP4+ Digital Microphone Module
  2 +
  3 +Required properties:
  4 +- compatible: "ti,omap4-dmic"
  5 +- reg: Register location and size as an array:
  6 + <MPU access base address, size>,
  7 + <L3 interconnect address, size>;
  8 +- interrupts: Interrupt number for DMIC
  9 +- interrupt-parent: The parent interrupt controller
  10 +- ti,hwmods: Name of the hwmod associated with OMAP dmic IP
  11 +
  12 +Example:
  13 +
  14 +dmic: dmic@4012e000 {
  15 + compatible = "ti,omap4-dmic";
  16 + reg = <0x4012e000 0x7f>, /* MPU private access */
  17 + <0x4902e000 0x7f>; /* L3 Interconnect */
  18 + interrupts = <0 114 0x4>;
  19 + interrupt-parent = <&gic>;
  20 + ti,hwmods = "dmic";
  21 +};
Documentation/devicetree/bindings/sound/omap-mcpdm.txt
  1 +* Texas Instruments OMAP4+ McPDM
  2 +
  3 +Required properties:
  4 +- compatible: "ti,omap4-mcpdm"
  5 +- reg: Register location and size as an array:
  6 + <MPU access base address, size>,
  7 + <L3 interconnect address, size>;
  8 +- interrupts: Interrupt number for McPDM
  9 +- interrupt-parent: The parent interrupt controller
  10 +- ti,hwmods: Name of the hwmod associated to the McPDM
  11 +
  12 +Example:
  13 +
  14 +mcpdm: mcpdm@40132000 {
  15 + compatible = "ti,omap4-mcpdm";
  16 + reg = <0x40132000 0x7f>, /* MPU private access */
  17 + <0x49032000 0x7f>; /* L3 Interconnect */
  18 + interrupts = <0 112 0x4>;
  19 + interrupt-parent = <&gic>;
  20 + ti,hwmods = "mcpdm";
  21 +};
sound/soc/omap/Kconfig
... ... @@ -109,11 +109,12 @@
109 109 - PandaBoard (4430)
110 110 - PandaBoardES (4460)
111 111  
112   -config SND_OMAP_SOC_OMAP4_HDMI
113   - tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
114   - depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4
  112 +config SND_OMAP_SOC_OMAP_HDMI
  113 + tristate "SoC Audio support for Texas Instruments OMAP HDMI"
  114 + depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
115 115 select SND_OMAP_SOC_HDMI
116 116 select SND_SOC_OMAP_HDMI_CODEC
  117 + select OMAP4_DSS_HDMI_AUDIO
117 118 help
118 119 Say Y if you want to add support for SoC HDMI audio on Texas Instruments
119 120 OMAP4 chips
sound/soc/omap/Makefile
... ... @@ -25,7 +25,7 @@
25 25 snd-soc-omap3beagle-objs := omap3beagle.o
26 26 snd-soc-zoom2-objs := zoom2.o
27 27 snd-soc-igep0020-objs := igep0020.o
28   -snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o
  28 +snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o
29 29  
30 30 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
31 31 obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
... ... @@ -41,5 +41,5 @@
41 41 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
42 42 obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
43 43 obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
44   -obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o
  44 +obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o
sound/soc/omap/mcbsp.c
... ... @@ -109,6 +109,47 @@
109 109 dev_dbg(mcbsp->dev, "***********************\n");
110 110 }
111 111  
  112 +static irqreturn_t omap_mcbsp_irq_handler(int irq, void *dev_id)
  113 +{
  114 + struct omap_mcbsp *mcbsp = dev_id;
  115 + u16 irqst;
  116 +
  117 + irqst = MCBSP_READ(mcbsp, IRQST);
  118 + dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
  119 +
  120 + if (irqst & RSYNCERREN)
  121 + dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
  122 + if (irqst & RFSREN)
  123 + dev_dbg(mcbsp->dev, "RX Frame Sync\n");
  124 + if (irqst & REOFEN)
  125 + dev_dbg(mcbsp->dev, "RX End Of Frame\n");
  126 + if (irqst & RRDYEN)
  127 + dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
  128 + if (irqst & RUNDFLEN)
  129 + dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
  130 + if (irqst & ROVFLEN)
  131 + dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
  132 +
  133 + if (irqst & XSYNCERREN)
  134 + dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
  135 + if (irqst & XFSXEN)
  136 + dev_dbg(mcbsp->dev, "TX Frame Sync\n");
  137 + if (irqst & XEOFEN)
  138 + dev_dbg(mcbsp->dev, "TX End Of Frame\n");
  139 + if (irqst & XRDYEN)
  140 + dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
  141 + if (irqst & XUNDFLEN)
  142 + dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
  143 + if (irqst & XOVFLEN)
  144 + dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
  145 + if (irqst & XEMPTYEOFEN)
  146 + dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
  147 +
  148 + MCBSP_WRITE(mcbsp, IRQST, irqst);
  149 +
  150 + return IRQ_HANDLED;
  151 +}
  152 +
112 153 static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
113 154 {
114 155 struct omap_mcbsp *mcbsp_tx = dev_id;
... ... @@ -176,6 +217,10 @@
176 217 /* Enable wakeup behavior */
177 218 if (mcbsp->pdata->has_wakeup)
178 219 MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
  220 +
  221 + /* Enable TX/RX sync error interrupts by default */
  222 + if (mcbsp->irq)
  223 + MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN);
179 224 }
180 225  
181 226 /**
182 227  
183 228  
... ... @@ -489,23 +534,25 @@
489 534 MCBSP_WRITE(mcbsp, SPCR1, 0);
490 535 MCBSP_WRITE(mcbsp, SPCR2, 0);
491 536  
492   - err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler,
493   - 0, "McBSP", (void *)mcbsp);
494   - if (err != 0) {
495   - dev_err(mcbsp->dev, "Unable to request TX IRQ %d "
496   - "for McBSP%d\n", mcbsp->tx_irq,
497   - mcbsp->id);
498   - goto err_clk_disable;
499   - }
  537 + if (mcbsp->irq) {
  538 + err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
  539 + "McBSP", (void *)mcbsp);
  540 + if (err != 0) {
  541 + dev_err(mcbsp->dev, "Unable to request IRQ\n");
  542 + goto err_clk_disable;
  543 + }
  544 + } else {
  545 + err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
  546 + "McBSP TX", (void *)mcbsp);
  547 + if (err != 0) {
  548 + dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
  549 + goto err_clk_disable;
  550 + }
500 551  
501   - if (mcbsp->rx_irq) {
502   - err = request_irq(mcbsp->rx_irq,
503   - omap_mcbsp_rx_irq_handler,
504   - 0, "McBSP", (void *)mcbsp);
  552 + err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
  553 + "McBSP RX", (void *)mcbsp);
505 554 if (err != 0) {
506   - dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
507   - "for McBSP%d\n", mcbsp->rx_irq,
508   - mcbsp->id);
  555 + dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
509 556 goto err_free_irq;
510 557 }
511 558 }
512 559  
... ... @@ -542,9 +589,16 @@
542 589 if (mcbsp->pdata->has_wakeup)
543 590 MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
544 591  
545   - if (mcbsp->rx_irq)
  592 + /* Disable interrupt requests */
  593 + if (mcbsp->irq)
  594 + MCBSP_WRITE(mcbsp, IRQEN, 0);
  595 +
  596 + if (mcbsp->irq) {
  597 + free_irq(mcbsp->irq, (void *)mcbsp);
  598 + } else {
546 599 free_irq(mcbsp->rx_irq, (void *)mcbsp);
547   - free_irq(mcbsp->tx_irq, (void *)mcbsp);
  600 + free_irq(mcbsp->tx_irq, (void *)mcbsp);
  601 + }
548 602  
549 603 reg_cache = mcbsp->reg_cache;
550 604  
... ... @@ -754,7 +808,7 @@
754 808 THRESHOLD_PROP_BUILDER(max_rx_thres);
755 809  
756 810 static const char *dma_op_modes[] = {
757   - "element", "threshold", "frame",
  811 + "element", "threshold",
758 812 };
759 813  
760 814 static ssize_t dma_op_mode_show(struct device *dev,
761 815  
... ... @@ -949,13 +1003,24 @@
949 1003 else
950 1004 mcbsp->phys_dma_base = res->start;
951 1005  
952   - mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
953   - mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
  1006 + /*
  1007 + * OMAP1, 2 uses two interrupt lines: TX, RX
  1008 + * OMAP2430, OMAP3 SoC have combined IRQ line as well.
  1009 + * OMAP4 and newer SoC only have the combined IRQ line.
  1010 + * Use the combined IRQ if available since it gives better debugging
  1011 + * possibilities.
  1012 + */
  1013 + mcbsp->irq = platform_get_irq_byname(pdev, "common");
  1014 + if (mcbsp->irq == -ENXIO) {
  1015 + mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
954 1016  
955   - /* From OMAP4 there will be a single irq line */
956   - if (mcbsp->tx_irq == -ENXIO) {
957   - mcbsp->tx_irq = platform_get_irq(pdev, 0);
958   - mcbsp->rx_irq = 0;
  1017 + if (mcbsp->tx_irq == -ENXIO) {
  1018 + mcbsp->irq = platform_get_irq(pdev, 0);
  1019 + mcbsp->tx_irq = 0;
  1020 + } else {
  1021 + mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
  1022 + mcbsp->irq = 0;
  1023 + }
959 1024 }
960 1025  
961 1026 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
sound/soc/omap/mcbsp.h
... ... @@ -217,17 +217,20 @@
217 217 /********************** McBSP DMA operating modes **************************/
218 218 #define MCBSP_DMA_MODE_ELEMENT 0
219 219 #define MCBSP_DMA_MODE_THRESHOLD 1
220   -#define MCBSP_DMA_MODE_FRAME 2
221 220  
222   -/********************** McBSP WAKEUPEN bit definitions *********************/
  221 +/********************** McBSP WAKEUPEN/IRQST/IRQEN bit definitions *********/
223 222 #define RSYNCERREN BIT(0)
224 223 #define RFSREN BIT(1)
225 224 #define REOFEN BIT(2)
226 225 #define RRDYEN BIT(3)
  226 +#define RUNDFLEN BIT(4)
  227 +#define ROVFLEN BIT(5)
227 228 #define XSYNCERREN BIT(7)
228 229 #define XFSXEN BIT(8)
229 230 #define XEOFEN BIT(9)
230 231 #define XRDYEN BIT(10)
  232 +#define XUNDFLEN BIT(11)
  233 +#define XOVFLEN BIT(12)
231 234 #define XEMPTYEOFEN BIT(14)
232 235  
233 236 /* Clock signal muxing options */
... ... @@ -295,6 +298,7 @@
295 298 int configured;
296 299 u8 free;
297 300  
  301 + int irq;
298 302 int rx_irq;
299 303 int tx_irq;
300 304  
sound/soc/omap/omap-abe-twl6040.c
... ... @@ -40,6 +40,11 @@
40 40 #include "omap-pcm.h"
41 41 #include "../codecs/twl6040.h"
42 42  
  43 +struct abe_twl6040 {
  44 + int jack_detection; /* board can detect jack events */
  45 + int mclk_freq; /* MCLK frequency speed for twl6040 */
  46 +};
  47 +
43 48 static int omap_abe_hw_params(struct snd_pcm_substream *substream,
44 49 struct snd_pcm_hw_params *params)
45 50 {
46 51  
... ... @@ -47,13 +52,13 @@
47 52 struct snd_soc_dai *codec_dai = rtd->codec_dai;
48 53 struct snd_soc_codec *codec = rtd->codec;
49 54 struct snd_soc_card *card = codec->card;
50   - struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev);
  55 + struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
51 56 int clk_id, freq;
52 57 int ret;
53 58  
54 59 clk_id = twl6040_get_clk_id(rtd->codec);
55 60 if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
56   - freq = pdata->mclk_freq;
  61 + freq = priv->mclk_freq;
57 62 else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
58 63 freq = 32768;
59 64 else
... ... @@ -128,6 +133,9 @@
128 133 SND_SOC_DAPM_MIC("Main Handset Mic", NULL),
129 134 SND_SOC_DAPM_MIC("Sub Handset Mic", NULL),
130 135 SND_SOC_DAPM_LINE("Line In", NULL),
  136 +
  137 + /* Digital microphones */
  138 + SND_SOC_DAPM_MIC("Digital Mic", NULL),
131 139 };
132 140  
133 141 static const struct snd_soc_dapm_route audio_map[] = {
... ... @@ -173,6 +181,7 @@
173 181 struct snd_soc_card *card = codec->card;
174 182 struct snd_soc_dapm_context *dapm = &codec->dapm;
175 183 struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev);
  184 + struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
176 185 int hs_trim;
177 186 int ret = 0;
178 187  
... ... @@ -196,7 +205,7 @@
196 205 TWL6040_HSF_TRIM_RIGHT(hs_trim));
197 206  
198 207 /* Headset jack detection only if it is supported */
199   - if (pdata->jack_detection) {
  208 + if (priv->jack_detection) {
200 209 ret = snd_soc_jack_new(codec, "Headset Jack",
201 210 SND_JACK_HEADSET, &hs_jack);
202 211 if (ret)
... ... @@ -210,10 +219,6 @@
210 219 return ret;
211 220 }
212 221  
213   -static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
214   - SND_SOC_DAPM_MIC("Digital Mic", NULL),
215   -};
216   -
217 222 static const struct snd_soc_dapm_route dmic_audio_map[] = {
218 223 {"DMic", NULL, "Digital Mic"},
219 224 {"Digital Mic", NULL, "Digital Mic1 Bias"},
220 225  
221 226  
... ... @@ -223,19 +228,13 @@
223 228 {
224 229 struct snd_soc_codec *codec = rtd->codec;
225 230 struct snd_soc_dapm_context *dapm = &codec->dapm;
226   - int ret;
227 231  
228   - ret = snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets,
229   - ARRAY_SIZE(dmic_dapm_widgets));
230   - if (ret)
231   - return ret;
232   -
233 232 return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
234 233 ARRAY_SIZE(dmic_audio_map));
235 234 }
236 235  
237 236 /* Digital audio interface glue - connects codec <--> CPU */
238   -static struct snd_soc_dai_link twl6040_dmic_dai[] = {
  237 +static struct snd_soc_dai_link abe_twl6040_dai_links[] = {
239 238 {
240 239 .name = "TWL6040",
241 240 .stream_name = "TWL6040",
... ... @@ -258,19 +257,6 @@
258 257 },
259 258 };
260 259  
261   -static struct snd_soc_dai_link twl6040_only_dai[] = {
262   - {
263   - .name = "TWL6040",
264   - .stream_name = "TWL6040",
265   - .cpu_dai_name = "omap-mcpdm",
266   - .codec_dai_name = "twl6040-legacy",
267   - .platform_name = "omap-pcm-audio",
268   - .codec_name = "twl6040-codec",
269   - .init = omap_abe_twl6040_init,
270   - .ops = &omap_abe_ops,
271   - },
272   -};
273   -
274 260 /* Audio machine driver */
275 261 static struct snd_soc_card omap_abe_card = {
276 262 .owner = THIS_MODULE,
... ... @@ -285,6 +271,8 @@
285 271 {
286 272 struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
287 273 struct snd_soc_card *card = &omap_abe_card;
  274 + struct abe_twl6040 *priv;
  275 + int num_links = 0;
288 276 int ret;
289 277  
290 278 card->dev = &pdev->dev;
... ... @@ -294,6 +282,10 @@
294 282 return -ENODEV;
295 283 }
296 284  
  285 + priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
  286 + if (priv == NULL)
  287 + return -ENOMEM;
  288 +
297 289 if (pdata->card_name) {
298 290 card->name = pdata->card_name;
299 291 } else {
300 292  
... ... @@ -301,18 +293,24 @@
301 293 return -ENODEV;
302 294 }
303 295  
304   - if (!pdata->mclk_freq) {
  296 + priv->jack_detection = pdata->jack_detection;
  297 + priv->mclk_freq = pdata->mclk_freq;
  298 +
  299 +
  300 + if (!priv->mclk_freq) {
305 301 dev_err(&pdev->dev, "MCLK frequency missing\n");
306 302 return -ENODEV;
307 303 }
308 304  
309   - if (pdata->has_dmic) {
310   - card->dai_link = twl6040_dmic_dai;
311   - card->num_links = ARRAY_SIZE(twl6040_dmic_dai);
312   - } else {
313   - card->dai_link = twl6040_only_dai;
314   - card->num_links = ARRAY_SIZE(twl6040_only_dai);
315   - }
  305 + if (pdata->has_dmic)
  306 + num_links = 2;
  307 + else
  308 + num_links = 1;
  309 +
  310 + card->dai_link = abe_twl6040_dai_links;
  311 + card->num_links = num_links;
  312 +
  313 + snd_soc_card_set_drvdata(card, priv);
316 314  
317 315 ret = snd_soc_register_card(card);
318 316 if (ret)
sound/soc/omap/omap-dmic.c
... ... @@ -32,6 +32,7 @@
32 32 #include <linux/io.h>
33 33 #include <linux/slab.h>
34 34 #include <linux/pm_runtime.h>
  35 +#include <linux/of_device.h>
35 36 #include <plat/dma.h>
36 37  
37 38 #include <sound/core.h>
38 39  
... ... @@ -528,10 +529,17 @@
528 529 return 0;
529 530 }
530 531  
  532 +static const struct of_device_id omap_dmic_of_match[] = {
  533 + { .compatible = "ti,omap4-dmic", },
  534 + { }
  535 +};
  536 +MODULE_DEVICE_TABLE(of, omap_dmic_of_match);
  537 +
531 538 static struct platform_driver asoc_dmic_driver = {
532 539 .driver = {
533 540 .name = "omap-dmic",
534 541 .owner = THIS_MODULE,
  542 + .of_match_table = omap_dmic_of_match,
535 543 },
536 544 .probe = asoc_dmic_probe,
537 545 .remove = __devexit_p(asoc_dmic_remove),
sound/soc/omap/omap-hdmi-card.c
  1 +/*
  2 + * omap-hdmi-card.c
  3 + *
  4 + * OMAP ALSA SoC machine driver for TI OMAP HDMI
  5 + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
  6 + * Author: Ricardo Neri <ricardo.neri@ti.com>
  7 + *
  8 + * This program is free software; you can redistribute it and/or
  9 + * modify it under the terms of the GNU General Public License
  10 + * version 2 as published by the Free Software Foundation.
  11 + *
  12 + * This program is distributed in the hope that it will be useful, but
  13 + * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15 + * General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20 + * 02110-1301 USA
  21 + *
  22 + */
  23 +
  24 +#include <linux/module.h>
  25 +#include <sound/pcm.h>
  26 +#include <sound/soc.h>
  27 +#include <asm/mach-types.h>
  28 +#include <video/omapdss.h>
  29 +
  30 +#define DRV_NAME "omap-hdmi-audio"
  31 +
  32 +static struct snd_soc_dai_link omap_hdmi_dai = {
  33 + .name = "HDMI",
  34 + .stream_name = "HDMI",
  35 + .cpu_dai_name = "omap-hdmi-audio-dai",
  36 + .platform_name = "omap-pcm-audio",
  37 + .codec_name = "hdmi-audio-codec",
  38 + .codec_dai_name = "omap-hdmi-hifi",
  39 +};
  40 +
  41 +static struct snd_soc_card snd_soc_omap_hdmi = {
  42 + .name = "OMAPHDMI",
  43 + .owner = THIS_MODULE,
  44 + .dai_link = &omap_hdmi_dai,
  45 + .num_links = 1,
  46 +};
  47 +
  48 +static __devinit int omap_hdmi_probe(struct platform_device *pdev)
  49 +{
  50 + struct snd_soc_card *card = &snd_soc_omap_hdmi;
  51 + int ret;
  52 +
  53 + card->dev = &pdev->dev;
  54 +
  55 + ret = snd_soc_register_card(card);
  56 + if (ret) {
  57 + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
  58 + card->dev = NULL;
  59 + return ret;
  60 + }
  61 + return 0;
  62 +}
  63 +
  64 +static int __devexit omap_hdmi_remove(struct platform_device *pdev)
  65 +{
  66 + struct snd_soc_card *card = platform_get_drvdata(pdev);
  67 +
  68 + snd_soc_unregister_card(card);
  69 + card->dev = NULL;
  70 + return 0;
  71 +}
  72 +
  73 +static struct platform_driver omap_hdmi_driver = {
  74 + .driver = {
  75 + .name = DRV_NAME,
  76 + .owner = THIS_MODULE,
  77 + },
  78 + .probe = omap_hdmi_probe,
  79 + .remove = __devexit_p(omap_hdmi_remove),
  80 +};
  81 +
  82 +module_platform_driver(omap_hdmi_driver);
  83 +
  84 +MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
  85 +MODULE_DESCRIPTION("OMAP HDMI machine ASoC driver");
  86 +MODULE_LICENSE("GPL");
  87 +MODULE_ALIAS("platform:" DRV_NAME);
sound/soc/omap/omap-hdmi.c
... ... @@ -30,21 +30,28 @@
30 30 #include <sound/pcm_params.h>
31 31 #include <sound/initval.h>
32 32 #include <sound/soc.h>
  33 +#include <sound/asound.h>
  34 +#include <sound/asoundef.h>
  35 +#include <video/omapdss.h>
33 36  
34 37 #include <plat/dma.h>
35 38 #include "omap-pcm.h"
36 39 #include "omap-hdmi.h"
37 40  
38   -#define DRV_NAME "hdmi-audio-dai"
  41 +#define DRV_NAME "omap-hdmi-audio-dai"
39 42  
40   -static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = {
41   - .name = "HDMI playback",
42   - .sync_mode = OMAP_DMA_SYNC_PACKET,
  43 +struct hdmi_priv {
  44 + struct omap_pcm_dma_data dma_params;
  45 + struct omap_dss_audio dss_audio;
  46 + struct snd_aes_iec958 iec;
  47 + struct snd_cea_861_aud_if cea;
  48 + struct omap_dss_device *dssdev;
43 49 };
44 50  
45 51 static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
46 52 struct snd_soc_dai *dai)
47 53 {
  54 + struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
48 55 int err;
49 56 /*
50 57 * Make sure that the period bytes are multiple of the DMA packet size.
51 58  
52 59  
53 60  
54 61  
55 62  
56 63  
57 64  
58 65  
59 66  
60 67  
61 68  
62 69  
63 70  
... ... @@ -52,46 +59,201 @@
52 59 */
53 60 err = snd_pcm_hw_constraint_step(substream->runtime, 0,
54 61 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
55   - if (err < 0)
  62 + if (err < 0) {
  63 + dev_err(dai->dev, "could not apply constraint\n");
56 64 return err;
  65 + }
57 66  
  67 + if (!priv->dssdev->driver->audio_supported(priv->dssdev)) {
  68 + dev_err(dai->dev, "audio not supported\n");
  69 + return -ENODEV;
  70 + }
58 71 return 0;
59 72 }
60 73  
  74 +static int omap_hdmi_dai_prepare(struct snd_pcm_substream *substream,
  75 + struct snd_soc_dai *dai)
  76 +{
  77 + struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
  78 +
  79 + return priv->dssdev->driver->audio_enable(priv->dssdev);
  80 +}
  81 +
61 82 static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
62 83 struct snd_pcm_hw_params *params,
63 84 struct snd_soc_dai *dai)
64 85 {
  86 + struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
  87 + struct snd_aes_iec958 *iec = &priv->iec;
  88 + struct snd_cea_861_aud_if *cea = &priv->cea;
65 89 int err = 0;
66 90  
67 91 switch (params_format(params)) {
68 92 case SNDRV_PCM_FORMAT_S16_LE:
69   - omap_hdmi_dai_dma_params.packet_size = 16;
  93 + priv->dma_params.packet_size = 16;
70 94 break;
71 95 case SNDRV_PCM_FORMAT_S24_LE:
72   - omap_hdmi_dai_dma_params.packet_size = 32;
  96 + priv->dma_params.packet_size = 32;
73 97 break;
74 98 default:
75   - err = -EINVAL;
  99 + dev_err(dai->dev, "format not supported!\n");
  100 + return -EINVAL;
76 101 }
77 102  
78   - omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
  103 + priv->dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
79 104  
80 105 snd_soc_dai_set_dma_data(dai, substream,
81   - &omap_hdmi_dai_dma_params);
  106 + &priv->dma_params);
82 107  
  108 + /*
  109 + * fill the IEC-60958 channel status word
  110 + */
  111 +
  112 + /* specify IEC-60958-3 (commercial use) */
  113 + iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
  114 +
  115 + /* specify that the audio is LPCM*/
  116 + iec->status[0] &= ~IEC958_AES0_NONAUDIO;
  117 +
  118 + iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
  119 +
  120 + iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
  121 +
  122 + iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID;
  123 +
  124 + iec->status[1] = IEC958_AES1_CON_GENERAL;
  125 +
  126 + iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
  127 +
  128 + iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
  129 +
  130 + switch (params_rate(params)) {
  131 + case 32000:
  132 + iec->status[3] |= IEC958_AES3_CON_FS_32000;
  133 + break;
  134 + case 44100:
  135 + iec->status[3] |= IEC958_AES3_CON_FS_44100;
  136 + break;
  137 + case 48000:
  138 + iec->status[3] |= IEC958_AES3_CON_FS_48000;
  139 + break;
  140 + case 88200:
  141 + iec->status[3] |= IEC958_AES3_CON_FS_88200;
  142 + break;
  143 + case 96000:
  144 + iec->status[3] |= IEC958_AES3_CON_FS_96000;
  145 + break;
  146 + case 176400:
  147 + iec->status[3] |= IEC958_AES3_CON_FS_176400;
  148 + break;
  149 + case 192000:
  150 + iec->status[3] |= IEC958_AES3_CON_FS_192000;
  151 + break;
  152 + default:
  153 + dev_err(dai->dev, "rate not supported!\n");
  154 + return -EINVAL;
  155 + }
  156 +
  157 + /* specify the clock accuracy */
  158 + iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
  159 +
  160 + /*
  161 + * specify the word length. The same word length value can mean
  162 + * two different lengths. Hence, we need to specify the maximum
  163 + * word length as well.
  164 + */
  165 + switch (params_format(params)) {
  166 + case SNDRV_PCM_FORMAT_S16_LE:
  167 + iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
  168 + iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
  169 + break;
  170 + case SNDRV_PCM_FORMAT_S24_LE:
  171 + iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
  172 + iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
  173 + break;
  174 + default:
  175 + dev_err(dai->dev, "format not supported!\n");
  176 + return -EINVAL;
  177 + }
  178 +
  179 + /*
  180 + * Fill the CEA-861 audio infoframe (see spec for details)
  181 + */
  182 +
  183 + cea->db1_ct_cc = (params_channels(params) - 1)
  184 + & CEA861_AUDIO_INFOFRAME_DB1CC;
  185 + cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
  186 +
  187 + cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
  188 + cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
  189 +
  190 + cea->db3 = 0; /* not used, all zeros */
  191 +
  192 + /*
  193 + * The OMAP HDMI IP requires to use the 8-channel channel code when
  194 + * transmitting more than two channels.
  195 + */
  196 + if (params_channels(params) == 2)
  197 + cea->db4_ca = 0x0;
  198 + else
  199 + cea->db4_ca = 0x13;
  200 +
  201 + cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
  202 + /* the expression is trivial but makes clear what we are doing */
  203 + cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
  204 +
  205 + priv->dss_audio.iec = iec;
  206 + priv->dss_audio.cea = cea;
  207 +
  208 + err = priv->dssdev->driver->audio_config(priv->dssdev,
  209 + &priv->dss_audio);
  210 +
83 211 return err;
84 212 }
85 213  
  214 +static int omap_hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
  215 + struct snd_soc_dai *dai)
  216 +{
  217 + struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
  218 + int err = 0;
  219 +
  220 + switch (cmd) {
  221 + case SNDRV_PCM_TRIGGER_START:
  222 + case SNDRV_PCM_TRIGGER_RESUME:
  223 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  224 + err = priv->dssdev->driver->audio_start(priv->dssdev);
  225 + break;
  226 + case SNDRV_PCM_TRIGGER_STOP:
  227 + case SNDRV_PCM_TRIGGER_SUSPEND:
  228 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  229 + priv->dssdev->driver->audio_stop(priv->dssdev);
  230 + break;
  231 + default:
  232 + err = -EINVAL;
  233 + }
  234 + return err;
  235 +}
  236 +
  237 +static void omap_hdmi_dai_shutdown(struct snd_pcm_substream *substream,
  238 + struct snd_soc_dai *dai)
  239 +{
  240 + struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
  241 +
  242 + priv->dssdev->driver->audio_disable(priv->dssdev);
  243 +}
  244 +
86 245 static const struct snd_soc_dai_ops omap_hdmi_dai_ops = {
87 246 .startup = omap_hdmi_dai_startup,
88 247 .hw_params = omap_hdmi_dai_hw_params,
  248 + .prepare = omap_hdmi_dai_prepare,
  249 + .trigger = omap_hdmi_dai_trigger,
  250 + .shutdown = omap_hdmi_dai_shutdown,
89 251 };
90 252  
91 253 static struct snd_soc_dai_driver omap_hdmi_dai = {
92 254 .playback = {
93 255 .channels_min = 2,
94   - .channels_max = 2,
  256 + .channels_max = 8,
95 257 .rates = OMAP_HDMI_RATES,
96 258 .formats = OMAP_HDMI_FORMATS,
97 259 },
98 260  
99 261  
100 262  
101 263  
102 264  
103 265  
104 266  
105 267  
106 268  
... ... @@ -102,31 +264,77 @@
102 264 {
103 265 int ret;
104 266 struct resource *hdmi_rsrc;
  267 + struct hdmi_priv *hdmi_data;
  268 + bool hdmi_dev_found = false;
105 269  
  270 + hdmi_data = devm_kzalloc(&pdev->dev, sizeof(*hdmi_data), GFP_KERNEL);
  271 + if (hdmi_data == NULL) {
  272 + dev_err(&pdev->dev, "Cannot allocate memory for HDMI data\n");
  273 + return -ENOMEM;
  274 + }
  275 +
106 276 hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
107 277 if (!hdmi_rsrc) {
108 278 dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n");
109   - return -EINVAL;
  279 + return -ENODEV;
110 280 }
111 281  
112   - omap_hdmi_dai_dma_params.port_addr = hdmi_rsrc->start
  282 + hdmi_data->dma_params.port_addr = hdmi_rsrc->start
113 283 + OMAP_HDMI_AUDIO_DMA_PORT;
114 284  
115 285 hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
116 286 if (!hdmi_rsrc) {
117 287 dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n");
118   - return -EINVAL;
  288 + return -ENODEV;
119 289 }
120 290  
121   - omap_hdmi_dai_dma_params.dma_req = hdmi_rsrc->start;
  291 + hdmi_data->dma_params.dma_req = hdmi_rsrc->start;
  292 + hdmi_data->dma_params.name = "HDMI playback";
  293 + hdmi_data->dma_params.sync_mode = OMAP_DMA_SYNC_PACKET;
122 294  
  295 + /*
  296 + * TODO: We assume that there is only one DSS HDMI device. Future
  297 + * OMAP implementations may support more than one HDMI devices and
  298 + * we should provided separate audio support for all of them.
  299 + */
  300 + /* Find an HDMI device. */
  301 + for_each_dss_dev(hdmi_data->dssdev) {
  302 + omap_dss_get_device(hdmi_data->dssdev);
  303 +
  304 + if (!hdmi_data->dssdev->driver) {
  305 + omap_dss_put_device(hdmi_data->dssdev);
  306 + continue;
  307 + }
  308 +
  309 + if (hdmi_data->dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
  310 + hdmi_dev_found = true;
  311 + break;
  312 + }
  313 + }
  314 +
  315 + if (!hdmi_dev_found) {
  316 + dev_err(&pdev->dev, "no driver for HDMI display found\n");
  317 + return -ENODEV;
  318 + }
  319 +
  320 + dev_set_drvdata(&pdev->dev, hdmi_data);
123 321 ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
  322 +
124 323 return ret;
125 324 }
126 325  
127 326 static int __devexit omap_hdmi_remove(struct platform_device *pdev)
128 327 {
  328 + struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
  329 +
129 330 snd_soc_unregister_dai(&pdev->dev);
  331 +
  332 + if (hdmi_data == NULL) {
  333 + dev_err(&pdev->dev, "cannot obtain HDMi data\n");
  334 + return -ENODEV;
  335 + }
  336 +
  337 + omap_dss_put_device(hdmi_data->dssdev);
130 338 return 0;
131 339 }
132 340  
sound/soc/omap/omap-hdmi.h
... ... @@ -28,7 +28,9 @@
28 28 #define OMAP_HDMI_AUDIO_DMA_PORT 0x8c
29 29  
30 30 #define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \
31   - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
  31 + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
  32 + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
  33 + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
32 34  
33 35 #define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
34 36 SNDRV_PCM_FMTBIT_S24_LE)
sound/soc/omap/omap-mcbsp.c
... ... @@ -71,18 +71,17 @@
71 71  
72 72 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
73 73  
74   - /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
75   - if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
76   - /*
77   - * Configure McBSP threshold based on either:
78   - * packet_size, when the sDMA is in packet mode, or
79   - * based on the period size.
80   - */
81   - if (dma_data->packet_size)
82   - words = dma_data->packet_size;
83   - else
84   - words = snd_pcm_lib_period_bytes(substream) /
85   - (mcbsp->wlen / 8);
  74 + /*
  75 + * Configure McBSP threshold based on either:
  76 + * packet_size, when the sDMA is in packet mode, or based on the
  77 + * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
  78 + * for mono streams.
  79 + */
  80 + if (dma_data->packet_size)
  81 + words = dma_data->packet_size;
  82 + else if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
  83 + words = snd_pcm_lib_period_bytes(substream) /
  84 + (mcbsp->wlen / 8);
86 85 else
87 86 words = 1;
88 87  
89 88  
... ... @@ -139,13 +138,15 @@
139 138 if (mcbsp->pdata->buffer_size) {
140 139 /*
141 140 * Rule for the buffer size. We should not allow
142   - * smaller buffer than the FIFO size to avoid underruns
  141 + * smaller buffer than the FIFO size to avoid underruns.
  142 + * This applies only for the playback stream.
143 143 */
144   - snd_pcm_hw_rule_add(substream->runtime, 0,
145   - SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
146   - omap_mcbsp_hwrule_min_buffersize,
147   - mcbsp,
148   - SNDRV_PCM_HW_PARAM_CHANNELS, -1);
  144 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  145 + snd_pcm_hw_rule_add(substream->runtime, 0,
  146 + SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
  147 + omap_mcbsp_hwrule_min_buffersize,
  148 + mcbsp,
  149 + SNDRV_PCM_HW_PARAM_CHANNELS, -1);
149 150  
150 151 /* Make sure, that the period size is always even */
151 152 snd_pcm_hw_constraint_step(substream->runtime, 0,
... ... @@ -230,6 +231,7 @@
230 231 unsigned int format, div, framesize, master;
231 232  
232 233 dma_data = &mcbsp->dma_data[substream->stream];
  234 + channels = params_channels(params);
233 235  
234 236 switch (params_format(params)) {
235 237 case SNDRV_PCM_FORMAT_S16_LE:
... ... @@ -245,7 +247,6 @@
245 247 }
246 248 if (mcbsp->pdata->buffer_size) {
247 249 dma_data->set_threshold = omap_mcbsp_set_threshold;
248   - /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
249 250 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
250 251 int period_words, max_thrsh;
251 252  
... ... @@ -283,6 +284,10 @@
283 284 } else {
284 285 sync_mode = OMAP_DMA_SYNC_FRAME;
285 286 }
  287 + } else if (channels > 1) {
  288 + /* Use packet mode for non mono streams */
  289 + pkt_size = channels;
  290 + sync_mode = OMAP_DMA_SYNC_PACKET;
286 291 }
287 292 }
288 293  
... ... @@ -301,7 +306,7 @@
301 306 regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
302 307 regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
303 308 format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
304   - wpf = channels = params_channels(params);
  309 + wpf = channels;
305 310 if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
306 311 format == SND_SOC_DAIFMT_LEFT_J)) {
307 312 /* Use dual-phase frames */
sound/soc/omap/omap-mcpdm.c
... ... @@ -33,6 +33,7 @@
33 33 #include <linux/irq.h>
34 34 #include <linux/slab.h>
35 35 #include <linux/pm_runtime.h>
  36 +#include <linux/of_device.h>
36 37  
37 38 #include <sound/core.h>
38 39 #include <sound/pcm.h>
39 40  
... ... @@ -507,10 +508,17 @@
507 508 return 0;
508 509 }
509 510  
  511 +static const struct of_device_id omap_mcpdm_of_match[] = {
  512 + { .compatible = "ti,omap4-mcpdm", },
  513 + { }
  514 +};
  515 +MODULE_DEVICE_TABLE(of, omap_mcpdm_of_match);
  516 +
510 517 static struct platform_driver asoc_mcpdm_driver = {
511 518 .driver = {
512 519 .name = "omap-mcpdm",
513 520 .owner = THIS_MODULE,
  521 + .of_match_table = omap_mcpdm_of_match,
514 522 },
515 523  
516 524 .probe = asoc_mcpdm_probe,
sound/soc/omap/omap4-hdmi-card.c
1   -/*
2   - * omap4-hdmi-card.c
3   - *
4   - * OMAP ALSA SoC machine driver for TI OMAP4 HDMI
5   - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
6   - * Author: Ricardo Neri <ricardo.neri@ti.com>
7   - *
8   - * This program is free software; you can redistribute it and/or
9   - * modify it under the terms of the GNU General Public License
10   - * version 2 as published by the Free Software Foundation.
11   - *
12   - * This program is distributed in the hope that it will be useful, but
13   - * WITHOUT ANY WARRANTY; without even the implied warranty of
14   - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   - * General Public License for more details.
16   - *
17   - * You should have received a copy of the GNU General Public License
18   - * along with this program; if not, write to the Free Software
19   - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   - * 02110-1301 USA
21   - *
22   - */
23   -
24   -#include <linux/module.h>
25   -#include <sound/pcm.h>
26   -#include <sound/soc.h>
27   -#include <asm/mach-types.h>
28   -#include <video/omapdss.h>
29   -
30   -#define DRV_NAME "omap4-hdmi-audio"
31   -
32   -static int omap4_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
33   - struct snd_pcm_hw_params *params)
34   -{
35   - int i;
36   - struct omap_overlay_manager *mgr = NULL;
37   - struct device *dev = substream->pcm->card->dev;
38   -
39   - /* Find DSS HDMI device */
40   - for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
41   - mgr = omap_dss_get_overlay_manager(i);
42   - if (mgr && mgr->device
43   - && mgr->device->type == OMAP_DISPLAY_TYPE_HDMI)
44   - break;
45   - }
46   -
47   - if (i == omap_dss_get_num_overlay_managers()) {
48   - dev_err(dev, "HDMI display device not found!\n");
49   - return -ENODEV;
50   - }
51   -
52   - /* Make sure HDMI is power-on to avoid L3 interconnect errors */
53   - if (mgr->device->state != OMAP_DSS_DISPLAY_ACTIVE) {
54   - dev_err(dev, "HDMI display is not active!\n");
55   - return -EIO;
56   - }
57   -
58   - return 0;
59   -}
60   -
61   -static struct snd_soc_ops omap4_hdmi_dai_ops = {
62   - .hw_params = omap4_hdmi_dai_hw_params,
63   -};
64   -
65   -static struct snd_soc_dai_link omap4_hdmi_dai = {
66   - .name = "HDMI",
67   - .stream_name = "HDMI",
68   - .cpu_dai_name = "hdmi-audio-dai",
69   - .platform_name = "omap-pcm-audio",
70   - .codec_name = "omapdss_hdmi",
71   - .codec_dai_name = "hdmi-audio-codec",
72   - .ops = &omap4_hdmi_dai_ops,
73   -};
74   -
75   -static struct snd_soc_card snd_soc_omap4_hdmi = {
76   - .name = "OMAP4HDMI",
77   - .owner = THIS_MODULE,
78   - .dai_link = &omap4_hdmi_dai,
79   - .num_links = 1,
80   -};
81   -
82   -static __devinit int omap4_hdmi_probe(struct platform_device *pdev)
83   -{
84   - struct snd_soc_card *card = &snd_soc_omap4_hdmi;
85   - int ret;
86   -
87   - card->dev = &pdev->dev;
88   -
89   - ret = snd_soc_register_card(card);
90   - if (ret) {
91   - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
92   - card->dev = NULL;
93   - return ret;
94   - }
95   - return 0;
96   -}
97   -
98   -static int __devexit omap4_hdmi_remove(struct platform_device *pdev)
99   -{
100   - struct snd_soc_card *card = platform_get_drvdata(pdev);
101   -
102   - snd_soc_unregister_card(card);
103   - card->dev = NULL;
104   - return 0;
105   -}
106   -
107   -static struct platform_driver omap4_hdmi_driver = {
108   - .driver = {
109   - .name = "omap4-hdmi-audio",
110   - .owner = THIS_MODULE,
111   - },
112   - .probe = omap4_hdmi_probe,
113   - .remove = __devexit_p(omap4_hdmi_remove),
114   -};
115   -
116   -module_platform_driver(omap4_hdmi_driver);
117   -
118   -MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
119   -MODULE_DESCRIPTION("OMAP4 HDMI machine ASoC driver");
120   -MODULE_LICENSE("GPL");
121   -MODULE_ALIAS("platform:" DRV_NAME);