diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-05-22 19:37:59 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-05-22 19:37:59 -0400 |
commit | 599ed4b0aeceb6d45ea33f64639e745e3da72766 (patch) | |
tree | d1d68299eacda3b12097bd3a7d4e7c895e3d6a13 /sound | |
parent | 85e184e4c3cd3e2285ceab91ff8f0cac094e8a85 (diff) | |
parent | ced47a3117ba084b404f3fc28de3ef6eaba1b911 (diff) |
Merge branch 'for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/asoc into topic/asoc
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/omap/Kconfig | 7 | ||||
-rw-r--r-- | sound/soc/omap/Makefile | 4 | ||||
-rw-r--r-- | sound/soc/omap/mcbsp.c | 115 | ||||
-rw-r--r-- | sound/soc/omap/mcbsp.h | 8 | ||||
-rw-r--r-- | sound/soc/omap/omap-abe-twl6040.c | 68 | ||||
-rw-r--r-- | sound/soc/omap/omap-dmic.c | 8 | ||||
-rw-r--r-- | sound/soc/omap/omap-hdmi-card.c | 87 | ||||
-rw-r--r-- | sound/soc/omap/omap-hdmi.c | 238 | ||||
-rw-r--r-- | sound/soc/omap/omap-hdmi.h | 4 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 45 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcpdm.c | 8 | ||||
-rw-r--r-- | sound/soc/omap/omap4-hdmi-card.c | 121 |
12 files changed, 489 insertions, 224 deletions
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 9ccfa5e1c11b..57a2fa751085 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -109,11 +109,12 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040 | |||
109 | - PandaBoard (4430) | 109 | - PandaBoard (4430) |
110 | - PandaBoardES (4460) | 110 | - PandaBoardES (4460) |
111 | 111 | ||
112 | config SND_OMAP_SOC_OMAP4_HDMI | 112 | config 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 1d656bce01d4..0e14dd322565 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile | |||
@@ -25,7 +25,7 @@ snd-soc-omap3pandora-objs := omap3pandora.o | |||
25 | snd-soc-omap3beagle-objs := omap3beagle.o | 25 | snd-soc-omap3beagle-objs := omap3beagle.o |
26 | snd-soc-zoom2-objs := zoom2.o | 26 | snd-soc-zoom2-objs := zoom2.o |
27 | snd-soc-igep0020-objs := igep0020.o | 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 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | 30 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o |
31 | obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o | 31 | 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 | |||
41 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o | 41 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o |
42 | obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o | 42 | obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o |
43 | obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o | 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 |
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index e5f44440d1b9..34835e8a9160 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c | |||
@@ -109,6 +109,47 @@ static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp) | |||
109 | dev_dbg(mcbsp->dev, "***********************\n"); | 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 | static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) | 153 | static 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); | |||
754 | THRESHOLD_PROP_BUILDER(max_rx_thres); | 808 | THRESHOLD_PROP_BUILDER(max_rx_thres); |
755 | 809 | ||
756 | static const char *dma_op_modes[] = { | 810 | static const char *dma_op_modes[] = { |
757 | "element", "threshold", "frame", | 811 | "element", "threshold", |
758 | }; | 812 | }; |
759 | 813 | ||
760 | static ssize_t dma_op_mode_show(struct device *dev, | 814 | static 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 a944fcc9073c..262a6152111f 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 93bb8eee22b3..9d93793d3077 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 | ||
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 | static int omap_abe_hw_params(struct snd_pcm_substream *substream, | 48 | static 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 | ||
133 | static const struct snd_soc_dapm_route audio_map[] = { | 141 | 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) | |||
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 | ||
213 | static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = { | ||
214 | SND_SOC_DAPM_MIC("Digital Mic", NULL), | ||
215 | }; | ||
216 | |||
217 | static const struct snd_soc_dapm_route dmic_audio_map[] = { | 222 | static 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 */ |
238 | static struct snd_soc_dai_link twl6040_dmic_dai[] = { | 237 | static 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 | ||
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 | /* Audio machine driver */ | 260 | /* Audio machine driver */ |
275 | static struct snd_soc_card omap_abe_card = { | 261 | static 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 4dcb5a7e40e8..75f5dca0e8d2 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 | ||
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 | static struct platform_driver asoc_dmic_driver = { | 538 | static 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 000000000000..eaa2ea0e3f81 --- /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 | |||
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); | ||
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c index 38e0defa7078..a08245d9203c 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 | ||
40 | static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = { | 43 | struct 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 | ||
45 | static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, | 51 | static 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 | ||
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 | static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream, | 82 | static 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 | ||
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 | static const struct snd_soc_dai_ops omap_hdmi_dai_ops = { | 245 | static 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 | ||
91 | static struct snd_soc_dai_driver omap_hdmi_dai = { | 253 | static 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 | ||
127 | static int __devexit omap_hdmi_remove(struct platform_device *pdev) | 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 | 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 34c298d5057e..6ad2bf4f2697 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 6912ac7cb625..1046083e90a0 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 39705561131a..59d47ab5b15d 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 | ||
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 | static struct platform_driver asoc_mcpdm_driver = { | 517 | static 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 28d689b2714d..000000000000 --- 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 | |||
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); | ||