aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/omap-dmic.txt21
-rw-r--r--Documentation/devicetree/bindings/sound/omap-mcpdm.txt21
-rw-r--r--sound/core/pcm_lib.c23
-rw-r--r--sound/pci/hda/patch_realtek.c38
-rw-r--r--sound/soc/omap/Kconfig7
-rw-r--r--sound/soc/omap/Makefile4
-rw-r--r--sound/soc/omap/mcbsp.c115
-rw-r--r--sound/soc/omap/mcbsp.h8
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c68
-rw-r--r--sound/soc/omap/omap-dmic.c8
-rw-r--r--sound/soc/omap/omap-hdmi-card.c87
-rw-r--r--sound/soc/omap/omap-hdmi.c238
-rw-r--r--sound/soc/omap/omap-hdmi.h4
-rw-r--r--sound/soc/omap/omap-mcbsp.c45
-rw-r--r--sound/soc/omap/omap-mcpdm.c8
-rw-r--r--sound/soc/omap/omap4-hdmi-card.c121
16 files changed, 582 insertions, 234 deletions
diff --git a/Documentation/devicetree/bindings/sound/omap-dmic.txt b/Documentation/devicetree/bindings/sound/omap-dmic.txt
new file mode 100644
index 00000000000..fd8105f1897
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/omap-dmic.txt
@@ -0,0 +1,21 @@
1* Texas Instruments OMAP4+ Digital Microphone Module
2
3Required 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
12Example:
13
14dmic: 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};
diff --git a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
new file mode 100644
index 00000000000..0741dff048d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
@@ -0,0 +1,21 @@
1* Texas Instruments OMAP4+ McPDM
2
3Required 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
12Example:
13
14mcpdm: 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};
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index faedb1481b2..8f312fa6c28 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -313,9 +313,22 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
313 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; 313 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
314 snd_pcm_sframes_t hdelta, delta; 314 snd_pcm_sframes_t hdelta, delta;
315 unsigned long jdelta; 315 unsigned long jdelta;
316 unsigned long curr_jiffies;
317 struct timespec curr_tstamp;
316 318
317 old_hw_ptr = runtime->status->hw_ptr; 319 old_hw_ptr = runtime->status->hw_ptr;
320
321 /*
322 * group pointer, time and jiffies reads to allow for more
323 * accurate correlations/corrections.
324 * The values are stored at the end of this routine after
325 * corrections for hw_ptr position
326 */
318 pos = substream->ops->pointer(substream); 327 pos = substream->ops->pointer(substream);
328 curr_jiffies = jiffies;
329 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
330 snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
331
319 if (pos == SNDRV_PCM_POS_XRUN) { 332 if (pos == SNDRV_PCM_POS_XRUN) {
320 xrun(substream); 333 xrun(substream);
321 return -EPIPE; 334 return -EPIPE;
@@ -343,7 +356,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
343 delta = runtime->hw_ptr_interrupt + runtime->period_size; 356 delta = runtime->hw_ptr_interrupt + runtime->period_size;
344 if (delta > new_hw_ptr) { 357 if (delta > new_hw_ptr) {
345 /* check for double acknowledged interrupts */ 358 /* check for double acknowledged interrupts */
346 hdelta = jiffies - runtime->hw_ptr_jiffies; 359 hdelta = curr_jiffies - runtime->hw_ptr_jiffies;
347 if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { 360 if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
348 hw_base += runtime->buffer_size; 361 hw_base += runtime->buffer_size;
349 if (hw_base >= runtime->boundary) 362 if (hw_base >= runtime->boundary)
@@ -388,7 +401,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
388 * Without regular period interrupts, we have to check 401 * Without regular period interrupts, we have to check
389 * the elapsed time to detect xruns. 402 * the elapsed time to detect xruns.
390 */ 403 */
391 jdelta = jiffies - runtime->hw_ptr_jiffies; 404 jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
392 if (jdelta < runtime->hw_ptr_buffer_jiffies / 2) 405 if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
393 goto no_delta_check; 406 goto no_delta_check;
394 hdelta = jdelta - delta * HZ / runtime->rate; 407 hdelta = jdelta - delta * HZ / runtime->rate;
@@ -430,7 +443,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
430 if (hdelta < runtime->delay) 443 if (hdelta < runtime->delay)
431 goto no_jiffies_check; 444 goto no_jiffies_check;
432 hdelta -= runtime->delay; 445 hdelta -= runtime->delay;
433 jdelta = jiffies - runtime->hw_ptr_jiffies; 446 jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
434 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) { 447 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
435 delta = jdelta / 448 delta = jdelta /
436 (((runtime->period_size * HZ) / runtime->rate) 449 (((runtime->period_size * HZ) / runtime->rate)
@@ -492,9 +505,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
492 } 505 }
493 runtime->hw_ptr_base = hw_base; 506 runtime->hw_ptr_base = hw_base;
494 runtime->status->hw_ptr = new_hw_ptr; 507 runtime->status->hw_ptr = new_hw_ptr;
495 runtime->hw_ptr_jiffies = jiffies; 508 runtime->hw_ptr_jiffies = curr_jiffies;
496 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) 509 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
497 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); 510 runtime->status->tstamp = curr_tstamp;
498 511
499 return snd_pcm_update_state(substream, runtime); 512 return snd_pcm_update_state(substream, runtime);
500} 513}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index ff71dcef08e..224410e8e9e 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2368,6 +2368,7 @@ static struct alc_codec_rename_table rename_tbl[] = {
2368 { 0x10ec0269, 0xffff, 0xa023, "ALC259" }, 2368 { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
2369 { 0x10ec0269, 0xffff, 0x6023, "ALC281X" }, 2369 { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
2370 { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" }, 2370 { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
2371 { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
2371 { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" }, 2372 { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
2372 { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" }, 2373 { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
2373 { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" }, 2374 { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
@@ -5614,6 +5615,7 @@ enum {
5614 ALC269_TYPE_ALC269VA, 5615 ALC269_TYPE_ALC269VA,
5615 ALC269_TYPE_ALC269VB, 5616 ALC269_TYPE_ALC269VB,
5616 ALC269_TYPE_ALC269VC, 5617 ALC269_TYPE_ALC269VC,
5618 ALC269_TYPE_ALC269VD,
5617}; 5619};
5618 5620
5619/* 5621/*
@@ -5625,8 +5627,21 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
5625 static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 }; 5627 static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
5626 static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 }; 5628 static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
5627 struct alc_spec *spec = codec->spec; 5629 struct alc_spec *spec = codec->spec;
5628 const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ? 5630 const hda_nid_t *ssids;
5629 alc269va_ssids : alc269_ssids; 5631
5632 switch (spec->codec_variant) {
5633 case ALC269_TYPE_ALC269VA:
5634 case ALC269_TYPE_ALC269VC:
5635 ssids = alc269va_ssids;
5636 break;
5637 case ALC269_TYPE_ALC269VB:
5638 case ALC269_TYPE_ALC269VD:
5639 ssids = alc269_ssids;
5640 break;
5641 default:
5642 ssids = alc269_ssids;
5643 break;
5644 }
5630 5645
5631 return alc_parse_auto_config(codec, alc269_ignore, ssids); 5646 return alc_parse_auto_config(codec, alc269_ignore, ssids);
5632} 5647}
@@ -5643,6 +5658,11 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
5643 5658
5644static void alc269_shutup(struct hda_codec *codec) 5659static void alc269_shutup(struct hda_codec *codec)
5645{ 5660{
5661 struct alc_spec *spec = codec->spec;
5662
5663 if (spec->codec_variant != ALC269_TYPE_ALC269VB)
5664 return;
5665
5646 if ((alc_get_coef0(codec) & 0x00ff) == 0x017) 5666 if ((alc_get_coef0(codec) & 0x00ff) == 0x017)
5647 alc269_toggle_power_output(codec, 0); 5667 alc269_toggle_power_output(codec, 0);
5648 if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { 5668 if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
@@ -5654,19 +5674,24 @@ static void alc269_shutup(struct hda_codec *codec)
5654#ifdef CONFIG_PM 5674#ifdef CONFIG_PM
5655static int alc269_resume(struct hda_codec *codec) 5675static int alc269_resume(struct hda_codec *codec)
5656{ 5676{
5657 if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { 5677 struct alc_spec *spec = codec->spec;
5678
5679 if (spec->codec_variant == ALC269_TYPE_ALC269VB ||
5680 (alc_get_coef0(codec) & 0x00ff) == 0x018) {
5658 alc269_toggle_power_output(codec, 0); 5681 alc269_toggle_power_output(codec, 0);
5659 msleep(150); 5682 msleep(150);
5660 } 5683 }
5661 5684
5662 codec->patch_ops.init(codec); 5685 codec->patch_ops.init(codec);
5663 5686
5664 if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { 5687 if (spec->codec_variant == ALC269_TYPE_ALC269VB ||
5688 (alc_get_coef0(codec) & 0x00ff) == 0x017) {
5665 alc269_toggle_power_output(codec, 1); 5689 alc269_toggle_power_output(codec, 1);
5666 msleep(200); 5690 msleep(200);
5667 } 5691 }
5668 5692
5669 if ((alc_get_coef0(codec) & 0x00ff) == 0x018) 5693 if (spec->codec_variant == ALC269_TYPE_ALC269VB ||
5694 (alc_get_coef0(codec) & 0x00ff) == 0x018)
5670 alc269_toggle_power_output(codec, 1); 5695 alc269_toggle_power_output(codec, 1);
5671 5696
5672 snd_hda_codec_resume_amp(codec); 5697 snd_hda_codec_resume_amp(codec);
@@ -6081,6 +6106,9 @@ static int patch_alc269(struct hda_codec *codec)
6081 err = alc_codec_rename(codec, "ALC3202"); 6106 err = alc_codec_rename(codec, "ALC3202");
6082 spec->codec_variant = ALC269_TYPE_ALC269VC; 6107 spec->codec_variant = ALC269_TYPE_ALC269VC;
6083 break; 6108 break;
6109 case 0x0030:
6110 spec->codec_variant = ALC269_TYPE_ALC269VD;
6111 break;
6084 default: 6112 default:
6085 alc_fix_pll_init(codec, 0x20, 0x04, 15); 6113 alc_fix_pll_init(codec, 0x20, 0x04, 15);
6086 } 6114 }
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 9ccfa5e1c11..57a2fa75108 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -109,11 +109,12 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040
109 - PandaBoard (4430) 109 - PandaBoard (4430)
110 - PandaBoardES (4460) 110 - PandaBoardES (4460)
111 111
112config SND_OMAP_SOC_OMAP4_HDMI 112config SND_OMAP_SOC_OMAP_HDMI
113 tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" 113 tristate "SoC Audio support for Texas Instruments OMAP HDMI"
114 depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 114 depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
115 select SND_OMAP_SOC_HDMI 115 select SND_OMAP_SOC_HDMI
116 select SND_SOC_OMAP_HDMI_CODEC 116 select SND_SOC_OMAP_HDMI_CODEC
117 select OMAP4_DSS_HDMI_AUDIO
117 help 118 help
118 Say Y if you want to add support for SoC HDMI audio on Texas Instruments 119 Say Y if you want to add support for SoC HDMI audio on Texas Instruments
119 OMAP4 chips 120 OMAP4 chips
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 1d656bce01d..0e14dd32256 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -25,7 +25,7 @@ snd-soc-omap3pandora-objs := omap3pandora.o
25snd-soc-omap3beagle-objs := omap3beagle.o 25snd-soc-omap3beagle-objs := omap3beagle.o
26snd-soc-zoom2-objs := zoom2.o 26snd-soc-zoom2-objs := zoom2.o
27snd-soc-igep0020-objs := igep0020.o 27snd-soc-igep0020-objs := igep0020.o
28snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o 28snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o
29 29
30obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o 30obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
31obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o 31obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
@@ -41,4 +41,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
41obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o 41obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
42obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o 42obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
43obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o 43obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
44obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o 44obj-$(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 e5f44440d1b..34835e8a916 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)
109 dev_dbg(mcbsp->dev, "***********************\n"); 109 dev_dbg(mcbsp->dev, "***********************\n");
110} 110}
111 111
112static 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
112static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) 153static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
113{ 154{
114 struct omap_mcbsp *mcbsp_tx = dev_id; 155 struct omap_mcbsp *mcbsp_tx = dev_id;
@@ -176,6 +217,10 @@ void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
176 /* Enable wakeup behavior */ 217 /* Enable wakeup behavior */
177 if (mcbsp->pdata->has_wakeup) 218 if (mcbsp->pdata->has_wakeup)
178 MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); 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/**
@@ -489,23 +534,25 @@ int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
489 MCBSP_WRITE(mcbsp, SPCR1, 0); 534 MCBSP_WRITE(mcbsp, SPCR1, 0);
490 MCBSP_WRITE(mcbsp, SPCR2, 0); 535 MCBSP_WRITE(mcbsp, SPCR2, 0);
491 536
492 err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 537 if (mcbsp->irq) {
493 0, "McBSP", (void *)mcbsp); 538 err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
494 if (err != 0) { 539 "McBSP", (void *)mcbsp);
495 dev_err(mcbsp->dev, "Unable to request TX IRQ %d " 540 if (err != 0) {
496 "for McBSP%d\n", mcbsp->tx_irq, 541 dev_err(mcbsp->dev, "Unable to request IRQ\n");
497 mcbsp->id); 542 goto err_clk_disable;
498 goto err_clk_disable; 543 }
499 } 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) { 552 err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
502 err = request_irq(mcbsp->rx_irq, 553 "McBSP RX", (void *)mcbsp);
503 omap_mcbsp_rx_irq_handler,
504 0, "McBSP", (void *)mcbsp);
505 if (err != 0) { 554 if (err != 0) {
506 dev_err(mcbsp->dev, "Unable to request RX IRQ %d " 555 dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
507 "for McBSP%d\n", mcbsp->rx_irq,
508 mcbsp->id);
509 goto err_free_irq; 556 goto err_free_irq;
510 } 557 }
511 } 558 }
@@ -542,9 +589,16 @@ void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
542 if (mcbsp->pdata->has_wakeup) 589 if (mcbsp->pdata->has_wakeup)
543 MCBSP_WRITE(mcbsp, WAKEUPEN, 0); 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 free_irq(mcbsp->rx_irq, (void *)mcbsp); 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 reg_cache = mcbsp->reg_cache; 603 reg_cache = mcbsp->reg_cache;
550 604
@@ -754,7 +808,7 @@ THRESHOLD_PROP_BUILDER(max_tx_thres);
754THRESHOLD_PROP_BUILDER(max_rx_thres); 808THRESHOLD_PROP_BUILDER(max_rx_thres);
755 809
756static const char *dma_op_modes[] = { 810static const char *dma_op_modes[] = {
757 "element", "threshold", "frame", 811 "element", "threshold",
758}; 812};
759 813
760static ssize_t dma_op_mode_show(struct device *dev, 814static ssize_t dma_op_mode_show(struct device *dev,
@@ -949,13 +1003,24 @@ int __devinit omap_mcbsp_init(struct platform_device *pdev)
949 else 1003 else
950 mcbsp->phys_dma_base = res->start; 1004 mcbsp->phys_dma_base = res->start;
951 1005
952 mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx"); 1006 /*
953 mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx"); 1007 * OMAP1, 2 uses two interrupt lines: TX, RX
954 1008 * OMAP2430, OMAP3 SoC have combined IRQ line as well.
955 /* From OMAP4 there will be a single irq line */ 1009 * OMAP4 and newer SoC only have the combined IRQ line.
956 if (mcbsp->tx_irq == -ENXIO) { 1010 * Use the combined IRQ if available since it gives better debugging
957 mcbsp->tx_irq = platform_get_irq(pdev, 0); 1011 * possibilities.
958 mcbsp->rx_irq = 0; 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");
1016
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 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); 1026 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h
index a944fcc9073..262a6152111 100644
--- a/sound/soc/omap/mcbsp.h
+++ b/sound/soc/omap/mcbsp.h
@@ -217,17 +217,20 @@ enum {
217/********************** McBSP DMA operating modes **************************/ 217/********************** McBSP DMA operating modes **************************/
218#define MCBSP_DMA_MODE_ELEMENT 0 218#define MCBSP_DMA_MODE_ELEMENT 0
219#define MCBSP_DMA_MODE_THRESHOLD 1 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#define RSYNCERREN BIT(0) 222#define RSYNCERREN BIT(0)
224#define RFSREN BIT(1) 223#define RFSREN BIT(1)
225#define REOFEN BIT(2) 224#define REOFEN BIT(2)
226#define RRDYEN BIT(3) 225#define RRDYEN BIT(3)
226#define RUNDFLEN BIT(4)
227#define ROVFLEN BIT(5)
227#define XSYNCERREN BIT(7) 228#define XSYNCERREN BIT(7)
228#define XFSXEN BIT(8) 229#define XFSXEN BIT(8)
229#define XEOFEN BIT(9) 230#define XEOFEN BIT(9)
230#define XRDYEN BIT(10) 231#define XRDYEN BIT(10)
232#define XUNDFLEN BIT(11)
233#define XOVFLEN BIT(12)
231#define XEMPTYEOFEN BIT(14) 234#define XEMPTYEOFEN BIT(14)
232 235
233/* Clock signal muxing options */ 236/* Clock signal muxing options */
@@ -295,6 +298,7 @@ struct omap_mcbsp {
295 int configured; 298 int configured;
296 u8 free; 299 u8 free;
297 300
301 int irq;
298 int rx_irq; 302 int rx_irq;
299 int tx_irq; 303 int tx_irq;
300 304
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index 93bb8eee22b..9d93793d307 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -40,6 +40,11 @@
40#include "omap-pcm.h" 40#include "omap-pcm.h"
41#include "../codecs/twl6040.h" 41#include "../codecs/twl6040.h"
42 42
43struct abe_twl6040 {
44 int jack_detection; /* board can detect jack events */
45 int mclk_freq; /* MCLK frequency speed for twl6040 */
46};
47
43static int omap_abe_hw_params(struct snd_pcm_substream *substream, 48static int omap_abe_hw_params(struct snd_pcm_substream *substream,
44 struct snd_pcm_hw_params *params) 49 struct snd_pcm_hw_params *params)
45{ 50{
@@ -47,13 +52,13 @@ static int omap_abe_hw_params(struct snd_pcm_substream *substream,
47 struct snd_soc_dai *codec_dai = rtd->codec_dai; 52 struct snd_soc_dai *codec_dai = rtd->codec_dai;
48 struct snd_soc_codec *codec = rtd->codec; 53 struct snd_soc_codec *codec = rtd->codec;
49 struct snd_soc_card *card = codec->card; 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 int clk_id, freq; 56 int clk_id, freq;
52 int ret; 57 int ret;
53 58
54 clk_id = twl6040_get_clk_id(rtd->codec); 59 clk_id = twl6040_get_clk_id(rtd->codec);
55 if (clk_id == TWL6040_SYSCLK_SEL_HPPLL) 60 if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
56 freq = pdata->mclk_freq; 61 freq = priv->mclk_freq;
57 else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL) 62 else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
58 freq = 32768; 63 freq = 32768;
59 else 64 else
@@ -128,6 +133,9 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
128 SND_SOC_DAPM_MIC("Main Handset Mic", NULL), 133 SND_SOC_DAPM_MIC("Main Handset Mic", NULL),
129 SND_SOC_DAPM_MIC("Sub Handset Mic", NULL), 134 SND_SOC_DAPM_MIC("Sub Handset Mic", NULL),
130 SND_SOC_DAPM_LINE("Line In", NULL), 135 SND_SOC_DAPM_LINE("Line In", NULL),
136
137 /* Digital microphones */
138 SND_SOC_DAPM_MIC("Digital Mic", NULL),
131}; 139};
132 140
133static const struct snd_soc_dapm_route audio_map[] = { 141static const struct snd_soc_dapm_route audio_map[] = {
@@ -173,6 +181,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
173 struct snd_soc_card *card = codec->card; 181 struct snd_soc_card *card = codec->card;
174 struct snd_soc_dapm_context *dapm = &codec->dapm; 182 struct snd_soc_dapm_context *dapm = &codec->dapm;
175 struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev); 183 struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev);
184 struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
176 int hs_trim; 185 int hs_trim;
177 int ret = 0; 186 int ret = 0;
178 187
@@ -196,7 +205,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
196 TWL6040_HSF_TRIM_RIGHT(hs_trim)); 205 TWL6040_HSF_TRIM_RIGHT(hs_trim));
197 206
198 /* Headset jack detection only if it is supported */ 207 /* Headset jack detection only if it is supported */
199 if (pdata->jack_detection) { 208 if (priv->jack_detection) {
200 ret = snd_soc_jack_new(codec, "Headset Jack", 209 ret = snd_soc_jack_new(codec, "Headset Jack",
201 SND_JACK_HEADSET, &hs_jack); 210 SND_JACK_HEADSET, &hs_jack);
202 if (ret) 211 if (ret)
@@ -210,10 +219,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
210 return ret; 219 return ret;
211} 220}
212 221
213static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
214 SND_SOC_DAPM_MIC("Digital Mic", NULL),
215};
216
217static const struct snd_soc_dapm_route dmic_audio_map[] = { 222static const struct snd_soc_dapm_route dmic_audio_map[] = {
218 {"DMic", NULL, "Digital Mic"}, 223 {"DMic", NULL, "Digital Mic"},
219 {"Digital Mic", NULL, "Digital Mic1 Bias"}, 224 {"Digital Mic", NULL, "Digital Mic1 Bias"},
@@ -223,19 +228,13 @@ static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
223{ 228{
224 struct snd_soc_codec *codec = rtd->codec; 229 struct snd_soc_codec *codec = rtd->codec;
225 struct snd_soc_dapm_context *dapm = &codec->dapm; 230 struct snd_soc_dapm_context *dapm = &codec->dapm;
226 int ret;
227
228 ret = snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets,
229 ARRAY_SIZE(dmic_dapm_widgets));
230 if (ret)
231 return ret;
232 231
233 return snd_soc_dapm_add_routes(dapm, dmic_audio_map, 232 return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
234 ARRAY_SIZE(dmic_audio_map)); 233 ARRAY_SIZE(dmic_audio_map));
235} 234}
236 235
237/* Digital audio interface glue - connects codec <--> CPU */ 236/* Digital audio interface glue - connects codec <--> CPU */
238static struct snd_soc_dai_link twl6040_dmic_dai[] = { 237static struct snd_soc_dai_link abe_twl6040_dai_links[] = {
239 { 238 {
240 .name = "TWL6040", 239 .name = "TWL6040",
241 .stream_name = "TWL6040", 240 .stream_name = "TWL6040",
@@ -258,19 +257,6 @@ static struct snd_soc_dai_link twl6040_dmic_dai[] = {
258 }, 257 },
259}; 258};
260 259
261static 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/* Audio machine driver */ 260/* Audio machine driver */
275static struct snd_soc_card omap_abe_card = { 261static struct snd_soc_card omap_abe_card = {
276 .owner = THIS_MODULE, 262 .owner = THIS_MODULE,
@@ -285,6 +271,8 @@ static __devinit int omap_abe_probe(struct platform_device *pdev)
285{ 271{
286 struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); 272 struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
287 struct snd_soc_card *card = &omap_abe_card; 273 struct snd_soc_card *card = &omap_abe_card;
274 struct abe_twl6040 *priv;
275 int num_links = 0;
288 int ret; 276 int ret;
289 277
290 card->dev = &pdev->dev; 278 card->dev = &pdev->dev;
@@ -294,6 +282,10 @@ static __devinit int omap_abe_probe(struct platform_device *pdev)
294 return -ENODEV; 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 if (pdata->card_name) { 289 if (pdata->card_name) {
298 card->name = pdata->card_name; 290 card->name = pdata->card_name;
299 } else { 291 } else {
@@ -301,18 +293,24 @@ static __devinit int omap_abe_probe(struct platform_device *pdev)
301 return -ENODEV; 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 dev_err(&pdev->dev, "MCLK frequency missing\n"); 301 dev_err(&pdev->dev, "MCLK frequency missing\n");
306 return -ENODEV; 302 return -ENODEV;
307 } 303 }
308 304
309 if (pdata->has_dmic) { 305 if (pdata->has_dmic)
310 card->dai_link = twl6040_dmic_dai; 306 num_links = 2;
311 card->num_links = ARRAY_SIZE(twl6040_dmic_dai); 307 else
312 } else { 308 num_links = 1;
313 card->dai_link = twl6040_only_dai; 309
314 card->num_links = ARRAY_SIZE(twl6040_only_dai); 310 card->dai_link = abe_twl6040_dai_links;
315 } 311 card->num_links = num_links;
312
313 snd_soc_card_set_drvdata(card, priv);
316 314
317 ret = snd_soc_register_card(card); 315 ret = snd_soc_register_card(card);
318 if (ret) 316 if (ret)
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 4dcb5a7e40e..75f5dca0e8d 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -32,6 +32,7 @@
32#include <linux/io.h> 32#include <linux/io.h>
33#include <linux/slab.h> 33#include <linux/slab.h>
34#include <linux/pm_runtime.h> 34#include <linux/pm_runtime.h>
35#include <linux/of_device.h>
35#include <plat/dma.h> 36#include <plat/dma.h>
36 37
37#include <sound/core.h> 38#include <sound/core.h>
@@ -528,10 +529,17 @@ static int __devexit asoc_dmic_remove(struct platform_device *pdev)
528 return 0; 529 return 0;
529} 530}
530 531
532static const struct of_device_id omap_dmic_of_match[] = {
533 { .compatible = "ti,omap4-dmic", },
534 { }
535};
536MODULE_DEVICE_TABLE(of, omap_dmic_of_match);
537
531static struct platform_driver asoc_dmic_driver = { 538static struct platform_driver asoc_dmic_driver = {
532 .driver = { 539 .driver = {
533 .name = "omap-dmic", 540 .name = "omap-dmic",
534 .owner = THIS_MODULE, 541 .owner = THIS_MODULE,
542 .of_match_table = omap_dmic_of_match,
535 }, 543 },
536 .probe = asoc_dmic_probe, 544 .probe = asoc_dmic_probe,
537 .remove = __devexit_p(asoc_dmic_remove), 545 .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 00000000000..eaa2ea0e3f8
--- /dev/null
+++ b/sound/soc/omap/omap-hdmi-card.c
@@ -0,0 +1,87 @@
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
32static 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
41static 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
48static __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
64static 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
73static 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
82module_platform_driver(omap_hdmi_driver);
83
84MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
85MODULE_DESCRIPTION("OMAP HDMI machine ASoC driver");
86MODULE_LICENSE("GPL");
87MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c
index 38e0defa707..a08245d9203 100644
--- a/sound/soc/omap/omap-hdmi.c
+++ b/sound/soc/omap/omap-hdmi.c
@@ -30,21 +30,28 @@
30#include <sound/pcm_params.h> 30#include <sound/pcm_params.h>
31#include <sound/initval.h> 31#include <sound/initval.h>
32#include <sound/soc.h> 32#include <sound/soc.h>
33#include <sound/asound.h>
34#include <sound/asoundef.h>
35#include <video/omapdss.h>
33 36
34#include <plat/dma.h> 37#include <plat/dma.h>
35#include "omap-pcm.h" 38#include "omap-pcm.h"
36#include "omap-hdmi.h" 39#include "omap-hdmi.h"
37 40
38#define DRV_NAME "hdmi-audio-dai" 41#define DRV_NAME "omap-hdmi-audio-dai"
39 42
40static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = { 43struct hdmi_priv {
41 .name = "HDMI playback", 44 struct omap_pcm_dma_data dma_params;
42 .sync_mode = OMAP_DMA_SYNC_PACKET, 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
45static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, 51static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
46 struct snd_soc_dai *dai) 52 struct snd_soc_dai *dai)
47{ 53{
54 struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
48 int err; 55 int err;
49 /* 56 /*
50 * Make sure that the period bytes are multiple of the DMA packet size. 57 * 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,
52 */ 59 */
53 err = snd_pcm_hw_constraint_step(substream->runtime, 0, 60 err = snd_pcm_hw_constraint_step(substream->runtime, 0,
54 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); 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 return err; 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 return 0; 71 return 0;
59} 72}
60 73
74static 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
61static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream, 82static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
62 struct snd_pcm_hw_params *params, 83 struct snd_pcm_hw_params *params,
63 struct snd_soc_dai *dai) 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 int err = 0; 89 int err = 0;
66 90
67 switch (params_format(params)) { 91 switch (params_format(params)) {
68 case SNDRV_PCM_FORMAT_S16_LE: 92 case SNDRV_PCM_FORMAT_S16_LE:
69 omap_hdmi_dai_dma_params.packet_size = 16; 93 priv->dma_params.packet_size = 16;
70 break; 94 break;
71 case SNDRV_PCM_FORMAT_S24_LE: 95 case SNDRV_PCM_FORMAT_S24_LE:
72 omap_hdmi_dai_dma_params.packet_size = 32; 96 priv->dma_params.packet_size = 32;
73 break; 97 break;
74 default: 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 snd_soc_dai_set_dma_data(dai, substream, 105 snd_soc_dai_set_dma_data(dai, substream,
81 &omap_hdmi_dai_dma_params); 106 &priv->dma_params);
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);
82 210
83 return err; 211 return err;
84} 212}
85 213
214static 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
237static 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
86static const struct snd_soc_dai_ops omap_hdmi_dai_ops = { 245static const struct snd_soc_dai_ops omap_hdmi_dai_ops = {
87 .startup = omap_hdmi_dai_startup, 246 .startup = omap_hdmi_dai_startup,
88 .hw_params = omap_hdmi_dai_hw_params, 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
91static struct snd_soc_dai_driver omap_hdmi_dai = { 253static struct snd_soc_dai_driver omap_hdmi_dai = {
92 .playback = { 254 .playback = {
93 .channels_min = 2, 255 .channels_min = 2,
94 .channels_max = 2, 256 .channels_max = 8,
95 .rates = OMAP_HDMI_RATES, 257 .rates = OMAP_HDMI_RATES,
96 .formats = OMAP_HDMI_FORMATS, 258 .formats = OMAP_HDMI_FORMATS,
97 }, 259 },
@@ -102,31 +264,77 @@ static __devinit int omap_hdmi_probe(struct platform_device *pdev)
102{ 264{
103 int ret; 265 int ret;
104 struct resource *hdmi_rsrc; 266 struct resource *hdmi_rsrc;
267 struct hdmi_priv *hdmi_data;
268 bool hdmi_dev_found = false;
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 }
105 275
106 hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0); 276 hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
107 if (!hdmi_rsrc) { 277 if (!hdmi_rsrc) {
108 dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n"); 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 + OMAP_HDMI_AUDIO_DMA_PORT; 283 + OMAP_HDMI_AUDIO_DMA_PORT;
114 284
115 hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0); 285 hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
116 if (!hdmi_rsrc) { 286 if (!hdmi_rsrc) {
117 dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n"); 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;
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);
122 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 ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai); 321 ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
322
124 return ret; 323 return ret;
125} 324}
126 325
127static int __devexit omap_hdmi_remove(struct platform_device *pdev) 326static int __devexit omap_hdmi_remove(struct platform_device *pdev)
128{ 327{
328 struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
329
129 snd_soc_unregister_dai(&pdev->dev); 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 return 0; 338 return 0;
131} 339}
132 340
diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h
index 34c298d5057..6ad2bf4f269 100644
--- a/sound/soc/omap/omap-hdmi.h
+++ b/sound/soc/omap/omap-hdmi.h
@@ -28,7 +28,9 @@
28#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c 28#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c
29 29
30#define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \ 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#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 35#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
34 SNDRV_PCM_FMTBIT_S24_LE) 36 SNDRV_PCM_FMTBIT_S24_LE)
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 6912ac7cb62..1046083e90a 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -71,18 +71,17 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
71 71
72 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); 72 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
73 73
74 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ 74 /*
75 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) 75 * Configure McBSP threshold based on either:
76 /* 76 * packet_size, when the sDMA is in packet mode, or based on the
77 * Configure McBSP threshold based on either: 77 * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
78 * packet_size, when the sDMA is in packet mode, or 78 * for mono streams.
79 * based on the period size. 79 */
80 */ 80 if (dma_data->packet_size)
81 if (dma_data->packet_size) 81 words = dma_data->packet_size;
82 words = dma_data->packet_size; 82 else if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
83 else 83 words = snd_pcm_lib_period_bytes(substream) /
84 words = snd_pcm_lib_period_bytes(substream) / 84 (mcbsp->wlen / 8);
85 (mcbsp->wlen / 8);
86 else 85 else
87 words = 1; 86 words = 1;
88 87
@@ -139,13 +138,15 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
139 if (mcbsp->pdata->buffer_size) { 138 if (mcbsp->pdata->buffer_size) {
140 /* 139 /*
141 * Rule for the buffer size. We should not allow 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, 144 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
145 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 145 snd_pcm_hw_rule_add(substream->runtime, 0,
146 omap_mcbsp_hwrule_min_buffersize, 146 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
147 mcbsp, 147 omap_mcbsp_hwrule_min_buffersize,
148 SNDRV_PCM_HW_PARAM_CHANNELS, -1); 148 mcbsp,
149 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
149 150
150 /* Make sure, that the period size is always even */ 151 /* Make sure, that the period size is always even */
151 snd_pcm_hw_constraint_step(substream->runtime, 0, 152 snd_pcm_hw_constraint_step(substream->runtime, 0,
@@ -230,6 +231,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
230 unsigned int format, div, framesize, master; 231 unsigned int format, div, framesize, master;
231 232
232 dma_data = &mcbsp->dma_data[substream->stream]; 233 dma_data = &mcbsp->dma_data[substream->stream];
234 channels = params_channels(params);
233 235
234 switch (params_format(params)) { 236 switch (params_format(params)) {
235 case SNDRV_PCM_FORMAT_S16_LE: 237 case SNDRV_PCM_FORMAT_S16_LE:
@@ -245,7 +247,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
245 } 247 }
246 if (mcbsp->pdata->buffer_size) { 248 if (mcbsp->pdata->buffer_size) {
247 dma_data->set_threshold = omap_mcbsp_set_threshold; 249 dma_data->set_threshold = omap_mcbsp_set_threshold;
248 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
249 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { 250 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
250 int period_words, max_thrsh; 251 int period_words, max_thrsh;
251 252
@@ -283,6 +284,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
283 } else { 284 } else {
284 sync_mode = OMAP_DMA_SYNC_FRAME; 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 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
301 regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7)); 306 regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
302 regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7)); 307 regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
303 format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK; 308 format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
304 wpf = channels = params_channels(params); 309 wpf = channels;
305 if (channels == 2 && (format == SND_SOC_DAIFMT_I2S || 310 if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
306 format == SND_SOC_DAIFMT_LEFT_J)) { 311 format == SND_SOC_DAIFMT_LEFT_J)) {
307 /* Use dual-phase frames */ 312 /* Use dual-phase frames */
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 39705561131..59d47ab5b15 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -33,6 +33,7 @@
33#include <linux/irq.h> 33#include <linux/irq.h>
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include <linux/pm_runtime.h> 35#include <linux/pm_runtime.h>
36#include <linux/of_device.h>
36 37
37#include <sound/core.h> 38#include <sound/core.h>
38#include <sound/pcm.h> 39#include <sound/pcm.h>
@@ -507,10 +508,17 @@ static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
507 return 0; 508 return 0;
508} 509}
509 510
511static const struct of_device_id omap_mcpdm_of_match[] = {
512 { .compatible = "ti,omap4-mcpdm", },
513 { }
514};
515MODULE_DEVICE_TABLE(of, omap_mcpdm_of_match);
516
510static struct platform_driver asoc_mcpdm_driver = { 517static struct platform_driver asoc_mcpdm_driver = {
511 .driver = { 518 .driver = {
512 .name = "omap-mcpdm", 519 .name = "omap-mcpdm",
513 .owner = THIS_MODULE, 520 .owner = THIS_MODULE,
521 .of_match_table = omap_mcpdm_of_match,
514 }, 522 },
515 523
516 .probe = asoc_mcpdm_probe, 524 .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
index 28d689b2714..00000000000
--- a/sound/soc/omap/omap4-hdmi-card.c
+++ /dev/null
@@ -1,121 +0,0 @@
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
32static 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
61static struct snd_soc_ops omap4_hdmi_dai_ops = {
62 .hw_params = omap4_hdmi_dai_hw_params,
63};
64
65static 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
75static 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
82static __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
98static 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
107static 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
116module_platform_driver(omap4_hdmi_driver);
117
118MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
119MODULE_DESCRIPTION("OMAP4 HDMI machine ASoC driver");
120MODULE_LICENSE("GPL");
121MODULE_ALIAS("platform:" DRV_NAME);