Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+100 -1485
+10
Documentation/devicetree/bindings/sound/sgtl5000.txt
··· 7 7 8 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 + 14 + Optional properties: 15 + 16 + - VDDD-supply : the regulator provider of VDDD 17 + 10 18 Example: 11 19 12 20 codec: sgtl5000@0a { 13 21 compatible = "fsl,sgtl5000"; 14 22 reg = <0x0a>; 15 23 clocks = <&clks 150>; 24 + VDDA-supply = <&reg_3p3v>; 25 + VDDIO-supply = <&reg_3p3v>; 16 26 };
+2
sound/core/pcm_compat.c
··· 210 210 if (err < 0) 211 211 return err; 212 212 213 + if (clear_user(src, sizeof(*src))) 214 + return -EFAULT; 213 215 if (put_user(status.state, &src->state) || 214 216 compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || 215 217 compat_put_timespec(&status.tstamp, &src->tstamp) ||
+49 -15
sound/firewire/bebob/bebob_focusrite.c
··· 27 27 #define SAFFIRE_CLOCK_SOURCE_INTERNAL 0 28 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 31 #define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 32 + #define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */ 32 33 #define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 33 - #define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 34 - #define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 34 + #define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 /* not used on s.pro. 10 */ 35 + #define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 /* not used on s.pro. 10 */ 35 36 #define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5 37 + #define SAFFIREPRO_CLOCK_SOURCE_COUNT 6 36 38 37 39 /* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */ 38 40 #define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4 ··· 103 101 &data, sizeof(__be32), 0); 104 102 } 105 103 106 - static char *const saffirepro_26_clk_src_labels[] = { 107 - SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock" 108 - }; 109 - 110 104 static char *const saffirepro_10_clk_src_labels[] = { 111 105 SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock" 112 106 }; 107 + static char *const saffirepro_26_clk_src_labels[] = { 108 + SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock" 109 + }; 110 + /* Value maps between registers and labels for SaffirePro 10/26. */ 111 + static const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = { 112 + /* SaffirePro 10 */ 113 + [0] = { 114 + [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, 115 + [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ 116 + [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, 117 + [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = -1, /* not supported */ 118 + [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = -1, /* not supported */ 119 + [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 2, 120 + }, 121 + /* SaffirePro 26 */ 122 + [1] = { 123 + [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, 124 + [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ 125 + [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, 126 + [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = 2, 127 + [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = 3, 128 + [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 4, 129 + } 130 + }; 131 + 113 132 static int 114 133 saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate) 115 134 { ··· 161 138 162 139 return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id); 163 140 } 141 + 142 + /* 143 + * query hardware for current clock source, return our internally 144 + * used clock index in *id, depending on hardware. 145 + */ 164 146 static int 165 147 saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) 166 148 { 167 149 int err; 168 - u32 value; 150 + u32 value; /* clock source read from hw register */ 151 + const signed char *map; 169 152 170 153 err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value); 171 154 if (err < 0) 172 155 goto end; 173 156 174 - if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) { 175 - if (value == SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK) 176 - *id = 2; 177 - else if (value == SAFFIREPRO_CLOCK_SOURCE_SPDIF) 178 - *id = 1; 179 - } else if (value > 1) { 180 - *id = value - 1; 157 + /* depending on hardware, use a different mapping */ 158 + if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) 159 + map = saffirepro_clk_maps[0]; 160 + else 161 + map = saffirepro_clk_maps[1]; 162 + 163 + /* In a case that this driver cannot handle the value of register. */ 164 + if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) { 165 + err = -EIO; 166 + goto end; 181 167 } 168 + 169 + *id = (unsigned int)map[value]; 182 170 end: 183 171 return err; 184 172 }
+15 -3
sound/firewire/bebob/bebob_stream.c
··· 129 129 /* 1.The device has its own operation to switch source of clock */ 130 130 if (clk_spec) { 131 131 err = clk_spec->get(bebob, &id); 132 - if (err < 0) 132 + if (err < 0) { 133 133 dev_err(&bebob->unit->device, 134 134 "fail to get clock source: %d\n", err); 135 - else if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL, 136 - strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0) 135 + goto end; 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 148 *internal = true; 149 + 138 150 goto end; 139 151 } 140 152
+6 -1
sound/firewire/bebob/bebob_terratec.c
··· 24 24 if (err < 0) 25 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; 28 33 end: 29 34 return err; 30 35 }
+4 -4
sound/pci/ad1889.c
··· 681 681 682 682 /* WARQ is at offset 12 */ 683 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 685 tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; 686 686 687 687 snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp, ··· 693 693 694 694 /* SYRQ is at offset 4 */ 695 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 697 tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; 698 698 699 699 snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp, ··· 709 709 710 710 /* ACRQ is at offset 4 */ 711 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 713 tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; 714 714 715 715 snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp, ··· 720 720 721 721 /* RERQ is at offset 12 */ 722 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 724 tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; 725 725 726 726 snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp,
+3 -1
sound/pci/hda/hda_intel.c
··· 374 374 #ifdef CONFIG_SND_DMA_SGBUF 375 375 if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { 376 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 379 if (on) 378 380 set_pages_array_wc(sgbuf->page_table, sgbuf->pages); 379 381 else ··· 1771 1769 #ifdef CONFIG_X86 1772 1770 struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 1773 1771 struct azx *chip = apcm->chip; 1774 - if (!azx_snoop(chip)) 1772 + if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA) 1775 1773 area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); 1776 1774 #endif 1777 1775 }
+4 -2
sound/pci/hda/patch_realtek.c
··· 2675 2675 2676 2676 static struct coef_fw alc282_coefs[] = { 2677 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 2679 WRITE_COEF(0x07, 0x0200), /* DMIC control */ 2680 2680 UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ 2681 2681 UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ ··· 2786 2786 2787 2787 static struct coef_fw alc283_coefs[] = { 2788 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 2790 WRITE_COEF(0x07, 0x0200), /* DMIC control */ 2791 2791 UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ 2792 2792 UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ ··· 2817 2817 UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */ 2818 2818 UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */ 2819 2819 WRITE_COEF(0x37, 0xfc06), /* Class D amp control */ 2820 + UPDATE_COEF(0x1b, 0x8000, 0), /* HP JD control */ 2820 2821 {} 2821 2822 }; 2822 2823 ··· 5923 5922 SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), 5924 5923 SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), 5925 5924 SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), 5925 + SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), 5926 5926 SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), 5927 5927 SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A), 5928 5928 SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
-1
sound/soc/Kconfig
··· 49 49 source "sound/soc/pxa/Kconfig" 50 50 source "sound/soc/rockchip/Kconfig" 51 51 source "sound/soc/samsung/Kconfig" 52 - source "sound/soc/s6000/Kconfig" 53 52 source "sound/soc/sh/Kconfig" 54 53 source "sound/soc/sirf/Kconfig" 55 54 source "sound/soc/spear/Kconfig"
-1
sound/soc/Makefile
··· 26 26 obj-$(CONFIG_SND_SOC) += pxa/ 27 27 obj-$(CONFIG_SND_SOC) += rockchip/ 28 28 obj-$(CONFIG_SND_SOC) += samsung/ 29 - obj-$(CONFIG_SND_SOC) += s6000/ 30 29 obj-$(CONFIG_SND_SOC) += sh/ 31 30 obj-$(CONFIG_SND_SOC) += sirf/ 32 31 obj-$(CONFIG_SND_SOC) += spear/
+4
sound/soc/codecs/adau1761.c
··· 405 405 2, 0, NULL, 0), 406 406 407 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 410 SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1, 410 411 0, 0, NULL, 0), ··· 436 435 { "Slew Clock", NULL, "Digital Clock 0" }, 437 436 { "Right Playback Mixer", NULL, "Slew Clock" }, 438 437 { "Left Playback Mixer", NULL, "Slew Clock" }, 438 + 439 + { "Left Input Mixer", NULL, "ALC Clock" }, 440 + { "Right Input Mixer", NULL, "ALC Clock" }, 439 441 440 442 { "Digital Clock 0", NULL, "SYSCLK" }, 441 443 { "Digital Clock 1", NULL, "SYSCLK" },
+1 -1
sound/soc/fsl/fsl_asrc.c
··· 792 792 return -ENOMEM; 793 793 794 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 797 /* Get the addresses and IRQ */ 798 798 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+1 -1
sound/soc/fsl/fsl_esai.c
··· 734 734 return -ENOMEM; 735 735 736 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 739 /* Get the addresses and IRQ */ 740 740 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+1 -3
sound/soc/intel/sst-haswell-pcm.c
··· 691 691 } 692 692 693 693 #define HSW_FORMATS \ 694 - (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ 695 - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\ 696 - SNDRV_PCM_FMTBIT_S8) 694 + (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) 697 695 698 696 static struct snd_soc_dai_driver hsw_dais[] = { 699 697 {
-26
sound/soc/s6000/Kconfig
··· 1 - config 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 - 11 - config SND_S6000_SOC_PCM 12 - tristate 13 - 14 - config SND_S6000_SOC_I2S 15 - tristate 16 - 17 - config 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.
-11
sound/soc/s6000/Makefile
··· 1 - # s6000 Platform Support 2 - snd-soc-s6000-objs := s6000-pcm.o 3 - snd-soc-s6000-i2s-objs := s6000-i2s.o 4 - 5 - obj-$(CONFIG_SND_S6000_SOC_PCM) += snd-soc-s6000.o 6 - obj-$(CONFIG_SND_S6000_SOC_I2S) += snd-soc-s6000-i2s.o 7 - 8 - # s6105 Machine Support 9 - snd-soc-s6ipcam-objs := s6105-ipcam.o 10 - 11 - obj-$(CONFIG_SND_S6000_SOC_S6IPCAM) += snd-soc-s6ipcam.o
-617
sound/soc/s6000/s6000-i2s.c
··· 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 - 30 - struct 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 - 92 - static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val) 93 - { 94 - writel(val, dev->scbbase + reg); 95 - } 96 - 97 - static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg) 98 - { 99 - return readl(dev->scbbase + reg); 100 - } 101 - 102 - static 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 - 109 - static 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 - 135 - static 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 - 140 - static 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 - 152 - static 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 - 164 - static 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 - 183 - static 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 - 195 - static 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 - 215 - static 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 - 232 - static 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 - 274 - static 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 - 286 - static 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 - 329 - static 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 - 411 - static 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 - 417 - static 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 - 438 - static const struct snd_soc_component_driver s6000_i2s_component = { 439 - .name = "s6000-i2s", 440 - }; 441 - 442 - static 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 - 556 - err_release_dev: 557 - kfree(dev); 558 - err_release_dma2: 559 - if (dma2) 560 - release_mem_region(dma2->start, resource_size(dma2)); 561 - err_release_dma1: 562 - release_mem_region(dma1->start, resource_size(dma1)); 563 - err_release_sif: 564 - release_mem_region(sifmem->start, resource_size(sifmem)); 565 - err_release_map: 566 - iounmap(mmio); 567 - err_release_scb: 568 - release_mem_region(scbmem->start, resource_size(scbmem)); 569 - err_release_none: 570 - return ret; 571 - } 572 - 573 - static 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 - 604 - static 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 - 613 - module_platform_driver(s6000_i2s_driver); 614 - 615 - MODULE_AUTHOR("Daniel Gloeckner"); 616 - MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface"); 617 - MODULE_LICENSE("GPL");
-23
sound/soc/s6000/s6000-i2s.h
··· 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 - 15 - struct 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
-521
sound/soc/s6000/s6000-pcm.c
··· 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 - 32 - static 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 - 44 - struct s6000_runtime_data { 45 - spinlock_t lock; 46 - int period; /* current DMA period */ 47 - }; 48 - 49 - static 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 - 96 - static 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 - 172 - static 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 - 214 - static 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 - 241 - static 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 - 273 - static 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 - 282 - static 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 - 314 - static 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 - 363 - static 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 - 373 - static 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 - 404 - static 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 - 419 - static 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 - 430 - static 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 - 441 - static 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 - 490 - static 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 - 496 - static int s6000_soc_platform_probe(struct platform_device *pdev) 497 - { 498 - return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform); 499 - } 500 - 501 - static int s6000_soc_platform_remove(struct platform_device *pdev) 502 - { 503 - snd_soc_unregister_platform(&pdev->dev); 504 - return 0; 505 - } 506 - 507 - static 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 - 517 - module_platform_driver(s6000_pcm_driver); 518 - 519 - MODULE_AUTHOR("Daniel Gloeckner"); 520 - MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module"); 521 - MODULE_LICENSE("GPL");
-33
sound/soc/s6000/s6000-pcm.h
··· 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 - 15 - struct snd_soc_dai; 16 - struct snd_pcm_substream; 17 - 18 - struct 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
-221
sound/soc/s6000/s6105-ipcam.c
··· 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 - 27 - static 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 - 56 - static struct snd_soc_ops s6105_ops = { 57 - .hw_params = s6105_hw_params, 58 - }; 59 - 60 - /* s6105 machine dapm widgets */ 61 - static 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 */ 68 - static 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 - 80 - static 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 - 95 - static 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 - 102 - static 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 - 122 - static 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 */ 134 - static 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 */ 147 - static 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 */ 159 - static 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 - 172 - static 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 - 181 - static struct platform_device *s6105_snd_device; 182 - 183 - /* temporary i2c device creation until this can be moved into the machine 184 - * support file. 185 - */ 186 - static struct i2c_board_info i2c_device[] = { 187 - { I2C_BOARD_INFO("tlv320aic33", 0x18), } 188 - }; 189 - 190 - static 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 - 211 - static void __exit s6105_exit(void) 212 - { 213 - platform_device_unregister(s6105_snd_device); 214 - } 215 - 216 - module_init(s6105_init); 217 - module_exit(s6105_exit); 218 - 219 - MODULE_AUTHOR("Daniel Gloeckner"); 220 - MODULE_DESCRIPTION("Stretch s6105 IP camera ASoC driver"); 221 - MODULE_LICENSE("GPL");