aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS2
-rw-r--r--include/sound/tlv320aic3x.h2
-rw-r--r--sound/pci/azt3328.c11
-rw-r--r--sound/pci/hda/patch_sigmatel.c2
-rw-r--r--sound/soc/codecs/wm8750.c8
-rw-r--r--sound/soc/codecs/wm8903.c5
-rw-r--r--sound/soc/codecs/wm8994.c1
-rw-r--r--sound/soc/omap/n810.c4
-rw-r--r--sound/soc/omap/omap-mcbsp.c4
-rw-r--r--sound/soc/omap/omap-mcbsp.h2
-rw-r--r--sound/soc/omap/omap-pcm.c4
-rw-r--r--sound/soc/omap/omap-pcm.h2
-rw-r--r--sound/soc/omap/rx51.c2
-rw-r--r--sound/soc/samsung/Makefile2
-rw-r--r--sound/soc/samsung/idma.c453
-rw-r--r--sound/soc/samsung/idma.h26
-rw-r--r--sound/soc/samsung/jive_wm8750.c2
-rw-r--r--sound/soc/samsung/speyside_wm8962.c2
-rw-r--r--sound/soc/tegra/tegra_pcm.c9
-rw-r--r--sound/soc/tegra/tegra_wm8903.c15
-rw-r--r--sound/usb/caiaq/audio.c6
-rw-r--r--sound/usb/quirks-table.h34
22 files changed, 573 insertions, 25 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 1e55e1eeb811..1d445f572987 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4604,7 +4604,7 @@ F: arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
4604F: arch/arm/mach-omap2/clockdomain44xx.c 4604F: arch/arm/mach-omap2/clockdomain44xx.c
4605 4605
4606OMAP AUDIO SUPPORT 4606OMAP AUDIO SUPPORT
4607M: Jarkko Nikula <jhnikula@gmail.com> 4607M: Jarkko Nikula <jarkko.nikula@bitmer.com>
4608L: alsa-devel@alsa-project.org (subscribers-only) 4608L: alsa-devel@alsa-project.org (subscribers-only)
4609L: linux-omap@vger.kernel.org 4609L: linux-omap@vger.kernel.org
4610S: Maintained 4610S: Maintained
diff --git a/include/sound/tlv320aic3x.h b/include/sound/tlv320aic3x.h
index 99e0308bf2c2..ffd9bc793105 100644
--- a/include/sound/tlv320aic3x.h
+++ b/include/sound/tlv320aic3x.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * Platform data for Texas Instruments TLV320AIC3x codec 2 * Platform data for Texas Instruments TLV320AIC3x codec
3 * 3 *
4 * Author: Jarkko Nikula <jhnikula@gmail.com> 4 * Author: Jarkko Nikula <jarkko.nikula@bitmer.com>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index e4d76a270c9f..579fc0dce128 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -2625,16 +2625,19 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
2625 int err; 2625 int err;
2626 2626
2627 snd_azf3328_dbgcallenter(); 2627 snd_azf3328_dbgcallenter();
2628 if (dev >= SNDRV_CARDS) 2628 if (dev >= SNDRV_CARDS) {
2629 return -ENODEV; 2629 err = -ENODEV;
2630 goto out;
2631 }
2630 if (!enable[dev]) { 2632 if (!enable[dev]) {
2631 dev++; 2633 dev++;
2632 return -ENOENT; 2634 err = -ENOENT;
2635 goto out;
2633 } 2636 }
2634 2637
2635 err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); 2638 err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
2636 if (err < 0) 2639 if (err < 0)
2637 return err; 2640 goto out;
2638 2641
2639 strcpy(card->driver, "AZF3328"); 2642 strcpy(card->driver, "AZF3328");
2640 strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); 2643 strcpy(card->shortname, "Aztech AZF3328 (PCI168)");
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index aa376b59c006..5145b663ef6e 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -673,6 +673,7 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
673 return 0; 673 return 0;
674} 674}
675 675
676#ifdef CONFIG_SND_HDA_POWER_SAVE
676static int stac_vrefout_set(struct hda_codec *codec, 677static int stac_vrefout_set(struct hda_codec *codec,
677 hda_nid_t nid, unsigned int new_vref) 678 hda_nid_t nid, unsigned int new_vref)
678{ 679{
@@ -696,6 +697,7 @@ static int stac_vrefout_set(struct hda_codec *codec,
696 697
697 return 1; 698 return 1;
698} 699}
700#endif
699 701
700static unsigned int stac92xx_vref_set(struct hda_codec *codec, 702static unsigned int stac92xx_vref_set(struct hda_codec *codec,
701 hda_nid_t nid, unsigned int new_vref) 703 hda_nid_t nid, unsigned int new_vref)
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 38f38fddd190..d0003cc3bcd6 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -778,11 +778,19 @@ static int __devexit wm8750_spi_remove(struct spi_device *spi)
778 return 0; 778 return 0;
779} 779}
780 780
781static const struct spi_device_id wm8750_spi_ids[] = {
782 { "wm8750", 0 },
783 { "wm8987", 0 },
784 { },
785};
786MODULE_DEVICE_TABLE(spi, wm8750_spi_ids);
787
781static struct spi_driver wm8750_spi_driver = { 788static struct spi_driver wm8750_spi_driver = {
782 .driver = { 789 .driver = {
783 .name = "wm8750-codec", 790 .name = "wm8750-codec",
784 .owner = THIS_MODULE, 791 .owner = THIS_MODULE,
785 }, 792 },
793 .id_table = wm8750_spi_ids,
786 .probe = wm8750_spi_probe, 794 .probe = wm8750_spi_probe,
787 .remove = __devexit_p(wm8750_spi_remove), 795 .remove = __devexit_p(wm8750_spi_remove),
788}; 796};
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 43e3d760766f..4ad8ebd290e3 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -2046,8 +2046,13 @@ static int wm8903_probe(struct snd_soc_codec *codec)
2046/* power down chip */ 2046/* power down chip */
2047static int wm8903_remove(struct snd_soc_codec *codec) 2047static int wm8903_remove(struct snd_soc_codec *codec)
2048{ 2048{
2049 struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
2050
2049 wm8903_free_gpio(codec); 2051 wm8903_free_gpio(codec);
2050 wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); 2052 wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
2053 if (wm8903->irq)
2054 free_irq(wm8903->irq, codec);
2055
2051 return 0; 2056 return 0;
2052} 2057}
2053 2058
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 09e680ae88b2..b393f9fac97a 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -2981,6 +2981,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
2981 wm8994->hubs.dcs_readback_mode = 1; 2981 wm8994->hubs.dcs_readback_mode = 1;
2982 break; 2982 break;
2983 } 2983 }
2984 break;
2984 2985
2985 case WM8958: 2986 case WM8958:
2986 wm8994->hubs.dcs_readback_mode = 1; 2987 wm8994->hubs.dcs_readback_mode = 1;
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 83d213bfd3d1..62e292f49313 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 2008 Nokia Corporation 4 * Copyright (C) 2008 Nokia Corporation
5 * 5 *
6 * Contact: Jarkko Nikula <jhnikula@gmail.com> 6 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7 * 7 *
8 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License 9 * modify it under the terms of the GNU General Public License
@@ -402,6 +402,6 @@ static void __exit n810_soc_exit(void)
402module_init(n810_soc_init); 402module_init(n810_soc_init);
403module_exit(n810_soc_exit); 403module_exit(n810_soc_exit);
404 404
405MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>"); 405MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
406MODULE_DESCRIPTION("ALSA SoC Nokia N810"); 406MODULE_DESCRIPTION("ALSA SoC Nokia N810");
407MODULE_LICENSE("GPL"); 407MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 07b772357244..ebcc2d4d2b18 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 2008 Nokia Corporation 4 * Copyright (C) 2008 Nokia Corporation
5 * 5 *
6 * Contact: Jarkko Nikula <jhnikula@gmail.com> 6 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7 * Peter Ujfalusi <peter.ujfalusi@ti.com> 7 * Peter Ujfalusi <peter.ujfalusi@ti.com>
8 * 8 *
9 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
@@ -780,6 +780,6 @@ static void __exit snd_omap_mcbsp_exit(void)
780} 780}
781module_exit(snd_omap_mcbsp_exit); 781module_exit(snd_omap_mcbsp_exit);
782 782
783MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>"); 783MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
784MODULE_DESCRIPTION("OMAP I2S SoC Interface"); 784MODULE_DESCRIPTION("OMAP I2S SoC Interface");
785MODULE_LICENSE("GPL"); 785MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 9a7dedd6f5a9..65cde9d3807b 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 2008 Nokia Corporation 4 * Copyright (C) 2008 Nokia Corporation
5 * 5 *
6 * Contact: Jarkko Nikula <jhnikula@gmail.com> 6 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7 * Peter Ujfalusi <peter.ujfalusi@ti.com> 7 * Peter Ujfalusi <peter.ujfalusi@ti.com>
8 * 8 *
9 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index b2f5751edae3..9b5c88ac35b9 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 2008 Nokia Corporation 4 * Copyright (C) 2008 Nokia Corporation
5 * 5 *
6 * Contact: Jarkko Nikula <jhnikula@gmail.com> 6 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7 * Peter Ujfalusi <peter.ujfalusi@ti.com> 7 * Peter Ujfalusi <peter.ujfalusi@ti.com>
8 * 8 *
9 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
@@ -436,6 +436,6 @@ static void __exit snd_omap_pcm_exit(void)
436} 436}
437module_exit(snd_omap_pcm_exit); 437module_exit(snd_omap_pcm_exit);
438 438
439MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>"); 439MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
440MODULE_DESCRIPTION("OMAP PCM DMA module"); 440MODULE_DESCRIPTION("OMAP PCM DMA module");
441MODULE_LICENSE("GPL"); 441MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index a0ed1dbb52d6..f95fe3064172 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 2008 Nokia Corporation 4 * Copyright (C) 2008 Nokia Corporation
5 * 5 *
6 * Contact: Jarkko Nikula <jhnikula@gmail.com> 6 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7 * Peter Ujfalusi <peter.ujfalusi@ti.com> 7 * Peter Ujfalusi <peter.ujfalusi@ti.com>
8 * 8 *
9 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 0aae998b6540..893300a53bab 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -5,7 +5,7 @@
5 * 5 *
6 * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com> 6 * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
7 * Eduardo Valentin <eduardo.valentin@nokia.com> 7 * Eduardo Valentin <eduardo.valentin@nokia.com>
8 * Jarkko Nikula <jhnikula@gmail.com> 8 * Jarkko Nikula <jarkko.nikula@bitmer.com>
9 * 9 *
10 * This program is free software; you can redistribute it and/or 10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License 11 * modify it under the terms of the GNU General Public License
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 9eb3b12eb72f..8509d3c4366e 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -1,5 +1,6 @@
1# S3c24XX Platform Support 1# S3c24XX Platform Support
2snd-soc-s3c24xx-objs := dma.o 2snd-soc-s3c24xx-objs := dma.o
3snd-soc-idma-objs := idma.o
3snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o 4snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
4snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o 5snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
5snd-soc-ac97-objs := ac97.o 6snd-soc-ac97-objs := ac97.o
@@ -16,6 +17,7 @@ obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
16obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o 17obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
17obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o 18obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
18obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o 19obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
20obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-idma.o
19 21
20# S3C24XX Machine Support 22# S3C24XX Machine Support
21snd-soc-jive-wm8750-objs := jive_wm8750.o 23snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
new file mode 100644
index 000000000000..ebde0740ab19
--- /dev/null
+++ b/sound/soc/samsung/idma.c
@@ -0,0 +1,453 @@
1/*
2 * sound/soc/samsung/idma.c
3 *
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com
6 *
7 * I2S0's Internal DMA driver
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
14#include <linux/interrupt.h>
15#include <linux/platform_device.h>
16#include <linux/dma-mapping.h>
17#include <linux/slab.h>
18#include <sound/pcm.h>
19#include <sound/pcm_params.h>
20#include <sound/soc.h>
21
22#include "i2s.h"
23#include "idma.h"
24#include "dma.h"
25#include "i2s-regs.h"
26
27#define ST_RUNNING (1<<0)
28#define ST_OPENED (1<<1)
29
30static const struct snd_pcm_hardware idma_hardware = {
31 .info = SNDRV_PCM_INFO_INTERLEAVED |
32 SNDRV_PCM_INFO_BLOCK_TRANSFER |
33 SNDRV_PCM_INFO_MMAP |
34 SNDRV_PCM_INFO_MMAP_VALID |
35 SNDRV_PCM_INFO_PAUSE |
36 SNDRV_PCM_INFO_RESUME,
37 .formats = SNDRV_PCM_FMTBIT_S16_LE |
38 SNDRV_PCM_FMTBIT_U16_LE |
39 SNDRV_PCM_FMTBIT_S24_LE |
40 SNDRV_PCM_FMTBIT_U24_LE |
41 SNDRV_PCM_FMTBIT_U8 |
42 SNDRV_PCM_FMTBIT_S8,
43 .channels_min = 2,
44 .channels_max = 2,
45 .buffer_bytes_max = MAX_IDMA_BUFFER,
46 .period_bytes_min = 128,
47 .period_bytes_max = MAX_IDMA_PERIOD,
48 .periods_min = 1,
49 .periods_max = 2,
50};
51
52struct idma_ctrl {
53 spinlock_t lock;
54 int state;
55 dma_addr_t start;
56 dma_addr_t pos;
57 dma_addr_t end;
58 dma_addr_t period;
59 dma_addr_t periodsz;
60 void *token;
61 void (*cb)(void *dt, int bytes_xfer);
62};
63
64static struct idma_info {
65 spinlock_t lock;
66 void __iomem *regs;
67 dma_addr_t lp_tx_addr;
68} idma;
69
70static void idma_getpos(dma_addr_t *src)
71{
72 *src = idma.lp_tx_addr +
73 (readl(idma.regs + I2STRNCNT) & 0xffffff) * 4;
74}
75
76static int idma_enqueue(struct snd_pcm_substream *substream)
77{
78 struct snd_pcm_runtime *runtime = substream->runtime;
79 struct idma_ctrl *prtd = substream->runtime->private_data;
80 u32 val;
81
82 spin_lock(&prtd->lock);
83 prtd->token = (void *) substream;
84 spin_unlock(&prtd->lock);
85
86 /* Internal DMA Level0 Interrupt Address */
87 val = idma.lp_tx_addr + prtd->periodsz;
88 writel(val, idma.regs + I2SLVL0ADDR);
89
90 /* Start address0 of I2S internal DMA operation. */
91 val = idma.lp_tx_addr;
92 writel(val, idma.regs + I2SSTR0);
93
94 /*
95 * Transfer block size for I2S internal DMA.
96 * Should decide transfer size before start dma operation
97 */
98 val = readl(idma.regs + I2SSIZE);
99 val &= ~(I2SSIZE_TRNMSK << I2SSIZE_SHIFT);
100 val |= (((runtime->dma_bytes >> 2) &
101 I2SSIZE_TRNMSK) << I2SSIZE_SHIFT);
102 writel(val, idma.regs + I2SSIZE);
103
104 val = readl(idma.regs + I2SAHB);
105 val |= AHB_INTENLVL0;
106 writel(val, idma.regs + I2SAHB);
107
108 return 0;
109}
110
111static void idma_setcallbk(struct snd_pcm_substream *substream,
112 void (*cb)(void *, int))
113{
114 struct idma_ctrl *prtd = substream->runtime->private_data;
115
116 spin_lock(&prtd->lock);
117 prtd->cb = cb;
118 spin_unlock(&prtd->lock);
119}
120
121static void idma_control(int op)
122{
123 u32 val = readl(idma.regs + I2SAHB);
124
125 spin_lock(&idma.lock);
126
127 switch (op) {
128 case LPAM_DMA_START:
129 val |= (AHB_INTENLVL0 | AHB_DMAEN);
130 break;
131 case LPAM_DMA_STOP:
132 val &= ~(AHB_INTENLVL0 | AHB_DMAEN);
133 break;
134 default:
135 spin_unlock(&idma.lock);
136 return;
137 }
138
139 writel(val, idma.regs + I2SAHB);
140 spin_unlock(&idma.lock);
141}
142
143static void idma_done(void *id, int bytes_xfer)
144{
145 struct snd_pcm_substream *substream = id;
146 struct idma_ctrl *prtd = substream->runtime->private_data;
147
148 if (prtd && (prtd->state & ST_RUNNING))
149 snd_pcm_period_elapsed(substream);
150}
151
152static int idma_hw_params(struct snd_pcm_substream *substream,
153 struct snd_pcm_hw_params *params)
154{
155 struct snd_pcm_runtime *runtime = substream->runtime;
156 struct idma_ctrl *prtd = substream->runtime->private_data;
157 u32 mod = readl(idma.regs + I2SMOD);
158 u32 ahb = readl(idma.regs + I2SAHB);
159
160 ahb |= (AHB_DMARLD | AHB_INTMASK);
161 mod |= MOD_TXS_IDMA;
162 writel(ahb, idma.regs + I2SAHB);
163 writel(mod, idma.regs + I2SMOD);
164
165 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
166 runtime->dma_bytes = params_buffer_bytes(params);
167
168 prtd->start = prtd->pos = runtime->dma_addr;
169 prtd->period = params_periods(params);
170 prtd->periodsz = params_period_bytes(params);
171 prtd->end = runtime->dma_addr + runtime->dma_bytes;
172
173 idma_setcallbk(substream, idma_done);
174
175 return 0;
176}
177
178static int idma_hw_free(struct snd_pcm_substream *substream)
179{
180 snd_pcm_set_runtime_buffer(substream, NULL);
181
182 return 0;
183}
184
185static int idma_prepare(struct snd_pcm_substream *substream)
186{
187 struct idma_ctrl *prtd = substream->runtime->private_data;
188
189 prtd->pos = prtd->start;
190
191 /* flush the DMA channel */
192 idma_control(LPAM_DMA_STOP);
193 idma_enqueue(substream);
194
195 return 0;
196}
197
198static int idma_trigger(struct snd_pcm_substream *substream, int cmd)
199{
200 struct idma_ctrl *prtd = substream->runtime->private_data;
201 int ret = 0;
202
203 spin_lock(&prtd->lock);
204
205 switch (cmd) {
206 case SNDRV_PCM_TRIGGER_RESUME:
207 case SNDRV_PCM_TRIGGER_START:
208 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
209 prtd->state |= ST_RUNNING;
210 idma_control(LPAM_DMA_START);
211 break;
212
213 case SNDRV_PCM_TRIGGER_SUSPEND:
214 case SNDRV_PCM_TRIGGER_STOP:
215 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
216 prtd->state &= ~ST_RUNNING;
217 idma_control(LPAM_DMA_STOP);
218 break;
219
220 default:
221 ret = -EINVAL;
222 break;
223 }
224
225 spin_unlock(&prtd->lock);
226
227 return ret;
228}
229
230static snd_pcm_uframes_t
231 idma_pointer(struct snd_pcm_substream *substream)
232{
233 struct snd_pcm_runtime *runtime = substream->runtime;
234 struct idma_ctrl *prtd = runtime->private_data;
235 dma_addr_t src;
236 unsigned long res;
237
238 spin_lock(&prtd->lock);
239
240 idma_getpos(&src);
241 res = src - prtd->start;
242
243 spin_unlock(&prtd->lock);
244
245 return bytes_to_frames(substream->runtime, res);
246}
247
248static int idma_mmap(struct snd_pcm_substream *substream,
249 struct vm_area_struct *vma)
250{
251 struct snd_pcm_runtime *runtime = substream->runtime;
252 unsigned long size, offset;
253 int ret;
254
255 /* From snd_pcm_lib_mmap_iomem */
256 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
257 vma->vm_flags |= VM_IO;
258 size = vma->vm_end - vma->vm_start;
259 offset = vma->vm_pgoff << PAGE_SHIFT;
260 ret = io_remap_pfn_range(vma, vma->vm_start,
261 (runtime->dma_addr + offset) >> PAGE_SHIFT,
262 size, vma->vm_page_prot);
263
264 return ret;
265}
266
267static irqreturn_t iis_irq(int irqno, void *dev_id)
268{
269 struct idma_ctrl *prtd = (struct idma_ctrl *)dev_id;
270 u32 iiscon, iisahb, val, addr;
271
272 iisahb = readl(idma.regs + I2SAHB);
273 iiscon = readl(idma.regs + I2SCON);
274
275 val = (iisahb & AHB_LVL0INT) ? AHB_CLRLVL0INT : 0;
276
277 if (val) {
278 iisahb |= val;
279 writel(iisahb, idma.regs + I2SAHB);
280
281 addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr;
282 addr += prtd->periodsz;
283 addr %= (prtd->end - prtd->start);
284 addr += idma.lp_tx_addr;
285
286 writel(addr, idma.regs + I2SLVL0ADDR);
287
288 if (prtd->cb)
289 prtd->cb(prtd->token, prtd->period);
290 }
291
292 return IRQ_HANDLED;
293}
294
295static int idma_open(struct snd_pcm_substream *substream)
296{
297 struct snd_pcm_runtime *runtime = substream->runtime;
298 struct idma_ctrl *prtd;
299 int ret;
300
301 snd_soc_set_runtime_hwparams(substream, &idma_hardware);
302
303 prtd = kzalloc(sizeof(struct idma_ctrl), GFP_KERNEL);
304 if (prtd == NULL)
305 return -ENOMEM;
306
307 ret = request_irq(IRQ_I2S0, iis_irq, 0, "i2s", prtd);
308 if (ret < 0) {
309 pr_err("fail to claim i2s irq , ret = %d\n", ret);
310 kfree(prtd);
311 return ret;
312 }
313
314 spin_lock_init(&prtd->lock);
315
316 runtime->private_data = prtd;
317
318 return 0;
319}
320
321static int idma_close(struct snd_pcm_substream *substream)
322{
323 struct snd_pcm_runtime *runtime = substream->runtime;
324 struct idma_ctrl *prtd = runtime->private_data;
325
326 free_irq(IRQ_I2S0, prtd);
327
328 if (!prtd)
329 pr_err("idma_close called with prtd == NULL\n");
330
331 kfree(prtd);
332
333 return 0;
334}
335
336static struct snd_pcm_ops idma_ops = {
337 .open = idma_open,
338 .close = idma_close,
339 .ioctl = snd_pcm_lib_ioctl,
340 .trigger = idma_trigger,
341 .pointer = idma_pointer,
342 .mmap = idma_mmap,
343 .hw_params = idma_hw_params,
344 .hw_free = idma_hw_free,
345 .prepare = idma_prepare,
346};
347
348static void idma_free(struct snd_pcm *pcm)
349{
350 struct snd_pcm_substream *substream;
351 struct snd_dma_buffer *buf;
352
353 substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
354 if (!substream)
355 return;
356
357 buf = &substream->dma_buffer;
358 if (!buf->area)
359 return;
360
361 iounmap(buf->area);
362
363 buf->area = NULL;
364 buf->addr = 0;
365}
366
367static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream)
368{
369 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
370 struct snd_dma_buffer *buf = &substream->dma_buffer;
371
372 buf->dev.dev = pcm->card->dev;
373 buf->private_data = NULL;
374
375 /* Assign PCM buffer pointers */
376 buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
377 buf->addr = idma.lp_tx_addr;
378 buf->bytes = idma_hardware.buffer_bytes_max;
379 buf->area = (unsigned char *)ioremap(buf->addr, buf->bytes);
380
381 return 0;
382}
383
384static u64 idma_mask = DMA_BIT_MASK(32);
385
386static int idma_new(struct snd_soc_pcm_runtime *rtd)
387{
388 struct snd_card *card = rtd->card->snd_card;
389 struct snd_soc_dai *dai = rtd->cpu_dai;
390 struct snd_pcm *pcm = rtd->pcm;
391 int ret = 0;
392
393 if (!card->dev->dma_mask)
394 card->dev->dma_mask = &idma_mask;
395 if (!card->dev->coherent_dma_mask)
396 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
397
398 if (dai->driver->playback.channels_min)
399 ret = preallocate_idma_buffer(pcm,
400 SNDRV_PCM_STREAM_PLAYBACK);
401
402 return ret;
403}
404
405void idma_reg_addr_init(void *regs, dma_addr_t addr)
406{
407 spin_lock_init(&idma.lock);
408 idma.regs = regs;
409 idma.lp_tx_addr = addr;
410}
411
412struct snd_soc_platform_driver asoc_idma_platform = {
413 .ops = &idma_ops,
414 .pcm_new = idma_new,
415 .pcm_free = idma_free,
416};
417
418static int __devinit asoc_idma_platform_probe(struct platform_device *pdev)
419{
420 return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform);
421}
422
423static int __devexit asoc_idma_platform_remove(struct platform_device *pdev)
424{
425 snd_soc_unregister_platform(&pdev->dev);
426 return 0;
427}
428
429static struct platform_driver asoc_idma_driver = {
430 .driver = {
431 .name = "samsung-idma",
432 .owner = THIS_MODULE,
433 },
434
435 .probe = asoc_idma_platform_probe,
436 .remove = __devexit_p(asoc_idma_platform_remove),
437};
438
439static int __init asoc_idma_init(void)
440{
441 return platform_driver_register(&asoc_idma_driver);
442}
443module_init(asoc_idma_init);
444
445static void __exit asoc_idma_exit(void)
446{
447 platform_driver_unregister(&asoc_idma_driver);
448}
449module_exit(asoc_idma_exit);
450
451MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
452MODULE_DESCRIPTION("Samsung ASoC IDMA Driver");
453MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/idma.h b/sound/soc/samsung/idma.h
new file mode 100644
index 000000000000..48273216166e
--- /dev/null
+++ b/sound/soc/samsung/idma.h
@@ -0,0 +1,26 @@
1/*
2 * sound/soc/samsung/idma.h
3 *
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd
5 * http://www.samsung.com
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#ifndef __SND_SOC_SAMSUNG_IDMA_H_
15#define __SND_SOC_SAMSUNG_IDMA_H_
16
17extern void idma_reg_addr_init(void *regs, dma_addr_t addr);
18
19/* dma_state */
20#define LPAM_DMA_STOP 0
21#define LPAM_DMA_START 1
22
23#define MAX_IDMA_PERIOD (128 * 1024)
24#define MAX_IDMA_BUFFER (160 * 1024)
25
26#endif /* __SND_SOC_SAMSUNG_IDMA_H_ */
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
index 3b53ad54bc33..14eb6ea69e7c 100644
--- a/sound/soc/samsung/jive_wm8750.c
+++ b/sound/soc/samsung/jive_wm8750.c
@@ -131,7 +131,7 @@ static struct snd_soc_dai_link jive_dai = {
131 .cpu_dai_name = "s3c2412-i2s", 131 .cpu_dai_name = "s3c2412-i2s",
132 .codec_dai_name = "wm8750-hifi", 132 .codec_dai_name = "wm8750-hifi",
133 .platform_name = "samsung-audio", 133 .platform_name = "samsung-audio",
134 .codec_name = "wm8750-codec.0-0x1a", 134 .codec_name = "wm8750-codec.0-001a",
135 .init = jive_wm8750_init, 135 .init = jive_wm8750_init,
136 .ops = &jive_ops, 136 .ops = &jive_ops,
137}; 137};
diff --git a/sound/soc/samsung/speyside_wm8962.c b/sound/soc/samsung/speyside_wm8962.c
index 8ac42bf82090..0b9eb5f7ec4c 100644
--- a/sound/soc/samsung/speyside_wm8962.c
+++ b/sound/soc/samsung/speyside_wm8962.c
@@ -37,7 +37,7 @@ static int speyside_wm8962_set_bias_level(struct snd_soc_card *card,
37 44100 * 256, 37 44100 * 256,
38 SND_SOC_CLOCK_IN); 38 SND_SOC_CLOCK_IN);
39 if (ret < 0) { 39 if (ret < 0) {
40 pr_err("Failed to set SYSCLK: %d\n"); 40 pr_err("Failed to set SYSCLK: %d\n", ret);
41 return ret; 41 return ret;
42 } 42 }
43 } 43 }
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index ff86e5e3db68..c7cfd96e991e 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -309,9 +309,14 @@ static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
309 309
310static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) 310static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
311{ 311{
312 struct snd_pcm_substream *substream = pcm->streams[stream].substream; 312 struct snd_pcm_substream *substream;
313 struct snd_dma_buffer *buf = &substream->dma_buffer; 313 struct snd_dma_buffer *buf;
314
315 substream = pcm->streams[stream].substream;
316 if (!substream)
317 return;
314 318
319 buf = &substream->dma_buffer;
315 if (!buf->area) 320 if (!buf->area)
316 return; 321 return;
317 322
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index a42e9ac30f28..661373c2352a 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -56,6 +56,7 @@
56#define GPIO_HP_MUTE BIT(1) 56#define GPIO_HP_MUTE BIT(1)
57#define GPIO_INT_MIC_EN BIT(2) 57#define GPIO_INT_MIC_EN BIT(2)
58#define GPIO_EXT_MIC_EN BIT(3) 58#define GPIO_EXT_MIC_EN BIT(3)
59#define GPIO_HP_DET BIT(4)
59 60
60struct tegra_wm8903 { 61struct tegra_wm8903 {
61 struct tegra_asoc_utils_data util_data; 62 struct tegra_asoc_utils_data util_data;
@@ -304,6 +305,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
304 snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, 305 snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
305 1, 306 1,
306 &tegra_wm8903_hp_jack_gpio); 307 &tegra_wm8903_hp_jack_gpio);
308 machine->gpio_requested |= GPIO_HP_DET;
307 } 309 }
308 310
309 snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, 311 snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
@@ -429,10 +431,10 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
429 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 431 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
430 struct tegra_wm8903_platform_data *pdata = machine->pdata; 432 struct tegra_wm8903_platform_data *pdata = machine->pdata;
431 433
432 snd_soc_unregister_card(card); 434 if (machine->gpio_requested & GPIO_HP_DET)
433 435 snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
434 tegra_asoc_utils_fini(&machine->util_data); 436 1,
435 437 &tegra_wm8903_hp_jack_gpio);
436 if (machine->gpio_requested & GPIO_EXT_MIC_EN) 438 if (machine->gpio_requested & GPIO_EXT_MIC_EN)
437 gpio_free(pdata->gpio_ext_mic_en); 439 gpio_free(pdata->gpio_ext_mic_en);
438 if (machine->gpio_requested & GPIO_INT_MIC_EN) 440 if (machine->gpio_requested & GPIO_INT_MIC_EN)
@@ -441,6 +443,11 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
441 gpio_free(pdata->gpio_hp_mute); 443 gpio_free(pdata->gpio_hp_mute);
442 if (machine->gpio_requested & GPIO_SPKR_EN) 444 if (machine->gpio_requested & GPIO_SPKR_EN)
443 gpio_free(pdata->gpio_spkr_en); 445 gpio_free(pdata->gpio_spkr_en);
446 machine->gpio_requested = 0;
447
448 snd_soc_unregister_card(card);
449
450 tegra_asoc_utils_fini(&machine->util_data);
444 451
445 kfree(machine); 452 kfree(machine);
446 453
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index d0d493ca28ae..aa52b3e13bb5 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -614,6 +614,7 @@ static void read_completed(struct urb *urb)
614 struct snd_usb_caiaqdev *dev; 614 struct snd_usb_caiaqdev *dev;
615 struct urb *out; 615 struct urb *out;
616 int frame, len, send_it = 0, outframe = 0; 616 int frame, len, send_it = 0, outframe = 0;
617 size_t offset = 0;
617 618
618 if (urb->status || !info) 619 if (urb->status || !info)
619 return; 620 return;
@@ -634,7 +635,8 @@ static void read_completed(struct urb *urb)
634 len = urb->iso_frame_desc[outframe].actual_length; 635 len = urb->iso_frame_desc[outframe].actual_length;
635 out->iso_frame_desc[outframe].length = len; 636 out->iso_frame_desc[outframe].length = len;
636 out->iso_frame_desc[outframe].actual_length = 0; 637 out->iso_frame_desc[outframe].actual_length = 0;
637 out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; 638 out->iso_frame_desc[outframe].offset = offset;
639 offset += len;
638 640
639 if (len > 0) { 641 if (len > 0) {
640 spin_lock(&dev->spinlock); 642 spin_lock(&dev->spinlock);
@@ -650,7 +652,7 @@ static void read_completed(struct urb *urb)
650 } 652 }
651 653
652 if (send_it) { 654 if (send_it) {
653 out->number_of_packets = FRAMES_PER_URB; 655 out->number_of_packets = outframe;
654 out->transfer_flags = URB_ISO_ASAP; 656 out->transfer_flags = URB_ISO_ASAP;
655 usb_submit_urb(out, GFP_ATOMIC); 657 usb_submit_urb(out, GFP_ATOMIC);
656 } 658 }
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 4d4f86552a23..a42e3ef3832d 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -1707,6 +1707,40 @@ YAMAHA_DEVICE(0x7010, "UB99"),
1707 } 1707 }
1708 } 1708 }
1709}, 1709},
1710{
1711 USB_DEVICE(0x0582, 0x0130),
1712 .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
1713 /* .vendor_name = "BOSS", */
1714 /* .product_name = "MICRO BR-80", */
1715 .ifnum = QUIRK_ANY_INTERFACE,
1716 .type = QUIRK_COMPOSITE,
1717 .data = (const struct snd_usb_audio_quirk[]) {
1718 {
1719 .ifnum = 0,
1720 .type = QUIRK_IGNORE_INTERFACE
1721 },
1722 {
1723 .ifnum = 1,
1724 .type = QUIRK_AUDIO_STANDARD_INTERFACE
1725 },
1726 {
1727 .ifnum = 2,
1728 .type = QUIRK_AUDIO_STANDARD_INTERFACE
1729 },
1730 {
1731 .ifnum = 3,
1732 .type = QUIRK_MIDI_FIXED_ENDPOINT,
1733 .data = & (const struct snd_usb_midi_endpoint_info) {
1734 .out_cables = 0x0001,
1735 .in_cables = 0x0001
1736 }
1737 },
1738 {
1739 .ifnum = -1
1740 }
1741 }
1742 }
1743},
1710 1744
1711/* Guillemot devices */ 1745/* Guillemot devices */
1712{ 1746{