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