aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-30 12:11:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-30 12:11:38 -0400
commit94712927d06c19b785bae92db07ef84b89f156c8 (patch)
treefae768f48e91d84584a5b9bb5580ca2c5884a167
parenta7ca10f263d7e673c74d8e0946d6b9993405cc9c (diff)
parent3b70bdba2fcb374a2235a56ab73334348d819579 (diff)
Merge tag 'sound-3.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai: "Although the diffstat looks scary, it's just because of the removal of the dead code (s6000), thus it must not affect anything serious. Other than that, all small fixes. The only core fix is zero-clear for a PCM compat ioctl. The rest are driver-specific, bebob, sgtl500, adau1761, intel-sst, ad1889 and a few HD-audio quirks as usual" * tag 'sound-3.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: ALSA: hda - Add workaround for CMI8888 snoop behavior ALSA: pcm: Zero-clear reserved fields of PCM status ioctl in compat mode ALSA: bebob: Uninitialized id returned by saffirepro_both_clk_src_get ALSA: hda/realtek - New SSID for Headset quirk ALSA: ad1889: Fix probable mask then right shift defects ALSA: bebob: fix wrong decoding of clock information for Terratec PHASE 88 Rack FW ALSA: hda/realtek - Update restore default value for ALC283 ALSA: hda/realtek - Update restore default value for ALC282 ASoC: fsl: use strncpy() to prevent copying of over-long names ASoC: adau1761: Fix input PGA volume ASoC: s6000: remove driver ASoC: Intel: HSW/BDW only support S16 and S24 formats. ASoC: sgtl500: Document the required supplies
-rw-r--r--Documentation/devicetree/bindings/sound/sgtl5000.txt10
-rw-r--r--sound/core/pcm_compat.c2
-rw-r--r--sound/firewire/bebob/bebob_focusrite.c62
-rw-r--r--sound/firewire/bebob/bebob_stream.c18
-rw-r--r--sound/firewire/bebob/bebob_terratec.c7
-rw-r--r--sound/pci/ad1889.c8
-rw-r--r--sound/pci/hda/hda_intel.c4
-rw-r--r--sound/pci/hda/patch_realtek.c6
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/codecs/adau1761.c4
-rw-r--r--sound/soc/fsl/fsl_asrc.c2
-rw-r--r--sound/soc/fsl/fsl_esai.c2
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c4
-rw-r--r--sound/soc/s6000/Kconfig26
-rw-r--r--sound/soc/s6000/Makefile11
-rw-r--r--sound/soc/s6000/s6000-i2s.c617
-rw-r--r--sound/soc/s6000/s6000-i2s.h23
-rw-r--r--sound/soc/s6000/s6000-pcm.c521
-rw-r--r--sound/soc/s6000/s6000-pcm.h33
-rw-r--r--sound/soc/s6000/s6105-ipcam.c221
21 files changed, 99 insertions, 1484 deletions
diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt
index 955df60a118c..d556dcb8816b 100644
--- a/Documentation/devicetree/bindings/sound/sgtl5000.txt
+++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt
@@ -7,10 +7,20 @@ Required properties:
7 7
8- clocks : the clock provider of SYS_MCLK 8- clocks : the clock provider of SYS_MCLK
9 9
10- VDDA-supply : the regulator provider of VDDA
11
12- VDDIO-supply: the regulator provider of VDDIO
13
14Optional properties:
15
16- VDDD-supply : the regulator provider of VDDD
17
10Example: 18Example:
11 19
12codec: sgtl5000@0a { 20codec: sgtl5000@0a {
13 compatible = "fsl,sgtl5000"; 21 compatible = "fsl,sgtl5000";
14 reg = <0x0a>; 22 reg = <0x0a>;
15 clocks = <&clks 150>; 23 clocks = <&clks 150>;
24 VDDA-supply = <&reg_3p3v>;
25 VDDIO-supply = <&reg_3p3v>;
16}; 26};
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 102e8fd1d450..2d957ba63557 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -210,6 +210,8 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
210 if (err < 0) 210 if (err < 0)
211 return err; 211 return err;
212 212
213 if (clear_user(src, sizeof(*src)))
214 return -EFAULT;
213 if (put_user(status.state, &src->state) || 215 if (put_user(status.state, &src->state) ||
214 compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || 216 compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
215 compat_put_timespec(&status.tstamp, &src->tstamp) || 217 compat_put_timespec(&status.tstamp, &src->tstamp) ||
diff --git a/sound/firewire/bebob/bebob_focusrite.c b/sound/firewire/bebob/bebob_focusrite.c
index 45a0eed6d5b1..3b052ed0fbf5 100644
--- a/sound/firewire/bebob/bebob_focusrite.c
+++ b/sound/firewire/bebob/bebob_focusrite.c
@@ -27,12 +27,14 @@
27#define SAFFIRE_CLOCK_SOURCE_INTERNAL 0 27#define SAFFIRE_CLOCK_SOURCE_INTERNAL 0
28#define SAFFIRE_CLOCK_SOURCE_SPDIF 1 28#define SAFFIRE_CLOCK_SOURCE_SPDIF 1
29 29
30/* '1' is absent, why... */ 30/* clock sources as returned from register of Saffire Pro 10 and 26 */
31#define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 31#define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0
32#define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */
32#define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 33#define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2
33#define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 34#define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 /* not used on s.pro. 10 */
34#define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 35#define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 /* not used on s.pro. 10 */
35#define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5 36#define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5
37#define SAFFIREPRO_CLOCK_SOURCE_COUNT 6
36 38
37/* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */ 39/* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */
38#define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4 40#define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4
@@ -101,13 +103,34 @@ saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value)
101 &data, sizeof(__be32), 0); 103 &data, sizeof(__be32), 0);
102} 104}
103 105
106static char *const saffirepro_10_clk_src_labels[] = {
107 SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock"
108};
104static char *const saffirepro_26_clk_src_labels[] = { 109static char *const saffirepro_26_clk_src_labels[] = {
105 SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock" 110 SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock"
106}; 111};
107 112/* Value maps between registers and labels for SaffirePro 10/26. */
108static char *const saffirepro_10_clk_src_labels[] = { 113static const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = {
109 SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock" 114 /* SaffirePro 10 */
115 [0] = {
116 [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0,
117 [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */
118 [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1,
119 [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = -1, /* not supported */
120 [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = -1, /* not supported */
121 [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 2,
122 },
123 /* SaffirePro 26 */
124 [1] = {
125 [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0,
126 [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */
127 [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1,
128 [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = 2,
129 [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = 3,
130 [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 4,
131 }
110}; 132};
133
111static int 134static int
112saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate) 135saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate)
113{ 136{
@@ -138,24 +161,35 @@ saffirepro_both_clk_freq_set(struct snd_bebob *bebob, unsigned int rate)
138 161
139 return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id); 162 return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id);
140} 163}
164
165/*
166 * query hardware for current clock source, return our internally
167 * used clock index in *id, depending on hardware.
168 */
141static int 169static int
142saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) 170saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
143{ 171{
144 int err; 172 int err;
145 u32 value; 173 u32 value; /* clock source read from hw register */
174 const signed char *map;
146 175
147 err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value); 176 err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value);
148 if (err < 0) 177 if (err < 0)
149 goto end; 178 goto end;
150 179
151 if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) { 180 /* depending on hardware, use a different mapping */
152 if (value == SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK) 181 if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels)
153 *id = 2; 182 map = saffirepro_clk_maps[0];
154 else if (value == SAFFIREPRO_CLOCK_SOURCE_SPDIF) 183 else
155 *id = 1; 184 map = saffirepro_clk_maps[1];
156 } else if (value > 1) { 185
157 *id = value - 1; 186 /* In a case that this driver cannot handle the value of register. */
187 if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) {
188 err = -EIO;
189 goto end;
158 } 190 }
191
192 *id = (unsigned int)map[value];
159end: 193end:
160 return err; 194 return err;
161} 195}
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c
index ef4d0c9f6578..1aab0a32870c 100644
--- a/sound/firewire/bebob/bebob_stream.c
+++ b/sound/firewire/bebob/bebob_stream.c
@@ -129,12 +129,24 @@ snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal)
129 /* 1.The device has its own operation to switch source of clock */ 129 /* 1.The device has its own operation to switch source of clock */
130 if (clk_spec) { 130 if (clk_spec) {
131 err = clk_spec->get(bebob, &id); 131 err = clk_spec->get(bebob, &id);
132 if (err < 0) 132 if (err < 0) {
133 dev_err(&bebob->unit->device, 133 dev_err(&bebob->unit->device,
134 "fail to get clock source: %d\n", err); 134 "fail to get clock source: %d\n", err);
135 else if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL, 135 goto end;
136 strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0) 136 }
137
138 if (id >= clk_spec->num) {
139 dev_err(&bebob->unit->device,
140 "clock source %d out of range 0..%d\n",
141 id, clk_spec->num - 1);
142 err = -EIO;
143 goto end;
144 }
145
146 if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL,
147 strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0)
137 *internal = true; 148 *internal = true;
149
138 goto end; 150 goto end;
139 } 151 }
140 152
diff --git a/sound/firewire/bebob/bebob_terratec.c b/sound/firewire/bebob/bebob_terratec.c
index 0e4c0bfc463b..9940611f2e1b 100644
--- a/sound/firewire/bebob/bebob_terratec.c
+++ b/sound/firewire/bebob/bebob_terratec.c
@@ -24,7 +24,12 @@ phase88_rack_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
24 if (err < 0) 24 if (err < 0)
25 goto end; 25 goto end;
26 26
27 *id = (enable_ext & 0x01) | ((enable_word & 0x01) << 1); 27 if (enable_ext == 0)
28 *id = 0;
29 else if (enable_word == 0)
30 *id = 1;
31 else
32 *id = 2;
28end: 33end:
29 return err; 34 return err;
30} 35}
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 7bfdf9c51416..1610c38337af 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -681,7 +681,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe
681 681
682 /* WARQ is at offset 12 */ 682 /* WARQ is at offset 12 */
683 tmp = (reg & AD_DS_WSMC_WARQ) ? 683 tmp = (reg & AD_DS_WSMC_WARQ) ?
684 (((reg & AD_DS_WSMC_WARQ >> 12) & 0x01) ? 12 : 18) : 4; 684 ((((reg & AD_DS_WSMC_WARQ) >> 12) & 0x01) ? 12 : 18) : 4;
685 tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; 685 tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;
686 686
687 snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp, 687 snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp,
@@ -693,7 +693,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe
693 693
694 /* SYRQ is at offset 4 */ 694 /* SYRQ is at offset 4 */
695 tmp = (reg & AD_DS_WSMC_SYRQ) ? 695 tmp = (reg & AD_DS_WSMC_SYRQ) ?
696 (((reg & AD_DS_WSMC_SYRQ >> 4) & 0x01) ? 12 : 18) : 4; 696 ((((reg & AD_DS_WSMC_SYRQ) >> 4) & 0x01) ? 12 : 18) : 4;
697 tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; 697 tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;
698 698
699 snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp, 699 snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp,
@@ -709,7 +709,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe
709 709
710 /* ACRQ is at offset 4 */ 710 /* ACRQ is at offset 4 */
711 tmp = (reg & AD_DS_RAMC_ACRQ) ? 711 tmp = (reg & AD_DS_RAMC_ACRQ) ?
712 (((reg & AD_DS_RAMC_ACRQ >> 4) & 0x01) ? 12 : 18) : 4; 712 ((((reg & AD_DS_RAMC_ACRQ) >> 4) & 0x01) ? 12 : 18) : 4;
713 tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; 713 tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;
714 714
715 snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp, 715 snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp,
@@ -720,7 +720,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe
720 720
721 /* RERQ is at offset 12 */ 721 /* RERQ is at offset 12 */
722 tmp = (reg & AD_DS_RAMC_RERQ) ? 722 tmp = (reg & AD_DS_RAMC_RERQ) ?
723 (((reg & AD_DS_RAMC_RERQ >> 12) & 0x01) ? 12 : 18) : 4; 723 ((((reg & AD_DS_RAMC_RERQ) >> 12) & 0x01) ? 12 : 18) : 4;
724 tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; 724 tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;
725 725
726 snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp, 726 snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp,
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index cfcca4c30d4d..9ab1e631cb32 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -374,6 +374,8 @@ static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool
374#ifdef CONFIG_SND_DMA_SGBUF 374#ifdef CONFIG_SND_DMA_SGBUF
375 if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { 375 if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
376 struct snd_sg_buf *sgbuf = dmab->private_data; 376 struct snd_sg_buf *sgbuf = dmab->private_data;
377 if (chip->driver_type == AZX_DRIVER_CMEDIA)
378 return; /* deal with only CORB/RIRB buffers */
377 if (on) 379 if (on)
378 set_pages_array_wc(sgbuf->page_table, sgbuf->pages); 380 set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
379 else 381 else
@@ -1769,7 +1771,7 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
1769#ifdef CONFIG_X86 1771#ifdef CONFIG_X86
1770 struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 1772 struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
1771 struct azx *chip = apcm->chip; 1773 struct azx *chip = apcm->chip;
1772 if (!azx_snoop(chip)) 1774 if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA)
1773 area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); 1775 area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
1774#endif 1776#endif
1775} 1777}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 34b7bdb510c7..c9cf248ce8ec 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2675,7 +2675,7 @@ static void alc269_shutup(struct hda_codec *codec)
2675 2675
2676static struct coef_fw alc282_coefs[] = { 2676static struct coef_fw alc282_coefs[] = {
2677 WRITE_COEF(0x03, 0x0002), /* Power Down Control */ 2677 WRITE_COEF(0x03, 0x0002), /* Power Down Control */
2678 WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */ 2678 UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
2679 WRITE_COEF(0x07, 0x0200), /* DMIC control */ 2679 WRITE_COEF(0x07, 0x0200), /* DMIC control */
2680 UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ 2680 UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
2681 UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ 2681 UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
@@ -2786,7 +2786,7 @@ static void alc282_shutup(struct hda_codec *codec)
2786 2786
2787static struct coef_fw alc283_coefs[] = { 2787static struct coef_fw alc283_coefs[] = {
2788 WRITE_COEF(0x03, 0x0002), /* Power Down Control */ 2788 WRITE_COEF(0x03, 0x0002), /* Power Down Control */
2789 WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */ 2789 UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
2790 WRITE_COEF(0x07, 0x0200), /* DMIC control */ 2790 WRITE_COEF(0x07, 0x0200), /* DMIC control */
2791 UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ 2791 UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
2792 UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ 2792 UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
@@ -2817,6 +2817,7 @@ static struct coef_fw alc283_coefs[] = {
2817 UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */ 2817 UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */
2818 UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */ 2818 UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */
2819 WRITE_COEF(0x37, 0xfc06), /* Class D amp control */ 2819 WRITE_COEF(0x37, 0xfc06), /* Class D amp control */
2820 UPDATE_COEF(0x1b, 0x8000, 0), /* HP JD control */
2820 {} 2821 {}
2821}; 2822};
2822 2823
@@ -5922,6 +5923,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
5922 SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), 5923 SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
5923 SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), 5924 SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
5924 SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), 5925 SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
5926 SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
5925 SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), 5927 SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
5926 SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A), 5928 SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A),
5927 SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), 5929 SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 0e9623368ab0..7d5d6444a837 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -49,7 +49,6 @@ source "sound/soc/mxs/Kconfig"
49source "sound/soc/pxa/Kconfig" 49source "sound/soc/pxa/Kconfig"
50source "sound/soc/rockchip/Kconfig" 50source "sound/soc/rockchip/Kconfig"
51source "sound/soc/samsung/Kconfig" 51source "sound/soc/samsung/Kconfig"
52source "sound/soc/s6000/Kconfig"
53source "sound/soc/sh/Kconfig" 52source "sound/soc/sh/Kconfig"
54source "sound/soc/sirf/Kconfig" 53source "sound/soc/sirf/Kconfig"
55source "sound/soc/spear/Kconfig" 54source "sound/soc/spear/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 534714a1ca44..d88edfced8c4 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -26,7 +26,6 @@ obj-$(CONFIG_SND_SOC) += kirkwood/
26obj-$(CONFIG_SND_SOC) += pxa/ 26obj-$(CONFIG_SND_SOC) += pxa/
27obj-$(CONFIG_SND_SOC) += rockchip/ 27obj-$(CONFIG_SND_SOC) += rockchip/
28obj-$(CONFIG_SND_SOC) += samsung/ 28obj-$(CONFIG_SND_SOC) += samsung/
29obj-$(CONFIG_SND_SOC) += s6000/
30obj-$(CONFIG_SND_SOC) += sh/ 29obj-$(CONFIG_SND_SOC) += sh/
31obj-$(CONFIG_SND_SOC) += sirf/ 30obj-$(CONFIG_SND_SOC) += sirf/
32obj-$(CONFIG_SND_SOC) += spear/ 31obj-$(CONFIG_SND_SOC) += spear/
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index 5518ebd6947c..91f60282fd2f 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -405,6 +405,7 @@ static const struct snd_soc_dapm_widget adau1761_dapm_widgets[] = {
405 2, 0, NULL, 0), 405 2, 0, NULL, 0),
406 406
407 SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0), 407 SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0),
408 SND_SOC_DAPM_SUPPLY("ALC Clock", ADAU1761_CLK_ENABLE0, 5, 0, NULL, 0),
408 409
409 SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1, 410 SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1,
410 0, 0, NULL, 0), 411 0, 0, NULL, 0),
@@ -436,6 +437,9 @@ static const struct snd_soc_dapm_route adau1761_dapm_routes[] = {
436 { "Right Playback Mixer", NULL, "Slew Clock" }, 437 { "Right Playback Mixer", NULL, "Slew Clock" },
437 { "Left Playback Mixer", NULL, "Slew Clock" }, 438 { "Left Playback Mixer", NULL, "Slew Clock" },
438 439
440 { "Left Input Mixer", NULL, "ALC Clock" },
441 { "Right Input Mixer", NULL, "ALC Clock" },
442
439 { "Digital Clock 0", NULL, "SYSCLK" }, 443 { "Digital Clock 0", NULL, "SYSCLK" },
440 { "Digital Clock 1", NULL, "SYSCLK" }, 444 { "Digital Clock 1", NULL, "SYSCLK" },
441}; 445};
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 3b145313f93e..ed866e9a2928 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -792,7 +792,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
792 return -ENOMEM; 792 return -ENOMEM;
793 793
794 asrc_priv->pdev = pdev; 794 asrc_priv->pdev = pdev;
795 strcpy(asrc_priv->name, np->name); 795 strncpy(asrc_priv->name, np->name, sizeof(asrc_priv->name) - 1);
796 796
797 /* Get the addresses and IRQ */ 797 /* Get the addresses and IRQ */
798 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 798 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 8bcdfda09d7a..a645e296199e 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -734,7 +734,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
734 return -ENOMEM; 734 return -ENOMEM;
735 735
736 esai_priv->pdev = pdev; 736 esai_priv->pdev = pdev;
737 strcpy(esai_priv->name, np->name); 737 strncpy(esai_priv->name, np->name, sizeof(esai_priv->name) - 1);
738 738
739 /* Get the addresses and IRQ */ 739 /* Get the addresses and IRQ */
740 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 740 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 33fc5c3abf55..4df867cbb92a 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -691,9 +691,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
691} 691}
692 692
693#define HSW_FORMATS \ 693#define HSW_FORMATS \
694 (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ 694 (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
695 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\
696 SNDRV_PCM_FMTBIT_S8)
697 695
698static struct snd_soc_dai_driver hsw_dais[] = { 696static struct snd_soc_dai_driver hsw_dais[] = {
699 { 697 {
diff --git a/sound/soc/s6000/Kconfig b/sound/soc/s6000/Kconfig
deleted file mode 100644
index f244a2566f20..000000000000
--- a/sound/soc/s6000/Kconfig
+++ /dev/null
@@ -1,26 +0,0 @@
1config SND_S6000_SOC
2 tristate "SoC Audio for the Stretch s6000 family"
3 depends on XTENSA_VARIANT_S6000 || COMPILE_TEST
4 depends on HAS_IOMEM
5 select SND_S6000_SOC_PCM if XTENSA_VARIANT_S6000
6 help
7 Say Y or M if you want to add support for codecs attached to
8 s6000 family chips. You will also need to select the platform
9 to support below.
10
11config SND_S6000_SOC_PCM
12 tristate
13
14config SND_S6000_SOC_I2S
15 tristate
16
17config SND_S6000_SOC_S6IPCAM
18 bool "SoC Audio support for Stretch 6105 IP Camera"
19 depends on SND_S6000_SOC=y
20 depends on I2C=y
21 depends on XTENSA_PLATFORM_S6105 || COMPILE_TEST
22 select SND_S6000_SOC_I2S
23 select SND_SOC_TLV320AIC3X
24 help
25 Say Y if you want to add support for SoC audio on the
26 Stretch s6105 IP Camera Reference Design.
diff --git a/sound/soc/s6000/Makefile b/sound/soc/s6000/Makefile
deleted file mode 100644
index 0f0ae2a012aa..000000000000
--- a/sound/soc/s6000/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
1# s6000 Platform Support
2snd-soc-s6000-objs := s6000-pcm.o
3snd-soc-s6000-i2s-objs := s6000-i2s.o
4
5obj-$(CONFIG_SND_S6000_SOC_PCM) += snd-soc-s6000.o
6obj-$(CONFIG_SND_S6000_SOC_I2S) += snd-soc-s6000-i2s.o
7
8# s6105 Machine Support
9snd-soc-s6ipcam-objs := s6105-ipcam.o
10
11obj-$(CONFIG_SND_S6000_SOC_S6IPCAM) += snd-soc-s6ipcam.o
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
deleted file mode 100644
index 1c8d01166e5b..000000000000
--- a/sound/soc/s6000/s6000-i2s.c
+++ /dev/null
@@ -1,617 +0,0 @@
1/*
2 * ALSA SoC I2S Audio Layer for the Stretch S6000 family
3 *
4 * Author: Daniel Gloeckner, <dg@emlix.com>
5 * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/device.h>
15#include <linux/delay.h>
16#include <linux/clk.h>
17#include <linux/interrupt.h>
18#include <linux/io.h>
19#include <linux/slab.h>
20
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/initval.h>
25#include <sound/soc.h>
26
27#include "s6000-i2s.h"
28#include "s6000-pcm.h"
29
30struct s6000_i2s_dev {
31 dma_addr_t sifbase;
32 u8 __iomem *scbbase;
33 unsigned int wide;
34 unsigned int channel_in;
35 unsigned int channel_out;
36 unsigned int lines_in;
37 unsigned int lines_out;
38 struct s6000_pcm_dma_params dma_params;
39};
40
41#define S6_I2S_INTERRUPT_STATUS 0x00
42#define S6_I2S_INT_OVERRUN 1
43#define S6_I2S_INT_UNDERRUN 2
44#define S6_I2S_INT_ALIGNMENT 4
45#define S6_I2S_INTERRUPT_ENABLE 0x04
46#define S6_I2S_INTERRUPT_RAW 0x08
47#define S6_I2S_INTERRUPT_CLEAR 0x0C
48#define S6_I2S_INTERRUPT_SET 0x10
49#define S6_I2S_MODE 0x20
50#define S6_I2S_DUAL 0
51#define S6_I2S_WIDE 1
52#define S6_I2S_TX_DEFAULT 0x24
53#define S6_I2S_DATA_CFG(c) (0x40 + 0x10 * (c))
54#define S6_I2S_IN 0
55#define S6_I2S_OUT 1
56#define S6_I2S_UNUSED 2
57#define S6_I2S_INTERFACE_CFG(c) (0x44 + 0x10 * (c))
58#define S6_I2S_DIV_MASK 0x001fff
59#define S6_I2S_16BIT 0x000000
60#define S6_I2S_20BIT 0x002000
61#define S6_I2S_24BIT 0x004000
62#define S6_I2S_32BIT 0x006000
63#define S6_I2S_BITS_MASK 0x006000
64#define S6_I2S_MEM_16BIT 0x000000
65#define S6_I2S_MEM_32BIT 0x008000
66#define S6_I2S_MEM_MASK 0x008000
67#define S6_I2S_CHANNELS_SHIFT 16
68#define S6_I2S_CHANNELS_MASK 0x030000
69#define S6_I2S_SCK_IN 0x000000
70#define S6_I2S_SCK_OUT 0x040000
71#define S6_I2S_SCK_DIR 0x040000
72#define S6_I2S_WS_IN 0x000000
73#define S6_I2S_WS_OUT 0x080000
74#define S6_I2S_WS_DIR 0x080000
75#define S6_I2S_LEFT_FIRST 0x000000
76#define S6_I2S_RIGHT_FIRST 0x100000
77#define S6_I2S_FIRST 0x100000
78#define S6_I2S_CUR_SCK 0x200000
79#define S6_I2S_CUR_WS 0x400000
80#define S6_I2S_ENABLE(c) (0x48 + 0x10 * (c))
81#define S6_I2S_DISABLE_IF 0x02
82#define S6_I2S_ENABLE_IF 0x03
83#define S6_I2S_IS_BUSY 0x04
84#define S6_I2S_DMA_ACTIVE 0x08
85#define S6_I2S_IS_ENABLED 0x10
86
87#define S6_I2S_NUM_LINES 4
88
89#define S6_I2S_SIF_PORT0 0x0000000
90#define S6_I2S_SIF_PORT1 0x0000080 /* docs say 0x0000010 */
91
92static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val)
93{
94 writel(val, dev->scbbase + reg);
95}
96
97static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg)
98{
99 return readl(dev->scbbase + reg);
100}
101
102static inline void s6_i2s_mod_reg(struct s6000_i2s_dev *dev, int reg,
103 u32 mask, u32 val)
104{
105 val ^= s6_i2s_read_reg(dev, reg) & ~mask;
106 s6_i2s_write_reg(dev, reg, val);
107}
108
109static void s6000_i2s_start_channel(struct s6000_i2s_dev *dev, int channel)
110{
111 int i, j, cur, prev;
112
113 /*
114 * Wait for WCLK to toggle 5 times before enabling the channel
115 * s6000 Family Datasheet 3.6.4:
116 * "At least two cycles of WS must occur between commands
117 * to disable or enable the interface"
118 */
119 j = 0;
120 prev = ~S6_I2S_CUR_WS;
121 for (i = 1000000; --i && j < 6; ) {
122 cur = s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(channel))
123 & S6_I2S_CUR_WS;
124 if (prev != cur) {
125 prev = cur;
126 j++;
127 }
128 }
129 if (j < 6)
130 printk(KERN_WARNING "s6000-i2s: timeout waiting for WCLK\n");
131
132 s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_ENABLE_IF);
133}
134
135static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel)
136{
137 s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_DISABLE_IF);
138}
139
140static void s6000_i2s_start(struct snd_pcm_substream *substream)
141{
142 struct snd_soc_pcm_runtime *rtd = substream->private_data;
143 struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
144 int channel;
145
146 channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
147 dev->channel_out : dev->channel_in;
148
149 s6000_i2s_start_channel(dev, channel);
150}
151
152static void s6000_i2s_stop(struct snd_pcm_substream *substream)
153{
154 struct snd_soc_pcm_runtime *rtd = substream->private_data;
155 struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
156 int channel;
157
158 channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
159 dev->channel_out : dev->channel_in;
160
161 s6000_i2s_stop_channel(dev, channel);
162}
163
164static int s6000_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
165 int after)
166{
167 switch (cmd) {
168 case SNDRV_PCM_TRIGGER_START:
169 case SNDRV_PCM_TRIGGER_RESUME:
170 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
171 if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ^ !after)
172 s6000_i2s_start(substream);
173 break;
174 case SNDRV_PCM_TRIGGER_STOP:
175 case SNDRV_PCM_TRIGGER_SUSPEND:
176 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
177 if (!after)
178 s6000_i2s_stop(substream);
179 }
180 return 0;
181}
182
183static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev)
184{
185 unsigned int pending;
186 pending = s6_i2s_read_reg(dev, S6_I2S_INTERRUPT_RAW);
187 pending &= S6_I2S_INT_ALIGNMENT |
188 S6_I2S_INT_UNDERRUN |
189 S6_I2S_INT_OVERRUN;
190 s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, pending);
191
192 return pending;
193}
194
195static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai)
196{
197 struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
198 unsigned int errors;
199 unsigned int ret;
200
201 errors = s6000_i2s_int_sources(dev);
202 if (likely(!errors))
203 return 0;
204
205 ret = 0;
206 if (errors & S6_I2S_INT_ALIGNMENT)
207 printk(KERN_ERR "s6000-i2s: WCLK misaligned\n");
208 if (errors & S6_I2S_INT_UNDERRUN)
209 ret |= 1 << SNDRV_PCM_STREAM_PLAYBACK;
210 if (errors & S6_I2S_INT_OVERRUN)
211 ret |= 1 << SNDRV_PCM_STREAM_CAPTURE;
212 return ret;
213}
214
215static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev)
216{
217 int channel;
218 int n = 50;
219 for (channel = 0; channel < 2; channel++) {
220 while (--n >= 0) {
221 int v = s6_i2s_read_reg(dev, S6_I2S_ENABLE(channel));
222 if ((v & S6_I2S_IS_ENABLED)
223 || !(v & (S6_I2S_DMA_ACTIVE | S6_I2S_IS_BUSY)))
224 break;
225 udelay(20);
226 }
227 }
228 if (n < 0)
229 printk(KERN_WARNING "s6000-i2s: timeout disabling interfaces");
230}
231
232static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
233 unsigned int fmt)
234{
235 struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
236 u32 w;
237
238 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
239 case SND_SOC_DAIFMT_CBM_CFM:
240 w = S6_I2S_SCK_IN | S6_I2S_WS_IN;
241 break;
242 case SND_SOC_DAIFMT_CBS_CFM:
243 w = S6_I2S_SCK_OUT | S6_I2S_WS_IN;
244 break;
245 case SND_SOC_DAIFMT_CBM_CFS:
246 w = S6_I2S_SCK_IN | S6_I2S_WS_OUT;
247 break;
248 case SND_SOC_DAIFMT_CBS_CFS:
249 w = S6_I2S_SCK_OUT | S6_I2S_WS_OUT;
250 break;
251 default:
252 return -EINVAL;
253 }
254
255 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
256 case SND_SOC_DAIFMT_NB_NF:
257 w |= S6_I2S_LEFT_FIRST;
258 break;
259 case SND_SOC_DAIFMT_NB_IF:
260 w |= S6_I2S_RIGHT_FIRST;
261 break;
262 default:
263 return -EINVAL;
264 }
265
266 s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(0),
267 S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
268 s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(1),
269 S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
270
271 return 0;
272}
273
274static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
275{
276 struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
277
278 if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2)
279 return -EINVAL;
280
281 s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(div_id),
282 S6_I2S_DIV_MASK, div / 2 - 1);
283 return 0;
284}
285
286static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
287 struct snd_pcm_hw_params *params,
288 struct snd_soc_dai *dai)
289{
290 struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
291 int interf;
292 u32 w = 0;
293
294 if (dev->wide)
295 interf = 0;
296 else {
297 w |= (((params_channels(params) - 2) / 2)
298 << S6_I2S_CHANNELS_SHIFT) & S6_I2S_CHANNELS_MASK;
299 interf = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
300 ? dev->channel_out : dev->channel_in;
301 }
302
303 switch (params_format(params)) {
304 case SNDRV_PCM_FORMAT_S16_LE:
305 w |= S6_I2S_16BIT | S6_I2S_MEM_16BIT;
306 break;
307 case SNDRV_PCM_FORMAT_S32_LE:
308 w |= S6_I2S_32BIT | S6_I2S_MEM_32BIT;
309 break;
310 default:
311 printk(KERN_WARNING "s6000-i2s: unsupported PCM format %x\n",
312 params_format(params));
313 return -EINVAL;
314 }
315
316 if (s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(interf))
317 & S6_I2S_IS_ENABLED) {
318 printk(KERN_ERR "s6000-i2s: interface already enabled\n");
319 return -EBUSY;
320 }
321
322 s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(interf),
323 S6_I2S_CHANNELS_MASK|S6_I2S_MEM_MASK|S6_I2S_BITS_MASK,
324 w);
325
326 return 0;
327}
328
329static int s6000_i2s_dai_probe(struct snd_soc_dai *dai)
330{
331 struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
332 struct s6000_snd_platform_data *pdata = dai->dev->platform_data;
333
334 if (!pdata)
335 return -EINVAL;
336
337 dai->capture_dma_data = &dev->dma_params;
338 dai->playback_dma_data = &dev->dma_params;
339
340 dev->wide = pdata->wide;
341 dev->channel_in = pdata->channel_in;
342 dev->channel_out = pdata->channel_out;
343 dev->lines_in = pdata->lines_in;
344 dev->lines_out = pdata->lines_out;
345
346 s6_i2s_write_reg(dev, S6_I2S_MODE,
347 dev->wide ? S6_I2S_WIDE : S6_I2S_DUAL);
348
349 if (dev->wide) {
350 int i;
351
352 if (dev->lines_in + dev->lines_out > S6_I2S_NUM_LINES)
353 return -EINVAL;
354
355 dev->channel_in = 0;
356 dev->channel_out = 1;
357 dai->driver->capture.channels_min = 2 * dev->lines_in;
358 dai->driver->capture.channels_max = dai->driver->capture.channels_min;
359 dai->driver->playback.channels_min = 2 * dev->lines_out;
360 dai->driver->playback.channels_max = dai->driver->playback.channels_min;
361
362 for (i = 0; i < dev->lines_out; i++)
363 s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT);
364
365 for (; i < S6_I2S_NUM_LINES - dev->lines_in; i++)
366 s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i),
367 S6_I2S_UNUSED);
368
369 for (; i < S6_I2S_NUM_LINES; i++)
370 s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_IN);
371 } else {
372 unsigned int cfg[2] = {S6_I2S_UNUSED, S6_I2S_UNUSED};
373
374 if (dev->lines_in > 1 || dev->lines_out > 1)
375 return -EINVAL;
376
377 dai->driver->capture.channels_min = 2 * dev->lines_in;
378 dai->driver->capture.channels_max = 8 * dev->lines_in;
379 dai->driver->playback.channels_min = 2 * dev->lines_out;
380 dai->driver->playback.channels_max = 8 * dev->lines_out;
381
382 if (dev->lines_in)
383 cfg[dev->channel_in] = S6_I2S_IN;
384 if (dev->lines_out)
385 cfg[dev->channel_out] = S6_I2S_OUT;
386
387 s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(0), cfg[0]);
388 s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(1), cfg[1]);
389 }
390
391 if (dev->lines_out) {
392 if (dev->lines_in) {
393 if (!dev->dma_params.dma_out)
394 return -ENODEV;
395 } else {
396 dev->dma_params.dma_out = dev->dma_params.dma_in;
397 dev->dma_params.dma_in = 0;
398 }
399 }
400 dev->dma_params.sif_in = dev->sifbase + (dev->channel_in ?
401 S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
402 dev->dma_params.sif_out = dev->sifbase + (dev->channel_out ?
403 S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
404 dev->dma_params.same_rate = pdata->same_rate | pdata->wide;
405 return 0;
406}
407
408#define S6000_I2S_RATES SNDRV_PCM_RATE_CONTINUOUS
409#define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
410
411static const struct snd_soc_dai_ops s6000_i2s_dai_ops = {
412 .set_fmt = s6000_i2s_set_dai_fmt,
413 .set_clkdiv = s6000_i2s_set_clkdiv,
414 .hw_params = s6000_i2s_hw_params,
415};
416
417static struct snd_soc_dai_driver s6000_i2s_dai = {
418 .probe = s6000_i2s_dai_probe,
419 .playback = {
420 .channels_min = 2,
421 .channels_max = 8,
422 .formats = S6000_I2S_FORMATS,
423 .rates = S6000_I2S_RATES,
424 .rate_min = 0,
425 .rate_max = 1562500,
426 },
427 .capture = {
428 .channels_min = 2,
429 .channels_max = 8,
430 .formats = S6000_I2S_FORMATS,
431 .rates = S6000_I2S_RATES,
432 .rate_min = 0,
433 .rate_max = 1562500,
434 },
435 .ops = &s6000_i2s_dai_ops,
436};
437
438static const struct snd_soc_component_driver s6000_i2s_component = {
439 .name = "s6000-i2s",
440};
441
442static int s6000_i2s_probe(struct platform_device *pdev)
443{
444 struct s6000_i2s_dev *dev;
445 struct resource *scbmem, *sifmem, *region, *dma1, *dma2;
446 u8 __iomem *mmio;
447 int ret;
448
449 scbmem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
450 if (!scbmem) {
451 dev_err(&pdev->dev, "no mem resource?\n");
452 ret = -ENODEV;
453 goto err_release_none;
454 }
455
456 region = request_mem_region(scbmem->start, resource_size(scbmem),
457 pdev->name);
458 if (!region) {
459 dev_err(&pdev->dev, "I2S SCB region already claimed\n");
460 ret = -EBUSY;
461 goto err_release_none;
462 }
463
464 mmio = ioremap(scbmem->start, resource_size(scbmem));
465 if (!mmio) {
466 dev_err(&pdev->dev, "can't ioremap SCB region\n");
467 ret = -ENOMEM;
468 goto err_release_scb;
469 }
470
471 sifmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
472 if (!sifmem) {
473 dev_err(&pdev->dev, "no second mem resource?\n");
474 ret = -ENODEV;
475 goto err_release_map;
476 }
477
478 region = request_mem_region(sifmem->start, resource_size(sifmem),
479 pdev->name);
480 if (!region) {
481 dev_err(&pdev->dev, "I2S SIF region already claimed\n");
482 ret = -EBUSY;
483 goto err_release_map;
484 }
485
486 dma1 = platform_get_resource(pdev, IORESOURCE_DMA, 0);
487 if (!dma1) {
488 dev_err(&pdev->dev, "no dma resource?\n");
489 ret = -ENODEV;
490 goto err_release_sif;
491 }
492
493 region = request_mem_region(dma1->start, resource_size(dma1),
494 pdev->name);
495 if (!region) {
496 dev_err(&pdev->dev, "I2S DMA region already claimed\n");
497 ret = -EBUSY;
498 goto err_release_sif;
499 }
500
501 dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1);
502 if (dma2) {
503 region = request_mem_region(dma2->start, resource_size(dma2),
504 pdev->name);
505 if (!region) {
506 dev_err(&pdev->dev,
507 "I2S DMA region already claimed\n");
508 ret = -EBUSY;
509 goto err_release_dma1;
510 }
511 }
512
513 dev = kzalloc(sizeof(struct s6000_i2s_dev), GFP_KERNEL);
514 if (!dev) {
515 ret = -ENOMEM;
516 goto err_release_dma2;
517 }
518 dev_set_drvdata(&pdev->dev, dev);
519
520 dev->sifbase = sifmem->start;
521 dev->scbbase = mmio;
522
523 s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
524 s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR,
525 S6_I2S_INT_ALIGNMENT |
526 S6_I2S_INT_UNDERRUN |
527 S6_I2S_INT_OVERRUN);
528
529 s6000_i2s_stop_channel(dev, 0);
530 s6000_i2s_stop_channel(dev, 1);
531 s6000_i2s_wait_disabled(dev);
532
533 dev->dma_params.check_xrun = s6000_i2s_check_xrun;
534 dev->dma_params.trigger = s6000_i2s_trigger;
535 dev->dma_params.dma_in = dma1->start;
536 dev->dma_params.dma_out = dma2 ? dma2->start : 0;
537 dev->dma_params.irq = platform_get_irq(pdev, 0);
538 if (dev->dma_params.irq < 0) {
539 dev_err(&pdev->dev, "no irq resource?\n");
540 ret = -ENODEV;
541 goto err_release_dev;
542 }
543
544 s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE,
545 S6_I2S_INT_ALIGNMENT |
546 S6_I2S_INT_UNDERRUN |
547 S6_I2S_INT_OVERRUN);
548
549 ret = snd_soc_register_component(&pdev->dev, &s6000_i2s_component,
550 &s6000_i2s_dai, 1);
551 if (ret)
552 goto err_release_dev;
553
554 return 0;
555
556err_release_dev:
557 kfree(dev);
558err_release_dma2:
559 if (dma2)
560 release_mem_region(dma2->start, resource_size(dma2));
561err_release_dma1:
562 release_mem_region(dma1->start, resource_size(dma1));
563err_release_sif:
564 release_mem_region(sifmem->start, resource_size(sifmem));
565err_release_map:
566 iounmap(mmio);
567err_release_scb:
568 release_mem_region(scbmem->start, resource_size(scbmem));
569err_release_none:
570 return ret;
571}
572
573static int s6000_i2s_remove(struct platform_device *pdev)
574{
575 struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
576 struct resource *region;
577 void __iomem *mmio = dev->scbbase;
578
579 snd_soc_unregister_component(&pdev->dev);
580
581 s6000_i2s_stop_channel(dev, 0);
582 s6000_i2s_stop_channel(dev, 1);
583
584 s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
585 kfree(dev);
586
587 region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
588 release_mem_region(region->start, resource_size(region));
589
590 region = platform_get_resource(pdev, IORESOURCE_DMA, 1);
591 if (region)
592 release_mem_region(region->start, resource_size(region));
593
594 region = platform_get_resource(pdev, IORESOURCE_MEM, 0);
595 release_mem_region(region->start, resource_size(region));
596
597 iounmap(mmio);
598 region = platform_get_resource(pdev, IORESOURCE_IO, 0);
599 release_mem_region(region->start, resource_size(region));
600
601 return 0;
602}
603
604static struct platform_driver s6000_i2s_driver = {
605 .probe = s6000_i2s_probe,
606 .remove = s6000_i2s_remove,
607 .driver = {
608 .name = "s6000-i2s",
609 .owner = THIS_MODULE,
610 },
611};
612
613module_platform_driver(s6000_i2s_driver);
614
615MODULE_AUTHOR("Daniel Gloeckner");
616MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface");
617MODULE_LICENSE("GPL");
diff --git a/sound/soc/s6000/s6000-i2s.h b/sound/soc/s6000/s6000-i2s.h
deleted file mode 100644
index 86aa1921c89e..000000000000
--- a/sound/soc/s6000/s6000-i2s.h
+++ /dev/null
@@ -1,23 +0,0 @@
1/*
2 * ALSA SoC I2S Audio Layer for the Stretch s6000 family
3 *
4 * Author: Daniel Gloeckner, <dg@emlix.com>
5 * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef _S6000_I2S_H
13#define _S6000_I2S_H
14
15struct s6000_snd_platform_data {
16 int lines_in;
17 int lines_out;
18 int channel_in;
19 int channel_out;
20 int wide;
21 int same_rate;
22};
23#endif
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
deleted file mode 100644
index fb8461e1b1f6..000000000000
--- a/sound/soc/s6000/s6000-pcm.c
+++ /dev/null
@@ -1,521 +0,0 @@
1/*
2 * ALSA PCM interface for the Stetch s6000 family
3 *
4 * Author: Daniel Gloeckner, <dg@emlix.com>
5 * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16#include <linux/dma-mapping.h>
17#include <linux/interrupt.h>
18
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/pcm_params.h>
22#include <sound/soc.h>
23
24#include <asm/dma.h>
25#include <variant/dmac.h>
26
27#include "s6000-pcm.h"
28
29#define S6_PCM_PREALLOCATE_SIZE (96 * 1024)
30#define S6_PCM_PREALLOCATE_MAX (2048 * 1024)
31
32static struct snd_pcm_hardware s6000_pcm_hardware = {
33 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
34 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
35 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_JOINT_DUPLEX),
36 .buffer_bytes_max = 0x7ffffff0,
37 .period_bytes_min = 16,
38 .period_bytes_max = 0xfffff0,
39 .periods_min = 2,
40 .periods_max = 1024, /* no limit */
41 .fifo_size = 0,
42};
43
44struct s6000_runtime_data {
45 spinlock_t lock;
46 int period; /* current DMA period */
47};
48
49static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)
50{
51 struct snd_pcm_runtime *runtime = substream->runtime;
52 struct s6000_runtime_data *prtd = runtime->private_data;
53 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
54 struct s6000_pcm_dma_params *par;
55 int channel;
56 unsigned int period_size;
57 unsigned int dma_offset;
58 dma_addr_t dma_pos;
59 dma_addr_t src, dst;
60
61 par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
62
63 period_size = snd_pcm_lib_period_bytes(substream);
64 dma_offset = prtd->period * period_size;
65 dma_pos = runtime->dma_addr + dma_offset;
66
67 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
68 src = dma_pos;
69 dst = par->sif_out;
70 channel = par->dma_out;
71 } else {
72 src = par->sif_in;
73 dst = dma_pos;
74 channel = par->dma_in;
75 }
76
77 if (!s6dmac_channel_enabled(DMA_MASK_DMAC(channel),
78 DMA_INDEX_CHNL(channel)))
79 return;
80
81 if (s6dmac_fifo_full(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel))) {
82 printk(KERN_ERR "s6000-pcm: fifo full\n");
83 return;
84 }
85
86 if (WARN_ON(period_size & 15))
87 return;
88 s6dmac_put_fifo(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel),
89 src, dst, period_size);
90
91 prtd->period++;
92 if (unlikely(prtd->period >= runtime->periods))
93 prtd->period = 0;
94}
95
96static irqreturn_t s6000_pcm_irq(int irq, void *data)
97{
98 struct snd_pcm *pcm = data;
99 struct snd_soc_pcm_runtime *runtime = pcm->private_data;
100 struct s6000_runtime_data *prtd;
101 unsigned int has_xrun;
102 int i, ret = IRQ_NONE;
103
104 for (i = 0; i < 2; ++i) {
105 struct snd_pcm_substream *substream = pcm->streams[i].substream;
106 struct s6000_pcm_dma_params *params =
107 snd_soc_dai_get_dma_data(runtime->cpu_dai, substream);
108 u32 channel;
109 unsigned int pending;
110
111 if (substream == SNDRV_PCM_STREAM_PLAYBACK)
112 channel = params->dma_out;
113 else
114 channel = params->dma_in;
115
116 has_xrun = params->check_xrun(runtime->cpu_dai);
117
118 if (!channel)
119 continue;
120
121 if (unlikely(has_xrun & (1 << i)) &&
122 substream->runtime &&
123 snd_pcm_running(substream)) {
124 dev_dbg(pcm->dev, "xrun\n");
125 snd_pcm_stream_lock(substream);
126 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
127 snd_pcm_stream_unlock(substream);
128 ret = IRQ_HANDLED;
129 }
130
131 pending = s6dmac_int_sources(DMA_MASK_DMAC(channel),
132 DMA_INDEX_CHNL(channel));
133
134 if (pending & 1) {
135 ret = IRQ_HANDLED;
136 if (likely(substream->runtime &&
137 snd_pcm_running(substream))) {
138 snd_pcm_period_elapsed(substream);
139 dev_dbg(pcm->dev, "period elapsed %x %x\n",
140 s6dmac_cur_src(DMA_MASK_DMAC(channel),
141 DMA_INDEX_CHNL(channel)),
142 s6dmac_cur_dst(DMA_MASK_DMAC(channel),
143 DMA_INDEX_CHNL(channel)));
144 prtd = substream->runtime->private_data;
145 spin_lock(&prtd->lock);
146 s6000_pcm_enqueue_dma(substream);
147 spin_unlock(&prtd->lock);
148 }
149 }
150
151 if (unlikely(pending & ~7)) {
152 if (pending & (1 << 3))
153 printk(KERN_WARNING
154 "s6000-pcm: DMA %x Underflow\n",
155 channel);
156 if (pending & (1 << 4))
157 printk(KERN_WARNING
158 "s6000-pcm: DMA %x Overflow\n",
159 channel);
160 if (pending & 0x1e0)
161 printk(KERN_WARNING
162 "s6000-pcm: DMA %x Master Error "
163 "(mask %x)\n",
164 channel, pending >> 5);
165
166 }
167 }
168
169 return ret;
170}
171
172static int s6000_pcm_start(struct snd_pcm_substream *substream)
173{
174 struct s6000_runtime_data *prtd = substream->runtime->private_data;
175 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
176 struct s6000_pcm_dma_params *par;
177 unsigned long flags;
178 int srcinc;
179 u32 dma;
180
181 par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
182
183 spin_lock_irqsave(&prtd->lock, flags);
184
185 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
186 srcinc = 1;
187 dma = par->dma_out;
188 } else {
189 srcinc = 0;
190 dma = par->dma_in;
191 }
192 s6dmac_enable_chan(DMA_MASK_DMAC(dma), DMA_INDEX_CHNL(dma),
193 1 /* priority 1 (0 is max) */,
194 0 /* peripheral requests w/o xfer length mode */,
195 srcinc /* source address increment */,
196 srcinc^1 /* destination address increment */,
197 0 /* chunksize 0 (skip impossible on this dma) */,
198 0 /* source skip after chunk (impossible) */,
199 0 /* destination skip after chunk (impossible) */,
200 4 /* 16 byte burst size */,
201 -1 /* don't conserve bandwidth */,
202 0 /* low watermark irq descriptor threshold */,
203 0 /* disable hardware timestamps */,
204 1 /* enable channel */);
205
206 s6000_pcm_enqueue_dma(substream);
207 s6000_pcm_enqueue_dma(substream);
208
209 spin_unlock_irqrestore(&prtd->lock, flags);
210
211 return 0;
212}
213
214static int s6000_pcm_stop(struct snd_pcm_substream *substream)
215{
216 struct s6000_runtime_data *prtd = substream->runtime->private_data;
217 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
218 struct s6000_pcm_dma_params *par;
219 unsigned long flags;
220 u32 channel;
221
222 par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
223
224 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
225 channel = par->dma_out;
226 else
227 channel = par->dma_in;
228
229 s6dmac_set_terminal_count(DMA_MASK_DMAC(channel),
230 DMA_INDEX_CHNL(channel), 0);
231
232 spin_lock_irqsave(&prtd->lock, flags);
233
234 s6dmac_disable_chan(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel));
235
236 spin_unlock_irqrestore(&prtd->lock, flags);
237
238 return 0;
239}
240
241static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
242{
243 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
244 struct s6000_pcm_dma_params *par;
245 int ret;
246
247 par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
248
249 ret = par->trigger(substream, cmd, 0);
250 if (ret < 0)
251 return ret;
252
253 switch (cmd) {
254 case SNDRV_PCM_TRIGGER_START:
255 case SNDRV_PCM_TRIGGER_RESUME:
256 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
257 ret = s6000_pcm_start(substream);
258 break;
259 case SNDRV_PCM_TRIGGER_STOP:
260 case SNDRV_PCM_TRIGGER_SUSPEND:
261 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
262 ret = s6000_pcm_stop(substream);
263 break;
264 default:
265 ret = -EINVAL;
266 }
267 if (ret < 0)
268 return ret;
269
270 return par->trigger(substream, cmd, 1);
271}
272
273static int s6000_pcm_prepare(struct snd_pcm_substream *substream)
274{
275 struct s6000_runtime_data *prtd = substream->runtime->private_data;
276
277 prtd->period = 0;
278
279 return 0;
280}
281
282static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)
283{
284 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
285 struct s6000_pcm_dma_params *par;
286 struct snd_pcm_runtime *runtime = substream->runtime;
287 struct s6000_runtime_data *prtd = runtime->private_data;
288 unsigned long flags;
289 unsigned int offset;
290 dma_addr_t count;
291
292 par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
293
294 spin_lock_irqsave(&prtd->lock, flags);
295
296 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
297 count = s6dmac_cur_src(DMA_MASK_DMAC(par->dma_out),
298 DMA_INDEX_CHNL(par->dma_out));
299 else
300 count = s6dmac_cur_dst(DMA_MASK_DMAC(par->dma_in),
301 DMA_INDEX_CHNL(par->dma_in));
302
303 count -= runtime->dma_addr;
304
305 spin_unlock_irqrestore(&prtd->lock, flags);
306
307 offset = bytes_to_frames(runtime, count);
308 if (unlikely(offset >= runtime->buffer_size))
309 offset = 0;
310
311 return offset;
312}
313
314static int s6000_pcm_open(struct snd_pcm_substream *substream)
315{
316 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
317 struct s6000_pcm_dma_params *par;
318 struct snd_pcm_runtime *runtime = substream->runtime;
319 struct s6000_runtime_data *prtd;
320 int ret;
321
322 par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
323 snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware);
324
325 ret = snd_pcm_hw_constraint_step(runtime, 0,
326 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16);
327 if (ret < 0)
328 return ret;
329 ret = snd_pcm_hw_constraint_step(runtime, 0,
330 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
331 if (ret < 0)
332 return ret;
333 ret = snd_pcm_hw_constraint_integer(runtime,
334 SNDRV_PCM_HW_PARAM_PERIODS);
335 if (ret < 0)
336 return ret;
337
338 if (par->same_rate) {
339 int rate;
340 spin_lock(&par->lock); /* needed? */
341 rate = par->rate;
342 spin_unlock(&par->lock);
343 if (rate != -1) {
344 ret = snd_pcm_hw_constraint_minmax(runtime,
345 SNDRV_PCM_HW_PARAM_RATE,
346 rate, rate);
347 if (ret < 0)
348 return ret;
349 }
350 }
351
352 prtd = kzalloc(sizeof(struct s6000_runtime_data), GFP_KERNEL);
353 if (prtd == NULL)
354 return -ENOMEM;
355
356 spin_lock_init(&prtd->lock);
357
358 runtime->private_data = prtd;
359
360 return 0;
361}
362
363static int s6000_pcm_close(struct snd_pcm_substream *substream)
364{
365 struct snd_pcm_runtime *runtime = substream->runtime;
366 struct s6000_runtime_data *prtd = runtime->private_data;
367
368 kfree(prtd);
369
370 return 0;
371}
372
373static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,
374 struct snd_pcm_hw_params *hw_params)
375{
376 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
377 struct s6000_pcm_dma_params *par;
378 int ret;
379 ret = snd_pcm_lib_malloc_pages(substream,
380 params_buffer_bytes(hw_params));
381 if (ret < 0) {
382 printk(KERN_WARNING "s6000-pcm: allocation of memory failed\n");
383 return ret;
384 }
385
386 par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
387
388 if (par->same_rate) {
389 spin_lock(&par->lock);
390 if (par->rate == -1 ||
391 !(par->in_use & ~(1 << substream->stream))) {
392 par->rate = params_rate(hw_params);
393 par->in_use |= 1 << substream->stream;
394 } else if (params_rate(hw_params) != par->rate) {
395 snd_pcm_lib_free_pages(substream);
396 par->in_use &= ~(1 << substream->stream);
397 ret = -EBUSY;
398 }
399 spin_unlock(&par->lock);
400 }
401 return ret;
402}
403
404static int s6000_pcm_hw_free(struct snd_pcm_substream *substream)
405{
406 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
407 struct s6000_pcm_dma_params *par =
408 snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
409
410 spin_lock(&par->lock);
411 par->in_use &= ~(1 << substream->stream);
412 if (!par->in_use)
413 par->rate = -1;
414 spin_unlock(&par->lock);
415
416 return snd_pcm_lib_free_pages(substream);
417}
418
419static struct snd_pcm_ops s6000_pcm_ops = {
420 .open = s6000_pcm_open,
421 .close = s6000_pcm_close,
422 .ioctl = snd_pcm_lib_ioctl,
423 .hw_params = s6000_pcm_hw_params,
424 .hw_free = s6000_pcm_hw_free,
425 .trigger = s6000_pcm_trigger,
426 .prepare = s6000_pcm_prepare,
427 .pointer = s6000_pcm_pointer,
428};
429
430static void s6000_pcm_free(struct snd_pcm *pcm)
431{
432 struct snd_soc_pcm_runtime *runtime = pcm->private_data;
433 struct s6000_pcm_dma_params *params =
434 snd_soc_dai_get_dma_data(runtime->cpu_dai,
435 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
436
437 free_irq(params->irq, pcm);
438 snd_pcm_lib_preallocate_free_for_all(pcm);
439}
440
441static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime)
442{
443 struct snd_card *card = runtime->card->snd_card;
444 struct snd_pcm *pcm = runtime->pcm;
445 struct s6000_pcm_dma_params *params;
446 int res;
447
448 params = snd_soc_dai_get_dma_data(runtime->cpu_dai,
449 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
450
451 res = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
452 if (res)
453 return res;
454
455 if (params->dma_in) {
456 s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in),
457 DMA_INDEX_CHNL(params->dma_in));
458 s6dmac_int_sources(DMA_MASK_DMAC(params->dma_in),
459 DMA_INDEX_CHNL(params->dma_in));
460 }
461
462 if (params->dma_out) {
463 s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_out),
464 DMA_INDEX_CHNL(params->dma_out));
465 s6dmac_int_sources(DMA_MASK_DMAC(params->dma_out),
466 DMA_INDEX_CHNL(params->dma_out));
467 }
468
469 res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED,
470 "s6000-audio", pcm);
471 if (res) {
472 printk(KERN_ERR "s6000-pcm couldn't get IRQ\n");
473 return res;
474 }
475
476 res = snd_pcm_lib_preallocate_pages_for_all(pcm,
477 SNDRV_DMA_TYPE_DEV,
478 card->dev,
479 S6_PCM_PREALLOCATE_SIZE,
480 S6_PCM_PREALLOCATE_MAX);
481 if (res)
482 printk(KERN_WARNING "s6000-pcm: preallocation failed\n");
483
484 spin_lock_init(&params->lock);
485 params->in_use = 0;
486 params->rate = -1;
487 return 0;
488}
489
490static struct snd_soc_platform_driver s6000_soc_platform = {
491 .ops = &s6000_pcm_ops,
492 .pcm_new = s6000_pcm_new,
493 .pcm_free = s6000_pcm_free,
494};
495
496static int s6000_soc_platform_probe(struct platform_device *pdev)
497{
498 return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform);
499}
500
501static int s6000_soc_platform_remove(struct platform_device *pdev)
502{
503 snd_soc_unregister_platform(&pdev->dev);
504 return 0;
505}
506
507static struct platform_driver s6000_pcm_driver = {
508 .driver = {
509 .name = "s6000-pcm-audio",
510 .owner = THIS_MODULE,
511 },
512
513 .probe = s6000_soc_platform_probe,
514 .remove = s6000_soc_platform_remove,
515};
516
517module_platform_driver(s6000_pcm_driver);
518
519MODULE_AUTHOR("Daniel Gloeckner");
520MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module");
521MODULE_LICENSE("GPL");
diff --git a/sound/soc/s6000/s6000-pcm.h b/sound/soc/s6000/s6000-pcm.h
deleted file mode 100644
index 09d9b883e58b..000000000000
--- a/sound/soc/s6000/s6000-pcm.h
+++ /dev/null
@@ -1,33 +0,0 @@
1/*
2 * ALSA PCM interface for the Stretch s6000 family
3 *
4 * Author: Daniel Gloeckner, <dg@emlix.com>
5 * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef _S6000_PCM_H
13#define _S6000_PCM_H
14
15struct snd_soc_dai;
16struct snd_pcm_substream;
17
18struct s6000_pcm_dma_params {
19 unsigned int (*check_xrun)(struct snd_soc_dai *cpu_dai);
20 int (*trigger)(struct snd_pcm_substream *substream, int cmd, int after);
21 dma_addr_t sif_in;
22 dma_addr_t sif_out;
23 u32 dma_in;
24 u32 dma_out;
25 int irq;
26 int same_rate;
27
28 spinlock_t lock;
29 int in_use;
30 int rate;
31};
32
33#endif
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c
deleted file mode 100644
index 3510c01f8a6a..000000000000
--- a/sound/soc/s6000/s6105-ipcam.c
+++ /dev/null
@@ -1,221 +0,0 @@
1/*
2 * ASoC driver for Stretch s6105 IP camera platform
3 *
4 * Author: Daniel Gloeckner, <dg@emlix.com>
5 * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/timer.h>
15#include <linux/interrupt.h>
16#include <linux/platform_device.h>
17#include <linux/i2c.h>
18#include <sound/core.h>
19#include <sound/pcm.h>
20#include <sound/soc.h>
21
22#include "s6000-pcm.h"
23#include "s6000-i2s.h"
24
25#define S6105_CAM_CODEC_CLOCK 12288000
26
27static int s6105_hw_params(struct snd_pcm_substream *substream,
28 struct snd_pcm_hw_params *params)
29{
30 struct snd_soc_pcm_runtime *rtd = substream->private_data;
31 struct snd_soc_dai *codec_dai = rtd->codec_dai;
32 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
33 int ret = 0;
34
35 /* set codec DAI configuration */
36 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
37 SND_SOC_DAIFMT_CBM_CFM);
38 if (ret < 0)
39 return ret;
40
41 /* set cpu DAI configuration */
42 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM |
43 SND_SOC_DAIFMT_NB_NF);
44 if (ret < 0)
45 return ret;
46
47 /* set the codec system clock */
48 ret = snd_soc_dai_set_sysclk(codec_dai, 0, S6105_CAM_CODEC_CLOCK,
49 SND_SOC_CLOCK_OUT);
50 if (ret < 0)
51 return ret;
52
53 return 0;
54}
55
56static struct snd_soc_ops s6105_ops = {
57 .hw_params = s6105_hw_params,
58};
59
60/* s6105 machine dapm widgets */
61static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
62 SND_SOC_DAPM_LINE("Audio Out Differential", NULL),
63 SND_SOC_DAPM_LINE("Audio Out Stereo", NULL),
64 SND_SOC_DAPM_LINE("Audio In", NULL),
65};
66
67/* s6105 machine audio_mapnections to the codec pins */
68static const struct snd_soc_dapm_route audio_map[] = {
69 /* Audio Out connected to HPLOUT, HPLCOM, HPROUT */
70 {"Audio Out Differential", NULL, "HPLOUT"},
71 {"Audio Out Differential", NULL, "HPLCOM"},
72 {"Audio Out Stereo", NULL, "HPLOUT"},
73 {"Audio Out Stereo", NULL, "HPROUT"},
74
75 /* Audio In connected to LINE1L, LINE1R */
76 {"LINE1L", NULL, "Audio In"},
77 {"LINE1R", NULL, "Audio In"},
78};
79
80static int output_type_info(struct snd_kcontrol *kcontrol,
81 struct snd_ctl_elem_info *uinfo)
82{
83 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
84 uinfo->count = 1;
85 uinfo->value.enumerated.items = 2;
86 if (uinfo->value.enumerated.item) {
87 uinfo->value.enumerated.item = 1;
88 strcpy(uinfo->value.enumerated.name, "HPLOUT/HPROUT");
89 } else {
90 strcpy(uinfo->value.enumerated.name, "HPLOUT/HPLCOM");
91 }
92 return 0;
93}
94
95static int output_type_get(struct snd_kcontrol *kcontrol,
96 struct snd_ctl_elem_value *ucontrol)
97{
98 ucontrol->value.enumerated.item[0] = kcontrol->private_value;
99 return 0;
100}
101
102static int output_type_put(struct snd_kcontrol *kcontrol,
103 struct snd_ctl_elem_value *ucontrol)
104{
105 struct snd_soc_card *card = kcontrol->private_data;
106 struct snd_soc_dapm_context *dapm = &card->dapm;
107 unsigned int val = (ucontrol->value.enumerated.item[0] != 0);
108 char *differential = "Audio Out Differential";
109 char *stereo = "Audio Out Stereo";
110
111 if (kcontrol->private_value == val)
112 return 0;
113 kcontrol->private_value = val;
114 snd_soc_dapm_disable_pin(dapm, val ? differential : stereo);
115 snd_soc_dapm_sync(dapm);
116 snd_soc_dapm_enable_pin(dapm, val ? stereo : differential);
117 snd_soc_dapm_sync(dapm);
118
119 return 1;
120}
121
122static const struct snd_kcontrol_new audio_out_mux = {
123 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
124 .name = "Master Output Mux",
125 .index = 0,
126 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
127 .info = output_type_info,
128 .get = output_type_get,
129 .put = output_type_put,
130 .private_value = 1 /* default to stereo */
131};
132
133/* Logic for a aic3x as connected on the s6105 ip camera ref design */
134static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
135{
136 struct snd_soc_card *card = rtd->card;
137
138 /* must correspond to audio_out_mux.private_value initializer */
139 snd_soc_dapm_disable_pin(&card->dapm, "Audio Out Differential");
140
141 snd_ctl_add(card->snd_card, snd_ctl_new1(&audio_out_mux, card));
142
143 return 0;
144}
145
146/* s6105 digital audio interface glue - connects codec <--> CPU */
147static struct snd_soc_dai_link s6105_dai = {
148 .name = "TLV320AIC31",
149 .stream_name = "AIC31",
150 .cpu_dai_name = "s6000-i2s",
151 .codec_dai_name = "tlv320aic3x-hifi",
152 .platform_name = "s6000-pcm-audio",
153 .codec_name = "tlv320aic3x-codec.0-001a",
154 .init = s6105_aic3x_init,
155 .ops = &s6105_ops,
156};
157
158/* s6105 audio machine driver */
159static struct snd_soc_card snd_soc_card_s6105 = {
160 .name = "Stretch IP Camera",
161 .owner = THIS_MODULE,
162 .dai_link = &s6105_dai,
163 .num_links = 1,
164
165 .dapm_widgets = aic3x_dapm_widgets,
166 .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets),
167 .dapm_routes = audio_map,
168 .num_dapm_routes = ARRAY_SIZE(audio_map),
169 .fully_routed = true,
170};
171
172static struct s6000_snd_platform_data s6105_snd_data __initdata = {
173 .wide = 0,
174 .channel_in = 0,
175 .channel_out = 1,
176 .lines_in = 1,
177 .lines_out = 1,
178 .same_rate = 1,
179};
180
181static struct platform_device *s6105_snd_device;
182
183/* temporary i2c device creation until this can be moved into the machine
184 * support file.
185*/
186static struct i2c_board_info i2c_device[] = {
187 { I2C_BOARD_INFO("tlv320aic33", 0x18), }
188};
189
190static int __init s6105_init(void)
191{
192 int ret;
193
194 i2c_register_board_info(0, i2c_device, ARRAY_SIZE(i2c_device));
195
196 s6105_snd_device = platform_device_alloc("soc-audio", -1);
197 if (!s6105_snd_device)
198 return -ENOMEM;
199
200 platform_set_drvdata(s6105_snd_device, &snd_soc_card_s6105);
201 platform_device_add_data(s6105_snd_device, &s6105_snd_data,
202 sizeof(s6105_snd_data));
203
204 ret = platform_device_add(s6105_snd_device);
205 if (ret)
206 platform_device_put(s6105_snd_device);
207
208 return ret;
209}
210
211static void __exit s6105_exit(void)
212{
213 platform_device_unregister(s6105_snd_device);
214}
215
216module_init(s6105_init);
217module_exit(s6105_exit);
218
219MODULE_AUTHOR("Daniel Gloeckner");
220MODULE_DESCRIPTION("Stretch s6105 IP camera ASoC driver");
221MODULE_LICENSE("GPL");